diff --git a/.claude/settings.json b/.claude/settings.json
index 3882ef3e7..8b1378917 100644
--- a/.claude/settings.json
+++ b/.claude/settings.json
@@ -1,8 +1 @@
-{
- "hooks": {
- "userPromptSubmitHook": {
- "command": "echo '\n\n---\n\nš TESTING REMINDER: After completing this task, create and run E2E tests to verify the changes work correctly. Tests should go in tests/e2e/ using Playwright.\n\n---\n'",
- "description": "Remind Claude to create E2E tests for all changes"
- }
- }
-}
+
diff --git a/.github/dependatbaot.yml b/.github/dependatbaot.yml
new file mode 100644
index 000000000..5e2280b62
--- /dev/null
+++ b/.github/dependatbaot.yml
@@ -0,0 +1,40 @@
+# Dependabot ā Automated dependency update PRs
+# https://docs.github.com/en/code-security/dependabot
+#
+# GitHub reads this file automatically ā no workflow, no secrets needed.
+# Dependabot will open PRs for:
+# 1. npm packages with known vulnerabilities (security updates ā always immediate)
+# 2. npm packages with new versions (version updates ā weekly batched)
+# 3. GitHub Actions with new versions (keeps CI workflows current)
+
+version: 2
+
+updates:
+ # npm dependencies
+ - package-ecosystem: "npm"
+ directory: "/"
+ schedule:
+ interval: "weekly"
+ day: "monday"
+ # Group minor + patch updates into a single PR to reduce noise
+ groups:
+ minor-and-patch:
+ update-types:
+ - "minor"
+ - "patch"
+ labels:
+ - "dependencies"
+ # Limit open PRs to avoid overwhelming the PR list
+ open-pull-requests-limit: 10
+ # Security updates are always immediate regardless of schedule
+
+ # GitHub Actions versions
+ - package-ecosystem: "github-actions"
+ directory: "/"
+ schedule:
+ interval: "weekly"
+ day: "monday"
+ labels:
+ - "dependencies"
+ - "ci"
+ open-pull-requests-limit: 5
diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml
new file mode 100644
index 000000000..862834718
--- /dev/null
+++ b/.github/workflows/codeql.yml
@@ -0,0 +1,58 @@
+# GitHub CodeQL ā Static Application Security Testing (SAST)
+# https://github.com/github/codeql-action
+#
+# Analyzes JavaScript/TypeScript for:
+# - SQL injection patterns
+# - Prototype pollution
+# - Path traversal
+# - Cross-site scripting (XSS)
+# - Insecure cryptography
+# - Regular expression denial of service (ReDoS)
+# - Missing authentication / authorization
+# - Hardcoded credentials
+# - And 100+ more security rules
+#
+# Results appear in GitHub Security tab ā Code Scanning Alerts.
+# Free for public repositories.
+
+name: CodeQL
+
+on:
+ push:
+ branches: [ main ]
+ pull_request:
+ branches: [ main ]
+ schedule:
+ # Weekly on Wednesdays at 04:15 UTC (catches new CVE patterns in query packs)
+ - cron: '15 4 * * 3'
+
+jobs:
+ analyze:
+ name: Analyze JavaScript/TypeScript
+ runs-on: ubuntu-latest
+ timeout-minutes: 30
+
+ permissions:
+ security-events: write # Upload SARIF results to Code Scanning
+ actions: read # Read workflow details
+ contents: read # Read repo contents
+
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@v4
+
+ - name: Initialize CodeQL
+ uses: github/codeql-action/init@v3
+ with:
+ languages: javascript-typescript
+ build-mode: none
+
+ # security-and-quality includes all security queries PLUS code quality
+ # checks (dead code, unused variables, etc). Use 'security-extended'
+ # if you only want security findings without quality noise.
+ queries: security-and-quality
+
+ - name: Run CodeQL analysis
+ uses: github/codeql-action/analyze@v3
+ with:
+ category: "/language:javascript-typescript"
diff --git a/.github/workflows/pr-tests.yml b/.github/workflows/pr-tests.yml
index 332e92a68..08c1ab7f4 100644
--- a/.github/workflows/pr-tests.yml
+++ b/.github/workflows/pr-tests.yml
@@ -24,16 +24,18 @@ jobs:
echo "PR Head Repo: ${{ github.event.pull_request.head.repo.full_name || 'N/A' }}"
echo "Is Fork: ${{ github.event.pull_request.head.repo.full_name != github.repository }}"
- test:
+ # Build, unit test, and deploy preview
+ build-and-deploy:
needs: authorize
runs-on: ubuntu-latest
- timeout-minutes: 60
+ timeout-minutes: 30
+ outputs:
+ preview_url: ${{ steps.deploy.outputs.preview_url }}
steps:
- name: Checkout code
uses: actions/checkout@v4
with:
- # For pull_request_target, we need to checkout the PR head
ref: ${{ github.event_name == 'pull_request_target' && github.event.pull_request.head.sha || github.sha }}
- name: Setup Node.js
@@ -45,6 +47,10 @@ jobs:
- name: Install dependencies
run: npm ci
+ - name: Security audit (npm)
+ run: npm audit --audit-level=high
+ continue-on-error: true
+
# TODO: Re-enable type checking after fixing remaining TypeScript errors
# Tracked in follow-up issue
# - name: Type check
@@ -65,7 +71,27 @@ jobs:
- name: Build core package
run: npm run build:core
- # Skip Cloudflare deployment and E2E tests for Dependabot PRs (no access to secrets)
+ - name: Configure wrangler for CI account
+ if: github.actor != 'dependabot[bot]'
+ run: |
+ cd my-sonicjs-app
+
+ # Remove hardcoded account_id ā the CLOUDFLARE_API_TOKEN is already
+ # scoped to the correct account, so wrangler derives it from the token.
+ # A wrong account_id in wrangler.toml causes auth failures on forks.
+ sed -i '/^account_id/d' wrangler.toml
+
+ # Remove KV namespace config if present ā the KV ID may reference a
+ # namespace on a different account. KV is optional for CI testing.
+ sed -i '/^\[\[kv_namespaces\]\]/,/^$/d' wrangler.toml
+ sed -i '/^binding = "CACHE_KV"/d' wrangler.toml
+ sed -i '/^id = "/d' wrangler.toml
+
+ echo "=== wrangler.toml configured for CI ==="
+ cat wrangler.toml
+ env:
+ CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
+
- name: Create fresh D1 database for PR
if: github.actor != 'dependabot[bot]'
id: create-db
@@ -135,15 +161,9 @@ jobs:
id: deploy
run: |
cd my-sonicjs-app
- # Deploy to preview with unique name based on PR/branch
- # Cloudflare Workers has a 54 character limit for script names with previews
- # Prefix "sonicjs-pr-" is 11 chars, so max branch name is 43 chars
BRANCH_NAME="${GITHUB_HEAD_REF:-${GITHUB_REF#refs/heads/}}"
- # Limit to 43 chars to allow for "sonicjs-pr-" prefix (11 chars) = 54 total
- # Remove trailing hyphens to avoid invalid worker names
SAFE_BRANCH=$(echo "$BRANCH_NAME" | sed 's/[^a-zA-Z0-9-]/-/g' | cut -c1-43 | sed 's/-*$//')
- # Deploy and capture the URL (don't exit on error)
set +e
echo "Deploying to preview environment: sonicjs-pr-${SAFE_BRANCH}"
DEPLOY_OUTPUT=$(npx wrangler deploy --name "sonicjs-pr-${SAFE_BRANCH}" 2>&1)
@@ -159,7 +179,6 @@ jobs:
exit 1
fi
- # Extract the URL from wrangler output
PREVIEW_URL=$(echo "$DEPLOY_OUTPUT" | grep -oP 'https://[^\s]+\.workers\.dev' | head -1)
if [ -z "$PREVIEW_URL" ]; then
@@ -188,30 +207,57 @@ jobs:
echo "Preview failed to become ready"
exit 1
+ # E2E tests ā split into 3 parallel shards for faster execution
+ e2e:
+ needs: build-and-deploy
+ if: github.actor != 'dependabot[bot]'
+ runs-on: ubuntu-latest
+ timeout-minutes: 45
+ strategy:
+ fail-fast: false
+ matrix:
+ shard: [1, 2, 3]
+
+ steps:
+ - name: Checkout code
+ uses: actions/checkout@v4
+ with:
+ ref: ${{ github.event_name == 'pull_request_target' && github.event.pull_request.head.sha || github.sha }}
+
+ - name: Setup Node.js
+ uses: actions/setup-node@v4
+ with:
+ node-version: '20'
+ cache: 'npm'
+
+ - name: Install dependencies
+ run: npm ci
+
+ - name: Build core package
+ run: npm run build:core
+
- name: Install Playwright browsers
- if: github.actor != 'dependabot[bot]'
run: npx playwright install --with-deps chromium
- - name: Run E2E tests against preview
- if: github.actor != 'dependabot[bot]'
- run: npm run e2e
+ - name: Run E2E tests (shard ${{ matrix.shard }}/3)
+ run: npm run e2e -- --shard=${{ matrix.shard }}/3
env:
CI: true
- BASE_URL: ${{ steps.deploy.outputs.preview_url }}
+ BASE_URL: ${{ needs.build-and-deploy.outputs.preview_url }}
- name: Upload test results
- if: always() && github.actor != 'dependabot[bot]'
+ if: always()
uses: actions/upload-artifact@v4
with:
- name: playwright-report
+ name: playwright-report-shard-${{ matrix.shard }}
path: playwright-report/
retention-days: 7
- name: Upload test videos
- if: always() && github.actor != 'dependabot[bot]'
+ if: always()
uses: actions/upload-artifact@v4
with:
- name: test-videos
+ name: test-videos-shard-${{ matrix.shard }}
path: |
test-results/**/*.webm
playwright-report/**/*.webm
diff --git a/.gitignore b/.gitignore
index 510ae0954..9e7705ab8 100644
--- a/.gitignore
+++ b/.gitignore
@@ -10,6 +10,7 @@ node_modules/
# Development
.wrangler/
.dev.vars
+.benchmark-temp/
# Environment variables
.env
diff --git a/my-sonicjs-app/src/index.ts b/my-sonicjs-app/src/index.ts
index 2a6729d06..183e6f486 100644
--- a/my-sonicjs-app/src/index.ts
+++ b/my-sonicjs-app/src/index.ts
@@ -5,7 +5,7 @@
*/
import { Hono } from 'hono'
-import { createSonicJSApp, registerCollections } from '@sonicjs-cms/core'
+import { createSonicJSApp, registerCollections, ExperimentService } from '@sonicjs-cms/core'
import type { SonicJSConfig } from '@sonicjs-cms/core'
// Import custom collections
@@ -53,4 +53,16 @@ if (contactFormPlugin.routes) {
// Mount core app last (catch-all)
app.route('/', coreApp)
-export default app
+export default {
+ fetch: app.fetch,
+ async scheduled(event: ScheduledEvent, env: any, ctx: ExecutionContext) {
+ const expService = new ExperimentService(env.DB, env.CACHE_KV, env.SEARCH_EXPERIMENTS)
+ const active = await expService.getActiveExperiment()
+ if (active) {
+ const result = await expService.evaluateExperiment(active.id)
+ if (result?.auto_completed) {
+ console.log('[Cron] Experiment ' + active.id + ' auto-completed: winner=' + result.winner)
+ }
+ }
+ }
+}
diff --git a/my-sonicjs-app/wrangler.toml b/my-sonicjs-app/wrangler.toml
index bd6623f50..601b0b155 100644
--- a/my-sonicjs-app/wrangler.toml
+++ b/my-sonicjs-app/wrangler.toml
@@ -4,33 +4,59 @@ compatibility_date = "2025-05-05"
compatibility_flags = ["nodejs_compat"]
# Cloudflare account
-account_id = "f9d6328dc3115e621758a741dda3d5c4"
+account_id = "f61c658f1de7911b0a529f38308adb21"
# Cloudflare Workers settings
workers_dev = true
-# D1 Database
-# Note: database_name and database_id are automatically updated by GitHub Actions
+# D1 Database ā persistent preview (not used by CI)
[[d1_databases]]
binding = "DB"
-database_name = "sonicjs-worktree-lane711-otp-email-branding"
-database_id = "68223153-215a-4c8f-a9bf-797f11236758"
+database_name = "sonicjs-preview-db"
+database_id = "0526b411-83d4-4e59-b23a-4e9f81011319"
migrations_dir = "./migrations"
-# R2 Bucket for media storage (using CI bucket)
+# R2 Bucket for media storage
[[r2_buckets]]
binding = "MEDIA_BUCKET"
-bucket_name = "sonicjs-ci-media"
+bucket_name = "sonicjs-preview-media"
-# KV Cache (using CI namespace)
+# KV Cache
[[kv_namespaces]]
binding = "CACHE_KV"
-id = "a16f8246fc294d809c90b0fb2df6d363"
+id = "6cd51bcf46d246798e54af26929134f9"
+
+# Workers AI (for embeddings)
+[ai]
+binding = "AI"
+
+# Vectorize index (for semantic/hybrid search)
+[[vectorize]]
+binding = "VECTORIZE_INDEX"
+index_name = "sonicjs-ai-search"
+
+# Vectorize index (for benchmark evaluation ā isolated from production data)
+[[vectorize]]
+binding = "VECTORIZE_BENCHMARK_INDEX"
+index_name = "sonicjs-benchmark"
# Environment variables
[vars]
ENVIRONMENT = "development"
+# Extended CPU time for benchmark seeding (57K+ docs) and large evaluations
+[limits]
+cpu_ms = 300000
+
+# Analytics Engine (for A/B experiment event tracking)
+[[analytics_engine_datasets]]
+binding = "SEARCH_EXPERIMENTS"
+dataset = "sonicjs_search_experiments"
+
+# Cron triggers (experiment auto-evaluation every 6 hours)
+[triggers]
+crons = ["0 */6 * * *"]
+
# Observability
[observability]
enabled = true
diff --git a/packages/core/dist/app-CYEm1ytG.d.cts b/packages/core/dist/app-3Zr8JaYf.d.cts
similarity index 94%
rename from packages/core/dist/app-CYEm1ytG.d.cts
rename to packages/core/dist/app-3Zr8JaYf.d.cts
index 165643841..2cb319eb9 100644
--- a/packages/core/dist/app-CYEm1ytG.d.cts
+++ b/packages/core/dist/app-3Zr8JaYf.d.cts
@@ -20,6 +20,7 @@ interface Bindings {
ENVIRONMENT?: string;
BUCKET_NAME?: string;
GOOGLE_MAPS_API_KEY?: string;
+ REQUIRE_API_KEY?: string;
}
interface Variables {
user?: {
@@ -32,6 +33,12 @@ interface Variables {
requestId?: string;
startTime?: number;
appVersion?: string;
+ apiKey?: {
+ id: string;
+ name: string;
+ scopes: string[];
+ userId: string;
+ };
}
interface SonicJSConfig {
collections?: {
diff --git a/packages/core/dist/app-CYEm1ytG.d.ts b/packages/core/dist/app-3Zr8JaYf.d.ts
similarity index 94%
rename from packages/core/dist/app-CYEm1ytG.d.ts
rename to packages/core/dist/app-3Zr8JaYf.d.ts
index 165643841..2cb319eb9 100644
--- a/packages/core/dist/app-CYEm1ytG.d.ts
+++ b/packages/core/dist/app-3Zr8JaYf.d.ts
@@ -20,6 +20,7 @@ interface Bindings {
ENVIRONMENT?: string;
BUCKET_NAME?: string;
GOOGLE_MAPS_API_KEY?: string;
+ REQUIRE_API_KEY?: string;
}
interface Variables {
user?: {
@@ -32,6 +33,12 @@ interface Variables {
requestId?: string;
startTime?: number;
appVersion?: string;
+ apiKey?: {
+ id: string;
+ name: string;
+ scopes: string[];
+ userId: string;
+ };
}
interface SonicJSConfig {
collections?: {
diff --git a/packages/core/dist/chunk-2YRNPIU4.cjs.map b/packages/core/dist/chunk-2YRNPIU4.cjs.map
deleted file mode 100644
index 50cd27f15..000000000
--- a/packages/core/dist/chunk-2YRNPIU4.cjs.map
+++ /dev/null
@@ -1 +0,0 @@
-{"version":3,"sources":["../src/db/migrations-bundle.ts","../src/services/migrations.ts"],"names":[],"mappings":"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","file":"chunk-2YRNPIU4.cjs","sourcesContent":["/**\n * AUTO-GENERATED FILE - DO NOT EDIT\n * Generated by: scripts/generate-migrations.ts\n * Generated at: 2026-01-30T06:55:27.442Z\n *\n * This file contains all migration SQL bundled for use in Cloudflare Workers\n * where filesystem access is not available at runtime.\n */\n\nexport interface BundledMigration {\n id: string\n name: string\n filename: string\n description: string\n sql: string\n}\n\nexport const bundledMigrations: BundledMigration[] = [\n {\n id: '001',\n name: 'Initial Schema',\n filename: '001_initial_schema.sql',\n description: 'Migration 001: Initial Schema',\n sql: \"-- Initial schema for SonicJS AI\\n-- Create users table for authentication\\nCREATE TABLE IF NOT EXISTS users (\\n id TEXT PRIMARY KEY,\\n email TEXT NOT NULL UNIQUE,\\n username TEXT NOT NULL UNIQUE,\\n first_name TEXT NOT NULL,\\n last_name TEXT NOT NULL,\\n password_hash TEXT,\\n role TEXT NOT NULL DEFAULT 'viewer',\\n avatar TEXT,\\n is_active INTEGER NOT NULL DEFAULT 1,\\n last_login_at INTEGER,\\n created_at INTEGER NOT NULL,\\n updated_at INTEGER NOT NULL\\n);\\n\\n-- Create collections table for content schema definitions\\nCREATE TABLE IF NOT EXISTS collections (\\n id TEXT PRIMARY KEY,\\n name TEXT NOT NULL UNIQUE,\\n display_name TEXT NOT NULL,\\n description TEXT,\\n schema TEXT NOT NULL, -- JSON schema definition\\n is_active INTEGER NOT NULL DEFAULT 1,\\n created_at INTEGER NOT NULL,\\n updated_at INTEGER NOT NULL\\n);\\n\\n-- Create content table for actual content data\\nCREATE TABLE IF NOT EXISTS content (\\n id TEXT PRIMARY KEY,\\n collection_id TEXT NOT NULL REFERENCES collections(id),\\n slug TEXT NOT NULL,\\n title TEXT NOT NULL,\\n data TEXT NOT NULL, -- JSON content data\\n status TEXT NOT NULL DEFAULT 'draft',\\n published_at INTEGER,\\n author_id TEXT NOT NULL REFERENCES users(id),\\n created_at INTEGER NOT NULL,\\n updated_at INTEGER NOT NULL\\n);\\n\\n-- Create content_versions table for versioning\\nCREATE TABLE IF NOT EXISTS content_versions (\\n id TEXT PRIMARY KEY,\\n content_id TEXT NOT NULL REFERENCES content(id),\\n version INTEGER NOT NULL,\\n data TEXT NOT NULL, -- JSON data\\n author_id TEXT NOT NULL REFERENCES users(id),\\n created_at INTEGER NOT NULL\\n);\\n\\n-- Create media/files table with comprehensive R2 integration\\nCREATE TABLE IF NOT EXISTS media (\\n id TEXT PRIMARY KEY,\\n filename TEXT NOT NULL,\\n original_name TEXT NOT NULL,\\n mime_type TEXT NOT NULL,\\n size INTEGER NOT NULL,\\n width INTEGER,\\n height INTEGER,\\n folder TEXT NOT NULL DEFAULT 'uploads',\\n r2_key TEXT NOT NULL, -- R2 storage key\\n public_url TEXT NOT NULL, -- CDN URL\\n thumbnail_url TEXT, -- Cloudflare Images URL\\n alt TEXT,\\n caption TEXT,\\n tags TEXT, -- JSON array of tags\\n uploaded_by TEXT NOT NULL REFERENCES users(id),\\n uploaded_at INTEGER NOT NULL,\\n updated_at INTEGER,\\n published_at INTEGER,\\n scheduled_at INTEGER,\\n archived_at INTEGER,\\n deleted_at INTEGER\\n);\\n\\n-- Create API tokens table for programmatic access\\nCREATE TABLE IF NOT EXISTS api_tokens (\\n id TEXT PRIMARY KEY,\\n name TEXT NOT NULL,\\n token TEXT NOT NULL UNIQUE,\\n user_id TEXT NOT NULL REFERENCES users(id),\\n permissions TEXT NOT NULL, -- JSON array of permissions\\n expires_at INTEGER,\\n last_used_at INTEGER,\\n created_at INTEGER NOT NULL\\n);\\n\\n-- Create workflow history table for content workflow tracking\\nCREATE TABLE IF NOT EXISTS workflow_history (\\n id TEXT PRIMARY KEY,\\n content_id TEXT NOT NULL REFERENCES content(id),\\n action TEXT NOT NULL,\\n from_status TEXT NOT NULL,\\n to_status TEXT NOT NULL,\\n user_id TEXT NOT NULL REFERENCES users(id),\\n comment TEXT,\\n created_at INTEGER NOT NULL\\n);\\n\\n-- Create indexes for better performance\\nCREATE INDEX IF NOT EXISTS idx_users_email ON users(email);\\nCREATE INDEX IF NOT EXISTS idx_users_username ON users(username);\\nCREATE INDEX IF NOT EXISTS idx_users_role ON users(role);\\n\\nCREATE INDEX IF NOT EXISTS idx_collections_name ON collections(name);\\nCREATE INDEX IF NOT EXISTS idx_collections_active ON collections(is_active);\\n\\nCREATE INDEX IF NOT EXISTS idx_content_collection ON content(collection_id);\\nCREATE INDEX IF NOT EXISTS idx_content_author ON content(author_id);\\nCREATE INDEX IF NOT EXISTS idx_content_status ON content(status);\\nCREATE INDEX IF NOT EXISTS idx_content_published ON content(published_at);\\nCREATE INDEX IF NOT EXISTS idx_content_slug ON content(slug);\\n\\nCREATE INDEX IF NOT EXISTS idx_content_versions_content ON content_versions(content_id);\\nCREATE INDEX IF NOT EXISTS idx_content_versions_version ON content_versions(version);\\n\\nCREATE INDEX IF NOT EXISTS idx_media_folder ON media(folder);\\nCREATE INDEX IF NOT EXISTS idx_media_type ON media(mime_type);\\nCREATE INDEX IF NOT EXISTS idx_media_uploaded_by ON media(uploaded_by);\\nCREATE INDEX IF NOT EXISTS idx_media_uploaded_at ON media(uploaded_at);\\nCREATE INDEX IF NOT EXISTS idx_media_deleted ON media(deleted_at);\\n\\nCREATE INDEX IF NOT EXISTS idx_api_tokens_user ON api_tokens(user_id);\\nCREATE INDEX IF NOT EXISTS idx_api_tokens_token ON api_tokens(token);\\n\\nCREATE INDEX IF NOT EXISTS idx_workflow_history_content ON workflow_history(content_id);\\nCREATE INDEX IF NOT EXISTS idx_workflow_history_user ON workflow_history(user_id);\\n\\n-- Note: Admin user is created via the seed script with user-provided credentials\\n-- Run 'npm run seed' after migrations to create the admin user\\n\\n-- Insert sample collections\\nINSERT OR IGNORE INTO collections (\\n id, name, display_name, description, schema, \\n is_active, created_at, updated_at\\n) VALUES (\\n 'blog-posts-collection',\\n 'blog_posts',\\n 'Blog Posts',\\n 'Blog post content collection',\\n '{\\\"type\\\":\\\"object\\\",\\\"properties\\\":{\\\"title\\\":{\\\"type\\\":\\\"string\\\",\\\"title\\\":\\\"Title\\\",\\\"required\\\":true},\\\"content\\\":{\\\"type\\\":\\\"string\\\",\\\"title\\\":\\\"Content\\\",\\\"format\\\":\\\"richtext\\\"},\\\"excerpt\\\":{\\\"type\\\":\\\"string\\\",\\\"title\\\":\\\"Excerpt\\\"},\\\"featured_image\\\":{\\\"type\\\":\\\"string\\\",\\\"title\\\":\\\"Featured Image\\\",\\\"format\\\":\\\"media\\\"},\\\"tags\\\":{\\\"type\\\":\\\"array\\\",\\\"title\\\":\\\"Tags\\\",\\\"items\\\":{\\\"type\\\":\\\"string\\\"}},\\\"status\\\":{\\\"type\\\":\\\"string\\\",\\\"title\\\":\\\"Status\\\",\\\"enum\\\":[\\\"draft\\\",\\\"published\\\",\\\"archived\\\"],\\\"default\\\":\\\"draft\\\"}},\\\"required\\\":[\\\"title\\\"]}',\\n 1,\\n strftime('%s', 'now') * 1000,\\n strftime('%s', 'now') * 1000\\n),\\n(\\n 'pages-collection',\\n 'pages',\\n 'Pages',\\n 'Static page content collection',\\n '{\\\"type\\\":\\\"object\\\",\\\"properties\\\":{\\\"title\\\":{\\\"type\\\":\\\"string\\\",\\\"title\\\":\\\"Title\\\",\\\"required\\\":true},\\\"content\\\":{\\\"type\\\":\\\"string\\\",\\\"title\\\":\\\"Content\\\",\\\"format\\\":\\\"richtext\\\"},\\\"slug\\\":{\\\"type\\\":\\\"string\\\",\\\"title\\\":\\\"Slug\\\"},\\\"meta_description\\\":{\\\"type\\\":\\\"string\\\",\\\"title\\\":\\\"Meta Description\\\"},\\\"featured_image\\\":{\\\"type\\\":\\\"string\\\",\\\"title\\\":\\\"Featured Image\\\",\\\"format\\\":\\\"media\\\"}},\\\"required\\\":[\\\"title\\\"]}',\\n 1,\\n strftime('%s', 'now') * 1000,\\n strftime('%s', 'now') * 1000\\n),\\n(\\n 'news-collection',\\n 'news',\\n 'News',\\n 'News article content collection',\\n '{\\\"type\\\":\\\"object\\\",\\\"properties\\\":{\\\"title\\\":{\\\"type\\\":\\\"string\\\",\\\"title\\\":\\\"Title\\\",\\\"required\\\":true},\\\"content\\\":{\\\"type\\\":\\\"string\\\",\\\"title\\\":\\\"Content\\\",\\\"format\\\":\\\"richtext\\\"},\\\"publish_date\\\":{\\\"type\\\":\\\"string\\\",\\\"title\\\":\\\"Publish Date\\\",\\\"format\\\":\\\"date\\\"},\\\"author\\\":{\\\"type\\\":\\\"string\\\",\\\"title\\\":\\\"Author\\\"},\\\"category\\\":{\\\"type\\\":\\\"string\\\",\\\"title\\\":\\\"Category\\\",\\\"enum\\\":[\\\"technology\\\",\\\"business\\\",\\\"general\\\"]}},\\\"required\\\":[\\\"title\\\"]}',\\n 1,\\n strftime('%s', 'now') * 1000,\\n strftime('%s', 'now') * 1000\\n);\\n\\n-- Note: Sample content can be created via the admin interface after the admin user is seeded\"\n },\n {\n id: '002',\n name: 'Faq Plugin',\n filename: '002_faq_plugin.sql',\n description: 'Migration 002: Faq Plugin',\n sql: \"-- FAQ Plugin Migration (DEPRECATED - Now managed by third-party plugin)\\n-- Creates FAQ table for the FAQ plugin\\n-- NOTE: This migration is kept for historical purposes. \\n-- The FAQ functionality is now provided by the faq-plugin third-party plugin.\\n\\nCREATE TABLE IF NOT EXISTS faqs (\\n id INTEGER PRIMARY KEY AUTOINCREMENT,\\n question TEXT NOT NULL,\\n answer TEXT NOT NULL,\\n category TEXT,\\n tags TEXT,\\n isPublished INTEGER NOT NULL DEFAULT 1,\\n sortOrder INTEGER NOT NULL DEFAULT 0,\\n created_at INTEGER NOT NULL DEFAULT (strftime('%s', 'now')),\\n updated_at INTEGER NOT NULL DEFAULT (strftime('%s', 'now'))\\n);\\n\\n-- Create indexes for better performance\\nCREATE INDEX IF NOT EXISTS idx_faqs_category ON faqs(category);\\nCREATE INDEX IF NOT EXISTS idx_faqs_published ON faqs(isPublished);\\nCREATE INDEX IF NOT EXISTS idx_faqs_sort_order ON faqs(sortOrder);\\n\\n-- Create trigger to update updated_at timestamp\\nCREATE TRIGGER IF NOT EXISTS faqs_updated_at\\n AFTER UPDATE ON faqs\\nBEGIN\\n UPDATE faqs SET updated_at = strftime('%s', 'now') WHERE id = NEW.id;\\nEND;\\n\\n-- Insert sample FAQ data\\nINSERT OR IGNORE INTO faqs (question, answer, category, tags, isPublished, sortOrder) VALUES \\n('What is SonicJS AI?', \\n'SonicJS AI is a modern, TypeScript-first headless CMS built for Cloudflare''s edge platform. It provides a complete content management system with admin interface, API endpoints, and plugin architecture.',\\n'general',\\n'sonicjs, cms, cloudflare',\\n1,\\n1),\\n\\n('How do I get started with SonicJS AI?',\\n'To get started: 1) Clone the repository, 2) Install dependencies with npm install, 3) Set up your Cloudflare account and services, 4) Run the development server with npm run dev, 5) Access the admin interface at /admin.',\\n'general',\\n'getting-started, setup',\\n1,\\n2),\\n\\n('What technologies does SonicJS AI use?',\\n'SonicJS AI is built with: TypeScript for type safety, Hono.js as the web framework, Cloudflare D1 for the database, Cloudflare R2 for media storage, Cloudflare Workers for serverless execution, and Tailwind CSS for styling.',\\n'technical',\\n'technology-stack, typescript, cloudflare',\\n1,\\n3),\\n\\n('How do I create content in SonicJS AI?',\\n'Content creation is done through the admin interface. Navigate to /admin, log in with your credentials, go to Content section, select a collection, and click \\\"New Content\\\" to create articles, pages, or other content types.',\\n'general',\\n'content-creation, admin',\\n1,\\n4),\\n\\n('Is SonicJS AI free to use?',\\n'SonicJS AI is open source and free to use. You only pay for the Cloudflare services you consume (D1 database, R2 storage, Workers execution time). Cloudflare offers generous free tiers for development and small projects.',\\n'billing',\\n'pricing, open-source, cloudflare',\\n1,\\n5),\\n\\n('How do I add custom functionality?',\\n'SonicJS AI features a plugin system that allows you to extend functionality. You can create plugins using the PluginBuilder API, add custom routes, models, admin pages, and integrate with external services.',\\n'technical',\\n'plugins, customization, development',\\n1,\\n6),\\n\\n('Can I customize the admin interface?',\\n'Yes! The admin interface is built with TypeScript templates and can be customized. You can modify existing templates, create new components, add custom pages, and integrate your own styling while maintaining the dark theme.',\\n'technical',\\n'admin-interface, customization, templates',\\n1,\\n7),\\n\\n('How does authentication work?',\\n'SonicJS AI includes a built-in authentication system with JWT tokens, role-based access control (admin, editor, viewer), secure password hashing, and session management. Users can be managed through the admin interface.',\\n'technical',\\n'authentication, security, users',\\n1,\\n8);\"\n },\n {\n id: '003',\n name: 'Stage5 Enhancements',\n filename: '003_stage5_enhancements.sql',\n description: 'Migration 003: Stage5 Enhancements',\n sql: \"-- Stage 5: Advanced Content Management enhancements\\n-- Add scheduling and workflow features to content table\\n\\n-- Add content scheduling columns\\nALTER TABLE content ADD COLUMN scheduled_publish_at INTEGER;\\nALTER TABLE content ADD COLUMN scheduled_unpublish_at INTEGER;\\n\\n-- Add workflow and review columns\\nALTER TABLE content ADD COLUMN review_status TEXT DEFAULT 'none'; -- none, pending, approved, rejected\\nALTER TABLE content ADD COLUMN reviewer_id TEXT REFERENCES users(id);\\nALTER TABLE content ADD COLUMN reviewed_at INTEGER;\\nALTER TABLE content ADD COLUMN review_notes TEXT;\\n\\n-- Add content metadata\\nALTER TABLE content ADD COLUMN meta_title TEXT;\\nALTER TABLE content ADD COLUMN meta_description TEXT;\\nALTER TABLE content ADD COLUMN featured_image_id TEXT REFERENCES media(id);\\nALTER TABLE content ADD COLUMN content_type TEXT DEFAULT 'standard'; -- standard, template, component\\n\\n-- Create content_fields table for dynamic field definitions\\nCREATE TABLE IF NOT EXISTS content_fields (\\n id TEXT PRIMARY KEY,\\n collection_id TEXT NOT NULL REFERENCES collections(id),\\n field_name TEXT NOT NULL,\\n field_type TEXT NOT NULL, -- text, richtext, number, boolean, date, select, media, relationship\\n field_label TEXT NOT NULL,\\n field_options TEXT, -- JSON for select options, validation rules, etc.\\n field_order INTEGER NOT NULL DEFAULT 0,\\n is_required INTEGER NOT NULL DEFAULT 0,\\n is_searchable INTEGER NOT NULL DEFAULT 0,\\n created_at INTEGER NOT NULL,\\n updated_at INTEGER NOT NULL,\\n UNIQUE(collection_id, field_name)\\n);\\n\\n-- Create content_relationships table for content relationships\\nCREATE TABLE IF NOT EXISTS content_relationships (\\n id TEXT PRIMARY KEY,\\n source_content_id TEXT NOT NULL REFERENCES content(id),\\n target_content_id TEXT NOT NULL REFERENCES content(id),\\n relationship_type TEXT NOT NULL, -- references, tags, categories\\n created_at INTEGER NOT NULL,\\n UNIQUE(source_content_id, target_content_id, relationship_type)\\n);\\n\\n-- Create workflow_templates table for reusable workflows\\nCREATE TABLE IF NOT EXISTS workflow_templates (\\n id TEXT PRIMARY KEY,\\n name TEXT NOT NULL,\\n description TEXT,\\n collection_id TEXT REFERENCES collections(id), -- null means applies to all collections\\n workflow_steps TEXT NOT NULL, -- JSON array of workflow steps\\n is_active INTEGER NOT NULL DEFAULT 1,\\n created_at INTEGER NOT NULL,\\n updated_at INTEGER NOT NULL\\n);\\n\\n-- Add indexes for new columns\\nCREATE INDEX IF NOT EXISTS idx_content_scheduled_publish ON content(scheduled_publish_at);\\nCREATE INDEX IF NOT EXISTS idx_content_scheduled_unpublish ON content(scheduled_unpublish_at);\\nCREATE INDEX IF NOT EXISTS idx_content_review_status ON content(review_status);\\nCREATE INDEX IF NOT EXISTS idx_content_reviewer ON content(reviewer_id);\\nCREATE INDEX IF NOT EXISTS idx_content_content_type ON content(content_type);\\n\\nCREATE INDEX IF NOT EXISTS idx_content_fields_collection ON content_fields(collection_id);\\nCREATE INDEX IF NOT EXISTS idx_content_fields_name ON content_fields(field_name);\\nCREATE INDEX IF NOT EXISTS idx_content_fields_type ON content_fields(field_type);\\nCREATE INDEX IF NOT EXISTS idx_content_fields_order ON content_fields(field_order);\\n\\nCREATE INDEX IF NOT EXISTS idx_content_relationships_source ON content_relationships(source_content_id);\\nCREATE INDEX IF NOT EXISTS idx_content_relationships_target ON content_relationships(target_content_id);\\nCREATE INDEX IF NOT EXISTS idx_content_relationships_type ON content_relationships(relationship_type);\\n\\nCREATE INDEX IF NOT EXISTS idx_workflow_templates_collection ON workflow_templates(collection_id);\\nCREATE INDEX IF NOT EXISTS idx_workflow_templates_active ON workflow_templates(is_active);\\n\\n-- Insert default workflow template\\nINSERT OR IGNORE INTO workflow_templates (\\n id, name, description, workflow_steps, is_active, created_at, updated_at\\n) VALUES (\\n 'default-content-workflow',\\n 'Default Content Workflow',\\n 'Standard content workflow: Draft ā Review ā Published',\\n '[\\n {\\\"step\\\": \\\"draft\\\", \\\"name\\\": \\\"Draft\\\", \\\"description\\\": \\\"Content is being created\\\", \\\"permissions\\\": [\\\"author\\\", \\\"editor\\\", \\\"admin\\\"]},\\n {\\\"step\\\": \\\"review\\\", \\\"name\\\": \\\"Under Review\\\", \\\"description\\\": \\\"Content is pending review\\\", \\\"permissions\\\": [\\\"editor\\\", \\\"admin\\\"]},\\n {\\\"step\\\": \\\"published\\\", \\\"name\\\": \\\"Published\\\", \\\"description\\\": \\\"Content is live\\\", \\\"permissions\\\": [\\\"editor\\\", \\\"admin\\\"]},\\n {\\\"step\\\": \\\"archived\\\", \\\"name\\\": \\\"Archived\\\", \\\"description\\\": \\\"Content is archived\\\", \\\"permissions\\\": [\\\"admin\\\"]}\\n ]',\\n 1,\\n strftime('%s', 'now') * 1000,\\n strftime('%s', 'now') * 1000\\n);\\n\\n-- Insert enhanced field definitions for existing collections\\nINSERT OR IGNORE INTO content_fields (\\n id, collection_id, field_name, field_type, field_label, field_options, field_order, is_required, is_searchable, created_at, updated_at\\n) VALUES \\n-- Blog Posts fields\\n('blog-title-field', 'blog-posts-collection', 'title', 'text', 'Title', '{\\\"maxLength\\\": 200, \\\"placeholder\\\": \\\"Enter blog post title\\\"}', 1, 1, 1, strftime('%s', 'now') * 1000, strftime('%s', 'now') * 1000),\\n('blog-content-field', 'blog-posts-collection', 'content', 'richtext', 'Content', '{\\\"toolbar\\\": \\\"full\\\", \\\"height\\\": 400}', 2, 1, 1, strftime('%s', 'now') * 1000, strftime('%s', 'now') * 1000),\\n('blog-excerpt-field', 'blog-posts-collection', 'excerpt', 'text', 'Excerpt', '{\\\"maxLength\\\": 500, \\\"rows\\\": 3, \\\"placeholder\\\": \\\"Brief description of the post\\\"}', 3, 0, 1, strftime('%s', 'now') * 1000, strftime('%s', 'now') * 1000),\\n('blog-tags-field', 'blog-posts-collection', 'tags', 'select', 'Tags', '{\\\"multiple\\\": true, \\\"options\\\": [\\\"technology\\\", \\\"business\\\", \\\"tutorial\\\", \\\"news\\\", \\\"update\\\"], \\\"allowCustom\\\": true}', 4, 0, 1, strftime('%s', 'now') * 1000, strftime('%s', 'now') * 1000),\\n('blog-featured-image-field', 'blog-posts-collection', 'featured_image', 'media', 'Featured Image', '{\\\"accept\\\": \\\"image/*\\\", \\\"maxSize\\\": \\\"5MB\\\"}', 5, 0, 0, strftime('%s', 'now') * 1000, strftime('%s', 'now') * 1000),\\n('blog-publish-date-field', 'blog-posts-collection', 'publish_date', 'date', 'Publish Date', '{\\\"format\\\": \\\"YYYY-MM-DD\\\", \\\"defaultToday\\\": true}', 6, 0, 0, strftime('%s', 'now') * 1000, strftime('%s', 'now') * 1000),\\n('blog-featured-field', 'blog-posts-collection', 'is_featured', 'boolean', 'Featured Post', '{\\\"default\\\": false}', 7, 0, 0, strftime('%s', 'now') * 1000, strftime('%s', 'now') * 1000),\\n\\n-- Pages fields\\n('pages-title-field', 'pages-collection', 'title', 'text', 'Title', '{\\\"maxLength\\\": 200, \\\"placeholder\\\": \\\"Enter page title\\\"}', 1, 1, 1, strftime('%s', 'now') * 1000, strftime('%s', 'now') * 1000),\\n('pages-content-field', 'pages-collection', 'content', 'richtext', 'Content', '{\\\"toolbar\\\": \\\"full\\\", \\\"height\\\": 500}', 2, 1, 1, strftime('%s', 'now') * 1000, strftime('%s', 'now') * 1000),\\n('pages-slug-field', 'pages-collection', 'slug', 'text', 'URL Slug', '{\\\"pattern\\\": \\\"^[a-z0-9-]+$\\\", \\\"placeholder\\\": \\\"url-friendly-slug\\\"}', 3, 1, 0, strftime('%s', 'now') * 1000, strftime('%s', 'now') * 1000),\\n('pages-meta-desc-field', 'pages-collection', 'meta_description', 'text', 'Meta Description', '{\\\"maxLength\\\": 160, \\\"rows\\\": 2, \\\"placeholder\\\": \\\"SEO description for search engines\\\"}', 4, 0, 0, strftime('%s', 'now') * 1000, strftime('%s', 'now') * 1000),\\n('pages-template-field', 'pages-collection', 'template', 'select', 'Page Template', '{\\\"options\\\": [\\\"default\\\", \\\"landing\\\", \\\"contact\\\", \\\"about\\\"], \\\"default\\\": \\\"default\\\"}', 5, 0, 0, strftime('%s', 'now') * 1000, strftime('%s', 'now') * 1000),\\n\\n-- News fields\\n('news-title-field', 'news-collection', 'title', 'text', 'Title', '{\\\"maxLength\\\": 200, \\\"placeholder\\\": \\\"Enter news title\\\"}', 1, 1, 1, strftime('%s', 'now') * 1000, strftime('%s', 'now') * 1000),\\n('news-content-field', 'news-collection', 'content', 'richtext', 'Content', '{\\\"toolbar\\\": \\\"news\\\", \\\"height\\\": 400}', 2, 1, 1, strftime('%s', 'now') * 1000, strftime('%s', 'now') * 1000),\\n('news-category-field', 'news-collection', 'category', 'select', 'Category', '{\\\"options\\\": [\\\"technology\\\", \\\"business\\\", \\\"politics\\\", \\\"sports\\\", \\\"entertainment\\\", \\\"health\\\"], \\\"required\\\": true}', 3, 1, 1, strftime('%s', 'now') * 1000, strftime('%s', 'now') * 1000),\\n('news-author-field', 'news-collection', 'author', 'text', 'Author', '{\\\"placeholder\\\": \\\"Author name\\\"}', 4, 1, 1, strftime('%s', 'now') * 1000, strftime('%s', 'now') * 1000),\\n('news-source-field', 'news-collection', 'source', 'text', 'Source', '{\\\"placeholder\\\": \\\"News source\\\"}', 5, 0, 1, strftime('%s', 'now') * 1000, strftime('%s', 'now') * 1000),\\n('news-priority-field', 'news-collection', 'priority', 'select', 'Priority', '{\\\"options\\\": [\\\"low\\\", \\\"normal\\\", \\\"high\\\", \\\"breaking\\\"], \\\"default\\\": \\\"normal\\\"}', 6, 0, 0, strftime('%s', 'now') * 1000, strftime('%s', 'now') * 1000);\"\n },\n {\n id: '004',\n name: 'Stage6 User Management',\n filename: '004_stage6_user_management.sql',\n description: 'Migration 004: Stage6 User Management',\n sql: \"-- Stage 6: User Management & Permissions enhancements\\n-- Enhanced user system with profiles, teams, permissions, and activity logging\\n\\n-- Add user profile and preferences columns\\nALTER TABLE users ADD COLUMN phone TEXT;\\nALTER TABLE users ADD COLUMN bio TEXT;\\nALTER TABLE users ADD COLUMN avatar_url TEXT;\\nALTER TABLE users ADD COLUMN timezone TEXT DEFAULT 'UTC';\\nALTER TABLE users ADD COLUMN language TEXT DEFAULT 'en';\\nALTER TABLE users ADD COLUMN email_notifications INTEGER DEFAULT 1;\\nALTER TABLE users ADD COLUMN theme TEXT DEFAULT 'dark';\\nALTER TABLE users ADD COLUMN two_factor_enabled INTEGER DEFAULT 0;\\nALTER TABLE users ADD COLUMN two_factor_secret TEXT;\\nALTER TABLE users ADD COLUMN password_reset_token TEXT;\\nALTER TABLE users ADD COLUMN password_reset_expires INTEGER;\\nALTER TABLE users ADD COLUMN email_verified INTEGER DEFAULT 0;\\nALTER TABLE users ADD COLUMN email_verification_token TEXT;\\nALTER TABLE users ADD COLUMN invitation_token TEXT;\\nALTER TABLE users ADD COLUMN invited_by TEXT REFERENCES users(id);\\nALTER TABLE users ADD COLUMN invited_at INTEGER;\\nALTER TABLE users ADD COLUMN accepted_invitation_at INTEGER;\\n\\n-- Create teams table for team-based collaboration\\nCREATE TABLE IF NOT EXISTS teams (\\n id TEXT PRIMARY KEY,\\n name TEXT NOT NULL,\\n description TEXT,\\n slug TEXT NOT NULL UNIQUE,\\n owner_id TEXT NOT NULL REFERENCES users(id),\\n settings TEXT, -- JSON for team settings\\n is_active INTEGER NOT NULL DEFAULT 1,\\n created_at INTEGER NOT NULL,\\n updated_at INTEGER NOT NULL\\n);\\n\\n-- Create team memberships table\\nCREATE TABLE IF NOT EXISTS team_memberships (\\n id TEXT PRIMARY KEY,\\n team_id TEXT NOT NULL REFERENCES teams(id) ON DELETE CASCADE,\\n user_id TEXT NOT NULL REFERENCES users(id) ON DELETE CASCADE,\\n role TEXT NOT NULL DEFAULT 'member', -- owner, admin, editor, member, viewer\\n permissions TEXT, -- JSON for specific permissions\\n joined_at INTEGER NOT NULL,\\n updated_at INTEGER NOT NULL,\\n UNIQUE(team_id, user_id)\\n);\\n\\n-- Create permissions table for granular access control\\nCREATE TABLE IF NOT EXISTS permissions (\\n id TEXT PRIMARY KEY,\\n name TEXT NOT NULL UNIQUE,\\n description TEXT,\\n category TEXT NOT NULL, -- content, users, collections, media, settings\\n created_at INTEGER NOT NULL\\n);\\n\\n-- Create role permissions mapping\\nCREATE TABLE IF NOT EXISTS role_permissions (\\n id TEXT PRIMARY KEY,\\n role TEXT NOT NULL,\\n permission_id TEXT NOT NULL REFERENCES permissions(id),\\n created_at INTEGER NOT NULL,\\n UNIQUE(role, permission_id)\\n);\\n\\n-- Create user sessions table for better session management\\nCREATE TABLE IF NOT EXISTS user_sessions (\\n id TEXT PRIMARY KEY,\\n user_id TEXT NOT NULL REFERENCES users(id) ON DELETE CASCADE,\\n token_hash TEXT NOT NULL,\\n ip_address TEXT,\\n user_agent TEXT,\\n is_active INTEGER NOT NULL DEFAULT 1,\\n expires_at INTEGER NOT NULL,\\n created_at INTEGER NOT NULL,\\n last_used_at INTEGER\\n);\\n\\n-- Create activity log table for audit trails\\nCREATE TABLE IF NOT EXISTS activity_logs (\\n id TEXT PRIMARY KEY,\\n user_id TEXT REFERENCES users(id),\\n action TEXT NOT NULL,\\n resource_type TEXT, -- users, content, collections, media, etc.\\n resource_id TEXT,\\n details TEXT, -- JSON with additional details\\n ip_address TEXT,\\n user_agent TEXT,\\n created_at INTEGER NOT NULL\\n);\\n\\n-- Create password history table for security\\nCREATE TABLE IF NOT EXISTS password_history (\\n id TEXT PRIMARY KEY,\\n user_id TEXT NOT NULL REFERENCES users(id) ON DELETE CASCADE,\\n password_hash TEXT NOT NULL,\\n created_at INTEGER NOT NULL\\n);\\n\\n-- Insert default permissions\\nINSERT OR IGNORE INTO permissions (id, name, description, category, created_at) VALUES\\n ('perm_content_create', 'content.create', 'Create new content', 'content', strftime('%s', 'now') * 1000),\\n ('perm_content_read', 'content.read', 'View content', 'content', strftime('%s', 'now') * 1000),\\n ('perm_content_update', 'content.update', 'Edit existing content', 'content', strftime('%s', 'now') * 1000),\\n ('perm_content_delete', 'content.delete', 'Delete content', 'content', strftime('%s', 'now') * 1000),\\n ('perm_content_publish', 'content.publish', 'Publish/unpublish content', 'content', strftime('%s', 'now') * 1000),\\n \\n ('perm_collections_create', 'collections.create', 'Create new collections', 'collections', strftime('%s', 'now') * 1000),\\n ('perm_collections_read', 'collections.read', 'View collections', 'collections', strftime('%s', 'now') * 1000),\\n ('perm_collections_update', 'collections.update', 'Edit collections', 'collections', strftime('%s', 'now') * 1000),\\n ('perm_collections_delete', 'collections.delete', 'Delete collections', 'collections', strftime('%s', 'now') * 1000),\\n ('perm_collections_fields', 'collections.fields', 'Manage collection fields', 'collections', strftime('%s', 'now') * 1000),\\n \\n ('perm_media_upload', 'media.upload', 'Upload media files', 'media', strftime('%s', 'now') * 1000),\\n ('perm_media_read', 'media.read', 'View media files', 'media', strftime('%s', 'now') * 1000),\\n ('perm_media_update', 'media.update', 'Edit media metadata', 'media', strftime('%s', 'now') * 1000),\\n ('perm_media_delete', 'media.delete', 'Delete media files', 'media', strftime('%s', 'now') * 1000),\\n \\n ('perm_users_create', 'users.create', 'Invite new users', 'users', strftime('%s', 'now') * 1000),\\n ('perm_users_read', 'users.read', 'View user profiles', 'users', strftime('%s', 'now') * 1000),\\n ('perm_users_update', 'users.update', 'Edit user profiles', 'users', strftime('%s', 'now') * 1000),\\n ('perm_users_delete', 'users.delete', 'Deactivate users', 'users', strftime('%s', 'now') * 1000),\\n ('perm_users_roles', 'users.roles', 'Manage user roles', 'users', strftime('%s', 'now') * 1000),\\n \\n ('perm_settings_read', 'settings.read', 'View system settings', 'settings', strftime('%s', 'now') * 1000),\\n ('perm_settings_update', 'settings.update', 'Modify system settings', 'settings', strftime('%s', 'now') * 1000),\\n ('perm_activity_read', 'activity.read', 'View activity logs', 'settings', strftime('%s', 'now') * 1000);\\n\\n-- Assign permissions to default roles\\nINSERT OR IGNORE INTO role_permissions (id, role, permission_id, created_at) VALUES\\n -- Admin has all permissions\\n ('rp_admin_content_create', 'admin', 'perm_content_create', strftime('%s', 'now') * 1000),\\n ('rp_admin_content_read', 'admin', 'perm_content_read', strftime('%s', 'now') * 1000),\\n ('rp_admin_content_update', 'admin', 'perm_content_update', strftime('%s', 'now') * 1000),\\n ('rp_admin_content_delete', 'admin', 'perm_content_delete', strftime('%s', 'now') * 1000),\\n ('rp_admin_content_publish', 'admin', 'perm_content_publish', strftime('%s', 'now') * 1000),\\n ('rp_admin_collections_create', 'admin', 'perm_collections_create', strftime('%s', 'now') * 1000),\\n ('rp_admin_collections_read', 'admin', 'perm_collections_read', strftime('%s', 'now') * 1000),\\n ('rp_admin_collections_update', 'admin', 'perm_collections_update', strftime('%s', 'now') * 1000),\\n ('rp_admin_collections_delete', 'admin', 'perm_collections_delete', strftime('%s', 'now') * 1000),\\n ('rp_admin_collections_fields', 'admin', 'perm_collections_fields', strftime('%s', 'now') * 1000),\\n ('rp_admin_media_upload', 'admin', 'perm_media_upload', strftime('%s', 'now') * 1000),\\n ('rp_admin_media_read', 'admin', 'perm_media_read', strftime('%s', 'now') * 1000),\\n ('rp_admin_media_update', 'admin', 'perm_media_update', strftime('%s', 'now') * 1000),\\n ('rp_admin_media_delete', 'admin', 'perm_media_delete', strftime('%s', 'now') * 1000),\\n ('rp_admin_users_create', 'admin', 'perm_users_create', strftime('%s', 'now') * 1000),\\n ('rp_admin_users_read', 'admin', 'perm_users_read', strftime('%s', 'now') * 1000),\\n ('rp_admin_users_update', 'admin', 'perm_users_update', strftime('%s', 'now') * 1000),\\n ('rp_admin_users_delete', 'admin', 'perm_users_delete', strftime('%s', 'now') * 1000),\\n ('rp_admin_users_roles', 'admin', 'perm_users_roles', strftime('%s', 'now') * 1000),\\n ('rp_admin_settings_read', 'admin', 'perm_settings_read', strftime('%s', 'now') * 1000),\\n ('rp_admin_settings_update', 'admin', 'perm_settings_update', strftime('%s', 'now') * 1000),\\n ('rp_admin_activity_read', 'admin', 'perm_activity_read', strftime('%s', 'now') * 1000),\\n \\n -- Editor permissions\\n ('rp_editor_content_create', 'editor', 'perm_content_create', strftime('%s', 'now') * 1000),\\n ('rp_editor_content_read', 'editor', 'perm_content_read', strftime('%s', 'now') * 1000),\\n ('rp_editor_content_update', 'editor', 'perm_content_update', strftime('%s', 'now') * 1000),\\n ('rp_editor_content_publish', 'editor', 'perm_content_publish', strftime('%s', 'now') * 1000),\\n ('rp_editor_collections_read', 'editor', 'perm_collections_read', strftime('%s', 'now') * 1000),\\n ('rp_editor_media_upload', 'editor', 'perm_media_upload', strftime('%s', 'now') * 1000),\\n ('rp_editor_media_read', 'editor', 'perm_media_read', strftime('%s', 'now') * 1000),\\n ('rp_editor_media_update', 'editor', 'perm_media_update', strftime('%s', 'now') * 1000),\\n ('rp_editor_users_read', 'editor', 'perm_users_read', strftime('%s', 'now') * 1000),\\n \\n -- Viewer permissions\\n ('rp_viewer_content_read', 'viewer', 'perm_content_read', strftime('%s', 'now') * 1000),\\n ('rp_viewer_collections_read', 'viewer', 'perm_collections_read', strftime('%s', 'now') * 1000),\\n ('rp_viewer_media_read', 'viewer', 'perm_media_read', strftime('%s', 'now') * 1000),\\n ('rp_viewer_users_read', 'viewer', 'perm_users_read', strftime('%s', 'now') * 1000);\\n\\n-- Create indexes for performance\\nCREATE INDEX IF NOT EXISTS idx_team_memberships_team_id ON team_memberships(team_id);\\nCREATE INDEX IF NOT EXISTS idx_team_memberships_user_id ON team_memberships(user_id);\\nCREATE INDEX IF NOT EXISTS idx_user_sessions_user_id ON user_sessions(user_id);\\nCREATE INDEX IF NOT EXISTS idx_user_sessions_token_hash ON user_sessions(token_hash);\\nCREATE INDEX IF NOT EXISTS idx_activity_logs_user_id ON activity_logs(user_id);\\nCREATE INDEX IF NOT EXISTS idx_activity_logs_created_at ON activity_logs(created_at);\\nCREATE INDEX IF NOT EXISTS idx_activity_logs_resource ON activity_logs(resource_type, resource_id);\\nCREATE INDEX IF NOT EXISTS idx_password_history_user_id ON password_history(user_id);\\nCREATE INDEX IF NOT EXISTS idx_users_email_verification_token ON users(email_verification_token);\\nCREATE INDEX IF NOT EXISTS idx_users_password_reset_token ON users(password_reset_token);\\nCREATE INDEX IF NOT EXISTS idx_users_invitation_token ON users(invitation_token);\"\n },\n {\n id: '005',\n name: 'Stage7 Workflow Automation',\n filename: '005_stage7_workflow_automation.sql',\n description: 'Migration 005: Stage7 Workflow Automation',\n sql: \"-- Stage 7: Workflow & Automation Migration\\n-- This migration adds workflow and automation capabilities to SonicJS\\n\\n-- Workflow States Table\\nCREATE TABLE IF NOT EXISTS workflow_states (\\n id TEXT PRIMARY KEY DEFAULT (lower(hex(randomblob(16)))),\\n name TEXT NOT NULL,\\n description TEXT,\\n color TEXT DEFAULT '#6B7280',\\n is_initial INTEGER DEFAULT 0,\\n is_final INTEGER DEFAULT 0,\\n created_at DATETIME DEFAULT CURRENT_TIMESTAMP\\n);\\n\\n-- Insert default workflow states\\nINSERT OR IGNORE INTO workflow_states (id, name, description, color, is_initial, is_final) VALUES\\n('draft', 'Draft', 'Content is being worked on', '#F59E0B', 1, 0),\\n('pending-review', 'Pending Review', 'Content is waiting for review', '#3B82F6', 0, 0),\\n('approved', 'Approved', 'Content has been approved', '#10B981', 0, 0),\\n('published', 'Published', 'Content is live', '#059669', 0, 1),\\n('rejected', 'Rejected', 'Content was rejected', '#EF4444', 0, 1),\\n('archived', 'Archived', 'Content has been archived', '#6B7280', 0, 1);\\n\\n-- Workflows Table\\nCREATE TABLE IF NOT EXISTS workflows (\\n id TEXT PRIMARY KEY DEFAULT (lower(hex(randomblob(16)))),\\n name TEXT NOT NULL,\\n description TEXT,\\n collection_id TEXT,\\n is_active INTEGER DEFAULT 1,\\n auto_publish INTEGER DEFAULT 0,\\n require_approval INTEGER DEFAULT 1,\\n approval_levels INTEGER DEFAULT 1,\\n created_at DATETIME DEFAULT CURRENT_TIMESTAMP,\\n updated_at DATETIME DEFAULT CURRENT_TIMESTAMP,\\n FOREIGN KEY (collection_id) REFERENCES collections(id) ON DELETE CASCADE\\n);\\n\\n-- Workflow Transitions Table\\nCREATE TABLE IF NOT EXISTS workflow_transitions (\\n id TEXT PRIMARY KEY DEFAULT (lower(hex(randomblob(16)))),\\n workflow_id TEXT NOT NULL,\\n from_state_id TEXT NOT NULL,\\n to_state_id TEXT NOT NULL,\\n required_permission TEXT,\\n auto_transition INTEGER DEFAULT 0,\\n transition_conditions TEXT, -- JSON\\n created_at DATETIME DEFAULT CURRENT_TIMESTAMP,\\n FOREIGN KEY (workflow_id) REFERENCES workflows(id) ON DELETE CASCADE,\\n FOREIGN KEY (from_state_id) REFERENCES workflow_states(id),\\n FOREIGN KEY (to_state_id) REFERENCES workflow_states(id)\\n);\\n\\n-- Content Workflow Status Table\\nCREATE TABLE IF NOT EXISTS content_workflow_status (\\n id TEXT PRIMARY KEY DEFAULT (lower(hex(randomblob(16)))),\\n content_id TEXT NOT NULL,\\n workflow_id TEXT NOT NULL,\\n current_state_id TEXT NOT NULL,\\n assigned_to TEXT,\\n due_date DATETIME,\\n created_at DATETIME DEFAULT CURRENT_TIMESTAMP,\\n updated_at DATETIME DEFAULT CURRENT_TIMESTAMP,\\n FOREIGN KEY (content_id) REFERENCES content(id) ON DELETE CASCADE,\\n FOREIGN KEY (workflow_id) REFERENCES workflows(id),\\n FOREIGN KEY (current_state_id) REFERENCES workflow_states(id),\\n FOREIGN KEY (assigned_to) REFERENCES users(id),\\n UNIQUE(content_id, workflow_id)\\n);\\n\\n-- Workflow History Table\\nCREATE TABLE IF NOT EXISTS workflow_history (\\n id TEXT PRIMARY KEY DEFAULT (lower(hex(randomblob(16)))),\\n content_id TEXT NOT NULL,\\n workflow_id TEXT NOT NULL,\\n from_state_id TEXT,\\n to_state_id TEXT NOT NULL,\\n user_id TEXT NOT NULL,\\n comment TEXT,\\n metadata TEXT, -- JSON\\n created_at DATETIME DEFAULT CURRENT_TIMESTAMP,\\n FOREIGN KEY (content_id) REFERENCES content(id) ON DELETE CASCADE,\\n FOREIGN KEY (workflow_id) REFERENCES workflows(id),\\n FOREIGN KEY (from_state_id) REFERENCES workflow_states(id),\\n FOREIGN KEY (to_state_id) REFERENCES workflow_states(id),\\n FOREIGN KEY (user_id) REFERENCES users(id)\\n);\\n\\n-- Scheduled Content Table\\nCREATE TABLE IF NOT EXISTS scheduled_content (\\n id TEXT PRIMARY KEY DEFAULT (lower(hex(randomblob(16)))),\\n content_id TEXT NOT NULL,\\n action TEXT NOT NULL, -- 'publish', 'unpublish', 'archive'\\n scheduled_at DATETIME NOT NULL,\\n timezone TEXT DEFAULT 'UTC',\\n user_id TEXT NOT NULL,\\n status TEXT DEFAULT 'pending', -- 'pending', 'completed', 'failed', 'cancelled'\\n executed_at DATETIME,\\n error_message TEXT,\\n created_at DATETIME DEFAULT CURRENT_TIMESTAMP,\\n FOREIGN KEY (content_id) REFERENCES content(id) ON DELETE CASCADE,\\n FOREIGN KEY (user_id) REFERENCES users(id)\\n);\\n\\n-- Notifications Table\\nCREATE TABLE IF NOT EXISTS notifications (\\n id TEXT PRIMARY KEY DEFAULT (lower(hex(randomblob(16)))),\\n user_id TEXT NOT NULL,\\n type TEXT NOT NULL, -- 'workflow', 'schedule', 'system'\\n title TEXT NOT NULL,\\n message TEXT NOT NULL,\\n data TEXT, -- JSON\\n is_read INTEGER DEFAULT 0,\\n created_at DATETIME DEFAULT CURRENT_TIMESTAMP,\\n FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE\\n);\\n\\n-- Notification Preferences Table\\nCREATE TABLE IF NOT EXISTS notification_preferences (\\n id TEXT PRIMARY KEY DEFAULT (lower(hex(randomblob(16)))),\\n user_id TEXT NOT NULL,\\n notification_type TEXT NOT NULL,\\n email_enabled INTEGER DEFAULT 1,\\n in_app_enabled INTEGER DEFAULT 1,\\n digest_frequency TEXT DEFAULT 'daily', -- 'immediate', 'hourly', 'daily', 'weekly'\\n created_at DATETIME DEFAULT CURRENT_TIMESTAMP,\\n updated_at DATETIME DEFAULT CURRENT_TIMESTAMP,\\n FOREIGN KEY (user_id) REFERENCES users(id) ON DELETE CASCADE,\\n UNIQUE(user_id, notification_type)\\n);\\n\\n-- Webhooks Table\\nCREATE TABLE IF NOT EXISTS webhooks (\\n id TEXT PRIMARY KEY DEFAULT (lower(hex(randomblob(16)))),\\n name TEXT NOT NULL,\\n url TEXT NOT NULL,\\n secret TEXT,\\n events TEXT NOT NULL, -- JSON array of event types\\n is_active INTEGER DEFAULT 1,\\n retry_count INTEGER DEFAULT 3,\\n timeout_seconds INTEGER DEFAULT 30,\\n last_success_at DATETIME,\\n last_failure_at DATETIME,\\n failure_count INTEGER DEFAULT 0,\\n created_at DATETIME DEFAULT CURRENT_TIMESTAMP,\\n updated_at DATETIME DEFAULT CURRENT_TIMESTAMP\\n);\\n\\n-- Webhook Deliveries Table\\nCREATE TABLE IF NOT EXISTS webhook_deliveries (\\n id TEXT PRIMARY KEY DEFAULT (lower(hex(randomblob(16)))),\\n webhook_id TEXT NOT NULL,\\n event_type TEXT NOT NULL,\\n payload TEXT NOT NULL, -- JSON\\n response_status INTEGER,\\n response_body TEXT,\\n attempt_count INTEGER DEFAULT 1,\\n delivered_at DATETIME DEFAULT CURRENT_TIMESTAMP,\\n FOREIGN KEY (webhook_id) REFERENCES webhooks(id) ON DELETE CASCADE\\n);\\n\\n-- Content Versions Table (for rollback functionality)\\nCREATE TABLE IF NOT EXISTS content_versions (\\n id TEXT PRIMARY KEY DEFAULT (lower(hex(randomblob(16)))),\\n content_id TEXT NOT NULL,\\n version_number INTEGER NOT NULL,\\n title TEXT NOT NULL,\\n content TEXT NOT NULL,\\n fields TEXT, -- JSON\\n user_id TEXT NOT NULL,\\n change_summary TEXT,\\n created_at DATETIME DEFAULT CURRENT_TIMESTAMP,\\n FOREIGN KEY (content_id) REFERENCES content(id) ON DELETE CASCADE,\\n FOREIGN KEY (user_id) REFERENCES users(id),\\n UNIQUE(content_id, version_number)\\n);\\n\\n-- Automation Rules Table\\nCREATE TABLE IF NOT EXISTS automation_rules (\\n id TEXT PRIMARY KEY DEFAULT (lower(hex(randomblob(16)))),\\n name TEXT NOT NULL,\\n description TEXT,\\n trigger_type TEXT NOT NULL, -- 'content_created', 'content_updated', 'workflow_transition', 'schedule'\\n trigger_conditions TEXT, -- JSON\\n action_type TEXT NOT NULL, -- 'workflow_transition', 'send_notification', 'webhook_call', 'auto_save'\\n action_config TEXT, -- JSON\\n is_active INTEGER DEFAULT 1,\\n created_at DATETIME DEFAULT CURRENT_TIMESTAMP,\\n updated_at DATETIME DEFAULT CURRENT_TIMESTAMP\\n);\\n\\n-- Auto-save Drafts Table\\nCREATE TABLE IF NOT EXISTS auto_save_drafts (\\n id TEXT PRIMARY KEY DEFAULT (lower(hex(randomblob(16)))),\\n content_id TEXT,\\n user_id TEXT NOT NULL,\\n title TEXT,\\n content TEXT,\\n fields TEXT, -- JSON\\n last_saved_at DATETIME DEFAULT CURRENT_TIMESTAMP,\\n FOREIGN KEY (content_id) REFERENCES content(id) ON DELETE CASCADE,\\n FOREIGN KEY (user_id) REFERENCES users(id),\\n UNIQUE(content_id, user_id)\\n);\\n\\n-- Add workflow-related columns to existing content table (skip existing columns)\\nALTER TABLE content ADD COLUMN workflow_state_id TEXT DEFAULT 'draft';\\nALTER TABLE content ADD COLUMN embargo_until DATETIME;\\nALTER TABLE content ADD COLUMN expires_at DATETIME;\\nALTER TABLE content ADD COLUMN version_number INTEGER DEFAULT 1;\\nALTER TABLE content ADD COLUMN is_auto_saved INTEGER DEFAULT 0;\\n\\n-- Create indexes for performance\\nCREATE INDEX IF NOT EXISTS idx_content_workflow_status_content_id ON content_workflow_status(content_id);\\nCREATE INDEX IF NOT EXISTS idx_content_workflow_status_workflow_id ON content_workflow_status(workflow_id);\\nCREATE INDEX IF NOT EXISTS idx_workflow_history_content_id ON workflow_history(content_id);\\nCREATE INDEX IF NOT EXISTS idx_scheduled_content_scheduled_at ON scheduled_content(scheduled_at);\\nCREATE INDEX IF NOT EXISTS idx_scheduled_content_status ON scheduled_content(status);\\nCREATE INDEX IF NOT EXISTS idx_notifications_user_id ON notifications(user_id);\\nCREATE INDEX IF NOT EXISTS idx_notifications_is_read ON notifications(is_read);\\nCREATE INDEX IF NOT EXISTS idx_content_versions_content_id ON content_versions(content_id);\\nCREATE INDEX IF NOT EXISTS idx_auto_save_drafts_user_id ON auto_save_drafts(user_id);\\nCREATE INDEX IF NOT EXISTS idx_content_workflow_state ON content(workflow_state_id);\\nCREATE INDEX IF NOT EXISTS idx_content_scheduled_publish ON content(scheduled_publish_at);\\n\\n-- Insert default workflow for collections\\nINSERT OR IGNORE INTO workflows (id, name, description, collection_id, is_active, require_approval, approval_levels) \\nSELECT \\n 'default-' || id,\\n 'Default Workflow for ' || name,\\n 'Standard content approval workflow',\\n id,\\n 1,\\n 1,\\n 1\\nFROM collections;\\n\\n-- Insert default workflow transitions\\nINSERT OR IGNORE INTO workflow_transitions (workflow_id, from_state_id, to_state_id, required_permission) \\nSELECT \\n w.id,\\n 'draft',\\n 'pending-review',\\n 'content:submit'\\nFROM workflows w;\\n\\nINSERT OR IGNORE INTO workflow_transitions (workflow_id, from_state_id, to_state_id, required_permission) \\nSELECT \\n w.id,\\n 'pending-review',\\n 'approved',\\n 'content:approve'\\nFROM workflows w;\\n\\nINSERT OR IGNORE INTO workflow_transitions (workflow_id, from_state_id, to_state_id, required_permission) \\nSELECT \\n w.id,\\n 'approved',\\n 'published',\\n 'content:publish'\\nFROM workflows w;\\n\\nINSERT OR IGNORE INTO workflow_transitions (workflow_id, from_state_id, to_state_id, required_permission) \\nSELECT \\n w.id,\\n 'pending-review',\\n 'rejected',\\n 'content:approve'\\nFROM workflows w;\\n\\n-- Insert default notification preferences for all users\\nINSERT OR IGNORE INTO notification_preferences (user_id, notification_type, email_enabled, in_app_enabled)\\nSELECT \\n id,\\n 'workflow_assigned',\\n 1,\\n 1\\nFROM users;\\n\\nINSERT OR IGNORE INTO notification_preferences (user_id, notification_type, email_enabled, in_app_enabled)\\nSELECT \\n id,\\n 'workflow_status_change',\\n 1,\\n 1\\nFROM users;\\n\\nINSERT OR IGNORE INTO notification_preferences (user_id, notification_type, email_enabled, in_app_enabled)\\nSELECT \\n id,\\n 'content_scheduled',\\n 1,\\n 1\\nFROM users;\"\n },\n {\n id: '006',\n name: 'Plugin System',\n filename: '006_plugin_system.sql',\n description: 'Migration 006: Plugin System',\n sql: \"-- Plugin System Tables\\n-- Migration: 006_plugin_system\\n-- Description: Add plugin management system tables\\n\\n-- Plugins table\\nCREATE TABLE IF NOT EXISTS plugins (\\n id TEXT PRIMARY KEY,\\n name TEXT NOT NULL UNIQUE,\\n display_name TEXT NOT NULL,\\n description TEXT,\\n version TEXT NOT NULL,\\n author TEXT NOT NULL,\\n category TEXT NOT NULL,\\n icon TEXT,\\n status TEXT DEFAULT 'inactive' CHECK (status IN ('active', 'inactive', 'error')),\\n is_core BOOLEAN DEFAULT FALSE,\\n settings JSON,\\n permissions JSON,\\n dependencies JSON,\\n download_count INTEGER DEFAULT 0,\\n rating REAL DEFAULT 0,\\n installed_at INTEGER NOT NULL,\\n activated_at INTEGER,\\n last_updated INTEGER NOT NULL,\\n error_message TEXT,\\n created_at INTEGER DEFAULT (unixepoch()),\\n updated_at INTEGER DEFAULT (unixepoch())\\n);\\n\\n-- Plugin hooks table (registered hooks by plugins)\\nCREATE TABLE IF NOT EXISTS plugin_hooks (\\n id TEXT PRIMARY KEY,\\n plugin_id TEXT NOT NULL,\\n hook_name TEXT NOT NULL,\\n handler_name TEXT NOT NULL,\\n priority INTEGER DEFAULT 10,\\n is_active BOOLEAN DEFAULT TRUE,\\n created_at INTEGER DEFAULT (unixepoch()),\\n FOREIGN KEY (plugin_id) REFERENCES plugins(id) ON DELETE CASCADE,\\n UNIQUE(plugin_id, hook_name, handler_name)\\n);\\n\\n-- Plugin routes table\\nCREATE TABLE IF NOT EXISTS plugin_routes (\\n id TEXT PRIMARY KEY,\\n plugin_id TEXT NOT NULL,\\n path TEXT NOT NULL,\\n method TEXT NOT NULL,\\n handler_name TEXT NOT NULL,\\n middleware JSON,\\n is_active BOOLEAN DEFAULT TRUE,\\n created_at INTEGER DEFAULT (unixepoch()),\\n FOREIGN KEY (plugin_id) REFERENCES plugins(id) ON DELETE CASCADE,\\n UNIQUE(plugin_id, path, method)\\n);\\n\\n-- Plugin assets table (CSS, JS files provided by plugins)\\nCREATE TABLE IF NOT EXISTS plugin_assets (\\n id TEXT PRIMARY KEY,\\n plugin_id TEXT NOT NULL,\\n asset_type TEXT NOT NULL CHECK (asset_type IN ('css', 'js', 'image', 'font')),\\n asset_path TEXT NOT NULL,\\n load_order INTEGER DEFAULT 100,\\n load_location TEXT DEFAULT 'footer' CHECK (load_location IN ('header', 'footer')),\\n is_active BOOLEAN DEFAULT TRUE,\\n created_at INTEGER DEFAULT (unixepoch()),\\n FOREIGN KEY (plugin_id) REFERENCES plugins(id) ON DELETE CASCADE\\n);\\n\\n-- Plugin activity log\\nCREATE TABLE IF NOT EXISTS plugin_activity_log (\\n id TEXT PRIMARY KEY,\\n plugin_id TEXT NOT NULL,\\n action TEXT NOT NULL,\\n user_id TEXT,\\n details JSON,\\n timestamp INTEGER DEFAULT (unixepoch()),\\n FOREIGN KEY (plugin_id) REFERENCES plugins(id) ON DELETE CASCADE\\n);\\n\\n-- Create indexes\\nCREATE INDEX IF NOT EXISTS idx_plugins_status ON plugins(status);\\nCREATE INDEX IF NOT EXISTS idx_plugins_category ON plugins(category);\\nCREATE INDEX IF NOT EXISTS idx_plugin_hooks_plugin ON plugin_hooks(plugin_id);\\nCREATE INDEX IF NOT EXISTS idx_plugin_routes_plugin ON plugin_routes(plugin_id);\\nCREATE INDEX IF NOT EXISTS idx_plugin_assets_plugin ON plugin_assets(plugin_id);\\nCREATE INDEX IF NOT EXISTS idx_plugin_activity_plugin ON plugin_activity_log(plugin_id);\\nCREATE INDEX IF NOT EXISTS idx_plugin_activity_timestamp ON plugin_activity_log(timestamp);\\n\\n-- Insert core plugins\\nINSERT OR IGNORE INTO plugins (\\n id, name, display_name, description, version, author, category, icon,\\n status, is_core, permissions, installed_at, last_updated\\n) VALUES \\n(\\n 'core-auth',\\n 'core-auth',\\n 'Authentication System',\\n 'Core authentication and user management system',\\n '1.0.0',\\n 'SonicJS Team',\\n 'security',\\n 'š',\\n 'active',\\n TRUE,\\n '[\\\"manage:users\\\", \\\"manage:roles\\\", \\\"manage:permissions\\\"]',\\n unixepoch(),\\n unixepoch()\\n),\\n(\\n 'core-media',\\n 'core-media', \\n 'Media Manager',\\n 'Core media upload and management system',\\n '1.0.0',\\n 'SonicJS Team',\\n 'media',\\n 'šø',\\n 'active',\\n TRUE,\\n '[\\\"manage:media\\\", \\\"upload:files\\\"]',\\n unixepoch(),\\n unixepoch()\\n),\\n(\\n 'core-workflow',\\n 'core-workflow',\\n 'Workflow Engine',\\n 'Content workflow and approval system',\\n '1.0.0',\\n 'SonicJS Team',\\n 'content',\\n 'š',\\n 'active',\\n TRUE,\\n '[\\\"manage:workflows\\\", \\\"approve:content\\\"]',\\n unixepoch(),\\n unixepoch()\\n);\\n\\n-- FAQ Plugin will be added as a third-party plugin through the admin interface\\n\\n-- Add plugin management permission\\nINSERT OR IGNORE INTO permissions (id, name, description, category, created_at)\\nVALUES (\\n 'manage:plugins',\\n 'Manage Plugins',\\n 'Install, uninstall, activate, and configure plugins',\\n 'system',\\n unixepoch()\\n);\\n\\n-- Grant plugin management permission to admin role\\nINSERT OR IGNORE INTO role_permissions (id, role, permission_id, created_at)\\nVALUES ('role-perm-manage-plugins', 'admin', 'manage:plugins', unixepoch());\"\n },\n {\n id: '007',\n name: 'Demo Login Plugin',\n filename: '007_demo_login_plugin.sql',\n description: 'Migration 007: Demo Login Plugin',\n sql: \"-- Demo Login Plugin Migration\\n-- Migration: 007_demo_login_plugin\\n-- Description: Add demo login prefill plugin to the plugin registry\\n\\n-- Insert demo login plugin\\nINSERT INTO plugins (\\n id, name, display_name, description, version, author, category, icon, \\n status, is_core, permissions, installed_at, last_updated\\n) VALUES (\\n 'demo-login-prefill',\\n 'demo-login-plugin',\\n 'Demo Login Prefill',\\n 'Prefills login form with demo credentials (admin@sonicjs.com/sonicjs!) for easy site demonstration',\\n '1.0.0',\\n 'SonicJS',\\n 'demo',\\n 'šÆ',\\n 'inactive',\\n TRUE,\\n '[]',\\n unixepoch(),\\n unixepoch()\\n);\"\n },\n {\n id: '008',\n name: 'Fix Slug Validation',\n filename: '008_fix_slug_validation.sql',\n description: 'Migration 008: Fix Slug Validation',\n sql: \"-- Migration: Fix overly restrictive slug validation patterns\\n-- This migration relaxes the slug field validation to be more user-friendly\\n\\n-- Update the pages collection slug field to allow underscores and be less restrictive\\nUPDATE content_fields \\nSET field_options = '{\\\"pattern\\\": \\\"^[a-zA-Z0-9_-]+$\\\", \\\"placeholder\\\": \\\"url-friendly-slug\\\", \\\"help\\\": \\\"Use letters, numbers, underscores, and hyphens only\\\"}'\\nWHERE field_name = 'slug' AND collection_id = 'pages-collection';\\n\\n-- Update blog posts slug field if it exists\\nUPDATE content_fields \\nSET field_options = '{\\\"pattern\\\": \\\"^[a-zA-Z0-9_-]+$\\\", \\\"placeholder\\\": \\\"url-friendly-slug\\\", \\\"help\\\": \\\"Use letters, numbers, underscores, and hyphens only\\\"}'\\nWHERE field_name = 'slug' AND collection_id = 'blog-posts-collection';\\n\\n-- Update news slug field if it exists\\nUPDATE content_fields \\nSET field_options = '{\\\"pattern\\\": \\\"^[a-zA-Z0-9_-]+$\\\", \\\"placeholder\\\": \\\"url-friendly-slug\\\", \\\"help\\\": \\\"Use letters, numbers, underscores, and hyphens only\\\"}'\\nWHERE field_name = 'slug' AND collection_id = 'news-collection';\\n\\n-- Update any other slug fields with the restrictive pattern\\nUPDATE content_fields \\nSET field_options = REPLACE(field_options, '\\\"pattern\\\": \\\"^[a-z0-9-]+$\\\"', '\\\"pattern\\\": \\\"^[a-zA-Z0-9_-]+$\\\"')\\nWHERE field_options LIKE '%\\\"pattern\\\": \\\"^[a-z0-9-]+$\\\"%';\"\n },\n {\n id: '009',\n name: 'System Logging',\n filename: '009_system_logging.sql',\n description: 'Migration 009: System Logging',\n sql: \"-- System Logging Tables\\n-- Migration: 009_system_logging\\n-- Description: Add system logging and configuration tables\\n\\n-- System logs table for tracking application events\\nCREATE TABLE IF NOT EXISTS system_logs (\\n id TEXT PRIMARY KEY,\\n level TEXT NOT NULL CHECK (level IN ('debug', 'info', 'warn', 'error', 'fatal')),\\n category TEXT NOT NULL CHECK (category IN ('auth', 'api', 'workflow', 'plugin', 'media', 'system', 'security', 'error')),\\n message TEXT NOT NULL,\\n data TEXT, -- JSON data\\n user_id TEXT,\\n session_id TEXT,\\n request_id TEXT,\\n ip_address TEXT,\\n user_agent TEXT,\\n method TEXT,\\n url TEXT,\\n status_code INTEGER,\\n duration INTEGER, -- milliseconds\\n stack_trace TEXT,\\n tags TEXT, -- JSON array\\n source TEXT, -- source of the log entry\\n created_at INTEGER NOT NULL DEFAULT (unixepoch()),\\n FOREIGN KEY (user_id) REFERENCES users(id)\\n);\\n\\n-- Log configuration table for managing log settings per category\\nCREATE TABLE IF NOT EXISTS log_config (\\n id TEXT PRIMARY KEY,\\n category TEXT NOT NULL UNIQUE CHECK (category IN ('auth', 'api', 'workflow', 'plugin', 'media', 'system', 'security', 'error')),\\n enabled BOOLEAN NOT NULL DEFAULT TRUE,\\n level TEXT NOT NULL DEFAULT 'info' CHECK (level IN ('debug', 'info', 'warn', 'error', 'fatal')),\\n retention_days INTEGER NOT NULL DEFAULT 30,\\n max_size_mb INTEGER NOT NULL DEFAULT 100,\\n created_at INTEGER NOT NULL DEFAULT (unixepoch()),\\n updated_at INTEGER NOT NULL DEFAULT (unixepoch())\\n);\\n\\n-- Create indexes for better performance\\nCREATE INDEX IF NOT EXISTS idx_system_logs_level ON system_logs(level);\\nCREATE INDEX IF NOT EXISTS idx_system_logs_category ON system_logs(category);\\nCREATE INDEX IF NOT EXISTS idx_system_logs_created_at ON system_logs(created_at);\\nCREATE INDEX IF NOT EXISTS idx_system_logs_user_id ON system_logs(user_id);\\nCREATE INDEX IF NOT EXISTS idx_system_logs_status_code ON system_logs(status_code);\\nCREATE INDEX IF NOT EXISTS idx_system_logs_source ON system_logs(source);\\n\\n-- Insert default log configurations\\nINSERT OR IGNORE INTO log_config (id, category, enabled, level, retention_days, max_size_mb) VALUES\\n('log-config-auth', 'auth', TRUE, 'info', 90, 50),\\n('log-config-api', 'api', TRUE, 'info', 30, 100),\\n('log-config-workflow', 'workflow', TRUE, 'info', 60, 50),\\n('log-config-plugin', 'plugin', TRUE, 'warn', 30, 25),\\n('log-config-media', 'media', TRUE, 'info', 30, 50),\\n('log-config-system', 'system', TRUE, 'info', 90, 100),\\n('log-config-security', 'security', TRUE, 'warn', 180, 100),\\n('log-config-error', 'error', TRUE, 'error', 90, 200);\"\n },\n {\n id: '011',\n name: 'Config Managed Collections',\n filename: '011_config_managed_collections.sql',\n description: 'Migration 011: Config Managed Collections',\n sql: \"-- Migration: Add Config-Managed Collections Support\\n-- Description: Add 'managed' column to collections table to support config-based collection definitions\\n-- Created: 2025-10-03\\n\\n-- Add 'managed' column to collections table\\n-- This column indicates whether a collection is managed by configuration files (true) or user-created (false)\\n-- Managed collections cannot be edited through the admin UI\\n-- Use a safe approach to add the column only if it doesn't exist\\nALTER TABLE collections ADD COLUMN managed INTEGER DEFAULT 0 NOT NULL;\\n\\n-- Create an index on the managed column for faster queries\\nCREATE INDEX IF NOT EXISTS idx_collections_managed ON collections(managed);\\n\\n-- Create an index on managed + is_active for efficient filtering\\nCREATE INDEX IF NOT EXISTS idx_collections_managed_active ON collections(managed, is_active);\\n\"\n },\n {\n id: '012',\n name: 'Testimonials Plugin',\n filename: '012_testimonials_plugin.sql',\n description: 'Migration 012: Testimonials Plugin',\n sql: \"-- Testimonials Plugin Migration\\n-- Creates testimonials table for the testimonials plugin\\n-- This demonstrates a code-based collection defined in src/plugins/core-plugins/testimonials-plugin.ts\\n\\nCREATE TABLE IF NOT EXISTS testimonials (\\n id INTEGER PRIMARY KEY AUTOINCREMENT,\\n author_name TEXT NOT NULL,\\n author_title TEXT,\\n author_company TEXT,\\n testimonial_text TEXT NOT NULL,\\n rating INTEGER CHECK(rating >= 1 AND rating <= 5),\\n isPublished INTEGER NOT NULL DEFAULT 1,\\n sortOrder INTEGER NOT NULL DEFAULT 0,\\n created_at INTEGER NOT NULL DEFAULT (strftime('%s', 'now')),\\n updated_at INTEGER NOT NULL DEFAULT (strftime('%s', 'now'))\\n);\\n\\n-- Create indexes for better performance\\nCREATE INDEX IF NOT EXISTS idx_testimonials_published ON testimonials(isPublished);\\nCREATE INDEX IF NOT EXISTS idx_testimonials_sort_order ON testimonials(sortOrder);\\nCREATE INDEX IF NOT EXISTS idx_testimonials_rating ON testimonials(rating);\\n\\n-- Create trigger to update updated_at timestamp\\nCREATE TRIGGER IF NOT EXISTS testimonials_updated_at\\n AFTER UPDATE ON testimonials\\nBEGIN\\n UPDATE testimonials SET updated_at = strftime('%s', 'now') WHERE id = NEW.id;\\nEND;\\n\\n-- Insert plugin record\\nINSERT OR IGNORE INTO plugins (name, display_name, description, version, status, category, settings) VALUES\\n('testimonials',\\n 'Customer Testimonials',\\n 'Manage customer testimonials and reviews with rating support. This is a code-based collection example.',\\n '1.0.0',\\n 'active',\\n 'content',\\n '{\\\"defaultPublished\\\": true, \\\"requireRating\\\": false}');\\n\\n-- Insert sample testimonial data\\nINSERT OR IGNORE INTO testimonials (author_name, author_title, author_company, testimonial_text, rating, isPublished, sortOrder) VALUES\\n('Jane Smith',\\n 'CTO',\\n 'TechStartup Inc',\\n 'SonicJS AI has transformed how we manage our content. The plugin architecture is brilliant and the edge deployment is blazing fast.',\\n 5,\\n 1,\\n 1),\\n\\n('Michael Chen',\\n 'Lead Developer',\\n 'Digital Agency Co',\\n 'We migrated from WordPress to SonicJS AI and couldn''t be happier. The TypeScript-first approach and modern tooling make development a joy.',\\n 5,\\n 1,\\n 2),\\n\\n('Sarah Johnson',\\n 'Product Manager',\\n 'E-commerce Solutions',\\n 'The headless CMS approach combined with Cloudflare Workers gives us unmatched performance. Our content is served globally with minimal latency.',\\n 4,\\n 1,\\n 3),\\n\\n('David Rodriguez',\\n 'Full Stack Developer',\\n 'Creative Studio',\\n 'Great CMS for modern web applications. The admin interface is clean and the API is well-designed. Plugin system is very flexible.',\\n 5,\\n 1,\\n 4),\\n\\n('Emily Watson',\\n 'Technical Director',\\n 'Media Company',\\n 'SonicJS AI solved our content distribution challenges. The R2 integration for media storage works flawlessly and scales effortlessly.',\\n 4,\\n 1,\\n 5);\\n\"\n },\n {\n id: '013',\n name: 'Code Examples Plugin',\n filename: '013_code_examples_plugin.sql',\n description: 'Migration 013: Code Examples Plugin',\n sql: \"-- Code Examples Plugin Migration\\n-- Creates code_examples table for the code examples plugin\\n-- This demonstrates a code-based collection for storing and managing code snippets\\n\\nCREATE TABLE IF NOT EXISTS code_examples (\\n id INTEGER PRIMARY KEY AUTOINCREMENT,\\n title TEXT NOT NULL,\\n description TEXT,\\n code TEXT NOT NULL,\\n language TEXT NOT NULL,\\n category TEXT,\\n tags TEXT,\\n isPublished INTEGER NOT NULL DEFAULT 1,\\n sortOrder INTEGER NOT NULL DEFAULT 0,\\n created_at INTEGER NOT NULL DEFAULT (strftime('%s', 'now')),\\n updated_at INTEGER NOT NULL DEFAULT (strftime('%s', 'now'))\\n);\\n\\n-- Create indexes for better performance\\nCREATE INDEX IF NOT EXISTS idx_code_examples_published ON code_examples(isPublished);\\nCREATE INDEX IF NOT EXISTS idx_code_examples_sort_order ON code_examples(sortOrder);\\nCREATE INDEX IF NOT EXISTS idx_code_examples_language ON code_examples(language);\\nCREATE INDEX IF NOT EXISTS idx_code_examples_category ON code_examples(category);\\n\\n-- Create trigger to update updated_at timestamp\\nCREATE TRIGGER IF NOT EXISTS code_examples_updated_at\\n AFTER UPDATE ON code_examples\\nBEGIN\\n UPDATE code_examples SET updated_at = strftime('%s', 'now') WHERE id = NEW.id;\\nEND;\\n\\n-- Insert plugin record\\nINSERT OR IGNORE INTO plugins (name, display_name, description, version, status, category, settings) VALUES\\n('code-examples',\\n 'Code Examples',\\n 'Manage code snippets and examples with syntax highlighting support. Perfect for documentation and tutorials.',\\n '1.0.0',\\n 'active',\\n 'content',\\n '{\\\"defaultPublished\\\": true, \\\"supportedLanguages\\\": [\\\"javascript\\\", \\\"typescript\\\", \\\"python\\\", \\\"go\\\", \\\"rust\\\", \\\"java\\\", \\\"php\\\", \\\"ruby\\\", \\\"sql\\\"]}');\\n\\n-- Insert sample code examples\\nINSERT OR IGNORE INTO code_examples (title, description, code, language, category, tags, isPublished, sortOrder) VALUES\\n('React useState Hook',\\n 'Basic example of using the useState hook in React for managing component state.',\\n 'import { useState } from ''react'';\\n\\nfunction Counter() {\\n const [count, setCount] = useState(0);\\n\\n return (\\n
\\n
Count: {count}
\\n
setCount(count + 1)}>\\n Increment\\n \\n
\\n );\\n}\\n\\nexport default Counter;',\\n 'javascript',\\n 'frontend',\\n 'react,hooks,state',\\n 1,\\n 1),\\n\\n('TypeScript Interface Example',\\n 'Defining a TypeScript interface for type-safe objects.',\\n 'interface User {\\n id: string;\\n email: string;\\n name: string;\\n role: ''admin'' | ''editor'' | ''viewer'';\\n createdAt: Date;\\n}\\n\\nfunction greetUser(user: User): string {\\n return `Hello, ${user.name}!`;\\n}\\n\\nconst user: User = {\\n id: ''123'',\\n email: ''user@example.com'',\\n name: ''John Doe'',\\n role: ''admin'',\\n createdAt: new Date()\\n};\\n\\nconsole.log(greetUser(user));',\\n 'typescript',\\n 'backend',\\n 'typescript,types,interface',\\n 1,\\n 2),\\n\\n('Python List Comprehension',\\n 'Elegant way to create lists in Python using list comprehensions.',\\n '# Basic list comprehension\\nsquares = [x**2 for x in range(10)]\\nprint(squares) # [0, 1, 4, 9, 16, 25, 36, 49, 64, 81]\\n\\n# With condition\\neven_squares = [x**2 for x in range(10) if x % 2 == 0]\\nprint(even_squares) # [0, 4, 16, 36, 64]\\n\\n# Nested list comprehension\\nmatrix = [[i+j for j in range(3)] for i in range(3)]\\nprint(matrix) # [[0, 1, 2], [1, 2, 3], [2, 3, 4]]',\\n 'python',\\n 'general',\\n 'python,lists,comprehension',\\n 1,\\n 3),\\n\\n('SQL Join Example',\\n 'Common SQL JOIN patterns for combining data from multiple tables.',\\n '-- INNER JOIN: Returns only matching rows\\nSELECT users.name, orders.total\\nFROM users\\nINNER JOIN orders ON users.id = orders.user_id;\\n\\n-- LEFT JOIN: Returns all users, even without orders\\nSELECT users.name, orders.total\\nFROM users\\nLEFT JOIN orders ON users.id = orders.user_id;\\n\\n-- Multiple JOINs\\nSELECT\\n users.name,\\n orders.order_date,\\n products.name AS product_name\\nFROM users\\nINNER JOIN orders ON users.id = orders.user_id\\nINNER JOIN order_items ON orders.id = order_items.order_id\\nINNER JOIN products ON order_items.product_id = products.id;',\\n 'sql',\\n 'database',\\n 'sql,joins,queries',\\n 1,\\n 4),\\n\\n('Go Error Handling',\\n 'Idiomatic error handling pattern in Go.',\\n 'package main\\n\\nimport (\\n\\t\\\"errors\\\"\\n\\t\\\"fmt\\\"\\n)\\n\\nfunc divide(a, b float64) (float64, error) {\\n\\tif b == 0 {\\n\\t\\treturn 0, errors.New(\\\"division by zero\\\")\\n\\t}\\n\\treturn a / b, nil\\n}\\n\\nfunc main() {\\n\\tresult, err := divide(10, 2)\\n\\tif err != nil {\\n\\t\\tfmt.Println(\\\"Error:\\\", err)\\n\\t\\treturn\\n\\t}\\n\\tfmt.Printf(\\\"Result: %.2f\\\\n\\\", result)\\n\\n\\t// This will error\\n\\t_, err = divide(10, 0)\\n\\tif err != nil {\\n\\t\\tfmt.Println(\\\"Error:\\\", err)\\n\\t}\\n}',\\n 'go',\\n 'backend',\\n 'go,error-handling,functions',\\n 1,\\n 5);\\n\"\n },\n {\n id: '014',\n name: 'Fix Plugin Registry',\n filename: '014_fix_plugin_registry.sql',\n description: 'Migration 014: Fix Plugin Registry',\n sql: \"-- Fix Plugin Registry\\n-- Migration: 014_fix_plugin_registry\\n-- Description: Add missing plugins and fix plugin name mismatches\\n\\n-- Note: Cannot easily update plugin names as they may be referenced elsewhere\\n-- Instead we'll add the missing plugins with correct names\\n\\n-- Insert missing plugins\\n\\n-- Core Analytics Plugin\\nINSERT OR IGNORE INTO plugins (\\n id, name, display_name, description, version, author, category, icon,\\n status, is_core, permissions, installed_at, last_updated\\n) VALUES (\\n 'core-analytics',\\n 'core-analytics',\\n 'Analytics & Tracking',\\n 'Core analytics tracking and reporting plugin with page views and event tracking',\\n '1.0.0',\\n 'SonicJS Team',\\n 'seo',\\n 'š',\\n 'active',\\n TRUE,\\n '[\\\"view:analytics\\\", \\\"manage:tracking\\\"]',\\n unixepoch(),\\n unixepoch()\\n);\\n\\n-- FAQ Plugin\\nINSERT OR IGNORE INTO plugins (\\n id, name, display_name, description, version, author, category, icon,\\n status, is_core, permissions, installed_at, last_updated\\n) VALUES (\\n 'faq-plugin',\\n 'faq-plugin',\\n 'FAQ Management',\\n 'Frequently Asked Questions management plugin with categories, search, and custom styling',\\n '1.0.0',\\n 'SonicJS',\\n 'content',\\n 'ā',\\n 'active',\\n FALSE,\\n '[\\\"manage:faqs\\\"]',\\n unixepoch(),\\n unixepoch()\\n);\\n\\n-- Seed Data Plugin\\nINSERT OR IGNORE INTO plugins (\\n id, name, display_name, description, version, author, category, icon,\\n status, is_core, permissions, installed_at, last_updated\\n) VALUES (\\n 'seed-data',\\n 'seed-data',\\n 'Seed Data Generator',\\n 'Generate realistic example users and content for testing and development',\\n '1.0.0',\\n 'SonicJS Team',\\n 'development',\\n 'š±',\\n 'inactive',\\n FALSE,\\n '[\\\"admin\\\"]',\\n unixepoch(),\\n unixepoch()\\n);\\n\\n-- Database Tools Plugin\\nINSERT OR IGNORE INTO plugins (\\n id, name, display_name, description, version, author, category, icon,\\n status, is_core, permissions, installed_at, last_updated\\n) VALUES (\\n 'database-tools',\\n 'database-tools',\\n 'Database Tools',\\n 'Database management tools including truncate, backup, and validation',\\n '1.0.0',\\n 'SonicJS Team',\\n 'system',\\n 'šļø',\\n 'active',\\n FALSE,\\n '[\\\"manage:database\\\", \\\"admin\\\"]',\\n unixepoch(),\\n unixepoch()\\n);\\n\"\n },\n {\n id: '015',\n name: 'Add Remaining Plugins',\n filename: '015_add_remaining_plugins.sql',\n description: 'Migration 015: Add Remaining Plugins',\n sql: \"-- Add Remaining Plugins\\n-- Migration: 015_add_remaining_plugins\\n-- Description: Add all remaining core plugins that were missing from the registry\\n\\n-- Testimonials Plugin (with correct name)\\nINSERT OR IGNORE INTO plugins (\\n id, name, display_name, description, version, author, category, icon,\\n status, is_core, permissions, dependencies, settings, installed_at, last_updated\\n) VALUES (\\n 'testimonials-plugin',\\n 'testimonials-plugin',\\n 'Customer Testimonials',\\n 'Manage customer testimonials and reviews with rating support',\\n '1.0.0',\\n 'SonicJS',\\n 'content',\\n 'ā',\\n 'active',\\n FALSE,\\n '[\\\"manage:testimonials\\\"]',\\n '[]',\\n '{\\\"defaultPublished\\\": true, \\\"requireRating\\\": false}',\\n unixepoch(),\\n unixepoch()\\n);\\n\\n-- Code Examples Plugin (with correct name)\\nINSERT OR IGNORE INTO plugins (\\n id, name, display_name, description, version, author, category, icon,\\n status, is_core, permissions, dependencies, settings, installed_at, last_updated\\n) VALUES (\\n 'code-examples-plugin',\\n 'code-examples-plugin',\\n 'Code Examples',\\n 'Manage code snippets and examples with syntax highlighting support',\\n '1.0.0',\\n 'SonicJS',\\n 'content',\\n 'š»',\\n 'active',\\n FALSE,\\n '[\\\"manage:code-examples\\\"]',\\n '[]',\\n '{\\\"defaultPublished\\\": true, \\\"supportedLanguages\\\": [\\\"javascript\\\", \\\"typescript\\\", \\\"python\\\", \\\"go\\\", \\\"rust\\\", \\\"java\\\", \\\"php\\\", \\\"ruby\\\", \\\"sql\\\"]}',\\n unixepoch(),\\n unixepoch()\\n);\\n\\n-- Workflow Plugin (with correct name)\\nINSERT OR IGNORE INTO plugins (\\n id, name, display_name, description, version, author, category, icon,\\n status, is_core, permissions, dependencies, installed_at, last_updated\\n) VALUES (\\n 'workflow-plugin',\\n 'workflow-plugin',\\n 'Workflow Engine',\\n 'Content workflow management with approval chains, scheduling, and automation',\\n '1.0.0',\\n 'SonicJS Team',\\n 'content',\\n 'š',\\n 'active',\\n TRUE,\\n '[\\\"manage:workflows\\\", \\\"approve:content\\\"]',\\n '[]',\\n unixepoch(),\\n unixepoch()\\n);\\n\\n-- Demo Login Plugin (already exists with correct name from migration 007, but let's ensure it's there)\\nINSERT OR IGNORE INTO plugins (\\n id, name, display_name, description, version, author, category, icon,\\n status, is_core, permissions, dependencies, installed_at, last_updated\\n) VALUES (\\n 'demo-login-plugin',\\n 'demo-login-plugin',\\n 'Demo Login Prefill',\\n 'Prefills login form with demo credentials for easy site demonstration',\\n '1.0.0',\\n 'SonicJS',\\n 'demo',\\n 'šÆ',\\n 'active',\\n FALSE,\\n '[]',\\n '[]',\\n unixepoch(),\\n unixepoch()\\n);\\n\"\n },\n {\n id: '016',\n name: 'Remove Duplicate Cache Plugin',\n filename: '016_remove_duplicate_cache_plugin.sql',\n description: 'Migration 016: Remove Duplicate Cache Plugin',\n sql: \"-- Migration: Remove duplicate cache plugin entry\\n-- Description: Removes the old 'cache' plugin (id: 'cache') that is a duplicate of 'core-cache'\\n-- This fixes the issue where Cache System appears twice in the plugins list\\n-- Created: 2025-10-14\\n\\n-- Remove the old 'cache' plugin entry if it exists\\n-- The correct plugin is 'core-cache' which is managed by plugin-bootstrap.ts\\nDELETE FROM plugins WHERE id = 'cache' AND name = 'cache';\\n\\n-- Clean up any related entries in plugin activity log\\nDELETE FROM plugin_activity_log WHERE plugin_id = 'cache';\\n\\n-- Clean up any related entries in plugin hooks\\nDELETE FROM plugin_hooks WHERE plugin_id = 'cache';\\n\\n-- Clean up any related entries in plugin routes\\nDELETE FROM plugin_routes WHERE plugin_id = 'cache';\\n\"\n },\n {\n id: '017',\n name: 'Auth Configurable Fields',\n filename: '017_auth_configurable_fields.sql',\n description: 'Migration 017: Auth Configurable Fields',\n sql: \"-- Migration: Make authentication fields configurable\\n-- This migration updates the core-auth plugin to support configurable required fields\\n\\n-- The settings will be stored in the plugins table as JSON\\n-- Default settings for core-auth plugin include:\\n-- {\\n-- \\\"requiredFields\\\": {\\n-- \\\"email\\\": { \\\"required\\\": true, \\\"minLength\\\": 5 },\\n-- \\\"password\\\": { \\\"required\\\": true, \\\"minLength\\\": 8 },\\n-- \\\"username\\\": { \\\"required\\\": true, \\\"minLength\\\": 3 },\\n-- \\\"firstName\\\": { \\\"required\\\": true, \\\"minLength\\\": 1 },\\n-- \\\"lastName\\\": { \\\"required\\\": true, \\\"minLength\\\": 1 }\\n-- },\\n-- \\\"validation\\\": {\\n-- \\\"emailFormat\\\": true,\\n-- \\\"allowDuplicateUsernames\\\": false\\n-- }\\n-- }\\n\\n-- Update core-auth plugin settings with configurable field requirements\\nUPDATE plugins\\nSET settings = json_object(\\n 'requiredFields', json_object(\\n 'email', json_object('required', 1, 'minLength', 5, 'label', 'Email', 'type', 'email'),\\n 'password', json_object('required', 1, 'minLength', 8, 'label', 'Password', 'type', 'password'),\\n 'username', json_object('required', 1, 'minLength', 3, 'label', 'Username', 'type', 'text'),\\n 'firstName', json_object('required', 1, 'minLength', 1, 'label', 'First Name', 'type', 'text'),\\n 'lastName', json_object('required', 1, 'minLength', 1, 'label', 'Last Name', 'type', 'text')\\n ),\\n 'validation', json_object(\\n 'emailFormat', 1,\\n 'allowDuplicateUsernames', 0,\\n 'passwordRequirements', json_object(\\n 'requireUppercase', 0,\\n 'requireLowercase', 0,\\n 'requireNumbers', 0,\\n 'requireSpecialChars', 0\\n )\\n ),\\n 'registration', json_object(\\n 'enabled', 1,\\n 'requireEmailVerification', 0,\\n 'defaultRole', 'viewer'\\n )\\n)\\nWHERE id = 'core-auth';\\n\\n-- If core-auth plugin doesn't exist, this migration will be handled by bootstrap\\n-- No need to insert here as plugin bootstrap handles initial plugin creation\\n\"\n },\n {\n id: '018',\n name: 'Settings Table',\n filename: '018_settings_table.sql',\n description: 'Migration 018: Settings Table',\n sql: \"-- Create settings table for storing application settings\\nCREATE TABLE IF NOT EXISTS settings (\\n id TEXT PRIMARY KEY,\\n category TEXT NOT NULL, -- 'general', 'appearance', 'security', etc.\\n key TEXT NOT NULL,\\n value TEXT NOT NULL, -- JSON value\\n created_at INTEGER NOT NULL,\\n updated_at INTEGER NOT NULL,\\n UNIQUE(category, key)\\n);\\n\\n-- Insert default general settings\\nINSERT OR IGNORE INTO settings (id, category, key, value, created_at, updated_at)\\nVALUES\\n (lower(hex(randomblob(16))), 'general', 'siteName', '\\\"SonicJS AI\\\"', unixepoch() * 1000, unixepoch() * 1000),\\n (lower(hex(randomblob(16))), 'general', 'siteDescription', '\\\"A modern headless CMS powered by AI\\\"', unixepoch() * 1000, unixepoch() * 1000),\\n (lower(hex(randomblob(16))), 'general', 'timezone', '\\\"UTC\\\"', unixepoch() * 1000, unixepoch() * 1000),\\n (lower(hex(randomblob(16))), 'general', 'language', '\\\"en\\\"', unixepoch() * 1000, unixepoch() * 1000),\\n (lower(hex(randomblob(16))), 'general', 'maintenanceMode', 'false', unixepoch() * 1000, unixepoch() * 1000);\\n\\n-- Create index for faster lookups\\nCREATE INDEX IF NOT EXISTS idx_settings_category ON settings(category);\\nCREATE INDEX IF NOT EXISTS idx_settings_category_key ON settings(category, key);\\n\"\n },\n {\n id: '019',\n name: 'Remove Blog Posts Collection',\n filename: '019_remove_blog_posts_collection.sql',\n description: 'Migration 019: Remove Blog Posts Collection',\n sql: \"-- Migration: Remove blog_posts from database-managed collections\\n-- Description: Remove blog-posts-collection from the database so it can be managed by code-based collection\\n-- Created: 2025-11-04\\n\\n-- Delete content associated with blog-posts-collection\\nDELETE FROM content WHERE collection_id = 'blog-posts-collection';\\n\\n-- Delete content fields for blog-posts-collection\\nDELETE FROM content_fields WHERE collection_id = 'blog-posts-collection';\\n\\n-- Delete the blog-posts collection itself\\nDELETE FROM collections WHERE id = 'blog-posts-collection';\\n\\n-- The blog-posts collection will now be managed by the code-based collection\\n-- in src/collections/blog-posts.collection.ts\\n\"\n },\n {\n id: '020',\n name: 'Add Email Plugin',\n filename: '020_add_email_plugin.sql',\n description: 'Migration 020: Add Email Plugin',\n sql: \"-- Add Email Plugin\\n-- Migration: 020_add_email_plugin\\n-- Description: Add email plugin for transactional emails via Resend\\n\\nINSERT OR IGNORE INTO plugins (\\n id, name, display_name, description, version, author, category, icon,\\n status, is_core, permissions, installed_at, last_updated\\n) VALUES (\\n 'email',\\n 'email',\\n 'Email',\\n 'Send transactional emails using Resend',\\n '1.0.0-beta.1',\\n 'SonicJS Team',\\n 'utilities',\\n 'š§',\\n 'inactive',\\n TRUE,\\n '[\\\"email:manage\\\", \\\"email:send\\\", \\\"email:view-logs\\\"]',\\n unixepoch(),\\n unixepoch()\\n);\\n\"\n },\n {\n id: '021',\n name: 'Add Magic Link Auth Plugin',\n filename: '021_add_magic_link_auth_plugin.sql',\n description: 'Migration 021: Add Magic Link Auth Plugin',\n sql: \"-- Add Magic Link Authentication Plugin\\n-- Migration: 021_add_magic_link_auth_plugin\\n-- Description: Add magic link authentication plugin for passwordless login\\n\\n-- Create magic_links table\\nCREATE TABLE IF NOT EXISTS magic_links (\\n id TEXT PRIMARY KEY,\\n user_email TEXT NOT NULL,\\n token TEXT NOT NULL UNIQUE,\\n expires_at INTEGER NOT NULL,\\n used INTEGER DEFAULT 0,\\n used_at INTEGER,\\n ip_address TEXT,\\n user_agent TEXT,\\n created_at INTEGER NOT NULL\\n);\\n\\n-- Create indexes for performance\\nCREATE INDEX IF NOT EXISTS idx_magic_links_token ON magic_links(token);\\nCREATE INDEX IF NOT EXISTS idx_magic_links_email ON magic_links(user_email);\\nCREATE INDEX IF NOT EXISTS idx_magic_links_expires ON magic_links(expires_at);\\n\\n-- Register the plugin\\nINSERT OR IGNORE INTO plugins (\\n id, name, display_name, description, version, author, category, icon,\\n status, is_core, permissions, dependencies, installed_at, last_updated\\n) VALUES (\\n 'magic-link-auth',\\n 'magic-link-auth',\\n 'Magic Link Authentication',\\n 'Passwordless authentication via email magic links. Users receive a secure one-time link to sign in without entering a password.',\\n '1.0.0',\\n 'SonicJS Team',\\n 'security',\\n 'š',\\n 'inactive',\\n FALSE,\\n '[\\\"auth:manage\\\", \\\"auth:magic-link\\\"]',\\n '[\\\"email\\\"]',\\n unixepoch(),\\n unixepoch()\\n);\\n\"\n },\n {\n id: '022',\n name: 'Add Tinymce Plugin',\n filename: '022_add_tinymce_plugin.sql',\n description: 'Migration 022: Add Tinymce Plugin',\n sql: \"-- Add TinyMCE Rich Text Editor Plugin\\n-- Migration: 022_add_tinymce_plugin\\n-- Description: Add TinyMCE plugin for WYSIWYG rich text editing\\n\\n-- Register the plugin (active by default since it replaces hardcoded TinyMCE)\\nINSERT OR IGNORE INTO plugins (\\n id, name, display_name, description, version, author, category, icon,\\n status, is_core, permissions, dependencies, settings, installed_at, last_updated\\n) VALUES (\\n 'tinymce-plugin',\\n 'tinymce-plugin',\\n 'TinyMCE Rich Text Editor',\\n 'Powerful WYSIWYG rich text editor for content creation. Provides a full-featured editor with formatting, media embedding, and customizable toolbars for richtext fields.',\\n '1.0.0',\\n 'SonicJS Team',\\n 'editor',\\n 'āļø',\\n 'active',\\n FALSE,\\n '[]',\\n '[]',\\n '{\\\"apiKey\\\":\\\"no-api-key\\\",\\\"defaultHeight\\\":300,\\\"defaultToolbar\\\":\\\"full\\\",\\\"skin\\\":\\\"oxide-dark\\\"}',\\n unixepoch(),\\n unixepoch()\\n);\\n\"\n },\n {\n id: '023',\n name: 'Add Easy Mdx Plugin',\n filename: '023_add_easy_mdx_plugin.sql',\n description: 'Migration 023: Add Easy Mdx Plugin',\n sql: \"-- Add EasyMDE Markdown Editor Plugin\\n-- Migration: 023_add_easy_mdx_plugin\\n-- Description: Add EasyMDE plugin for lightweight markdown editing\\n\\n-- Register the plugin (active by default)\\nINSERT OR IGNORE INTO plugins (\\n id, name, display_name, description, version, author, category, icon,\\n status, is_core, permissions, dependencies, settings, installed_at, last_updated\\n) VALUES (\\n 'easy-mdx',\\n 'easy-mdx',\\n 'EasyMDE Markdown Editor',\\n 'Lightweight markdown editor with live preview. Provides a simple and efficient editor with markdown support for richtext fields.',\\n '1.0.0',\\n 'SonicJS Team',\\n 'editor',\\n 'š',\\n 'active',\\n FALSE,\\n '[]',\\n '[]',\\n '{\\\"defaultHeight\\\":400,\\\"theme\\\":\\\"dark\\\",\\\"toolbar\\\":\\\"full\\\",\\\"placeholder\\\":\\\"Start writing your content...\\\"}',\\n unixepoch(),\\n unixepoch()\\n);\\n\"\n },\n {\n id: '024',\n name: 'Add Quill Editor Plugin',\n filename: '024_add_quill_editor_plugin.sql',\n description: 'Migration 024: Add Quill Editor Plugin',\n sql: \"-- Add Quill Rich Text Editor Plugin\\n-- Migration: 024_add_quill_editor_plugin\\n-- Description: Add Quill plugin for modern rich text editing\\n\\n-- Register the plugin (active by default)\\nINSERT OR IGNORE INTO plugins (\\n id, name, display_name, description, version, author, category, icon,\\n status, is_core, permissions, dependencies, settings, installed_at, last_updated\\n) VALUES (\\n 'quill-editor',\\n 'quill-editor',\\n 'Quill Rich Text Editor',\\n 'Modern rich text editor for content creation. Provides a clean, intuitive WYSIWYG editor with customizable toolbars for richtext fields.',\\n '1.0.0',\\n 'SonicJS Team',\\n 'editor',\\n 'āļø',\\n 'active',\\n FALSE,\\n '[]',\\n '[]',\\n '{\\\"theme\\\":\\\"snow\\\",\\\"defaultHeight\\\":300,\\\"defaultToolbar\\\":\\\"full\\\",\\\"placeholder\\\":\\\"Start writing your content...\\\"}',\\n unixepoch(),\\n unixepoch()\\n);\\n\"\n },\n {\n id: '025',\n name: 'Add Easymde Plugin',\n filename: '025_add_easymde_plugin.sql',\n description: 'Migration 025: Add Easymde Plugin',\n sql: \"-- Add EasyMDE Rich Text Editor Plugin\\n-- Migration: 025_add_easymde_plugin\\n-- Description: Add EasyMDE plugin for markdown-based rich text editing\\n\\n-- Register the plugin (inactive by default, replacing MDXEditor)\\nINSERT OR IGNORE INTO plugins (\\n id, name, display_name, description, version, author, category, icon,\\n status, is_core, permissions, dependencies, settings, installed_at, last_updated\\n) VALUES (\\n 'easymde-editor',\\n 'easymde-editor',\\n 'EasyMDE Editor',\\n 'Lightweight markdown editor for content creation. Simple, elegant WYSIWYG markdown editor with live preview, toolbar, and dark mode support for richtext fields.',\\n '1.0.0',\\n 'SonicJS Team',\\n 'editor',\\n 'āļø',\\n 'inactive',\\n TRUE,\\n '[]',\\n '[]',\\n '{\\\"theme\\\":\\\"dark\\\",\\\"defaultHeight\\\":300,\\\"toolbar\\\":\\\"full\\\",\\\"spellChecker\\\":false,\\\"placeholder\\\":\\\"Start writing your content...\\\"}',\\n unixepoch(),\\n unixepoch()\\n);\\n\"\n },\n {\n id: '026',\n name: 'Add Otp Login',\n filename: '026_add_otp_login.sql',\n description: 'Migration 026: Add Otp Login',\n sql: \"-- Add OTP Login Plugin\\n-- Migration: 021_add_otp_login\\n-- Description: Add OTP login plugin for passwordless authentication via email codes\\n\\n-- Create table for OTP codes\\nCREATE TABLE IF NOT EXISTS otp_codes (\\n id TEXT PRIMARY KEY,\\n user_email TEXT NOT NULL,\\n code TEXT NOT NULL,\\n expires_at INTEGER NOT NULL,\\n used INTEGER DEFAULT 0,\\n used_at INTEGER,\\n ip_address TEXT,\\n user_agent TEXT,\\n attempts INTEGER DEFAULT 0,\\n created_at INTEGER NOT NULL\\n);\\n\\n-- Create indexes for performance\\nCREATE INDEX IF NOT EXISTS idx_otp_email_code ON otp_codes(user_email, code);\\nCREATE INDEX IF NOT EXISTS idx_otp_expires ON otp_codes(expires_at);\\nCREATE INDEX IF NOT EXISTS idx_otp_used ON otp_codes(used);\\n\\n-- Add plugin record\\nINSERT OR IGNORE INTO plugins (\\n id, name, display_name, description, version, author, category, icon,\\n status, is_core, permissions, installed_at, last_updated\\n) VALUES (\\n 'otp-login',\\n 'otp-login',\\n 'OTP Login',\\n 'Passwordless authentication via email one-time codes',\\n '1.0.0-beta.1',\\n 'SonicJS Team',\\n 'security',\\n 'š¢',\\n 'inactive',\\n TRUE,\\n '[\\\"otp:manage\\\", \\\"otp:request\\\", \\\"otp:verify\\\"]',\\n unixepoch(),\\n unixepoch()\\n);\\n\"\n },\n {\n id: '027',\n name: 'Fix Slug Field Type',\n filename: '027_fix_slug_field_type.sql',\n description: 'Migration 027: Fix Slug Field Type',\n sql: \"-- Migration: Fix slug field type\\n-- Description: Update slug fields to use 'slug' field type instead of 'text' for proper auto-generation\\n-- Created: 2026-01-10\\n\\n-- Update pages collection slug field to use 'slug' field type\\nUPDATE content_fields \\nSET field_type = 'slug'\\nWHERE field_name = 'slug' AND collection_id = 'pages-collection';\\n\\n-- Update blog posts slug field if it exists\\nUPDATE content_fields \\nSET field_type = 'slug'\\nWHERE field_name = 'slug' AND collection_id = 'blog-posts-collection';\\n\\n-- Update news slug field if it exists\\nUPDATE content_fields \\nSET field_type = 'slug'\\nWHERE field_name = 'slug' AND collection_id = 'news-collection';\\n\"\n },\n {\n id: '028',\n name: 'Fix Slug Field Type In Schemas',\n filename: '028_fix_slug_field_type_in_schemas.sql',\n description: 'Migration 028: Fix Slug Field Type In Schemas',\n sql: \"-- Migration: Fix slug field type in collection schemas\\n-- Description: Update slug fields in collection schemas to use 'slug' type instead of 'string'\\n-- Created: 2026-01-10\\n\\n-- Update pages-collection schema\\nUPDATE collections \\nSET schema = REPLACE(\\n schema,\\n '\\\"slug\\\":{\\\"type\\\":\\\"string\\\"',\\n '\\\"slug\\\":{\\\"type\\\":\\\"slug\\\"'\\n)\\nWHERE id = 'pages-collection' AND schema LIKE '%\\\"slug\\\":{\\\"type\\\":\\\"string\\\"%';\\n\\n-- Update blog-posts-collection schema if it exists\\nUPDATE collections \\nSET schema = REPLACE(\\n schema,\\n '\\\"slug\\\":{\\\"type\\\":\\\"string\\\"',\\n '\\\"slug\\\":{\\\"type\\\":\\\"slug\\\"'\\n)\\nWHERE id = 'blog-posts-collection' AND schema LIKE '%\\\"slug\\\":{\\\"type\\\":\\\"string\\\"%';\\n\\n-- Update news-collection schema if it exists\\nUPDATE collections \\nSET schema = REPLACE(\\n schema,\\n '\\\"slug\\\":{\\\"type\\\":\\\"string\\\"',\\n '\\\"slug\\\":{\\\"type\\\":\\\"slug\\\"'\\n)\\nWHERE id = 'news-collection' AND schema LIKE '%\\\"slug\\\":{\\\"type\\\":\\\"string\\\"%';\\n\"\n },\n {\n id: '029',\n name: 'Add Forms System',\n filename: '029_add_forms_system.sql',\n description: 'Migration 029: Add Forms System',\n sql: \"-- Migration: 029_add_forms_system.sql\\n-- Description: Add Form.io integration for advanced form building\\n-- Date: January 23, 2026\\n-- Phase: 1 - Database Schema\\n\\n-- =====================================================\\n-- Table: forms\\n-- Description: Stores form definitions and configuration\\n-- =====================================================\\n\\nCREATE TABLE IF NOT EXISTS forms (\\n id TEXT PRIMARY KEY,\\n name TEXT NOT NULL UNIQUE, -- Machine name (e.g., \\\"contact-form\\\")\\n display_name TEXT NOT NULL, -- Human name (e.g., \\\"Contact Form\\\")\\n description TEXT, -- Optional description\\n category TEXT DEFAULT 'general', -- Form category (contact, survey, registration, etc.)\\n \\n -- Form.io schema (JSON)\\n formio_schema TEXT NOT NULL, -- Complete Form.io JSON schema\\n \\n -- Settings\\n settings TEXT, -- JSON: {\\n -- emailNotifications: true,\\n -- notifyEmail: \\\"admin@example.com\\\",\\n -- successMessage: \\\"Thank you!\\\",\\n -- redirectUrl: \\\"/thank-you\\\",\\n -- allowAnonymous: true,\\n -- requireAuth: false,\\n -- maxSubmissions: null,\\n -- submitButtonText: \\\"Submit\\\",\\n -- saveProgress: true,\\n -- webhookUrl: null\\n -- }\\n \\n -- Status & Management\\n is_active INTEGER DEFAULT 1, -- Active/inactive flag\\n is_public INTEGER DEFAULT 1, -- Public (anyone) vs private (auth required)\\n managed INTEGER DEFAULT 0, -- Code-managed (like collections)\\n \\n -- Metadata\\n icon TEXT, -- Optional icon for admin UI\\n color TEXT, -- Optional color (hex) for admin UI\\n tags TEXT, -- JSON array of tags\\n \\n -- Stats\\n submission_count INTEGER DEFAULT 0, -- Total submissions received\\n view_count INTEGER DEFAULT 0, -- Form views (optional tracking)\\n \\n -- Ownership\\n created_by TEXT REFERENCES users(id), -- User who created the form\\n updated_by TEXT REFERENCES users(id), -- User who last updated\\n \\n -- Timestamps\\n created_at INTEGER NOT NULL,\\n updated_at INTEGER NOT NULL\\n);\\n\\n-- Indexes for forms\\nCREATE INDEX IF NOT EXISTS idx_forms_name ON forms(name);\\nCREATE INDEX IF NOT EXISTS idx_forms_category ON forms(category);\\nCREATE INDEX IF NOT EXISTS idx_forms_active ON forms(is_active);\\nCREATE INDEX IF NOT EXISTS idx_forms_public ON forms(is_public);\\nCREATE INDEX IF NOT EXISTS idx_forms_created_by ON forms(created_by);\\n\\n-- =====================================================\\n-- Table: form_submissions\\n-- Description: Stores submitted form data\\n-- =====================================================\\n\\nCREATE TABLE IF NOT EXISTS form_submissions (\\n id TEXT PRIMARY KEY,\\n form_id TEXT NOT NULL REFERENCES forms(id) ON DELETE CASCADE,\\n \\n -- Submission data\\n submission_data TEXT NOT NULL, -- JSON: The actual form data submitted\\n \\n -- Submission metadata\\n status TEXT DEFAULT 'pending', -- pending, reviewed, approved, rejected, spam\\n submission_number INTEGER, -- Sequential number per form\\n \\n -- User information (if authenticated)\\n user_id TEXT REFERENCES users(id), -- Submitter user ID (if logged in)\\n user_email TEXT, -- Email from form (or user account)\\n \\n -- Tracking information\\n ip_address TEXT, -- IP address of submitter\\n user_agent TEXT, -- Browser user agent\\n referrer TEXT, -- Page that referred to form\\n utm_source TEXT, -- UTM tracking params\\n utm_medium TEXT,\\n utm_campaign TEXT,\\n \\n -- Review/Processing\\n reviewed_by TEXT REFERENCES users(id), -- Admin who reviewed\\n reviewed_at INTEGER, -- Review timestamp\\n review_notes TEXT, -- Admin notes\\n \\n -- Flags\\n is_spam INTEGER DEFAULT 0, -- Spam flag\\n is_archived INTEGER DEFAULT 0, -- Archived flag\\n \\n -- Timestamps\\n submitted_at INTEGER NOT NULL,\\n updated_at INTEGER NOT NULL\\n);\\n\\n-- Indexes for submissions\\nCREATE INDEX IF NOT EXISTS idx_form_submissions_form_id ON form_submissions(form_id);\\nCREATE INDEX IF NOT EXISTS idx_form_submissions_status ON form_submissions(status);\\nCREATE INDEX IF NOT EXISTS idx_form_submissions_user_id ON form_submissions(user_id);\\nCREATE INDEX IF NOT EXISTS idx_form_submissions_email ON form_submissions(user_email);\\nCREATE INDEX IF NOT EXISTS idx_form_submissions_submitted_at ON form_submissions(submitted_at);\\nCREATE INDEX IF NOT EXISTS idx_form_submissions_spam ON form_submissions(is_spam);\\n\\n-- Trigger to auto-increment submission_number per form\\nCREATE TRIGGER IF NOT EXISTS set_submission_number\\nAFTER INSERT ON form_submissions\\nBEGIN\\n UPDATE form_submissions \\n SET submission_number = (\\n SELECT COUNT(*) \\n FROM form_submissions \\n WHERE form_id = NEW.form_id \\n AND id <= NEW.id\\n )\\n WHERE id = NEW.id;\\nEND;\\n\\n-- Trigger to update form submission_count\\nCREATE TRIGGER IF NOT EXISTS increment_form_submission_count\\nAFTER INSERT ON form_submissions\\nBEGIN\\n UPDATE forms \\n SET submission_count = submission_count + 1,\\n updated_at = unixepoch() * 1000\\n WHERE id = NEW.form_id;\\nEND;\\n\\n-- =====================================================\\n-- Table: form_files (Optional)\\n-- Description: Link form submissions to uploaded files\\n-- =====================================================\\n\\nCREATE TABLE IF NOT EXISTS form_files (\\n id TEXT PRIMARY KEY,\\n submission_id TEXT NOT NULL REFERENCES form_submissions(id) ON DELETE CASCADE,\\n media_id TEXT NOT NULL REFERENCES media(id) ON DELETE CASCADE,\\n field_name TEXT NOT NULL, -- Form field that uploaded this file\\n uploaded_at INTEGER NOT NULL\\n);\\n\\n-- Indexes for form files\\nCREATE INDEX IF NOT EXISTS idx_form_files_submission ON form_files(submission_id);\\nCREATE INDEX IF NOT EXISTS idx_form_files_media ON form_files(media_id);\\n\\n-- =====================================================\\n-- Sample Data: Create a default contact form\\n-- =====================================================\\n\\nINSERT OR IGNORE INTO forms (\\n id,\\n name,\\n display_name,\\n description,\\n category,\\n formio_schema,\\n settings,\\n is_active,\\n is_public,\\n created_at,\\n updated_at\\n) VALUES (\\n 'default-contact-form',\\n 'contact',\\n 'Contact Form',\\n 'A simple contact form for getting in touch',\\n 'contact',\\n '{\\\"components\\\":[]}',\\n '{\\\"emailNotifications\\\":false,\\\"successMessage\\\":\\\"Thank you for your submission!\\\",\\\"submitButtonText\\\":\\\"Submit\\\",\\\"requireAuth\\\":false}',\\n 1,\\n 1,\\n unixepoch() * 1000,\\n unixepoch() * 1000\\n);\\n\"\n },\n {\n id: '030',\n name: 'Add Turnstile To Forms',\n filename: '030_add_turnstile_to_forms.sql',\n description: 'Migration 030: Add Turnstile To Forms',\n sql: \"-- Add Turnstile configuration to forms table\\n-- This allows per-form Turnstile settings with global fallback\\n\\n-- Add columns (D1 may not support CHECK constraints in ALTER TABLE)\\nALTER TABLE forms ADD COLUMN turnstile_enabled INTEGER DEFAULT 0;\\nALTER TABLE forms ADD COLUMN turnstile_settings TEXT;\\n\\n-- Set default to inherit global settings for existing forms\\nUPDATE forms \\nSET turnstile_settings = '{\\\"inherit\\\":true}' \\nWHERE turnstile_settings IS NULL;\\n\\n-- Add index for faster lookups\\nCREATE INDEX IF NOT EXISTS idx_forms_turnstile ON forms(turnstile_enabled);\\n\"\n },\n {\n id: '031',\n name: 'Ai Search Plugin',\n filename: '031_ai_search_plugin.sql',\n description: 'Migration 031: Ai Search Plugin',\n sql: \"-- AI Search plugin settings\\nCREATE TABLE IF NOT EXISTS ai_search_settings (\\n id INTEGER PRIMARY KEY AUTOINCREMENT,\\n enabled BOOLEAN DEFAULT 0,\\n ai_mode_enabled BOOLEAN DEFAULT 1,\\n selected_collections TEXT, -- JSON array of collection IDs to index\\n dismissed_collections TEXT, -- JSON array of collection IDs user chose not to index\\n autocomplete_enabled BOOLEAN DEFAULT 1,\\n cache_duration INTEGER DEFAULT 1, -- hours\\n results_limit INTEGER DEFAULT 20,\\n index_media BOOLEAN DEFAULT 0,\\n index_status TEXT, -- JSON object with status per collection\\n last_indexed_at INTEGER,\\n created_at INTEGER DEFAULT (strftime('%s', 'now') * 1000),\\n updated_at INTEGER DEFAULT (strftime('%s', 'now') * 1000)\\n);\\n\\n-- Search history/analytics\\nCREATE TABLE IF NOT EXISTS ai_search_history (\\n id INTEGER PRIMARY KEY AUTOINCREMENT,\\n query TEXT NOT NULL,\\n mode TEXT, -- 'ai' or 'keyword'\\n results_count INTEGER,\\n user_id INTEGER,\\n created_at INTEGER DEFAULT (strftime('%s', 'now') * 1000)\\n);\\n\\n-- Index metadata tracking (per collection)\\nCREATE TABLE IF NOT EXISTS ai_search_index_meta (\\n id INTEGER PRIMARY KEY AUTOINCREMENT,\\n collection_id INTEGER NOT NULL,\\n collection_name TEXT NOT NULL, -- Cache collection name for display\\n total_items INTEGER DEFAULT 0,\\n indexed_items INTEGER DEFAULT 0,\\n last_sync_at INTEGER,\\n status TEXT DEFAULT 'pending', -- 'pending', 'indexing', 'completed', 'error'\\n error_message TEXT,\\n UNIQUE(collection_id)\\n);\\n\\n-- Indexes for performance\\nCREATE INDEX IF NOT EXISTS idx_ai_search_history_created_at ON ai_search_history(created_at);\\nCREATE INDEX IF NOT EXISTS idx_ai_search_history_mode ON ai_search_history(mode);\\nCREATE INDEX IF NOT EXISTS idx_ai_search_index_meta_collection_id ON ai_search_index_meta(collection_id);\\nCREATE INDEX IF NOT EXISTS idx_ai_search_index_meta_status ON ai_search_index_meta(status);\\n\"\n }\n]\n\n// Map for quick lookup by ID\nexport const migrationsByIdMap = new Map(\n bundledMigrations.map(m => [m.id, m])\n)\n\n// Get migration SQL by ID\nexport function getMigrationSQLById(id: string): string | null {\n return migrationsByIdMap.get(id)?.sql ?? null\n}\n\n// Get all migration info (without SQL for lighter payloads)\nexport function getMigrationList(): Array> {\n return bundledMigrations.map(({ sql, ...rest }) => rest)\n}\n","import { D1Database } from '@cloudflare/workers-types'\nimport { bundledMigrations, getMigrationSQLById, type BundledMigration } from '../db/migrations-bundle'\n\nexport interface Migration {\n id: string\n name: string\n filename: string\n description?: string\n applied: boolean\n appliedAt?: string\n size?: number\n}\n\nexport interface MigrationStatus {\n totalMigrations: number\n appliedMigrations: number\n pendingMigrations: number\n lastApplied?: string\n migrations: Migration[]\n}\n\nexport class MigrationService {\n constructor(private db: D1Database) {}\n\n /**\n * Initialize the migrations tracking table\n */\n async initializeMigrationsTable(): Promise {\n const createTableQuery = `\n CREATE TABLE IF NOT EXISTS migrations (\n id TEXT PRIMARY KEY,\n name TEXT NOT NULL,\n filename TEXT NOT NULL,\n applied_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,\n checksum TEXT\n )\n `\n\n await this.db.prepare(createTableQuery).run()\n }\n\n /**\n * Get all available migrations from the bundled migrations\n */\n async getAvailableMigrations(): Promise {\n const migrations: Migration[] = []\n\n // Get applied migrations from database\n const appliedResult = await this.db.prepare(\n 'SELECT id, name, filename, applied_at FROM migrations ORDER BY applied_at ASC'\n ).all()\n\n const appliedMigrations = new Map(\n appliedResult.results?.map((row: any) => [row.id, row]) || []\n )\n\n // Auto-detect applied migrations by checking if their tables exist\n await this.autoDetectAppliedMigrations(appliedMigrations)\n\n // Use bundled migrations as the source of truth\n for (const bundled of bundledMigrations) {\n const applied = appliedMigrations.has(bundled.id)\n const appliedData = appliedMigrations.get(bundled.id)\n\n migrations.push({\n id: bundled.id,\n name: bundled.name,\n filename: bundled.filename,\n description: bundled.description,\n applied,\n appliedAt: applied ? appliedData?.applied_at : undefined,\n size: bundled.sql.length\n })\n }\n\n return migrations\n }\n\n /**\n * Auto-detect applied migrations by checking if their tables exist\n */\n private async autoDetectAppliedMigrations(appliedMigrations: Map): Promise {\n // Check if basic schema tables exist (migration 001)\n if (!appliedMigrations.has('001')) {\n const hasBasicTables = await this.checkTablesExist(['users', 'content', 'collections', 'media'])\n if (hasBasicTables) {\n appliedMigrations.set('001', {\n id: '001',\n applied_at: new Date().toISOString(),\n name: 'Initial Schema',\n filename: '001_initial_schema.sql'\n })\n await this.markMigrationApplied('001', 'Initial Schema', '001_initial_schema.sql')\n }\n }\n\n // Check if FAQ tables exist (migration 002)\n // Migration 002 creates only the 'faqs' table\n if (!appliedMigrations.has('002')) {\n const hasFaqTables = await this.checkTablesExist(['faqs'])\n if (hasFaqTables) {\n appliedMigrations.set('002', {\n id: '002',\n applied_at: new Date().toISOString(),\n name: 'Faq Plugin',\n filename: '002_faq_plugin.sql'\n })\n await this.markMigrationApplied('002', 'Faq Plugin', '002_faq_plugin.sql')\n }\n }\n\n // Check if stage 5 enhancement tables exist (migration 003)\n // Migration 003 creates content_fields, content_relationships, workflow_templates tables\n if (!appliedMigrations.has('003')) {\n const hasStage5Tables = await this.checkTablesExist(['content_fields', 'content_relationships', 'workflow_templates'])\n if (hasStage5Tables) {\n appliedMigrations.set('003', {\n id: '003',\n applied_at: new Date().toISOString(),\n name: 'Stage 5 Enhancements',\n filename: '003_stage5_enhancements.sql'\n })\n await this.markMigrationApplied('003', 'Stage 5 Enhancements', '003_stage5_enhancements.sql')\n }\n }\n\n // Check if testimonials table exists (migration 012)\n if (!appliedMigrations.has('012')) {\n const hasTestimonialsTables = await this.checkTablesExist(['testimonials'])\n if (hasTestimonialsTables) {\n appliedMigrations.set('012', {\n id: '012',\n applied_at: new Date().toISOString(),\n name: 'Testimonials Plugin',\n filename: '012_testimonials_plugin.sql'\n })\n await this.markMigrationApplied('012', 'Testimonials Plugin', '012_testimonials_plugin.sql')\n }\n }\n\n // Check if code_examples table exists (migration 013)\n if (!appliedMigrations.has('013')) {\n const hasCodeExamplesTables = await this.checkTablesExist(['code_examples'])\n if (hasCodeExamplesTables) {\n appliedMigrations.set('013', {\n id: '013',\n applied_at: new Date().toISOString(),\n name: 'Code Examples Plugin',\n filename: '013_code_examples_plugin.sql'\n })\n await this.markMigrationApplied('013', 'Code Examples Plugin', '013_code_examples_plugin.sql')\n }\n }\n\n // Check if user management tables exist (migration 004)\n if (!appliedMigrations.has('004')) {\n const hasUserTables = await this.checkTablesExist(['api_tokens', 'workflow_history'])\n if (hasUserTables) {\n appliedMigrations.set('004', {\n id: '004',\n applied_at: new Date().toISOString(),\n name: 'User Management',\n filename: '004_stage6_user_management.sql'\n })\n await this.markMigrationApplied('004', 'User Management', '004_stage6_user_management.sql')\n }\n }\n\n // Check if plugin system tables exist (migration 006)\n if (!appliedMigrations.has('006')) {\n const hasPluginTables = await this.checkTablesExist(['plugins', 'plugin_hooks'])\n if (hasPluginTables) {\n appliedMigrations.set('006', {\n id: '006',\n applied_at: new Date().toISOString(),\n name: 'Plugin System',\n filename: '006_plugin_system.sql'\n })\n await this.markMigrationApplied('006', 'Plugin System', '006_plugin_system.sql')\n }\n }\n\n // Check if managed column exists (migration 011)\n // This handles both cases:\n // 1. Migration not marked as applied but column exists -> mark as applied\n // 2. Migration marked as applied but column doesn't exist -> remove from applied (will re-run)\n const hasManagedColumn = await this.checkColumnExists('collections', 'managed')\n if (!appliedMigrations.has('011') && hasManagedColumn) {\n appliedMigrations.set('011', {\n id: '011',\n applied_at: new Date().toISOString(),\n name: 'Config Managed Collections',\n filename: '011_config_managed_collections.sql'\n })\n await this.markMigrationApplied('011', 'Config Managed Collections', '011_config_managed_collections.sql')\n } else if (appliedMigrations.has('011') && !hasManagedColumn) {\n // Migration was marked as applied but column doesn't exist - remove it so it will re-run\n console.log('[Migration] Migration 011 marked as applied but managed column missing - will re-run')\n appliedMigrations.delete('011')\n await this.removeMigrationApplied('011')\n }\n\n // Check if system_logs table exists (migration 009)\n if (!appliedMigrations.has('009')) {\n const hasLoggingTables = await this.checkTablesExist(['system_logs', 'log_config'])\n if (hasLoggingTables) {\n appliedMigrations.set('009', {\n id: '009',\n applied_at: new Date().toISOString(),\n name: 'System Logging',\n filename: '009_system_logging.sql'\n })\n await this.markMigrationApplied('009', 'System Logging', '009_system_logging.sql')\n }\n }\n\n // Check if settings table exists (migration 018)\n if (!appliedMigrations.has('018')) {\n const hasSettingsTable = await this.checkTablesExist(['settings'])\n if (hasSettingsTable) {\n appliedMigrations.set('018', {\n id: '018',\n applied_at: new Date().toISOString(),\n name: 'Settings Table',\n filename: '018_settings_table.sql'\n })\n await this.markMigrationApplied('018', 'Settings Table', '018_settings_table.sql')\n }\n }\n }\n\n /**\n * Check if specific tables exist in the database\n */\n private async checkTablesExist(tableNames: string[]): Promise {\n try {\n for (const tableName of tableNames) {\n const result = await this.db.prepare(\n `SELECT name FROM sqlite_master WHERE type='table' AND name=?`\n ).bind(tableName).first()\n\n if (!result) {\n return false\n }\n }\n return true\n } catch (error) {\n return false\n }\n }\n\n /**\n * Check if a specific column exists in a table\n */\n private async checkColumnExists(tableName: string, columnName: string): Promise {\n try {\n const result = await this.db.prepare(\n `SELECT * FROM pragma_table_info(?) WHERE name = ?`\n ).bind(tableName, columnName).first()\n\n return !!result\n } catch (error) {\n return false\n }\n }\n\n /**\n * Get migration status summary\n */\n async getMigrationStatus(): Promise {\n await this.initializeMigrationsTable()\n\n const migrations = await this.getAvailableMigrations()\n const appliedMigrations = migrations.filter(m => m.applied)\n const pendingMigrations = migrations.filter(m => !m.applied)\n\n const lastApplied = appliedMigrations.length > 0\n ? appliedMigrations[appliedMigrations.length - 1]?.appliedAt\n : undefined\n\n return {\n totalMigrations: migrations.length,\n appliedMigrations: appliedMigrations.length,\n pendingMigrations: pendingMigrations.length,\n lastApplied,\n migrations\n }\n }\n\n /**\n * Mark a migration as applied\n */\n async markMigrationApplied(migrationId: string, name: string, filename: string): Promise {\n await this.initializeMigrationsTable()\n\n await this.db.prepare(\n 'INSERT OR REPLACE INTO migrations (id, name, filename, applied_at) VALUES (?, ?, ?, CURRENT_TIMESTAMP)'\n ).bind(migrationId, name, filename).run()\n }\n\n /**\n * Remove a migration from the applied list (so it can be re-run)\n */\n async removeMigrationApplied(migrationId: string): Promise {\n await this.initializeMigrationsTable()\n\n await this.db.prepare(\n 'DELETE FROM migrations WHERE id = ?'\n ).bind(migrationId).run()\n }\n\n /**\n * Check if a specific migration has been applied\n */\n async isMigrationApplied(migrationId: string): Promise {\n await this.initializeMigrationsTable()\n\n const result = await this.db.prepare(\n 'SELECT COUNT(*) as count FROM migrations WHERE id = ?'\n ).bind(migrationId).first()\n\n return (result?.count as number) > 0\n }\n\n /**\n * Get the last applied migration\n */\n async getLastAppliedMigration(): Promise {\n await this.initializeMigrationsTable()\n\n const result = await this.db.prepare(\n 'SELECT id, name, filename, applied_at FROM migrations ORDER BY applied_at DESC LIMIT 1'\n ).first()\n\n if (!result) return null\n\n return {\n id: result.id as string,\n name: result.name as string,\n filename: result.filename as string,\n applied: true,\n appliedAt: result.applied_at as string\n }\n }\n\n /**\n * Run pending migrations\n */\n async runPendingMigrations(): Promise<{ success: boolean; message: string; applied: string[] }> {\n await this.initializeMigrationsTable()\n\n const status = await this.getMigrationStatus()\n const pendingMigrations = status.migrations.filter(m => !m.applied)\n\n if (pendingMigrations.length === 0) {\n return {\n success: true,\n message: 'All migrations are up to date',\n applied: []\n }\n }\n\n // Actually execute the migration files\n const applied: string[] = []\n const errors: string[] = []\n\n for (const migration of pendingMigrations) {\n try {\n console.log(`[Migration] Applying ${migration.id}: ${migration.name}`)\n await this.applyMigration(migration)\n await this.markMigrationApplied(migration.id, migration.name, migration.filename)\n applied.push(migration.id)\n console.log(`[Migration] Successfully applied ${migration.id}`)\n } catch (error) {\n const errorMessage = error instanceof Error ? error.message : String(error)\n console.error(`[Migration] Failed to apply migration ${migration.id}:`, errorMessage)\n errors.push(`${migration.id}: ${errorMessage}`)\n // Continue with other migrations instead of stopping on first failure\n // This allows independent migrations to still be applied\n }\n }\n\n if (errors.length > 0 && applied.length === 0) {\n return {\n success: false,\n message: `Failed to apply migrations: ${errors.join('; ')}`,\n applied\n }\n }\n\n return {\n success: true,\n message: applied.length > 0\n ? `Applied ${applied.length} migration(s)${errors.length > 0 ? ` (${errors.length} failed)` : ''}`\n : 'No migrations applied',\n applied\n }\n }\n\n /**\n * Apply a specific migration\n */\n private async applyMigration(migration: Migration): Promise {\n // Get the actual migration SQL from the bundle\n const migrationSQL = getMigrationSQLById(migration.id)\n\n if (migrationSQL === null) {\n throw new Error(`Migration SQL not found for ${migration.id}`)\n }\n\n if (migrationSQL.trim() === '') {\n console.log(`[Migration] Skipping empty migration ${migration.id}`)\n return\n }\n\n // Split SQL into individual statements, handling triggers properly\n const statements = this.splitSQLStatements(migrationSQL)\n\n for (const statement of statements) {\n if (statement.trim()) {\n try {\n await this.db.prepare(statement).run()\n } catch (error) {\n // Check if it's a \"already exists\" type error and skip it\n const errorMessage = error instanceof Error ? error.message : String(error)\n if (errorMessage.includes('already exists') ||\n errorMessage.includes('duplicate column name') ||\n errorMessage.includes('UNIQUE constraint failed')) {\n console.log(`[Migration] Skipping (already exists): ${statement.substring(0, 50)}...`)\n continue\n }\n console.error(`[Migration] Error executing statement: ${statement.substring(0, 100)}...`)\n throw error\n }\n }\n }\n }\n\n /**\n * Split SQL into statements, handling CREATE TRIGGER properly\n */\n private splitSQLStatements(sql: string): string[] {\n const statements: string[] = []\n let current = ''\n let inTrigger = false\n\n const lines = sql.split('\\n')\n\n for (const line of lines) {\n const trimmed = line.trim()\n\n // Skip comments and empty lines\n if (trimmed.startsWith('--') || trimmed.length === 0) {\n continue\n }\n\n // Check if we're entering a trigger\n if (trimmed.toUpperCase().includes('CREATE TRIGGER')) {\n inTrigger = true\n }\n\n current += line + '\\n'\n\n // Check if we're exiting a trigger\n if (inTrigger && trimmed.toUpperCase() === 'END;') {\n statements.push(current.trim())\n current = ''\n inTrigger = false\n }\n // Check for regular statement end (not in trigger)\n else if (!inTrigger && trimmed.endsWith(';')) {\n statements.push(current.trim())\n current = ''\n }\n }\n\n // Add any remaining statement\n if (current.trim()) {\n statements.push(current.trim())\n }\n\n return statements.filter(s => s.length > 0)\n }\n\n /**\n * Validate database schema\n */\n async validateSchema(): Promise<{ valid: boolean; issues: string[] }> {\n const issues: string[] = []\n\n // Basic table existence checks\n const requiredTables = [\n 'users', 'content', 'collections', 'media'\n ]\n\n for (const table of requiredTables) {\n try {\n await this.db.prepare(`SELECT COUNT(*) FROM ${table} LIMIT 1`).first()\n } catch (error) {\n issues.push(`Missing table: ${table}`)\n }\n }\n\n // Check for managed column in collections\n const hasManagedColumn = await this.checkColumnExists('collections', 'managed')\n if (!hasManagedColumn) {\n issues.push('Missing column: collections.managed')\n }\n\n return {\n valid: issues.length === 0,\n issues\n }\n }\n}\n"]}
\ No newline at end of file
diff --git a/packages/core/dist/chunk-7DU5PUKL.js b/packages/core/dist/chunk-3TMCOE5J.js
similarity index 71%
rename from packages/core/dist/chunk-7DU5PUKL.js
rename to packages/core/dist/chunk-3TMCOE5J.js
index 00f6ff553..15a9adc16 100644
--- a/packages/core/dist/chunk-7DU5PUKL.js
+++ b/packages/core/dist/chunk-3TMCOE5J.js
@@ -1,10 +1,10 @@
-import { getCacheService, CACHE_CONFIGS, getLogger, SettingsService } from './chunk-5PH7K7YR.js';
-import { requireAuth, isPluginActive, requireRole, AuthManager, logActivity } from './chunk-FQAOOSEB.js';
+import { getCacheService, CACHE_CONFIGS, getLogger, SettingsService } from './chunk-G44QUVNM.js';
+import { requireAuth, isPluginActive, requireRole, AuthManager, logActivity, VALID_SCOPES, hashApiKey } from './chunk-7I5MEIXX.js';
import { PluginService } from './chunk-YFJJU26H.js';
-import { MigrationService } from './chunk-DADFCDML.js';
-import { init_admin_layout_catalyst_template, renderDesignPage, renderCheckboxPage, renderTestimonialsList, renderCodeExamplesList, renderAlert, renderTable, renderPagination, renderConfirmationDialog, getConfirmationDialogScript, renderAdminLayoutCatalyst, renderAdminLayout, adminLayoutV2, renderForm } from './chunk-VCH6HXVP.js';
+import { MigrationService } from './chunk-LOUDW6VZ.js';
+import { init_admin_layout_catalyst_template, renderDesignPage, renderCheckboxPage, renderTestimonialsList, renderCodeExamplesList, renderAlert, renderTable, renderPagination, renderConfirmationDialog, getConfirmationDialogScript, renderAdminLayoutCatalyst, renderAdminLayout, adminLayoutV2, renderForm } from './chunk-AAU4BTDE.js';
import { PluginBuilder, TurnstileService } from './chunk-J5WGMRSU.js';
-import { QueryFilterBuilder, sanitizeInput, getCoreVersion, escapeHtml, getBlocksFieldConfig, parseBlocksValue } from './chunk-PSRPBW3W.js';
+import { QueryFilterBuilder, sanitizeInput, getCoreVersion, escapeHtml, getBlocksFieldConfig, parseBlocksValue } from './chunk-7DXWBEQP.js';
import { metricsTracker } from './chunk-FICTAGD4.js';
import { Hono } from 'hono';
import { cors } from 'hono/cors';
@@ -14,2287 +14,3510 @@ import { html, raw } from 'hono/html';
// src/schemas/index.ts
var schemaDefinitions = [];
-var apiContentCrudRoutes = new Hono();
-apiContentCrudRoutes.get("/check-slug", async (c) => {
- try {
- const db = c.env.DB;
- const collectionId = c.req.query("collectionId");
- const slug = c.req.query("slug");
- const excludeId = c.req.query("excludeId");
- if (!collectionId || !slug) {
- return c.json({ error: "collectionId and slug are required" }, 400);
- }
- let query = "SELECT id FROM content WHERE collection_id = ? AND slug = ?";
- const params = [collectionId, slug];
- if (excludeId) {
- query += " AND id != ?";
- params.push(excludeId);
- }
- const existing = await db.prepare(query).bind(...params).first();
- if (existing) {
- return c.json({
- available: false,
- message: "This URL slug is already in use in this collection"
- });
- }
- return c.json({ available: true });
- } catch (error) {
- console.error("Error checking slug:", error);
- return c.json({
- error: "Failed to check slug availability",
- details: error instanceof Error ? error.message : String(error)
- }, 500);
- }
-});
-apiContentCrudRoutes.get("/:id", async (c) => {
- try {
- const id = c.req.param("id");
- const db = c.env.DB;
- const stmt = db.prepare("SELECT * FROM content WHERE id = ?");
- const content = await stmt.bind(id).first();
- if (!content) {
- return c.json({ error: "Content not found" }, 404);
- }
- const transformedContent = {
- id: content.id,
- title: content.title,
- slug: content.slug,
- status: content.status,
- collectionId: content.collection_id,
- data: content.data ? JSON.parse(content.data) : {},
- created_at: content.created_at,
- updated_at: content.updated_at
- };
- return c.json({ data: transformedContent });
- } catch (error) {
- console.error("Error fetching content:", error);
- return c.json({
- error: "Failed to fetch content",
- details: error instanceof Error ? error.message : String(error)
- }, 500);
+
+// src/plugins/core-plugins/ai-search-plugin/services/facet.service.ts
+var NON_FACETABLE_FORMATS = /* @__PURE__ */ new Set(["richtext", "media", "date-time", "slug"]);
+var BUILTIN_FIELD_NAMES = /* @__PURE__ */ new Set(["author", "status"]);
+var FacetService = class _FacetService {
+ constructor(db) {
+ this.db = db;
}
-});
-apiContentCrudRoutes.post("/", requireAuth(), async (c) => {
- try {
- const db = c.env.DB;
- const user = c.get("user");
- const body = await c.req.json();
- const { collectionId, title, slug, status, data } = body;
- if (!collectionId) {
- return c.json({ error: "collectionId is required" }, 400);
- }
- if (!title) {
- return c.json({ error: "title is required" }, 400);
- }
- let finalSlug = slug || title;
- finalSlug = finalSlug.toLowerCase().replace(/[^a-z0-9\s-]/g, "").replace(/\s+/g, "-").replace(/-+/g, "-").trim();
- const duplicateCheck = db.prepare(
- "SELECT id FROM content WHERE collection_id = ? AND slug = ?"
+ // =============================================
+ // Discovery ā introspect collection schemas
+ // =============================================
+ /**
+ * Discover facetable fields from all active collection schemas.
+ * Returns built-in facets + custom fields classified by type.
+ */
+ async discoverFields() {
+ const discovered = [];
+ discovered.push(
+ { field: "collection_name", title: "Collection", type: "builtin", recommended: true, collections: [] },
+ { field: "status", title: "Status", type: "builtin", recommended: true, collections: [], enumValues: ["draft", "published", "archived"] },
+ { field: "author", title: "Author", type: "builtin", recommended: true, collections: [] }
);
- const existing = await duplicateCheck.bind(collectionId, finalSlug).first();
- if (existing) {
- return c.json({ error: "A content item with this slug already exists in this collection" }, 409);
- }
- const contentId = crypto.randomUUID();
- const now = Date.now();
- const insertStmt = db.prepare(`
- INSERT INTO content (
- id, collection_id, slug, title, data, status,
- author_id, created_at, updated_at
- )
- VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
- `);
- await insertStmt.bind(
- contentId,
- collectionId,
- finalSlug,
- title,
- JSON.stringify(data || {}),
- status || "draft",
- user?.userId || "system",
- now,
- now
- ).run();
- const cache = getCacheService(CACHE_CONFIGS.api);
- await cache.invalidate(`content:list:${collectionId}:*`);
- await cache.invalidate("content-filtered:*");
- const getStmt = db.prepare("SELECT * FROM content WHERE id = ?");
- const createdContent = await getStmt.bind(contentId).first();
- return c.json({
- data: {
- id: createdContent.id,
- title: createdContent.title,
- slug: createdContent.slug,
- status: createdContent.status,
- collectionId: createdContent.collection_id,
- data: createdContent.data ? JSON.parse(createdContent.data) : {},
- created_at: createdContent.created_at,
- updated_at: createdContent.updated_at
+ try {
+ const { results } = await this.db.prepare(`SELECT id, name, display_name, schema FROM collections WHERE is_active = 1`).all();
+ if (!results?.length) return discovered;
+ const fieldMap = /* @__PURE__ */ new Map();
+ for (const col of results) {
+ let schema;
+ try {
+ schema = typeof col.schema === "string" ? JSON.parse(col.schema) : col.schema;
+ } catch {
+ continue;
+ }
+ const properties = schema?.properties;
+ if (!properties || typeof properties !== "object") continue;
+ for (const [fieldName, fieldDef] of Object.entries(properties)) {
+ const def = fieldDef;
+ if (!def || typeof def !== "object") continue;
+ if (BUILTIN_FIELD_NAMES.has(fieldName)) continue;
+ const classification = this.classifyField(fieldName, def);
+ if (!classification) continue;
+ const path = `$.${fieldName}`;
+ const existing = fieldMap.get(path);
+ if (existing) {
+ existing.collections.push({ id: col.id, name: col.display_name });
+ } else {
+ fieldMap.set(path, {
+ title: def.title || fieldName,
+ type: classification.type,
+ recommended: classification.recommended,
+ collections: [{ id: col.id, name: col.display_name }],
+ enumValues: classification.enumValues
+ });
+ }
+ }
}
- }, 201);
- } catch (error) {
- console.error("Error creating content:", error);
- return c.json({
- error: "Failed to create content",
- details: error instanceof Error ? error.message : String(error)
- }, 500);
- }
-});
-apiContentCrudRoutes.put("/:id", requireAuth(), async (c) => {
- try {
- const id = c.req.param("id");
- const db = c.env.DB;
- const body = await c.req.json();
- const existingStmt = db.prepare("SELECT * FROM content WHERE id = ?");
- const existing = await existingStmt.bind(id).first();
- if (!existing) {
- return c.json({ error: "Content not found" }, 404);
+ for (const [field, info] of fieldMap) {
+ discovered.push({
+ field,
+ title: info.title,
+ type: info.type,
+ recommended: info.recommended,
+ collections: info.collections,
+ enumValues: info.enumValues
+ });
+ }
+ } catch (error) {
+ console.error("[FacetService] Discovery error:", error);
}
- const updates = [];
- const params = [];
- if (body.title !== void 0) {
- updates.push("title = ?");
- params.push(body.title);
+ return discovered;
+ }
+ /**
+ * Classify a field definition from collection schema.
+ * Returns null if the field is not facetable.
+ */
+ classifyField(fieldName, def) {
+ const fieldType = def.type;
+ const format = def.format;
+ if (format && NON_FACETABLE_FORMATS.has(format)) return null;
+ if (fieldType === "object") return null;
+ if (fieldType === "number" || fieldType === "integer") return null;
+ if (fieldType === "array" && def.items?.type === "string") {
+ return { type: "json_array", recommended: true };
}
- if (body.slug !== void 0) {
- let finalSlug = body.slug.toLowerCase().replace(/[^a-z0-9\s-]/g, "").replace(/\s+/g, "-").replace(/-+/g, "-").trim();
- updates.push("slug = ?");
- params.push(finalSlug);
+ if (fieldType === "string" && Array.isArray(def.enum) && def.enum.length > 0) {
+ return { type: "json_scalar", recommended: true, enumValues: def.enum };
}
- if (body.status !== void 0) {
- updates.push("status = ?");
- params.push(body.status);
+ if (fieldType === "boolean") {
+ return { type: "json_scalar", recommended: true, enumValues: ["true", "false"] };
}
- if (body.data !== void 0) {
- updates.push("data = ?");
- params.push(JSON.stringify(body.data));
+ if (fieldType === "string" && !format) {
+ return { type: "json_scalar", recommended: false };
}
- const now = Date.now();
- updates.push("updated_at = ?");
- params.push(now);
- params.push(id);
- const updateStmt = db.prepare(`
- UPDATE content SET ${updates.join(", ")}
- WHERE id = ?
- `);
- await updateStmt.bind(...params).run();
- const cache = getCacheService(CACHE_CONFIGS.api);
- await cache.delete(cache.generateKey("content", id));
- await cache.invalidate(`content:list:${existing.collection_id}:*`);
- await cache.invalidate("content-filtered:*");
- const getStmt = db.prepare("SELECT * FROM content WHERE id = ?");
- const updatedContent = await getStmt.bind(id).first();
- return c.json({
- data: {
- id: updatedContent.id,
- title: updatedContent.title,
- slug: updatedContent.slug,
- status: updatedContent.status,
- collectionId: updatedContent.collection_id,
- data: updatedContent.data ? JSON.parse(updatedContent.data) : {},
- created_at: updatedContent.created_at,
- updated_at: updatedContent.updated_at
+ return null;
+ }
+ // =============================================
+ // Auto-generation ā create default config
+ // =============================================
+ /**
+ * Generate default facet config from discovered fields.
+ * Only enables recommended fields.
+ */
+ autoGenerateConfig(discovered) {
+ return discovered.filter((d) => d.recommended).map((d, i) => ({
+ name: d.title,
+ field: d.field,
+ type: d.type,
+ collections: d.collections.map((c) => c.id),
+ enabled: true,
+ source: "auto",
+ position: i,
+ sortBy: "count"
+ }));
+ }
+ // =============================================
+ // Computation ā SQL GROUP BY (FTS5/keyword)
+ // =============================================
+ /**
+ * Compute facets for FTS5 mode using parallel SQL GROUP BY queries.
+ * Counts reflect the full matching result set (not just current page).
+ */
+ async computeFacetsFts(config, matchQuery, collectionIds, maxValues, activeFilters) {
+ const enabled = config.filter((f) => f.enabled);
+ if (enabled.length === 0 || collectionIds.length === 0) return [];
+ const collPlaceholders = collectionIds.map(() => "?").join(", ");
+ const promises = enabled.map(async (facet) => {
+ const limit = facet.maxValues || maxValues;
+ let extraConditions = [];
+ let extraParams = [];
+ if (activeFilters && Object.keys(activeFilters).length > 0) {
+ const cross = _FacetService.buildFacetFilterSQL(activeFilters, config, facet.field);
+ extraConditions = cross.conditions;
+ extraParams = cross.params;
+ }
+ try {
+ const values = await this.runFtsFacetQuery(facet, matchQuery, collectionIds, collPlaceholders, limit, extraConditions, extraParams);
+ return this.sortFacetValues(facet, values);
+ } catch (error) {
+ console.error(`[FacetService] Facet query error for ${facet.field}:`, error);
+ return { name: facet.name, field: facet.field, values: [] };
}
});
- } catch (error) {
- console.error("Error updating content:", error);
- return c.json({
- error: "Failed to update content",
- details: error instanceof Error ? error.message : String(error)
- }, 500);
+ return Promise.all(promises);
}
-});
-apiContentCrudRoutes.delete("/:id", requireAuth(), async (c) => {
- try {
- const id = c.req.param("id");
- const db = c.env.DB;
- const existingStmt = db.prepare("SELECT collection_id FROM content WHERE id = ?");
- const existing = await existingStmt.bind(id).first();
- if (!existing) {
- return c.json({ error: "Content not found" }, 404);
+ async runFtsFacetQuery(facet, matchQuery, collectionIds, collPlaceholders, limit, extraConditions = [], extraParams = []) {
+ const extraWhere = extraConditions.length > 0 ? "\n " + extraConditions.map((c) => `AND ${c}`).join("\n ") : "";
+ let sql;
+ let params;
+ switch (facet.field) {
+ case "collection_name":
+ sql = `
+ SELECT col.display_name as value, COUNT(*) as count
+ FROM content_fts fts
+ JOIN content c ON fts.content_id = c.id
+ JOIN collections col ON fts.collection_id = col.id
+ WHERE content_fts MATCH ?
+ AND fts.collection_id IN (${collPlaceholders})
+ AND c.status != 'deleted'${extraWhere}
+ GROUP BY value ORDER BY count DESC LIMIT ?
+ `;
+ params = [matchQuery, ...collectionIds, ...extraParams, limit];
+ break;
+ case "status":
+ sql = `
+ SELECT c.status as value, COUNT(*) as count
+ FROM content_fts fts
+ JOIN content c ON fts.content_id = c.id
+ WHERE content_fts MATCH ?
+ AND fts.collection_id IN (${collPlaceholders})
+ AND c.status != 'deleted'${extraWhere}
+ GROUP BY c.status ORDER BY count DESC LIMIT ?
+ `;
+ params = [matchQuery, ...collectionIds, ...extraParams, limit];
+ break;
+ case "author":
+ sql = `
+ SELECT COALESCE(u.email, 'Unknown') as value, COUNT(*) as count
+ FROM content_fts fts
+ JOIN content c ON fts.content_id = c.id
+ LEFT JOIN users u ON c.author_id = u.id
+ WHERE content_fts MATCH ?
+ AND fts.collection_id IN (${collPlaceholders})
+ AND c.status != 'deleted'${extraWhere}
+ GROUP BY value ORDER BY count DESC LIMIT ?
+ `;
+ params = [matchQuery, ...collectionIds, ...extraParams, limit];
+ break;
+ default:
+ if (facet.type === "json_array") {
+ const jsonPath = facet.field;
+ sql = `
+ SELECT j.value as value, COUNT(*) as count
+ FROM content_fts fts
+ JOIN content c ON fts.content_id = c.id,
+ json_each(json_extract(c.data, '${jsonPath}')) j
+ WHERE content_fts MATCH ?
+ AND fts.collection_id IN (${collPlaceholders})
+ AND c.status != 'deleted'${extraWhere}
+ GROUP BY j.value ORDER BY count DESC LIMIT ?
+ `;
+ } else {
+ const jsonPath = facet.field;
+ sql = `
+ SELECT json_extract(c.data, '${jsonPath}') as value, COUNT(*) as count
+ FROM content_fts fts
+ JOIN content c ON fts.content_id = c.id
+ WHERE content_fts MATCH ?
+ AND fts.collection_id IN (${collPlaceholders})
+ AND c.status != 'deleted'
+ AND json_extract(c.data, '${jsonPath}') IS NOT NULL${extraWhere}
+ GROUP BY value ORDER BY count DESC LIMIT ?
+ `;
+ }
+ params = [matchQuery, ...collectionIds, ...extraParams, limit];
}
- const deleteStmt = db.prepare("DELETE FROM content WHERE id = ?");
- await deleteStmt.bind(id).run();
- const cache = getCacheService(CACHE_CONFIGS.api);
- await cache.delete(cache.generateKey("content", id));
- await cache.invalidate(`content:list:${existing.collection_id}:*`);
- await cache.invalidate("content-filtered:*");
- return c.json({ success: true });
- } catch (error) {
- console.error("Error deleting content:", error);
- return c.json({
- error: "Failed to delete content",
- details: error instanceof Error ? error.message : String(error)
- }, 500);
+ const { results } = await this.db.prepare(sql).bind(...params).all();
+ return (results || []).map((r) => ({
+ value: String(r.value),
+ count: r.count
+ }));
}
-});
-var api_content_crud_default = apiContentCrudRoutes;
-
-// src/routes/api.ts
-var apiRoutes = new Hono();
-apiRoutes.use("*", async (c, next) => {
- const startTime = Date.now();
- c.set("startTime", startTime);
- await next();
- const totalTime = Date.now() - startTime;
- c.header("X-Response-Time", `${totalTime}ms`);
-});
-apiRoutes.use("*", async (c, next) => {
- const cacheEnabled = await isPluginActive(c.env.DB, "core-cache");
- c.set("cacheEnabled", cacheEnabled);
- await next();
-});
-apiRoutes.use("*", cors({
- origin: "*",
- allowMethods: ["GET", "POST", "PUT", "DELETE", "OPTIONS"],
- allowHeaders: ["Content-Type", "Authorization"]
-}));
-function addTimingMeta(c, meta = {}, executionStartTime) {
- const totalTime = Date.now() - c.get("startTime");
- const executionTime = executionStartTime ? Date.now() - executionStartTime : void 0;
- return {
- ...meta,
- timing: {
- total: totalTime,
- execution: executionTime,
- unit: "ms"
+ /**
+ * Compute facets for keyword mode using parallel SQL GROUP BY queries.
+ */
+ async computeFacetsKeyword(config, queryTerm, collectionIds, maxValues, activeFilters) {
+ const enabled = config.filter((f) => f.enabled);
+ if (enabled.length === 0 || collectionIds.length === 0) return [];
+ const collPlaceholders = collectionIds.map(() => "?").join(", ");
+ const likeTerm = `%${queryTerm}%`;
+ const promises = enabled.map(async (facet) => {
+ const limit = facet.maxValues || maxValues;
+ let extraConditions = [];
+ let extraParams = [];
+ if (activeFilters && Object.keys(activeFilters).length > 0) {
+ const cross = _FacetService.buildFacetFilterSQL(activeFilters, config, facet.field);
+ extraConditions = cross.conditions;
+ extraParams = cross.params;
+ }
+ try {
+ const values = await this.runKeywordFacetQuery(facet, likeTerm, collectionIds, collPlaceholders, limit, extraConditions, extraParams);
+ return this.sortFacetValues(facet, values);
+ } catch (error) {
+ console.error(`[FacetService] Keyword facet error for ${facet.field}:`, error);
+ return { name: facet.name, field: facet.field, values: [] };
+ }
+ });
+ return Promise.all(promises);
+ }
+ async runKeywordFacetQuery(facet, likeTerm, collectionIds, collPlaceholders, limit, extraConditions = [], extraParams = []) {
+ const extraWhere = extraConditions.length > 0 ? "\n " + extraConditions.map((c) => `AND ${c}`).join("\n ") : "";
+ const baseWhere = `
+ c.collection_id IN (${collPlaceholders})
+ AND c.status != 'deleted'
+ AND (c.title LIKE ? OR c.slug LIKE ? OR c.data LIKE ?)${extraWhere}
+ `;
+ const baseParams = [...collectionIds, likeTerm, likeTerm, likeTerm, ...extraParams];
+ let sql;
+ let params;
+ switch (facet.field) {
+ case "collection_name":
+ sql = `
+ SELECT col.display_name as value, COUNT(*) as count
+ FROM content c
+ JOIN collections col ON c.collection_id = col.id
+ WHERE ${baseWhere}
+ GROUP BY value ORDER BY count DESC LIMIT ?
+ `;
+ params = [...baseParams, limit];
+ break;
+ case "status":
+ sql = `
+ SELECT c.status as value, COUNT(*) as count
+ FROM content c
+ WHERE ${baseWhere}
+ GROUP BY c.status ORDER BY count DESC LIMIT ?
+ `;
+ params = [...baseParams, limit];
+ break;
+ case "author":
+ sql = `
+ SELECT COALESCE(u.email, 'Unknown') as value, COUNT(*) as count
+ FROM content c
+ LEFT JOIN users u ON c.author_id = u.id
+ WHERE ${baseWhere}
+ GROUP BY value ORDER BY count DESC LIMIT ?
+ `;
+ params = [...baseParams, limit];
+ break;
+ default:
+ if (facet.type === "json_array") {
+ sql = `
+ SELECT j.value as value, COUNT(*) as count
+ FROM content c,
+ json_each(json_extract(c.data, '${facet.field}')) j
+ WHERE ${baseWhere}
+ GROUP BY j.value ORDER BY count DESC LIMIT ?
+ `;
+ } else {
+ sql = `
+ SELECT json_extract(c.data, '${facet.field}') as value, COUNT(*) as count
+ FROM content c
+ WHERE ${baseWhere}
+ AND json_extract(c.data, '${facet.field}') IS NOT NULL
+ GROUP BY value ORDER BY count DESC LIMIT ?
+ `;
+ }
+ params = [...baseParams, limit];
}
- };
-}
-apiRoutes.get("/", (c) => {
- const baseUrl = new URL(c.req.url);
- const serverUrl = `${baseUrl.protocol}//${baseUrl.host}`;
- return c.json({
- openapi: "3.0.0",
- info: {
- title: "SonicJS AI API",
- version: "0.1.0",
- description: "RESTful API for SonicJS headless CMS - a modern, AI-powered content management system built on Cloudflare Workers",
- contact: {
- name: "SonicJS Support",
- url: `${serverUrl}/docs`,
- email: "support@sonicjs.com"
- },
- license: {
- name: "MIT",
- url: "https://opensource.org/licenses/MIT"
+ const { results } = await this.db.prepare(sql).bind(...params).all();
+ return (results || []).map((r) => ({
+ value: String(r.value),
+ count: r.count
+ }));
+ }
+ // =============================================
+ // Computation ā in-memory (AI/hybrid modes)
+ // =============================================
+ /**
+ * Compute facets from a set of content IDs by fetching their data
+ * and counting in-memory. Used for AI and hybrid modes where
+ * Vectorize returns max 50 results.
+ */
+ async computeFacetsFromIds(config, contentIds, maxValues) {
+ const enabled = config.filter((f) => f.enabled);
+ if (enabled.length === 0 || contentIds.length === 0) return [];
+ const placeholders = contentIds.map(() => "?").join(", ");
+ const { results: rows } = await this.db.prepare(`
+ SELECT c.id, c.data, c.status, c.collection_id, c.author_id,
+ col.display_name as collection_name,
+ u.email as author_email
+ FROM content c
+ JOIN collections col ON c.collection_id = col.id
+ LEFT JOIN users u ON c.author_id = u.id
+ WHERE c.id IN (${placeholders})
+ `).bind(...contentIds).all();
+ if (!rows?.length) {
+ return enabled.map((f) => ({ name: f.name, field: f.field, values: [] }));
+ }
+ return enabled.map((facet) => {
+ const limit = facet.maxValues || maxValues;
+ const counts = /* @__PURE__ */ new Map();
+ for (const row of rows) {
+ const values = this.extractFacetValues(facet, row);
+ for (const v of values) {
+ counts.set(v, (counts.get(v) || 0) + 1);
+ }
}
- },
- servers: [
- {
- url: serverUrl,
- description: "Current server"
+ let facetValues = Array.from(counts.entries()).map(([value, count]) => ({ value, count }));
+ facetValues = this.sortValues(facet, facetValues).slice(0, limit);
+ return { name: facet.name, field: facet.field, values: facetValues };
+ });
+ }
+ /**
+ * Also supports counting from already-loaded SearchResult array
+ * (used by InstantSearch adapter when facets come from search response).
+ */
+ computeFacetsFromResults(config, results, maxValues) {
+ const enabled = config.filter((f) => f.enabled);
+ if (enabled.length === 0 || results.length === 0) {
+ return enabled.map((f) => ({ name: f.name, field: f.field, values: [] }));
+ }
+ return enabled.map((facet) => {
+ const limit = facet.maxValues || maxValues;
+ const counts = /* @__PURE__ */ new Map();
+ for (const r of results) {
+ let value;
+ switch (facet.field) {
+ case "collection_name":
+ value = r.collection_name;
+ break;
+ case "status":
+ value = r.status;
+ break;
+ case "author":
+ value = r.author_name;
+ break;
+ }
+ if (value) counts.set(value, (counts.get(value) || 0) + 1);
}
- ],
- paths: {
- "/api/": {
- get: {
- summary: "API Information",
- description: "Returns OpenAPI specification for the SonicJS API",
- operationId: "getApiInfo",
- tags: ["System"],
- responses: {
- "200": {
- description: "OpenAPI specification",
- content: {
- "application/json": {
- schema: { type: "object" }
- }
- }
- }
+ let facetValues = Array.from(counts.entries()).map(([value, count]) => ({ value, count }));
+ facetValues = this.sortValues(facet, facetValues).slice(0, limit);
+ return { name: facet.name, field: facet.field, values: facetValues };
+ });
+ }
+ // =============================================
+ // Helpers
+ // =============================================
+ extractFacetValues(facet, row) {
+ switch (facet.field) {
+ case "collection_name":
+ return [row.collection_name];
+ case "status":
+ return [row.status];
+ case "author":
+ return [row.author_email || "Unknown"];
+ default: {
+ try {
+ const parsed = typeof row.data === "string" ? JSON.parse(row.data) : row.data;
+ const fieldName = facet.field.startsWith("$.") ? facet.field.slice(2) : facet.field;
+ const val = parsed[fieldName];
+ if (val == null) return [];
+ if (facet.type === "json_array" && Array.isArray(val)) {
+ return val.filter((v) => typeof v === "string");
}
+ return [String(val)];
+ } catch {
+ return [];
}
- },
- "/api/health": {
- get: {
- summary: "Health Check",
- description: "Returns API health status and available schemas",
- operationId: "getHealth",
- tags: ["System"],
- responses: {
- "200": {
- description: "Health status",
- content: {
- "application/json": {
- schema: {
- type: "object",
- properties: {
- status: { type: "string", example: "healthy" },
- timestamp: { type: "string", format: "date-time" },
- schemas: { type: "array", items: { type: "string" } }
- }
- }
- }
- }
- }
+ }
+ }
+ }
+ sortFacetValues(facet, values) {
+ return {
+ name: facet.name,
+ field: facet.field,
+ values: this.sortValues(facet, values)
+ };
+ }
+ sortValues(facet, values) {
+ if (facet.sortBy === "alpha") {
+ return values.sort((a, b) => a.value.localeCompare(b.value));
+ }
+ return values.sort((a, b) => b.count - a.count);
+ }
+ /**
+ * Convert filters.custom to SQL WHERE clause fragments.
+ * All conditions reference only the `c` (content) table alias,
+ * making them safe to inject into any query that joins content.
+ * Used by both search queries (narrowing results) and facet computation (cross-filtering).
+ *
+ * @param excludeField ā For cross-filtering: skip this field so facet X
+ * shows counts unaffected by its own selection.
+ */
+ static buildFacetFilterSQL(customFilters, facetConfig, excludeField) {
+ const conditions = [];
+ const params = [];
+ if (!customFilters || typeof customFilters !== "object") {
+ return { conditions, params };
+ }
+ const configMap = /* @__PURE__ */ new Map();
+ for (const fc of facetConfig) {
+ configMap.set(fc.field, fc);
+ }
+ for (const [field, values] of Object.entries(customFilters)) {
+ if (!values || Array.isArray(values) && values.length === 0) continue;
+ if (excludeField && field === excludeField) continue;
+ const valueArr = Array.isArray(values) ? values : [values];
+ if (valueArr.length === 0) continue;
+ const placeholders = valueArr.map(() => "?").join(", ");
+ switch (field) {
+ case "collection_name":
+ conditions.push(`c.collection_id IN (SELECT id FROM collections WHERE display_name IN (${placeholders}))`);
+ params.push(...valueArr);
+ break;
+ case "status":
+ conditions.push(`c.status IN (${placeholders})`);
+ params.push(...valueArr);
+ break;
+ case "author":
+ conditions.push(`c.author_id IN (SELECT id FROM users WHERE email IN (${placeholders}))`);
+ params.push(...valueArr);
+ break;
+ default: {
+ const config = configMap.get(field);
+ if (!config) break;
+ if (config.type === "json_array") {
+ conditions.push(
+ `EXISTS(SELECT 1 FROM json_each(json_extract(c.data, '${field}')) t WHERE t.value IN (${placeholders}))`
+ );
+ } else {
+ conditions.push(`json_extract(c.data, '${field}') IN (${placeholders})`);
}
+ params.push(...valueArr);
+ break;
}
- },
- "/api/collections": {
- get: {
- summary: "List Collections",
- description: "Returns all active collections with their schemas",
- operationId: "getCollections",
- tags: ["Content"],
- responses: {
- "200": {
- description: "List of collections",
- content: {
- "application/json": {
- schema: {
- type: "object",
- properties: {
- data: {
- type: "array",
- items: {
- type: "object",
- properties: {
- id: { type: "string" },
- name: { type: "string" },
- display_name: { type: "string" },
- schema: { type: "object" },
- is_active: { type: "integer" }
- }
- }
- },
- meta: { type: "object" }
- }
- }
- }
- }
- }
+ }
+ }
+ return { conditions, params };
+ }
+ /**
+ * Sanitize a query string for FTS5 MATCH syntax.
+ * Mirrors the logic in FTS5Service.sanitizeFTS5Query so facet GROUP BY
+ * queries use the same MATCH expression as the main search.
+ */
+ static sanitizeFTS5Query(query) {
+ if (!query || typeof query !== "string") return '""';
+ let sanitized = query.replace(/-/g, " ").replace(/[^a-zA-Z0-9\s]/g, "").replace(/\s+/g, " ").trim().toLowerCase();
+ const stopWords = /* @__PURE__ */ new Set([
+ "a",
+ "an",
+ "the",
+ "is",
+ "are",
+ "was",
+ "were",
+ "be",
+ "to",
+ "of",
+ "in",
+ "on",
+ "at",
+ "by",
+ "or",
+ "and",
+ "not",
+ "for",
+ "it",
+ "as",
+ "do",
+ "if",
+ "no",
+ "so",
+ "up",
+ "but",
+ "its",
+ "has",
+ "had",
+ "near"
+ ]);
+ const terms = sanitized.split(/\s+/).filter((t) => t.length > 1 && !stopWords.has(t));
+ if (terms.length === 0) return '""';
+ if (terms.length === 1) return `${terms[0]}*`;
+ return terms.join(" OR ");
+ }
+};
+
+// src/plugins/core-plugins/ai-search-plugin/services/fts5.service.ts
+var FTS5Service = class {
+ constructor(db, options = {}) {
+ this.db = db;
+ this.options = { ...this.defaultOptions, ...options };
+ }
+ defaultOptions = {
+ titleBoost: 5,
+ slugBoost: 2,
+ bodyBoost: 1,
+ snippetLength: 15,
+ // ~15 tokens per snippet fragment
+ highlightTag: "mark"
+ };
+ options;
+ synonymService;
+ /** Set synonym service for query expansion */
+ setSynonymService(service) {
+ this.synonymService = service;
+ }
+ /**
+ * Search using FTS5 with BM25 ranking and highlighting
+ * Auto-indexes any missing content in selected collections before searching
+ */
+ async search(query, settings, weightOverrides) {
+ const startTime = Date.now();
+ try {
+ let escapedQuery = this.sanitizeFTS5Query(query.query);
+ if (!escapedQuery || escapedQuery === '""') {
+ return {
+ results: [],
+ total: 0,
+ query_time_ms: Date.now() - startTime,
+ mode: "fts5"
+ };
+ }
+ if (this.synonymService && settings.query_synonyms_enabled !== false) {
+ escapedQuery = await this.expandWithSynonyms(escapedQuery);
+ }
+ const collections = query.filters?.collections?.length ? query.filters.collections : settings.selected_collections;
+ if (collections.length === 0) {
+ return {
+ results: [],
+ total: 0,
+ query_time_ms: Date.now() - startTime,
+ mode: "fts5"
+ };
+ }
+ await this.ensureCollectionsIndexed(collections);
+ const collectionPlaceholders = collections.map(() => "?").join(", ");
+ const tag = this.options.highlightTag || "mark";
+ const titleBoost = weightOverrides?.titleBoost ?? this.options.titleBoost;
+ const slugBoost = weightOverrides?.slugBoost ?? this.options.slugBoost;
+ const bodyBoost = weightOverrides?.bodyBoost ?? this.options.bodyBoost;
+ let filterWhere = "";
+ let filterParams = [];
+ if (query.filters?.custom && settings.facet_config?.length) {
+ const { conditions, params: fParams } = FacetService.buildFacetFilterSQL(
+ query.filters.custom,
+ settings.facet_config
+ );
+ if (conditions.length > 0) {
+ filterWhere = "\n " + conditions.map((c) => `AND ${c}`).join("\n ");
+ filterParams = fParams;
+ }
+ }
+ const sql = `
+ SELECT
+ fts.content_id,
+ fts.collection_id,
+ fts.title,
+ bm25(content_fts, ${titleBoost}, ${slugBoost}, ${bodyBoost}, 0, 0) as score,
+ snippet(content_fts, 2, '<${tag}>', '${tag}>', '...', ${this.options.snippetLength}) as body_snippet,
+ highlight(content_fts, 0, '<${tag}>', '${tag}>') as title_highlight,
+ c.slug,
+ c.status,
+ c.created_at,
+ c.updated_at,
+ col.display_name as collection_name
+ FROM content_fts fts
+ JOIN content c ON fts.content_id = c.id
+ JOIN collections col ON fts.collection_id = col.id
+ WHERE content_fts MATCH ?
+ AND fts.collection_id IN (${collectionPlaceholders})
+ AND c.status != 'deleted'${filterWhere}
+ ORDER BY score
+ LIMIT ? OFFSET ?
+ `;
+ const limit = query.limit || settings.results_limit || 20;
+ const offset = query.offset || 0;
+ const { results } = await this.db.prepare(sql).bind(escapedQuery, ...collections, ...filterParams, limit, offset).all();
+ const countSql = `
+ SELECT COUNT(*) as total
+ FROM content_fts fts
+ JOIN content c ON fts.content_id = c.id
+ WHERE content_fts MATCH ?
+ AND fts.collection_id IN (${collectionPlaceholders})
+ AND c.status != 'deleted'${filterWhere}
+ `;
+ const countResult = await this.db.prepare(countSql).bind(escapedQuery, ...collections, ...filterParams).first();
+ const searchResults = (results || []).map((row) => ({
+ id: row.content_id,
+ title: row.title,
+ slug: row.slug,
+ collection_id: row.collection_id,
+ collection_name: row.collection_name,
+ snippet: row.body_snippet,
+ status: row.status,
+ created_at: row.created_at,
+ updated_at: row.updated_at,
+ highlights: {
+ title: row.title_highlight,
+ body: row.body_snippet
+ },
+ // BM25 returns negative scores (more negative = better match)
+ // Convert to positive for display
+ bm25_score: Math.abs(row.score),
+ relevance_score: Math.abs(row.score)
+ }));
+ const queryTime = Date.now() - startTime;
+ console.log(`[FTS5Service] Search completed in ${queryTime}ms, ${searchResults.length} results`);
+ return {
+ results: searchResults,
+ total: countResult?.total || 0,
+ query_time_ms: queryTime,
+ mode: "fts5"
+ };
+ } catch (error) {
+ console.error("[FTS5Service] Search error:", error);
+ throw error;
+ }
+ }
+ /**
+ * Index a single content item
+ * Indexes all non-deleted content; removes deleted content from index
+ */
+ async indexContent(contentId) {
+ try {
+ const content = await this.db.prepare(`
+ SELECT c.id, c.collection_id, c.title, c.slug, c.data, c.status
+ FROM content c
+ WHERE c.id = ?
+ `).bind(contentId).first();
+ if (!content) {
+ console.warn(`[FTS5Service] Content ${contentId} not found`);
+ return;
+ }
+ if (content.status === "deleted") {
+ await this.removeFromIndex(contentId);
+ return;
+ }
+ const bodyText = this.extractSearchableText(content.data);
+ await this.db.batch([
+ this.db.prepare("DELETE FROM content_fts WHERE content_id = ?").bind(contentId),
+ this.db.prepare(`
+ INSERT INTO content_fts(title, slug, body, content_id, collection_id)
+ VALUES (?, ?, ?, ?, ?)
+ `).bind(
+ content.title || "",
+ content.slug || "",
+ bodyText,
+ content.id,
+ content.collection_id
+ ),
+ this.db.prepare(`
+ INSERT OR REPLACE INTO content_fts_sync(content_id, collection_id, indexed_at, status)
+ VALUES (?, ?, ?, 'indexed')
+ `).bind(contentId, content.collection_id, Date.now())
+ ]);
+ } catch (error) {
+ console.error(`[FTS5Service] Error indexing ${contentId}:`, error);
+ throw error;
+ }
+ }
+ /**
+ * Index all published content in a collection (bulk approach).
+ * Fetches all content in one query, processes text in memory,
+ * then inserts in D1 batches for efficiency.
+ */
+ async indexCollection(collectionId, onProgress) {
+ console.log(`[FTS5Service] Starting bulk indexing for collection: ${collectionId}`);
+ try {
+ const { results } = await this.db.prepare(`
+ SELECT id, title, slug, data, collection_id
+ FROM content
+ WHERE collection_id = ? AND status != 'deleted'
+ `).bind(collectionId).all();
+ const totalItems = results?.length || 0;
+ if (totalItems === 0) {
+ console.log(`[FTS5Service] No content found in collection ${collectionId}`);
+ if (onProgress) await onProgress(0, 0);
+ return { total_items: 0, indexed_items: 0, errors: 0 };
+ }
+ await this.db.batch([
+ this.db.prepare("DELETE FROM content_fts WHERE collection_id = ?").bind(collectionId),
+ this.db.prepare("DELETE FROM content_fts_sync WHERE collection_id = ?").bind(collectionId)
+ ]);
+ let indexedItems = 0;
+ let errors = 0;
+ const now = Date.now();
+ const BATCH_SIZE = 25;
+ for (let i = 0; i < totalItems; i += BATCH_SIZE) {
+ const batch = results.slice(i, i + BATCH_SIZE);
+ const statements = [];
+ for (const item of batch) {
+ try {
+ const bodyText = this.extractSearchableText(item.data);
+ statements.push(
+ this.db.prepare(`
+ INSERT INTO content_fts(title, slug, body, content_id, collection_id)
+ VALUES (?, ?, ?, ?, ?)
+ `).bind(item.title || "", item.slug || "", bodyText, item.id, item.collection_id)
+ );
+ statements.push(
+ this.db.prepare(`
+ INSERT OR REPLACE INTO content_fts_sync(content_id, collection_id, indexed_at, status)
+ VALUES (?, ?, ?, 'indexed')
+ `).bind(item.id, item.collection_id, now)
+ );
+ } catch (error) {
+ errors++;
}
}
- },
- "/api/collections/{collection}/content": {
- get: {
- summary: "Get Collection Content",
- description: "Returns content items from a specific collection with filtering support",
- operationId: "getCollectionContent",
- tags: ["Content"],
- parameters: [
- {
- name: "collection",
- in: "path",
- required: true,
- schema: { type: "string" },
- description: "Collection name"
- },
- {
- name: "limit",
- in: "query",
- schema: { type: "integer", default: 50, maximum: 1e3 },
- description: "Maximum number of items to return"
- },
- {
- name: "offset",
- in: "query",
- schema: { type: "integer", default: 0 },
- description: "Number of items to skip"
- },
- {
- name: "status",
- in: "query",
- schema: { type: "string", enum: ["draft", "published", "archived"] },
- description: "Filter by content status"
- }
- ],
- responses: {
- "200": {
- description: "List of content items",
- content: {
- "application/json": {
- schema: {
- type: "object",
- properties: {
- data: { type: "array", items: { type: "object" } },
- meta: { type: "object" }
- }
- }
- }
- }
- },
- "404": {
- description: "Collection not found"
- }
+ if (statements.length > 0) {
+ try {
+ await this.db.batch(statements);
+ indexedItems += statements.length / 2;
+ } catch (error) {
+ console.error(`[FTS5Service] Batch insert error at offset ${i}:`, error);
+ errors += batch.length;
}
}
- },
- "/api/content": {
- get: {
- summary: "List Content",
- description: "Returns content items with advanced filtering support",
- operationId: "getContent",
- tags: ["Content"],
- parameters: [
- {
- name: "collection",
- in: "query",
- schema: { type: "string" },
- description: "Filter by collection name"
- },
- {
- name: "limit",
- in: "query",
- schema: { type: "integer", default: 50, maximum: 1e3 },
- description: "Maximum number of items to return"
- },
- {
- name: "offset",
- in: "query",
- schema: { type: "integer", default: 0 },
- description: "Number of items to skip"
- }
- ],
- responses: {
- "200": {
- description: "List of content items",
- content: {
- "application/json": {
- schema: {
- type: "object",
- properties: {
- data: { type: "array", items: { type: "object" } },
- meta: { type: "object" }
- }
- }
- }
- }
- }
- }
- },
- post: {
- summary: "Create Content",
- description: "Creates a new content item",
- operationId: "createContent",
- tags: ["Content"],
- security: [{ bearerAuth: [] }],
- requestBody: {
- required: true,
- content: {
- "application/json": {
- schema: {
- type: "object",
- required: ["collection_id", "title"],
- properties: {
- collection_id: { type: "string" },
- title: { type: "string" },
- slug: { type: "string" },
- status: { type: "string", enum: ["draft", "published", "archived"] },
- data: { type: "object" }
- }
- }
- }
- }
- },
- responses: {
- "201": { description: "Content created successfully" },
- "400": { description: "Invalid request body" },
- "401": { description: "Unauthorized" }
- }
+ if (onProgress) {
+ await onProgress(indexedItems, totalItems);
}
- },
- "/api/content/{id}": {
- get: {
- summary: "Get Content by ID",
- description: "Returns a specific content item by ID",
- operationId: "getContentById",
- tags: ["Content"],
- parameters: [
- {
- name: "id",
- in: "path",
- required: true,
- schema: { type: "string" },
- description: "Content item ID"
- }
- ],
- responses: {
- "200": { description: "Content item" },
- "404": { description: "Content not found" }
- }
- },
- put: {
- summary: "Update Content",
- description: "Updates an existing content item",
- operationId: "updateContent",
- tags: ["Content"],
- security: [{ bearerAuth: [] }],
- parameters: [
- {
- name: "id",
- in: "path",
- required: true,
- schema: { type: "string" },
- description: "Content item ID"
- }
- ],
- responses: {
- "200": { description: "Content updated successfully" },
- "401": { description: "Unauthorized" },
- "404": { description: "Content not found" }
- }
- },
- delete: {
- summary: "Delete Content",
- description: "Deletes a content item",
- operationId: "deleteContent",
- tags: ["Content"],
- security: [{ bearerAuth: [] }],
- parameters: [
- {
- name: "id",
- in: "path",
- required: true,
- schema: { type: "string" },
- description: "Content item ID"
- }
- ],
- responses: {
- "200": { description: "Content deleted successfully" },
- "401": { description: "Unauthorized" },
- "404": { description: "Content not found" }
- }
+ }
+ console.log(`[FTS5Service] Bulk indexing complete: ${indexedItems}/${totalItems} items, ${errors} errors`);
+ return {
+ total_items: totalItems,
+ indexed_items: indexedItems,
+ errors
+ };
+ } catch (error) {
+ console.error(`[FTS5Service] Error indexing collection ${collectionId}:`, error);
+ throw error;
+ }
+ }
+ /**
+ * Index a batch of content items from a collection using batch D1 inserts.
+ * Returns the number remaining so the caller can loop.
+ */
+ async indexCollectionBatch(collectionId, batchSize = 200) {
+ const { results } = await this.db.prepare(`
+ SELECT c.id, c.title, c.slug, c.data, c.collection_id
+ FROM content c
+ LEFT JOIN content_fts_sync s ON c.id = s.content_id
+ WHERE c.collection_id = ? AND c.status != 'deleted'
+ AND s.content_id IS NULL
+ LIMIT ?
+ `).bind(collectionId, batchSize).all();
+ const toIndex = results || [];
+ const now = Date.now();
+ let indexed = 0;
+ const SUB_BATCH = 25;
+ for (let i = 0; i < toIndex.length; i += SUB_BATCH) {
+ const batch = toIndex.slice(i, i + SUB_BATCH);
+ const statements = [];
+ for (const item of batch) {
+ try {
+ const bodyText = this.extractSearchableText(item.data);
+ statements.push(
+ this.db.prepare(
+ "INSERT INTO content_fts(title, slug, body, content_id, collection_id) VALUES (?, ?, ?, ?, ?)"
+ ).bind(item.title || "", item.slug || "", bodyText, item.id, item.collection_id)
+ );
+ statements.push(
+ this.db.prepare(
+ "INSERT OR REPLACE INTO content_fts_sync(content_id, collection_id, indexed_at, status) VALUES (?, ?, ?, 'indexed')"
+ ).bind(item.id, item.collection_id, now)
+ );
+ } catch (error) {
}
- },
- "/api/media": {
- get: {
- summary: "List Media",
- description: "Returns all media files with pagination",
- operationId: "getMedia",
- tags: ["Media"],
- responses: {
- "200": { description: "List of media files" }
- }
+ }
+ if (statements.length > 0) {
+ try {
+ await this.db.batch(statements);
+ indexed += statements.length / 2;
+ } catch (error) {
+ console.error(`[FTS5Service] Batch insert error at offset ${i}:`, error);
}
- },
- "/api/media/upload": {
- post: {
- summary: "Upload Media",
- description: "Uploads a new media file to R2 storage",
- operationId: "uploadMedia",
- tags: ["Media"],
- security: [{ bearerAuth: [] }],
- requestBody: {
- required: true,
- content: {
- "multipart/form-data": {
- schema: {
- type: "object",
- properties: {
- file: { type: "string", format: "binary" }
- }
- }
- }
- }
- },
- responses: {
- "201": { description: "Media uploaded successfully" },
- "401": { description: "Unauthorized" }
- }
+ }
+ }
+ const remainResult = await this.db.prepare(`
+ SELECT COUNT(*) as cnt FROM content c
+ LEFT JOIN content_fts_sync s ON c.id = s.content_id
+ WHERE c.collection_id = ? AND c.status != 'deleted'
+ AND s.content_id IS NULL
+ `).bind(collectionId).first();
+ const totalResult = await this.db.prepare("SELECT COUNT(*) as cnt FROM content WHERE collection_id = ? AND status != 'deleted'").bind(collectionId).first();
+ return {
+ indexed,
+ remaining: remainResult?.cnt || 0,
+ total: totalResult?.cnt || 0
+ };
+ }
+ /**
+ * Remove content from FTS index
+ */
+ async removeFromIndex(contentId) {
+ try {
+ await this.db.batch([
+ this.db.prepare("DELETE FROM content_fts WHERE content_id = ?").bind(contentId),
+ this.db.prepare("DELETE FROM content_fts_sync WHERE content_id = ?").bind(contentId)
+ ]);
+ console.log(`[FTS5Service] Removed content ${contentId} from index`);
+ } catch (error) {
+ console.error(`[FTS5Service] Error removing ${contentId}:`, error);
+ throw error;
+ }
+ }
+ /**
+ * Process pending sync items (for deferred/batch indexing)
+ */
+ async processPendingSync(batchSize = 100) {
+ const { results } = await this.db.prepare(`
+ SELECT content_id FROM content_fts_sync
+ WHERE status = 'pending'
+ LIMIT ?
+ `).bind(batchSize).all();
+ let processed = 0;
+ for (const item of results || []) {
+ try {
+ await this.indexContent(item.content_id);
+ processed++;
+ } catch (error) {
+ console.error(`[FTS5Service] Error processing pending item ${item.content_id}:`, error);
+ }
+ }
+ return processed;
+ }
+ /**
+ * Get FTS5 index statistics
+ */
+ async getStats() {
+ try {
+ const totalResult = await this.db.prepare("SELECT COUNT(*) as count FROM content_fts").first();
+ const { results: collectionCounts } = await this.db.prepare(`
+ SELECT collection_id, COUNT(*) as count
+ FROM content_fts
+ GROUP BY collection_id
+ `).all();
+ const byCollection = {};
+ for (const row of collectionCounts || []) {
+ byCollection[row.collection_id] = row.count;
+ }
+ return {
+ total_indexed: totalResult?.count || 0,
+ by_collection: byCollection
+ };
+ } catch (error) {
+ console.error("[FTS5Service] Error getting stats:", error);
+ return { total_indexed: 0, by_collection: {} };
+ }
+ }
+ /**
+ * Check if FTS5 table is available
+ */
+ async isAvailable() {
+ try {
+ await this.db.prepare("SELECT * FROM content_fts LIMIT 0").run();
+ return true;
+ } catch {
+ return false;
+ }
+ }
+ /**
+ * Auto-index content in selected collections that isn't yet in the FTS5 index.
+ * This makes FTS5 self-healing - existing content that predates the FTS5 feature
+ * gets indexed on first search, so results match keyword search coverage.
+ */
+ async ensureCollectionsIndexed(collections) {
+ try {
+ const collectionPlaceholders = collections.map(() => "?").join(", ");
+ const { results } = await this.db.prepare(`
+ SELECT c.id FROM content c
+ LEFT JOIN content_fts_sync s ON c.id = s.content_id
+ WHERE c.collection_id IN (${collectionPlaceholders})
+ AND c.status != 'deleted'
+ AND s.content_id IS NULL
+ LIMIT 200
+ `).bind(...collections).all();
+ if (!results || results.length === 0) {
+ return;
+ }
+ console.log(`[FTS5Service] Auto-indexing ${results.length} unindexed items`);
+ let indexed = 0;
+ for (const item of results) {
+ try {
+ await this.indexContent(item.id);
+ indexed++;
+ } catch (error) {
+ console.error(`[FTS5Service] Error auto-indexing ${item.id}:`, error);
}
}
- },
- components: {
- securitySchemes: {
- bearerAuth: {
- type: "http",
- scheme: "bearer",
- bearerFormat: "JWT"
- }
- },
- schemas: {
- Content: {
- type: "object",
- properties: {
- id: { type: "string", format: "uuid" },
- title: { type: "string" },
- slug: { type: "string" },
- status: { type: "string", enum: ["draft", "published", "archived"] },
- collectionId: { type: "string", format: "uuid" },
- data: { type: "object" },
- created_at: { type: "integer" },
- updated_at: { type: "integer" }
- }
- },
- Collection: {
- type: "object",
- properties: {
- id: { type: "string", format: "uuid" },
- name: { type: "string" },
- display_name: { type: "string" },
- description: { type: "string" },
- schema: { type: "object" },
- is_active: { type: "integer" }
- }
- },
- Media: {
- type: "object",
- properties: {
- id: { type: "string", format: "uuid" },
- filename: { type: "string" },
- mimetype: { type: "string" },
- size: { type: "integer" },
- url: { type: "string" }
- }
- },
- Error: {
- type: "object",
- properties: {
- error: { type: "string" },
- details: { type: "string" }
+ console.log(`[FTS5Service] Auto-indexed ${indexed}/${results.length} items`);
+ } catch (error) {
+ console.error("[FTS5Service] Error during auto-indexing:", error);
+ }
+ }
+ /**
+ * Extract searchable text from JSON content data
+ * Reuses logic pattern from ChunkingService
+ */
+ extractSearchableText(data) {
+ try {
+ const parsed = typeof data === "string" ? JSON.parse(data) : data;
+ const parts = [];
+ if (parsed.description) parts.push(String(parsed.description));
+ if (parsed.content) parts.push(String(parsed.content));
+ if (parsed.body) parts.push(String(parsed.body));
+ if (parsed.text) parts.push(String(parsed.text));
+ if (parsed.summary) parts.push(String(parsed.summary));
+ if (parsed.excerpt) parts.push(String(parsed.excerpt));
+ const extractRecursive = (obj, depth = 0) => {
+ if (depth > 5) return;
+ if (typeof obj === "string") {
+ if (obj.length > 20 && !obj.startsWith("http") && !obj.match(/^[a-f0-9-]{36}$/i)) {
+ parts.push(obj);
}
+ } else if (Array.isArray(obj)) {
+ obj.forEach((item) => extractRecursive(item, depth + 1));
+ } else if (obj && typeof obj === "object") {
+ const skipKeys = /* @__PURE__ */ new Set([
+ "id",
+ "_id",
+ "slug",
+ "url",
+ "href",
+ "src",
+ "image",
+ "thumbnail",
+ "avatar",
+ "icon",
+ "logo",
+ "metadata",
+ "meta",
+ "created_at",
+ "updated_at",
+ "author_id",
+ "collection_id",
+ "parent_id"
+ ]);
+ Object.entries(obj).forEach(([key, value]) => {
+ if (!skipKeys.has(key.toLowerCase())) {
+ extractRecursive(value, depth + 1);
+ }
+ });
+ }
+ };
+ extractRecursive(parsed);
+ const combined = parts.join(" ").trim();
+ return combined.replace(/\s+/g, " ");
+ } catch (error) {
+ console.error("[FTS5Service] Error extracting text:", error);
+ return "";
+ }
+ }
+ /**
+ * Expand a sanitized FTS5 query string with synonym terms.
+ * Input: "coffee*" (single) or "coffee OR beans" (multiple)
+ * Output: "coffee* OR espresso OR caffeine" or "coffee OR espresso OR beans"
+ */
+ async expandWithSynonyms(sanitizedQuery) {
+ try {
+ let terms;
+ let hasPrefixMatch = false;
+ if (sanitizedQuery.endsWith("*")) {
+ terms = [sanitizedQuery.slice(0, -1)];
+ hasPrefixMatch = true;
+ } else {
+ terms = sanitizedQuery.split(" OR ").map((t) => t.trim()).filter(Boolean);
+ }
+ if (terms.length === 0) return sanitizedQuery;
+ const expanded = await this.synonymService.expandQuery(terms);
+ if (expanded.length === terms.length) return sanitizedQuery;
+ const capped = expanded.slice(0, 20);
+ if (hasPrefixMatch && terms.length === 1) {
+ const original = terms[0] + "*";
+ const synonyms = capped.filter((t) => t !== terms[0]);
+ return [original, ...synonyms].join(" OR ");
+ }
+ return capped.join(" OR ");
+ } catch (error) {
+ console.error("[FTS5Service] Synonym expansion error (using original query):", error);
+ return sanitizedQuery;
+ }
+ }
+ /**
+ * Sanitize user input for FTS5 MATCH clause
+ * Removes operators and special characters that could cause errors
+ */
+ sanitizeFTS5Query(query) {
+ if (!query || typeof query !== "string") {
+ return '""';
+ }
+ let sanitized = query.replace(/-/g, " ").replace(/[^a-zA-Z0-9\s]/g, "").replace(/\s+/g, " ").trim().toLowerCase();
+ const stopWords = /* @__PURE__ */ new Set([
+ "a",
+ "an",
+ "the",
+ "is",
+ "are",
+ "was",
+ "were",
+ "be",
+ "to",
+ "of",
+ "in",
+ "on",
+ "at",
+ "by",
+ "or",
+ "and",
+ "not",
+ "for",
+ "it",
+ "as",
+ "do",
+ "if",
+ "no",
+ "so",
+ "up",
+ "but",
+ "its",
+ "has",
+ "had",
+ "near"
+ ]);
+ const terms = sanitized.split(/\s+/).filter((t) => t.length > 1 && !stopWords.has(t));
+ if (terms.length === 0) {
+ return '""';
+ }
+ if (terms.length === 1) {
+ return `${terms[0]}*`;
+ }
+ return terms.join(" OR ");
+ }
+};
+
+// src/plugins/core-plugins/ai-search-plugin/services/search-cache.service.ts
+var SearchCacheService = class _SearchCacheService {
+ constructor(kv) {
+ this.kv = kv;
+ }
+ static PREFIX = "search-cache:v1:";
+ // KVNamespace
+ /**
+ * Build a deterministic cache key from post-rule query params.
+ * Returns null if caching should be skipped.
+ */
+ async buildKey(query) {
+ if (query.cache === false || !query.query?.trim()) {
+ return null;
+ }
+ const canonical = JSON.stringify({
+ q: query.query.toLowerCase().trim(),
+ m: query.mode,
+ l: query.limit ?? null,
+ o: query.offset ?? null,
+ f: this.normalizeFilters(query.filters),
+ fct: query.facets ?? false
+ });
+ const hash = await crypto.subtle.digest(
+ "SHA-256",
+ new TextEncoder().encode(canonical)
+ );
+ const hex = Array.from(new Uint8Array(hash)).map((b) => b.toString(16).padStart(2, "0")).join("");
+ return `${_SearchCacheService.PREFIX}${hex.slice(0, 16)}`;
+ }
+ /**
+ * Get cached search response. Returns null on miss or error.
+ */
+ async get(key) {
+ try {
+ return await this.kv.get(key, "json");
+ } catch (error) {
+ console.warn("[SearchCache] Get error:", error);
+ return null;
+ }
+ }
+ /**
+ * Store search response in cache. Fire-and-forget ā never blocks the response.
+ * Strips search_id before caching (must be fresh per search for click tracking).
+ */
+ async put(key, response, ttlSeconds) {
+ try {
+ const toCache = { ...response };
+ delete toCache.search_id;
+ delete toCache.cached;
+ const ttl = Math.max(60, ttlSeconds);
+ await this.kv.put(key, JSON.stringify(toCache), { expirationTtl: ttl });
+ } catch (error) {
+ console.warn("[SearchCache] Put error:", error);
+ }
+ }
+ /**
+ * Invalidate all cached search results by listing and deleting keys with our prefix.
+ * Returns the number of keys deleted.
+ */
+ async invalidateAll() {
+ let deleted = 0;
+ let cursor;
+ try {
+ do {
+ const listOptions = { prefix: _SearchCacheService.PREFIX, limit: 1e3 };
+ if (cursor) listOptions.cursor = cursor;
+ const list = await this.kv.list(listOptions);
+ const keys = list.keys || [];
+ for (const key of keys) {
+ await this.kv.delete(key.name);
+ deleted++;
}
+ cursor = list.list_complete ? void 0 : list.cursor;
+ } while (cursor);
+ } catch (error) {
+ console.warn("[SearchCache] Invalidation error:", error);
+ }
+ if (deleted > 0) {
+ console.log(`[SearchCache] Invalidated ${deleted} cached entries`);
+ }
+ return deleted;
+ }
+ /**
+ * Normalize filters for deterministic hashing.
+ * Sorts collections, status, and custom keys/values.
+ */
+ normalizeFilters(filters) {
+ if (!filters) return null;
+ const normalized = {};
+ if (filters.collections?.length) {
+ normalized.collections = [...filters.collections].sort();
+ }
+ if (filters.status?.length) {
+ normalized.status = [...filters.status].sort();
+ }
+ if (filters.tags?.length) {
+ normalized.tags = [...filters.tags].sort();
+ }
+ if (filters.author) {
+ normalized.author = filters.author;
+ }
+ if (filters.dateRange) {
+ normalized.dateRange = filters.dateRange;
+ }
+ if (filters.custom && Object.keys(filters.custom).length > 0) {
+ const sortedCustom = {};
+ for (const key of Object.keys(filters.custom).sort()) {
+ const val = filters.custom[key];
+ sortedCustom[key] = Array.isArray(val) ? [...val].sort() : val;
}
- },
- tags: [
- { name: "System", description: "System and health endpoints" },
- { name: "Content", description: "Content management operations" },
- { name: "Media", description: "Media file operations" }
- ]
- });
-});
-apiRoutes.get("/health", (c) => {
- return c.json({
- status: "healthy",
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
- schemas: schemaDefinitions.map((s) => s.name)
- });
+ normalized.custom = sortedCustom;
+ }
+ return Object.keys(normalized).length > 0 ? normalized : null;
+ }
+};
+
+// src/routes/api-content-crud.ts
+var apiContentCrudRoutes = new Hono();
+apiContentCrudRoutes.get("/check-slug", async (c) => {
+ try {
+ const db = c.env.DB;
+ const collectionId = c.req.query("collectionId");
+ const slug = c.req.query("slug");
+ const excludeId = c.req.query("excludeId");
+ if (!collectionId || !slug) {
+ return c.json({ error: "collectionId and slug are required" }, 400);
+ }
+ let query = "SELECT id FROM content WHERE collection_id = ? AND slug = ?";
+ const params = [collectionId, slug];
+ if (excludeId) {
+ query += " AND id != ?";
+ params.push(excludeId);
+ }
+ const existing = await db.prepare(query).bind(...params).first();
+ if (existing) {
+ return c.json({
+ available: false,
+ message: "This URL slug is already in use in this collection"
+ });
+ }
+ return c.json({ available: true });
+ } catch (error) {
+ console.error("Error checking slug:", error);
+ return c.json({
+ error: "Failed to check slug availability",
+ details: error instanceof Error ? error.message : String(error)
+ }, 500);
+ }
});
-apiRoutes.get("/collections", async (c) => {
- const executionStart = Date.now();
+apiContentCrudRoutes.get("/:id", async (c) => {
try {
+ const id = c.req.param("id");
const db = c.env.DB;
- const cacheEnabled = c.get("cacheEnabled");
- const cache = getCacheService(CACHE_CONFIGS.api);
- const cacheKey = cache.generateKey("collections", "all");
- if (cacheEnabled) {
- const cacheResult = await cache.getWithSource(cacheKey);
- if (cacheResult.hit && cacheResult.data) {
- c.header("X-Cache-Status", "HIT");
- c.header("X-Cache-Source", cacheResult.source);
- if (cacheResult.ttl) {
- c.header("X-Cache-TTL", Math.floor(cacheResult.ttl).toString());
- }
- const dataWithMeta = {
- ...cacheResult.data,
- meta: addTimingMeta(c, {
- ...cacheResult.data.meta,
- cache: {
- hit: true,
- source: cacheResult.source,
- ttl: cacheResult.ttl ? Math.floor(cacheResult.ttl) : void 0
- }
- }, executionStart)
- };
- return c.json(dataWithMeta);
- }
+ const stmt = db.prepare("SELECT * FROM content WHERE id = ?");
+ const content = await stmt.bind(id).first();
+ if (!content) {
+ return c.json({ error: "Content not found" }, 404);
}
- c.header("X-Cache-Status", "MISS");
- c.header("X-Cache-Source", "database");
- const stmt = db.prepare("SELECT * FROM collections WHERE is_active = 1");
- const { results } = await stmt.all();
- const transformedResults = results.map((row) => ({
- ...row,
- schema: row.schema ? JSON.parse(row.schema) : {},
- is_active: row.is_active
- // Keep as number (1 or 0)
- }));
- const responseData = {
- data: transformedResults,
- meta: addTimingMeta(c, {
- count: results.length,
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
- cache: {
- hit: false,
- source: "database"
- }
- }, executionStart)
+ const transformedContent = {
+ id: content.id,
+ title: content.title,
+ slug: content.slug,
+ status: content.status,
+ collectionId: content.collection_id,
+ data: content.data ? JSON.parse(content.data) : {},
+ created_at: content.created_at,
+ updated_at: content.updated_at
};
- if (cacheEnabled) {
- await cache.set(cacheKey, responseData);
- }
- return c.json(responseData);
+ return c.json({ data: transformedContent });
} catch (error) {
- console.error("Error fetching collections:", error);
- return c.json({ error: "Failed to fetch collections" }, 500);
+ console.error("Error fetching content:", error);
+ return c.json({
+ error: "Failed to fetch content",
+ details: error instanceof Error ? error.message : String(error)
+ }, 500);
}
});
-apiRoutes.get("/content", async (c) => {
- const executionStart = Date.now();
+apiContentCrudRoutes.post("/", requireAuth(), async (c) => {
try {
const db = c.env.DB;
- const queryParams = c.req.query();
- if (queryParams.collection) {
- const collectionName = queryParams.collection;
- const collectionStmt = db.prepare("SELECT id FROM collections WHERE name = ? AND is_active = 1");
- const collectionResult = await collectionStmt.bind(collectionName).first();
- if (collectionResult) {
- queryParams.collection_id = collectionResult.id;
- delete queryParams.collection;
- } else {
- return c.json({
- data: [],
- meta: addTimingMeta(c, {
- count: 0,
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
- message: `Collection '${collectionName}' not found`
- }, executionStart)
- });
- }
+ const user = c.get("user");
+ const body = await c.req.json();
+ const { collectionId, title, slug, status, data } = body;
+ if (!collectionId) {
+ return c.json({ error: "collectionId is required" }, 400);
}
- const filter = QueryFilterBuilder.parseFromQuery(queryParams);
- if (!filter.limit) {
- filter.limit = 50;
+ if (!title) {
+ return c.json({ error: "title is required" }, 400);
}
- filter.limit = Math.min(filter.limit, 1e3);
- const builder3 = new QueryFilterBuilder();
- const queryResult = builder3.build("content", filter);
- if (queryResult.errors.length > 0) {
- return c.json({
- error: "Invalid filter parameters",
- details: queryResult.errors
- }, 400);
+ let finalSlug = slug || title;
+ finalSlug = finalSlug.toLowerCase().replace(/[^a-z0-9\s-]/g, "").replace(/\s+/g, "-").replace(/-+/g, "-").trim();
+ const duplicateCheck = db.prepare(
+ "SELECT id FROM content WHERE collection_id = ? AND slug = ?"
+ );
+ const existing = await duplicateCheck.bind(collectionId, finalSlug).first();
+ if (existing) {
+ return c.json({ error: "A content item with this slug already exists in this collection" }, 409);
}
- const cacheEnabled = c.get("cacheEnabled");
+ const contentId = crypto.randomUUID();
+ const now = Date.now();
+ const insertStmt = db.prepare(`
+ INSERT INTO content (
+ id, collection_id, slug, title, data, status,
+ author_id, created_at, updated_at
+ )
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
+ `);
+ await insertStmt.bind(
+ contentId,
+ collectionId,
+ finalSlug,
+ title,
+ JSON.stringify(data || {}),
+ status || "draft",
+ user?.userId || "system",
+ now,
+ now
+ ).run();
const cache = getCacheService(CACHE_CONFIGS.api);
- const cacheKey = cache.generateKey("content-filtered", JSON.stringify({ filter, query: queryResult.sql }));
- if (cacheEnabled) {
- const cacheResult = await cache.getWithSource(cacheKey);
- if (cacheResult.hit && cacheResult.data) {
- c.header("X-Cache-Status", "HIT");
- c.header("X-Cache-Source", cacheResult.source);
- if (cacheResult.ttl) {
- c.header("X-Cache-TTL", Math.floor(cacheResult.ttl).toString());
- }
- const dataWithMeta = {
- ...cacheResult.data,
- meta: addTimingMeta(c, {
- ...cacheResult.data.meta,
- cache: {
- hit: true,
- source: cacheResult.source,
- ttl: cacheResult.ttl ? Math.floor(cacheResult.ttl) : void 0
- }
- }, executionStart)
- };
- return c.json(dataWithMeta);
- }
- }
- c.header("X-Cache-Status", "MISS");
- c.header("X-Cache-Source", "database");
- const stmt = db.prepare(queryResult.sql);
- const boundStmt = queryResult.params.length > 0 ? stmt.bind(...queryResult.params) : stmt;
- const { results } = await boundStmt.all();
- const transformedResults = results.map((row) => ({
- id: row.id,
- title: row.title,
- slug: row.slug,
- status: row.status,
- collectionId: row.collection_id,
- data: row.data ? JSON.parse(row.data) : {},
- created_at: row.created_at,
- updated_at: row.updated_at
- }));
- const responseData = {
- data: transformedResults,
- meta: addTimingMeta(c, {
- count: results.length,
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
- filter,
- query: {
- sql: queryResult.sql,
- params: queryResult.params
- },
- cache: {
- hit: false,
- source: "database"
- }
- }, executionStart)
- };
- if (cacheEnabled) {
- await cache.set(cacheKey, responseData);
+ await cache.invalidate(`content:list:${collectionId}:*`);
+ await cache.invalidate("content-filtered:*");
+ const fts5Service = new FTS5Service(db);
+ c.executionCtx.waitUntil(
+ fts5Service.indexContent(contentId).catch(
+ (err) => console.error("[API Content] FTS5 indexing failed:", err)
+ )
+ );
+ if (c.env.CACHE_KV) {
+ const searchCache = new SearchCacheService(c.env.CACHE_KV);
+ c.executionCtx.waitUntil(searchCache.invalidateAll());
}
- return c.json(responseData);
+ const getStmt = db.prepare("SELECT * FROM content WHERE id = ?");
+ const createdContent = await getStmt.bind(contentId).first();
+ return c.json({
+ data: {
+ id: createdContent.id,
+ title: createdContent.title,
+ slug: createdContent.slug,
+ status: createdContent.status,
+ collectionId: createdContent.collection_id,
+ data: createdContent.data ? JSON.parse(createdContent.data) : {},
+ created_at: createdContent.created_at,
+ updated_at: createdContent.updated_at
+ }
+ }, 201);
} catch (error) {
- console.error("Error fetching content:", error);
+ console.error("Error creating content:", error);
return c.json({
- error: "Failed to fetch content",
+ error: "Failed to create content",
details: error instanceof Error ? error.message : String(error)
}, 500);
}
});
-apiRoutes.get("/collections/:collection/content", async (c) => {
- const executionStart = Date.now();
+apiContentCrudRoutes.put("/:id", requireAuth(), async (c) => {
try {
- const collection = c.req.param("collection");
+ const id = c.req.param("id");
const db = c.env.DB;
- const queryParams = c.req.query();
- const collectionStmt = db.prepare("SELECT * FROM collections WHERE name = ? AND is_active = 1");
- const collectionResult = await collectionStmt.bind(collection).first();
- if (!collectionResult) {
- return c.json({ error: "Collection not found" }, 404);
+ const body = await c.req.json();
+ const existingStmt = db.prepare("SELECT * FROM content WHERE id = ?");
+ const existing = await existingStmt.bind(id).first();
+ if (!existing) {
+ return c.json({ error: "Content not found" }, 404);
}
- const filter = QueryFilterBuilder.parseFromQuery(queryParams);
- if (!filter.where) {
- filter.where = { and: [] };
+ const updates = [];
+ const params = [];
+ if (body.title !== void 0) {
+ updates.push("title = ?");
+ params.push(body.title);
}
- if (!filter.where.and) {
- filter.where.and = [];
+ if (body.slug !== void 0) {
+ let finalSlug = body.slug.toLowerCase().replace(/[^a-z0-9\s-]/g, "").replace(/\s+/g, "-").replace(/-+/g, "-").trim();
+ updates.push("slug = ?");
+ params.push(finalSlug);
}
- filter.where.and.push({
- field: "collection_id",
- operator: "equals",
- value: collectionResult.id
- });
- if (!filter.limit) {
- filter.limit = 50;
+ if (body.status !== void 0) {
+ updates.push("status = ?");
+ params.push(body.status);
}
- filter.limit = Math.min(filter.limit, 1e3);
- const builder3 = new QueryFilterBuilder();
- const queryResult = builder3.build("content", filter);
- if (queryResult.errors.length > 0) {
- return c.json({
- error: "Invalid filter parameters",
- details: queryResult.errors
- }, 400);
+ if (body.data !== void 0) {
+ updates.push("data = ?");
+ params.push(JSON.stringify(body.data));
}
- const cacheEnabled = c.get("cacheEnabled");
+ const now = Date.now();
+ updates.push("updated_at = ?");
+ params.push(now);
+ params.push(id);
+ const updateStmt = db.prepare(`
+ UPDATE content SET ${updates.join(", ")}
+ WHERE id = ?
+ `);
+ await updateStmt.bind(...params).run();
const cache = getCacheService(CACHE_CONFIGS.api);
- const cacheKey = cache.generateKey("collection-content-filtered", `${collection}:${JSON.stringify({ filter, query: queryResult.sql })}`);
- if (cacheEnabled) {
- const cacheResult = await cache.getWithSource(cacheKey);
- if (cacheResult.hit && cacheResult.data) {
- c.header("X-Cache-Status", "HIT");
- c.header("X-Cache-Source", cacheResult.source);
- if (cacheResult.ttl) {
- c.header("X-Cache-TTL", Math.floor(cacheResult.ttl).toString());
- }
- const dataWithMeta = {
- ...cacheResult.data,
- meta: addTimingMeta(c, {
- ...cacheResult.data.meta,
- cache: {
- hit: true,
- source: cacheResult.source,
- ttl: cacheResult.ttl ? Math.floor(cacheResult.ttl) : void 0
- }
- }, executionStart)
- };
- return c.json(dataWithMeta);
- }
- }
- c.header("X-Cache-Status", "MISS");
- c.header("X-Cache-Source", "database");
- const stmt = db.prepare(queryResult.sql);
- const boundStmt = queryResult.params.length > 0 ? stmt.bind(...queryResult.params) : stmt;
- const { results } = await boundStmt.all();
- const transformedResults = results.map((row) => ({
- id: row.id,
- title: row.title,
- slug: row.slug,
- status: row.status,
- collectionId: row.collection_id,
- data: row.data ? JSON.parse(row.data) : {},
- created_at: row.created_at,
- updated_at: row.updated_at
- }));
- const responseData = {
- data: transformedResults,
- meta: addTimingMeta(c, {
- collection: {
- ...collectionResult,
- schema: collectionResult.schema ? JSON.parse(collectionResult.schema) : {}
- },
- count: results.length,
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
- filter,
- query: {
- sql: queryResult.sql,
- params: queryResult.params
- },
- cache: {
- hit: false,
- source: "database"
- }
- }, executionStart)
- };
- if (cacheEnabled) {
- await cache.set(cacheKey, responseData);
+ await cache.delete(cache.generateKey("content", id));
+ await cache.invalidate(`content:list:${existing.collection_id}:*`);
+ await cache.invalidate("content-filtered:*");
+ const fts5Service = new FTS5Service(db);
+ c.executionCtx.waitUntil(
+ fts5Service.indexContent(id).catch(
+ (err) => console.error("[API Content] FTS5 reindexing failed:", err)
+ )
+ );
+ if (c.env.CACHE_KV) {
+ const searchCache = new SearchCacheService(c.env.CACHE_KV);
+ c.executionCtx.waitUntil(searchCache.invalidateAll());
}
- return c.json(responseData);
- } catch (error) {
- console.error("Error fetching content:", error);
+ const getStmt = db.prepare("SELECT * FROM content WHERE id = ?");
+ const updatedContent = await getStmt.bind(id).first();
return c.json({
- error: "Failed to fetch content",
- details: error instanceof Error ? error.message : String(error)
- }, 500);
- }
-});
-apiRoutes.route("/content", api_content_crud_default);
-var api_default = apiRoutes;
-function generateId() {
- return crypto.randomUUID().replace(/-/g, "").substring(0, 21);
-}
-async function emitEvent(eventName, data) {
- console.log(`[Event] ${eventName}:`, data);
-}
-var fileValidationSchema = z.object({
- name: z.string().min(1).max(255),
- type: z.string().refine(
- (type) => {
- const allowedTypes = [
- // Images
- "image/jpeg",
- "image/jpg",
- "image/png",
- "image/gif",
- "image/webp",
- "image/svg+xml",
- // Documents
- "application/pdf",
- "text/plain",
- "application/msword",
- "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
- // Videos
- "video/mp4",
- "video/webm",
- "video/ogg",
- "video/avi",
- "video/mov",
- // Audio
- "audio/mp3",
- "audio/wav",
- "audio/ogg",
- "audio/m4a"
- ];
- return allowedTypes.includes(type);
- },
- { message: "Unsupported file type" }
- ),
- size: z.number().min(1).max(50 * 1024 * 1024)
- // 50MB max
-});
-var apiMediaRoutes = new Hono();
-apiMediaRoutes.use("*", requireAuth());
-apiMediaRoutes.post("/upload", async (c) => {
- try {
- const user = c.get("user");
- const formData = await c.req.formData();
- const fileData = formData.get("file");
- if (!fileData || typeof fileData === "string") {
- return c.json({ error: "No file provided" }, 400);
- }
- const file = fileData;
- const validation = fileValidationSchema.safeParse({
- name: file.name,
- type: file.type,
- size: file.size
- });
- if (!validation.success) {
- return c.json({
- error: "File validation failed",
- details: validation.error.issues
- }, 400);
- }
- const fileId = generateId();
- const fileExtension = file.name.split(".").pop() || "";
- const filename = `${fileId}.${fileExtension}`;
- const folder = formData.get("folder") || "uploads";
- const r2Key = `${folder}/${filename}`;
- const arrayBuffer = await file.arrayBuffer();
- const uploadResult = await c.env.MEDIA_BUCKET.put(r2Key, arrayBuffer, {
- httpMetadata: {
- contentType: file.type,
- contentDisposition: `inline; filename="${file.name}"`
- },
- customMetadata: {
- originalName: file.name,
- uploadedBy: user.userId,
- uploadedAt: (/* @__PURE__ */ new Date()).toISOString()
- }
- });
- if (!uploadResult) {
- return c.json({ error: "Failed to upload file to storage" }, 500);
- }
- const bucketName = c.env.BUCKET_NAME || "sonicjs-media-dev";
- const publicUrl = `https://pub-${bucketName}.r2.dev/${r2Key}`;
- let width;
- let height;
- if (file.type.startsWith("image/") && !file.type.includes("svg")) {
- try {
- const dimensions = await getImageDimensions(arrayBuffer);
- width = dimensions.width;
- height = dimensions.height;
- } catch (error) {
- console.warn("Failed to extract image dimensions:", error);
- }
- }
- let thumbnailUrl;
- if (file.type.startsWith("image/") && c.env.IMAGES_ACCOUNT_ID) {
- thumbnailUrl = `https://imagedelivery.net/${c.env.IMAGES_ACCOUNT_ID}/${r2Key}/thumbnail`;
- }
- const mediaRecord = {
- id: fileId,
- filename,
- original_name: file.name,
- mime_type: file.type,
- size: file.size,
- width,
- height,
- folder,
- r2_key: r2Key,
- public_url: publicUrl,
- thumbnail_url: thumbnailUrl,
- uploaded_by: user.userId,
- uploaded_at: Math.floor(Date.now() / 1e3),
- created_at: Math.floor(Date.now() / 1e3)
- };
- const stmt = c.env.DB.prepare(`
- INSERT INTO media (
- id, filename, original_name, mime_type, size, width, height,
- folder, r2_key, public_url, thumbnail_url, uploaded_by, uploaded_at
- ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
- `);
- await stmt.bind(
- mediaRecord.id,
- mediaRecord.filename,
- mediaRecord.original_name,
- mediaRecord.mime_type,
- mediaRecord.size,
- mediaRecord.width ?? null,
- mediaRecord.height ?? null,
- mediaRecord.folder,
- mediaRecord.r2_key,
- mediaRecord.public_url,
- mediaRecord.thumbnail_url ?? null,
- mediaRecord.uploaded_by,
- mediaRecord.uploaded_at
- ).run();
- await emitEvent("media.upload", { id: mediaRecord.id, filename: mediaRecord.filename });
- return c.json({
- success: true,
- file: {
- id: mediaRecord.id,
- filename: mediaRecord.filename,
- originalName: mediaRecord.original_name,
- mimeType: mediaRecord.mime_type,
- size: mediaRecord.size,
- width: mediaRecord.width,
- height: mediaRecord.height,
- r2_key: mediaRecord.r2_key,
- publicUrl: mediaRecord.public_url,
- thumbnailUrl: mediaRecord.thumbnail_url,
- uploadedAt: new Date(mediaRecord.uploaded_at * 1e3).toISOString()
+ data: {
+ id: updatedContent.id,
+ title: updatedContent.title,
+ slug: updatedContent.slug,
+ status: updatedContent.status,
+ collectionId: updatedContent.collection_id,
+ data: updatedContent.data ? JSON.parse(updatedContent.data) : {},
+ created_at: updatedContent.created_at,
+ updated_at: updatedContent.updated_at
}
});
} catch (error) {
- console.error("Upload error:", error);
- return c.json({ error: "Upload failed" }, 500);
+ console.error("Error updating content:", error);
+ return c.json({
+ error: "Failed to update content",
+ details: error instanceof Error ? error.message : String(error)
+ }, 500);
}
});
-apiMediaRoutes.post("/upload-multiple", async (c) => {
+apiContentCrudRoutes.delete("/:id", requireAuth(), async (c) => {
try {
- const user = c.get("user");
- const formData = await c.req.formData();
- const filesData = formData.getAll("files");
- const files = [];
- for (const f of filesData) {
- if (typeof f !== "string") {
- files.push(f);
- }
+ const id = c.req.param("id");
+ const db = c.env.DB;
+ const existingStmt = db.prepare("SELECT collection_id FROM content WHERE id = ?");
+ const existing = await existingStmt.bind(id).first();
+ if (!existing) {
+ return c.json({ error: "Content not found" }, 404);
}
- if (!files || files.length === 0) {
- return c.json({ error: "No files provided" }, 400);
+ const deleteStmt = db.prepare("DELETE FROM content WHERE id = ?");
+ await deleteStmt.bind(id).run();
+ const cache = getCacheService(CACHE_CONFIGS.api);
+ await cache.delete(cache.generateKey("content", id));
+ await cache.invalidate(`content:list:${existing.collection_id}:*`);
+ await cache.invalidate("content-filtered:*");
+ const fts5Service = new FTS5Service(db);
+ c.executionCtx.waitUntil(
+ fts5Service.removeFromIndex(id).catch(
+ (err) => console.error("[API Content] FTS5 removal failed:", err)
+ )
+ );
+ if (c.env.CACHE_KV) {
+ const searchCache = new SearchCacheService(c.env.CACHE_KV);
+ c.executionCtx.waitUntil(searchCache.invalidateAll());
}
- const uploadResults = [];
- const errors = [];
- for (const file of files) {
- try {
- const validation = fileValidationSchema.safeParse({
- name: file.name,
- type: file.type,
- size: file.size
- });
- if (!validation.success) {
- errors.push({
- filename: file.name,
- error: "Validation failed",
- details: validation.error.issues
- });
- continue;
- }
- const fileId = generateId();
- const fileExtension = file.name.split(".").pop() || "";
- const filename = `${fileId}.${fileExtension}`;
- const folder = formData.get("folder") || "uploads";
- const r2Key = `${folder}/${filename}`;
- const arrayBuffer = await file.arrayBuffer();
- const uploadResult = await c.env.MEDIA_BUCKET.put(r2Key, arrayBuffer, {
- httpMetadata: {
- contentType: file.type,
- contentDisposition: `inline; filename="${file.name}"`
- },
- customMetadata: {
- originalName: file.name,
- uploadedBy: user.userId,
- uploadedAt: (/* @__PURE__ */ new Date()).toISOString()
- }
- });
- if (!uploadResult) {
- errors.push({
- filename: file.name,
- error: "Failed to upload to storage"
- });
- continue;
- }
- const bucketName = c.env.BUCKET_NAME || "sonicjs-media-dev";
- const publicUrl = `https://pub-${bucketName}.r2.dev/${r2Key}`;
- let width;
- let height;
- if (file.type.startsWith("image/") && !file.type.includes("svg")) {
- try {
- const dimensions = await getImageDimensions(arrayBuffer);
- width = dimensions.width;
- height = dimensions.height;
- } catch (error) {
- console.warn("Failed to extract image dimensions:", error);
- }
- }
- let thumbnailUrl;
- if (file.type.startsWith("image/") && c.env.IMAGES_ACCOUNT_ID) {
- thumbnailUrl = `https://imagedelivery.net/${c.env.IMAGES_ACCOUNT_ID}/${r2Key}/thumbnail`;
- }
- const mediaRecord = {
- id: fileId,
- filename,
- original_name: file.name,
- mime_type: file.type,
- size: file.size,
- width,
- height,
- folder,
- r2_key: r2Key,
- public_url: publicUrl,
- thumbnail_url: thumbnailUrl,
- uploaded_by: user.userId,
- uploaded_at: Math.floor(Date.now() / 1e3)
- };
- const stmt = c.env.DB.prepare(`
- INSERT INTO media (
- id, filename, original_name, mime_type, size, width, height,
- folder, r2_key, public_url, thumbnail_url, uploaded_by, uploaded_at
- ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
- `);
- await stmt.bind(
- mediaRecord.id,
- mediaRecord.filename,
- mediaRecord.original_name,
- mediaRecord.mime_type,
- mediaRecord.size,
- mediaRecord.width ?? null,
- mediaRecord.height ?? null,
- mediaRecord.folder,
- mediaRecord.r2_key,
- mediaRecord.public_url,
- mediaRecord.thumbnail_url ?? null,
- mediaRecord.uploaded_by,
- mediaRecord.uploaded_at
- ).run();
- uploadResults.push({
- id: mediaRecord.id,
- filename: mediaRecord.filename,
- originalName: mediaRecord.original_name,
- mimeType: mediaRecord.mime_type,
- size: mediaRecord.size,
- width: mediaRecord.width,
- height: mediaRecord.height,
- r2_key: mediaRecord.r2_key,
- publicUrl: mediaRecord.public_url,
- thumbnailUrl: mediaRecord.thumbnail_url,
- uploadedAt: new Date(mediaRecord.uploaded_at * 1e3).toISOString()
- });
- } catch (error) {
- errors.push({
- filename: file.name,
- error: "Upload failed",
- details: error instanceof Error ? error.message : "Unknown error"
- });
- }
- }
- if (uploadResults.length > 0) {
- await emitEvent("media.upload", { count: uploadResults.length });
- }
- return c.json({
- success: uploadResults.length > 0,
- uploaded: uploadResults,
- errors,
- summary: {
- total: files.length,
- successful: uploadResults.length,
- failed: errors.length
- }
- });
+ return c.json({ success: true });
} catch (error) {
- console.error("Multiple upload error:", error);
- return c.json({ error: "Upload failed" }, 500);
+ console.error("Error deleting content:", error);
+ return c.json({
+ error: "Failed to delete content",
+ details: error instanceof Error ? error.message : String(error)
+ }, 500);
}
});
-apiMediaRoutes.post("/bulk-delete", async (c) => {
- try {
- const user = c.get("user");
- const body = await c.req.json();
- const fileIds = body.fileIds;
- if (!fileIds || !Array.isArray(fileIds) || fileIds.length === 0) {
- return c.json({ error: "No file IDs provided" }, 400);
- }
- if (fileIds.length > 50) {
- return c.json({ error: "Too many files selected. Maximum 50 files per operation." }, 400);
+var api_content_crud_default = apiContentCrudRoutes;
+
+// src/routes/api.ts
+var apiRoutes = new Hono();
+apiRoutes.use("*", async (c, next) => {
+ const startTime = Date.now();
+ c.set("startTime", startTime);
+ await next();
+ const totalTime = Date.now() - startTime;
+ c.header("X-Response-Time", `${totalTime}ms`);
+});
+apiRoutes.use("*", async (c, next) => {
+ const cacheEnabled = await isPluginActive(c.env.DB, "core-cache");
+ c.set("cacheEnabled", cacheEnabled);
+ await next();
+});
+apiRoutes.use("*", cors({
+ origin: "*",
+ allowMethods: ["GET", "POST", "PUT", "DELETE", "OPTIONS"],
+ allowHeaders: ["Content-Type", "Authorization"]
+}));
+function addTimingMeta(c, meta = {}, executionStartTime) {
+ const totalTime = Date.now() - c.get("startTime");
+ const executionTime = executionStartTime ? Date.now() - executionStartTime : void 0;
+ return {
+ ...meta,
+ timing: {
+ total: totalTime,
+ execution: executionTime,
+ unit: "ms"
}
- const results = [];
- const errors = [];
- for (const fileId of fileIds) {
- try {
- const stmt = c.env.DB.prepare("SELECT * FROM media WHERE id = ?");
- const fileRecord = await stmt.bind(fileId).first();
- if (!fileRecord) {
- errors.push({ fileId, error: "File not found" });
- continue;
- }
- if (fileRecord.deleted_at !== null) {
- console.log(`File ${fileId} already deleted, skipping`);
- results.push({
- fileId,
- filename: fileRecord.original_name,
- success: true,
- alreadyDeleted: true
- });
- continue;
+ };
+}
+apiRoutes.get("/", (c) => {
+ const baseUrl = new URL(c.req.url);
+ const serverUrl = `${baseUrl.protocol}//${baseUrl.host}`;
+ return c.json({
+ openapi: "3.0.0",
+ info: {
+ title: "SonicJS AI API",
+ version: "0.1.0",
+ description: "RESTful API for SonicJS headless CMS - a modern, AI-powered content management system built on Cloudflare Workers",
+ contact: {
+ name: "SonicJS Support",
+ url: `${serverUrl}/docs`,
+ email: "support@sonicjs.com"
+ },
+ license: {
+ name: "MIT",
+ url: "https://opensource.org/licenses/MIT"
+ }
+ },
+ servers: [
+ {
+ url: serverUrl,
+ description: "Current server"
+ }
+ ],
+ paths: {
+ "/api/": {
+ get: {
+ summary: "API Information",
+ description: "Returns OpenAPI specification for the SonicJS API",
+ operationId: "getApiInfo",
+ tags: ["System"],
+ responses: {
+ "200": {
+ description: "OpenAPI specification",
+ content: {
+ "application/json": {
+ schema: { type: "object" }
+ }
+ }
+ }
+ }
}
- if (fileRecord.uploaded_by !== user.userId && user.role !== "admin") {
- errors.push({ fileId, error: "Permission denied" });
- continue;
+ },
+ "/api/health": {
+ get: {
+ summary: "Health Check",
+ description: "Returns API health status and available schemas",
+ operationId: "getHealth",
+ tags: ["System"],
+ responses: {
+ "200": {
+ description: "Health status",
+ content: {
+ "application/json": {
+ schema: {
+ type: "object",
+ properties: {
+ status: { type: "string", example: "healthy" },
+ timestamp: { type: "string", format: "date-time" },
+ schemas: { type: "array", items: { type: "string" } }
+ }
+ }
+ }
+ }
+ }
+ }
}
- try {
- await c.env.MEDIA_BUCKET.delete(fileRecord.r2_key);
- } catch (error) {
- console.warn(`Failed to delete from R2 for file ${fileId}:`, error);
+ },
+ "/api/collections": {
+ get: {
+ summary: "List Collections",
+ description: "Returns all active collections with their schemas",
+ operationId: "getCollections",
+ tags: ["Content"],
+ responses: {
+ "200": {
+ description: "List of collections",
+ content: {
+ "application/json": {
+ schema: {
+ type: "object",
+ properties: {
+ data: {
+ type: "array",
+ items: {
+ type: "object",
+ properties: {
+ id: { type: "string" },
+ name: { type: "string" },
+ display_name: { type: "string" },
+ schema: { type: "object" },
+ is_active: { type: "integer" }
+ }
+ }
+ },
+ meta: { type: "object" }
+ }
+ }
+ }
+ }
+ }
+ }
}
- const deleteStmt = c.env.DB.prepare("UPDATE media SET deleted_at = ? WHERE id = ?");
- await deleteStmt.bind(Math.floor(Date.now() / 1e3), fileId).run();
- results.push({
- fileId,
- filename: fileRecord.original_name,
- success: true
- });
- } catch (error) {
- errors.push({
- fileId,
- error: "Delete failed",
- details: error instanceof Error ? error.message : "Unknown error"
- });
- }
- }
- if (results.length > 0) {
- await emitEvent("media.delete", { count: results.length, ids: fileIds });
- }
- return c.json({
- success: results.length > 0,
- deleted: results,
- errors,
- summary: {
- total: fileIds.length,
- successful: results.length,
- failed: errors.length
- }
- });
- } catch (error) {
- console.error("Bulk delete error:", error);
- return c.json({ error: "Bulk delete failed" }, 500);
- }
-});
-apiMediaRoutes.post("/create-folder", async (c) => {
- try {
- const body = await c.req.json();
- const folderName = body.folderName;
- if (!folderName || typeof folderName !== "string") {
- return c.json({ success: false, error: "No folder name provided" }, 400);
- }
- const folderPattern = /^[a-z0-9-_]+$/;
- if (!folderPattern.test(folderName)) {
- return c.json({
- success: false,
- error: "Folder name can only contain lowercase letters, numbers, hyphens, and underscores"
- }, 400);
- }
- const checkStmt = c.env.DB.prepare("SELECT COUNT(*) as count FROM media WHERE folder = ? AND deleted_at IS NULL");
- const existingFolder = await checkStmt.bind(folderName).first();
- if (existingFolder && existingFolder.count > 0) {
- return c.json({
- success: false,
- error: `Folder "${folderName}" already exists`
- }, 400);
- }
- return c.json({
- success: true,
- message: `Folder "${folderName}" is ready. Upload files to this folder to make it appear in the media library.`,
- folder: folderName,
- note: "Folders appear automatically when you upload files to them"
- });
- } catch (error) {
- console.error("Create folder error:", error);
- return c.json({ success: false, error: "Failed to create folder" }, 500);
- }
-});
-apiMediaRoutes.post("/bulk-move", async (c) => {
- try {
- const user = c.get("user");
- const body = await c.req.json();
- const fileIds = body.fileIds;
- const targetFolder = body.folder;
- if (!fileIds || !Array.isArray(fileIds) || fileIds.length === 0) {
- return c.json({ error: "No file IDs provided" }, 400);
- }
- if (!targetFolder || typeof targetFolder !== "string") {
- return c.json({ error: "No target folder provided" }, 400);
- }
- if (fileIds.length > 50) {
- return c.json({ error: "Too many files selected. Maximum 50 files per operation." }, 400);
- }
- const results = [];
- const errors = [];
- for (const fileId of fileIds) {
- try {
- const stmt = c.env.DB.prepare("SELECT * FROM media WHERE id = ? AND deleted_at IS NULL");
- const fileRecord = await stmt.bind(fileId).first();
- if (!fileRecord) {
- errors.push({ fileId, error: "File not found" });
- continue;
- }
- if (fileRecord.uploaded_by !== user.userId && user.role !== "admin") {
- errors.push({ fileId, error: "Permission denied" });
- continue;
- }
- if (fileRecord.folder === targetFolder) {
- results.push({
- fileId,
- filename: fileRecord.original_name,
- success: true,
- skipped: true
- });
- continue;
+ },
+ "/api/collections/{collection}/content": {
+ get: {
+ summary: "Get Collection Content",
+ description: "Returns content items from a specific collection with filtering support",
+ operationId: "getCollectionContent",
+ tags: ["Content"],
+ parameters: [
+ {
+ name: "collection",
+ in: "path",
+ required: true,
+ schema: { type: "string" },
+ description: "Collection name"
+ },
+ {
+ name: "limit",
+ in: "query",
+ schema: { type: "integer", default: 50, maximum: 1e3 },
+ description: "Maximum number of items to return"
+ },
+ {
+ name: "offset",
+ in: "query",
+ schema: { type: "integer", default: 0 },
+ description: "Number of items to skip"
+ },
+ {
+ name: "status",
+ in: "query",
+ schema: { type: "string", enum: ["draft", "published", "archived"] },
+ description: "Filter by content status"
+ }
+ ],
+ responses: {
+ "200": {
+ description: "List of content items",
+ content: {
+ "application/json": {
+ schema: {
+ type: "object",
+ properties: {
+ data: { type: "array", items: { type: "object" } },
+ meta: { type: "object" }
+ }
+ }
+ }
+ }
+ },
+ "404": {
+ description: "Collection not found"
+ }
+ }
}
- const oldR2Key = fileRecord.r2_key;
- const filename = oldR2Key.split("/").pop() || fileRecord.filename;
- const newR2Key = `${targetFolder}/${filename}`;
- try {
- const object = await c.env.MEDIA_BUCKET.get(oldR2Key);
- if (!object) {
- errors.push({ fileId, error: "File not found in storage" });
- continue;
+ },
+ "/api/content": {
+ get: {
+ summary: "List Content",
+ description: "Returns content items with advanced filtering support",
+ operationId: "getContent",
+ tags: ["Content"],
+ parameters: [
+ {
+ name: "collection",
+ in: "query",
+ schema: { type: "string" },
+ description: "Filter by collection name"
+ },
+ {
+ name: "limit",
+ in: "query",
+ schema: { type: "integer", default: 50, maximum: 1e3 },
+ description: "Maximum number of items to return"
+ },
+ {
+ name: "offset",
+ in: "query",
+ schema: { type: "integer", default: 0 },
+ description: "Number of items to skip"
+ }
+ ],
+ responses: {
+ "200": {
+ description: "List of content items",
+ content: {
+ "application/json": {
+ schema: {
+ type: "object",
+ properties: {
+ data: { type: "array", items: { type: "object" } },
+ meta: { type: "object" }
+ }
+ }
+ }
+ }
+ }
}
- await c.env.MEDIA_BUCKET.put(newR2Key, object.body, {
- httpMetadata: object.httpMetadata,
- customMetadata: {
- ...object.customMetadata,
- movedBy: user.userId,
- movedAt: (/* @__PURE__ */ new Date()).toISOString()
+ },
+ post: {
+ summary: "Create Content",
+ description: "Creates a new content item",
+ operationId: "createContent",
+ tags: ["Content"],
+ security: [{ bearerAuth: [] }],
+ requestBody: {
+ required: true,
+ content: {
+ "application/json": {
+ schema: {
+ type: "object",
+ required: ["collection_id", "title"],
+ properties: {
+ collection_id: { type: "string" },
+ title: { type: "string" },
+ slug: { type: "string" },
+ status: { type: "string", enum: ["draft", "published", "archived"] },
+ data: { type: "object" }
+ }
+ }
+ }
}
- });
- await c.env.MEDIA_BUCKET.delete(oldR2Key);
- } catch (error) {
- console.warn(`Failed to move file in R2 for file ${fileId}:`, error);
- errors.push({ fileId, error: "Failed to move file in storage" });
- continue;
+ },
+ responses: {
+ "201": { description: "Content created successfully" },
+ "400": { description: "Invalid request body" },
+ "401": { description: "Unauthorized" }
+ }
}
- const bucketName = c.env.BUCKET_NAME || "sonicjs-media-dev";
- const newPublicUrl = `https://pub-${bucketName}.r2.dev/${newR2Key}`;
- const updateStmt = c.env.DB.prepare(`
- UPDATE media
- SET folder = ?, r2_key = ?, public_url = ?, updated_at = ?
- WHERE id = ?
- `);
- await updateStmt.bind(
- targetFolder,
- newR2Key,
- newPublicUrl,
- Math.floor(Date.now() / 1e3),
- fileId
- ).run();
- results.push({
- fileId,
- filename: fileRecord.original_name,
- success: true,
- skipped: false
- });
- } catch (error) {
- errors.push({
- fileId,
- error: "Move failed",
- details: error instanceof Error ? error.message : "Unknown error"
- });
+ },
+ "/api/content/{id}": {
+ get: {
+ summary: "Get Content by ID",
+ description: "Returns a specific content item by ID",
+ operationId: "getContentById",
+ tags: ["Content"],
+ parameters: [
+ {
+ name: "id",
+ in: "path",
+ required: true,
+ schema: { type: "string" },
+ description: "Content item ID"
+ }
+ ],
+ responses: {
+ "200": { description: "Content item" },
+ "404": { description: "Content not found" }
+ }
+ },
+ put: {
+ summary: "Update Content",
+ description: "Updates an existing content item",
+ operationId: "updateContent",
+ tags: ["Content"],
+ security: [{ bearerAuth: [] }],
+ parameters: [
+ {
+ name: "id",
+ in: "path",
+ required: true,
+ schema: { type: "string" },
+ description: "Content item ID"
+ }
+ ],
+ responses: {
+ "200": { description: "Content updated successfully" },
+ "401": { description: "Unauthorized" },
+ "404": { description: "Content not found" }
+ }
+ },
+ delete: {
+ summary: "Delete Content",
+ description: "Deletes a content item",
+ operationId: "deleteContent",
+ tags: ["Content"],
+ security: [{ bearerAuth: [] }],
+ parameters: [
+ {
+ name: "id",
+ in: "path",
+ required: true,
+ schema: { type: "string" },
+ description: "Content item ID"
+ }
+ ],
+ responses: {
+ "200": { description: "Content deleted successfully" },
+ "401": { description: "Unauthorized" },
+ "404": { description: "Content not found" }
+ }
+ }
+ },
+ "/api/media": {
+ get: {
+ summary: "List Media",
+ description: "Returns all media files with pagination",
+ operationId: "getMedia",
+ tags: ["Media"],
+ responses: {
+ "200": { description: "List of media files" }
+ }
+ }
+ },
+ "/api/media/upload": {
+ post: {
+ summary: "Upload Media",
+ description: "Uploads a new media file to R2 storage",
+ operationId: "uploadMedia",
+ tags: ["Media"],
+ security: [{ bearerAuth: [] }],
+ requestBody: {
+ required: true,
+ content: {
+ "multipart/form-data": {
+ schema: {
+ type: "object",
+ properties: {
+ file: { type: "string", format: "binary" }
+ }
+ }
+ }
+ }
+ },
+ responses: {
+ "201": { description: "Media uploaded successfully" },
+ "401": { description: "Unauthorized" }
+ }
+ }
+ }
+ },
+ components: {
+ securitySchemes: {
+ bearerAuth: {
+ type: "http",
+ scheme: "bearer",
+ bearerFormat: "JWT"
+ }
+ },
+ schemas: {
+ Content: {
+ type: "object",
+ properties: {
+ id: { type: "string", format: "uuid" },
+ title: { type: "string" },
+ slug: { type: "string" },
+ status: { type: "string", enum: ["draft", "published", "archived"] },
+ collectionId: { type: "string", format: "uuid" },
+ data: { type: "object" },
+ created_at: { type: "integer" },
+ updated_at: { type: "integer" }
+ }
+ },
+ Collection: {
+ type: "object",
+ properties: {
+ id: { type: "string", format: "uuid" },
+ name: { type: "string" },
+ display_name: { type: "string" },
+ description: { type: "string" },
+ schema: { type: "object" },
+ is_active: { type: "integer" }
+ }
+ },
+ Media: {
+ type: "object",
+ properties: {
+ id: { type: "string", format: "uuid" },
+ filename: { type: "string" },
+ mimetype: { type: "string" },
+ size: { type: "integer" },
+ url: { type: "string" }
+ }
+ },
+ Error: {
+ type: "object",
+ properties: {
+ error: { type: "string" },
+ details: { type: "string" }
+ }
+ }
+ }
+ },
+ tags: [
+ { name: "System", description: "System and health endpoints" },
+ { name: "Content", description: "Content management operations" },
+ { name: "Media", description: "Media file operations" }
+ ]
+ });
+});
+apiRoutes.get("/health", (c) => {
+ return c.json({
+ status: "healthy",
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
+ schemas: schemaDefinitions.map((s) => s.name)
+ });
+});
+apiRoutes.get("/collections", async (c) => {
+ const executionStart = Date.now();
+ try {
+ const db = c.env.DB;
+ const cacheEnabled = c.get("cacheEnabled");
+ const cache = getCacheService(CACHE_CONFIGS.api);
+ const cacheKey = cache.generateKey("collections", "all");
+ if (cacheEnabled) {
+ const cacheResult = await cache.getWithSource(cacheKey);
+ if (cacheResult.hit && cacheResult.data) {
+ c.header("X-Cache-Status", "HIT");
+ c.header("X-Cache-Source", cacheResult.source);
+ if (cacheResult.ttl) {
+ c.header("X-Cache-TTL", Math.floor(cacheResult.ttl).toString());
+ }
+ const dataWithMeta = {
+ ...cacheResult.data,
+ meta: addTimingMeta(c, {
+ ...cacheResult.data.meta,
+ cache: {
+ hit: true,
+ source: cacheResult.source,
+ ttl: cacheResult.ttl ? Math.floor(cacheResult.ttl) : void 0
+ }
+ }, executionStart)
+ };
+ return c.json(dataWithMeta);
}
}
- if (results.length > 0) {
- await emitEvent("media.move", { count: results.length, targetFolder, ids: fileIds });
+ c.header("X-Cache-Status", "MISS");
+ c.header("X-Cache-Source", "database");
+ const stmt = db.prepare("SELECT * FROM collections WHERE is_active = 1");
+ const { results } = await stmt.all();
+ const transformedResults = results.map((row) => ({
+ ...row,
+ schema: row.schema ? JSON.parse(row.schema) : {},
+ is_active: row.is_active
+ // Keep as number (1 or 0)
+ }));
+ const responseData = {
+ data: transformedResults,
+ meta: addTimingMeta(c, {
+ count: results.length,
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
+ cache: {
+ hit: false,
+ source: "database"
+ }
+ }, executionStart)
+ };
+ if (cacheEnabled) {
+ await cache.set(cacheKey, responseData);
}
- return c.json({
- success: results.length > 0,
- moved: results,
- errors,
- summary: {
- total: fileIds.length,
- successful: results.length,
- failed: errors.length
- }
- });
+ return c.json(responseData);
} catch (error) {
- console.error("Bulk move error:", error);
- return c.json({ error: "Bulk move failed" }, 500);
+ console.error("Error fetching collections:", error);
+ return c.json({ error: "Failed to fetch collections" }, 500);
}
});
-apiMediaRoutes.delete("/:id", async (c) => {
+apiRoutes.get("/content", async (c) => {
+ const executionStart = Date.now();
try {
- const user = c.get("user");
- const fileId = c.req.param("id");
- const stmt = c.env.DB.prepare("SELECT * FROM media WHERE id = ? AND deleted_at IS NULL");
- const fileRecord = await stmt.bind(fileId).first();
- if (!fileRecord) {
- return c.json({ error: "File not found" }, 404);
- }
- if (fileRecord.uploaded_by !== user.userId && user.role !== "admin") {
- return c.json({ error: "Permission denied" }, 403);
+ const db = c.env.DB;
+ const queryParams = c.req.query();
+ if (queryParams.collection) {
+ const collectionName = queryParams.collection;
+ const collectionStmt = db.prepare("SELECT id FROM collections WHERE name = ? AND is_active = 1");
+ const collectionResult = await collectionStmt.bind(collectionName).first();
+ if (collectionResult) {
+ queryParams.collection_id = collectionResult.id;
+ delete queryParams.collection;
+ } else {
+ return c.json({
+ data: [],
+ meta: addTimingMeta(c, {
+ count: 0,
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
+ message: `Collection '${collectionName}' not found`
+ }, executionStart)
+ });
+ }
}
- try {
- await c.env.MEDIA_BUCKET.delete(fileRecord.r2_key);
- } catch (error) {
- console.warn("Failed to delete from R2:", error);
+ const filter = QueryFilterBuilder.parseFromQuery(queryParams);
+ if (!filter.limit) {
+ filter.limit = 50;
}
- const deleteStmt = c.env.DB.prepare("UPDATE media SET deleted_at = ? WHERE id = ?");
- await deleteStmt.bind(Math.floor(Date.now() / 1e3), fileId).run();
- await emitEvent("media.delete", { id: fileId });
- return c.json({ success: true, message: "File deleted successfully" });
+ filter.limit = Math.min(filter.limit, 1e3);
+ const builder3 = new QueryFilterBuilder();
+ const queryResult = builder3.build("content", filter);
+ if (queryResult.errors.length > 0) {
+ return c.json({
+ error: "Invalid filter parameters",
+ details: queryResult.errors
+ }, 400);
+ }
+ const cacheEnabled = c.get("cacheEnabled");
+ const cache = getCacheService(CACHE_CONFIGS.api);
+ const cacheKey = cache.generateKey("content-filtered", JSON.stringify({ filter, query: queryResult.sql }));
+ if (cacheEnabled) {
+ const cacheResult = await cache.getWithSource(cacheKey);
+ if (cacheResult.hit && cacheResult.data) {
+ c.header("X-Cache-Status", "HIT");
+ c.header("X-Cache-Source", cacheResult.source);
+ if (cacheResult.ttl) {
+ c.header("X-Cache-TTL", Math.floor(cacheResult.ttl).toString());
+ }
+ const dataWithMeta = {
+ ...cacheResult.data,
+ meta: addTimingMeta(c, {
+ ...cacheResult.data.meta,
+ cache: {
+ hit: true,
+ source: cacheResult.source,
+ ttl: cacheResult.ttl ? Math.floor(cacheResult.ttl) : void 0
+ }
+ }, executionStart)
+ };
+ return c.json(dataWithMeta);
+ }
+ }
+ c.header("X-Cache-Status", "MISS");
+ c.header("X-Cache-Source", "database");
+ const stmt = db.prepare(queryResult.sql);
+ const boundStmt = queryResult.params.length > 0 ? stmt.bind(...queryResult.params) : stmt;
+ const { results } = await boundStmt.all();
+ const transformedResults = results.map((row) => ({
+ id: row.id,
+ title: row.title,
+ slug: row.slug,
+ status: row.status,
+ collectionId: row.collection_id,
+ data: row.data ? JSON.parse(row.data) : {},
+ created_at: row.created_at,
+ updated_at: row.updated_at
+ }));
+ const responseData = {
+ data: transformedResults,
+ meta: addTimingMeta(c, {
+ count: results.length,
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
+ filter,
+ query: {
+ sql: queryResult.sql,
+ params: queryResult.params
+ },
+ cache: {
+ hit: false,
+ source: "database"
+ }
+ }, executionStart)
+ };
+ if (cacheEnabled) {
+ await cache.set(cacheKey, responseData);
+ }
+ return c.json(responseData);
} catch (error) {
- console.error("Delete error:", error);
- return c.json({ error: "Delete failed" }, 500);
+ console.error("Error fetching content:", error);
+ return c.json({
+ error: "Failed to fetch content",
+ details: error instanceof Error ? error.message : String(error)
+ }, 500);
}
});
-apiMediaRoutes.patch("/:id", async (c) => {
+apiRoutes.get("/collections/:collection/content", async (c) => {
+ const executionStart = Date.now();
try {
- const user = c.get("user");
- const fileId = c.req.param("id");
- const body = await c.req.json();
- const stmt = c.env.DB.prepare("SELECT * FROM media WHERE id = ? AND deleted_at IS NULL");
- const fileRecord = await stmt.bind(fileId).first();
- if (!fileRecord) {
- return c.json({ error: "File not found" }, 404);
+ const collection = c.req.param("collection");
+ const db = c.env.DB;
+ const queryParams = c.req.query();
+ const collectionStmt = db.prepare("SELECT * FROM collections WHERE name = ? AND is_active = 1");
+ const collectionResult = await collectionStmt.bind(collection).first();
+ if (!collectionResult) {
+ return c.json({ error: "Collection not found" }, 404);
}
- if (fileRecord.uploaded_by !== user.userId && user.role !== "admin") {
- return c.json({ error: "Permission denied" }, 403);
+ const filter = QueryFilterBuilder.parseFromQuery(queryParams);
+ if (!filter.where) {
+ filter.where = { and: [] };
}
- const allowedFields = ["alt", "caption", "tags", "folder"];
- const updates = [];
- const values = [];
- for (const [key, value] of Object.entries(body)) {
- if (allowedFields.includes(key)) {
- updates.push(`${key} = ?`);
- values.push(key === "tags" ? JSON.stringify(value) : value);
+ if (!filter.where.and) {
+ filter.where.and = [];
+ }
+ filter.where.and.push({
+ field: "collection_id",
+ operator: "equals",
+ value: collectionResult.id
+ });
+ if (!filter.limit) {
+ filter.limit = 50;
+ }
+ filter.limit = Math.min(filter.limit, 1e3);
+ const builder3 = new QueryFilterBuilder();
+ const queryResult = builder3.build("content", filter);
+ if (queryResult.errors.length > 0) {
+ return c.json({
+ error: "Invalid filter parameters",
+ details: queryResult.errors
+ }, 400);
+ }
+ const cacheEnabled = c.get("cacheEnabled");
+ const cache = getCacheService(CACHE_CONFIGS.api);
+ const cacheKey = cache.generateKey("collection-content-filtered", `${collection}:${JSON.stringify({ filter, query: queryResult.sql })}`);
+ if (cacheEnabled) {
+ const cacheResult = await cache.getWithSource(cacheKey);
+ if (cacheResult.hit && cacheResult.data) {
+ c.header("X-Cache-Status", "HIT");
+ c.header("X-Cache-Source", cacheResult.source);
+ if (cacheResult.ttl) {
+ c.header("X-Cache-TTL", Math.floor(cacheResult.ttl).toString());
+ }
+ const dataWithMeta = {
+ ...cacheResult.data,
+ meta: addTimingMeta(c, {
+ ...cacheResult.data.meta,
+ cache: {
+ hit: true,
+ source: cacheResult.source,
+ ttl: cacheResult.ttl ? Math.floor(cacheResult.ttl) : void 0
+ }
+ }, executionStart)
+ };
+ return c.json(dataWithMeta);
}
}
- if (updates.length === 0) {
- return c.json({ error: "No valid fields to update" }, 400);
+ c.header("X-Cache-Status", "MISS");
+ c.header("X-Cache-Source", "database");
+ const stmt = db.prepare(queryResult.sql);
+ const boundStmt = queryResult.params.length > 0 ? stmt.bind(...queryResult.params) : stmt;
+ const { results } = await boundStmt.all();
+ const transformedResults = results.map((row) => ({
+ id: row.id,
+ title: row.title,
+ slug: row.slug,
+ status: row.status,
+ collectionId: row.collection_id,
+ data: row.data ? JSON.parse(row.data) : {},
+ created_at: row.created_at,
+ updated_at: row.updated_at
+ }));
+ const responseData = {
+ data: transformedResults,
+ meta: addTimingMeta(c, {
+ collection: {
+ ...collectionResult,
+ schema: collectionResult.schema ? JSON.parse(collectionResult.schema) : {}
+ },
+ count: results.length,
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
+ filter,
+ query: {
+ sql: queryResult.sql,
+ params: queryResult.params
+ },
+ cache: {
+ hit: false,
+ source: "database"
+ }
+ }, executionStart)
+ };
+ if (cacheEnabled) {
+ await cache.set(cacheKey, responseData);
}
- updates.push("updated_at = ?");
- values.push(Math.floor(Date.now() / 1e3));
- values.push(fileId);
- const updateStmt = c.env.DB.prepare(`
- UPDATE media SET ${updates.join(", ")} WHERE id = ?
- `);
- await updateStmt.bind(...values).run();
- await emitEvent("media.update", { id: fileId });
- return c.json({ success: true, message: "File updated successfully" });
+ return c.json(responseData);
} catch (error) {
- console.error("Update error:", error);
- return c.json({ error: "Update failed" }, 500);
+ console.error("Error fetching content:", error);
+ return c.json({
+ error: "Failed to fetch content",
+ details: error instanceof Error ? error.message : String(error)
+ }, 500);
}
});
-async function getImageDimensions(arrayBuffer) {
- const uint8Array = new Uint8Array(arrayBuffer);
- if (uint8Array[0] === 255 && uint8Array[1] === 216) {
- return getJPEGDimensions(uint8Array);
- }
- if (uint8Array[0] === 137 && uint8Array[1] === 80 && uint8Array[2] === 78 && uint8Array[3] === 71) {
- return getPNGDimensions(uint8Array);
- }
- return { width: 0, height: 0 };
+apiRoutes.route("/content", api_content_crud_default);
+var api_default = apiRoutes;
+function generateId() {
+ return crypto.randomUUID().replace(/-/g, "").substring(0, 21);
}
-function getJPEGDimensions(uint8Array) {
- let i = 2;
- while (i < uint8Array.length) {
- if (i + 8 >= uint8Array.length) break;
- if (uint8Array[i] === 255 && uint8Array[i + 1] === 192) {
- if (i + 8 < uint8Array.length) {
- return {
- height: uint8Array[i + 5] << 8 | uint8Array[i + 6],
- width: uint8Array[i + 7] << 8 | uint8Array[i + 8]
- };
- }
- }
- if (i + 3 < uint8Array.length) {
- i += 2 + (uint8Array[i + 2] << 8 | uint8Array[i + 3]);
- } else {
- break;
- }
- }
- return { width: 0, height: 0 };
-}
-function getPNGDimensions(uint8Array) {
- if (uint8Array.length < 24) {
- return { width: 0, height: 0 };
- }
- return {
- width: uint8Array[16] << 24 | uint8Array[17] << 16 | uint8Array[18] << 8 | uint8Array[19],
- height: uint8Array[20] << 24 | uint8Array[21] << 16 | uint8Array[22] << 8 | uint8Array[23]
- };
+async function emitEvent(eventName, data) {
+ console.log(`[Event] ${eventName}:`, data);
}
-var api_media_default = apiMediaRoutes;
-var apiSystemRoutes = new Hono();
-apiSystemRoutes.get("/health", async (c) => {
+var fileValidationSchema = z.object({
+ name: z.string().min(1).max(255),
+ type: z.string().refine(
+ (type) => {
+ const allowedTypes = [
+ // Images
+ "image/jpeg",
+ "image/jpg",
+ "image/png",
+ "image/gif",
+ "image/webp",
+ "image/svg+xml",
+ // Documents
+ "application/pdf",
+ "text/plain",
+ "application/msword",
+ "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
+ // Videos
+ "video/mp4",
+ "video/webm",
+ "video/ogg",
+ "video/avi",
+ "video/mov",
+ // Audio
+ "audio/mp3",
+ "audio/wav",
+ "audio/ogg",
+ "audio/m4a"
+ ];
+ return allowedTypes.includes(type);
+ },
+ { message: "Unsupported file type" }
+ ),
+ size: z.number().min(1).max(50 * 1024 * 1024)
+ // 50MB max
+});
+var apiMediaRoutes = new Hono();
+apiMediaRoutes.use("*", requireAuth());
+apiMediaRoutes.post("/upload", async (c) => {
try {
- const startTime = Date.now();
- let dbStatus = "unknown";
- let dbLatency = 0;
- try {
- const dbStart = Date.now();
- await c.env.DB.prepare("SELECT 1").first();
- dbLatency = Date.now() - dbStart;
- dbStatus = "healthy";
- } catch (error) {
- console.error("Database health check failed:", error);
- dbStatus = "unhealthy";
+ const user = c.get("user");
+ const formData = await c.req.formData();
+ const fileData = formData.get("file");
+ if (!fileData || typeof fileData === "string") {
+ return c.json({ error: "No file provided" }, 400);
}
- let kvStatus = "not_configured";
- let kvLatency = 0;
- if (c.env.CACHE_KV) {
- try {
- const kvStart = Date.now();
- await c.env.CACHE_KV.get("__health_check__");
- kvLatency = Date.now() - kvStart;
- kvStatus = "healthy";
- } catch (error) {
- console.error("KV health check failed:", error);
- kvStatus = "unhealthy";
+ const file = fileData;
+ const validation = fileValidationSchema.safeParse({
+ name: file.name,
+ type: file.type,
+ size: file.size
+ });
+ if (!validation.success) {
+ return c.json({
+ error: "File validation failed",
+ details: validation.error.issues
+ }, 400);
+ }
+ const fileId = generateId();
+ const fileExtension = file.name.split(".").pop() || "";
+ const filename = `${fileId}.${fileExtension}`;
+ const folder = formData.get("folder") || "uploads";
+ const r2Key = `${folder}/${filename}`;
+ const arrayBuffer = await file.arrayBuffer();
+ const uploadResult = await c.env.MEDIA_BUCKET.put(r2Key, arrayBuffer, {
+ httpMetadata: {
+ contentType: file.type,
+ contentDisposition: `inline; filename="${file.name}"`
+ },
+ customMetadata: {
+ originalName: file.name,
+ uploadedBy: user.userId,
+ uploadedAt: (/* @__PURE__ */ new Date()).toISOString()
}
+ });
+ if (!uploadResult) {
+ return c.json({ error: "Failed to upload file to storage" }, 500);
}
- let r2Status = "not_configured";
- if (c.env.MEDIA_BUCKET) {
+ const bucketName = c.env.BUCKET_NAME || "sonicjs-media-dev";
+ const publicUrl = `https://pub-${bucketName}.r2.dev/${r2Key}`;
+ let width;
+ let height;
+ if (file.type.startsWith("image/") && !file.type.includes("svg")) {
try {
- await c.env.MEDIA_BUCKET.head("__health_check__");
- r2Status = "healthy";
+ const dimensions = await getImageDimensions(arrayBuffer);
+ width = dimensions.width;
+ height = dimensions.height;
} catch (error) {
- r2Status = "healthy";
+ console.warn("Failed to extract image dimensions:", error);
}
}
- const totalLatency = Date.now() - startTime;
- const overall = dbStatus === "healthy" ? "healthy" : "degraded";
+ let thumbnailUrl;
+ if (file.type.startsWith("image/") && c.env.IMAGES_ACCOUNT_ID) {
+ thumbnailUrl = `https://imagedelivery.net/${c.env.IMAGES_ACCOUNT_ID}/${r2Key}/thumbnail`;
+ }
+ const mediaRecord = {
+ id: fileId,
+ filename,
+ original_name: file.name,
+ mime_type: file.type,
+ size: file.size,
+ width,
+ height,
+ folder,
+ r2_key: r2Key,
+ public_url: publicUrl,
+ thumbnail_url: thumbnailUrl,
+ uploaded_by: user.userId,
+ uploaded_at: Math.floor(Date.now() / 1e3),
+ created_at: Math.floor(Date.now() / 1e3)
+ };
+ const stmt = c.env.DB.prepare(`
+ INSERT INTO media (
+ id, filename, original_name, mime_type, size, width, height,
+ folder, r2_key, public_url, thumbnail_url, uploaded_by, uploaded_at
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
+ `);
+ await stmt.bind(
+ mediaRecord.id,
+ mediaRecord.filename,
+ mediaRecord.original_name,
+ mediaRecord.mime_type,
+ mediaRecord.size,
+ mediaRecord.width ?? null,
+ mediaRecord.height ?? null,
+ mediaRecord.folder,
+ mediaRecord.r2_key,
+ mediaRecord.public_url,
+ mediaRecord.thumbnail_url ?? null,
+ mediaRecord.uploaded_by,
+ mediaRecord.uploaded_at
+ ).run();
+ await emitEvent("media.upload", { id: mediaRecord.id, filename: mediaRecord.filename });
return c.json({
- status: overall,
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
- uptime: totalLatency,
- checks: {
- database: {
- status: dbStatus,
- latency: dbLatency
- },
- cache: {
- status: kvStatus,
- latency: kvLatency
- },
- storage: {
- status: r2Status
- }
- },
- environment: c.env.ENVIRONMENT || "production"
+ success: true,
+ file: {
+ id: mediaRecord.id,
+ filename: mediaRecord.filename,
+ originalName: mediaRecord.original_name,
+ mimeType: mediaRecord.mime_type,
+ size: mediaRecord.size,
+ width: mediaRecord.width,
+ height: mediaRecord.height,
+ r2_key: mediaRecord.r2_key,
+ publicUrl: mediaRecord.public_url,
+ thumbnailUrl: mediaRecord.thumbnail_url,
+ uploadedAt: new Date(mediaRecord.uploaded_at * 1e3).toISOString()
+ }
});
} catch (error) {
- console.error("Health check failed:", error);
- return c.json({
- status: "unhealthy",
- timestamp: (/* @__PURE__ */ new Date()).toISOString(),
- error: "Health check failed"
- }, 503);
+ console.error("Upload error:", error);
+ return c.json({ error: "Upload failed" }, 500);
}
});
-apiSystemRoutes.get("/info", (c) => {
- const appVersion = c.get("appVersion") || "1.0.0";
- return c.json({
- name: "SonicJS",
- version: appVersion,
- description: "Modern headless CMS built on Cloudflare Workers",
- endpoints: {
- api: "/api",
- auth: "/auth",
- health: "/api/system/health",
- docs: "/docs"
- },
- features: {
- content: true,
- media: true,
- auth: true,
- collections: true,
- caching: !!c.env.CACHE_KV,
- storage: !!c.env.MEDIA_BUCKET
- },
- timestamp: (/* @__PURE__ */ new Date()).toISOString()
- });
-});
-apiSystemRoutes.get("/stats", async (c) => {
+apiMediaRoutes.post("/upload-multiple", async (c) => {
try {
- const db = c.env.DB;
- const contentStats = await db.prepare(`
- SELECT COUNT(*) as total_content
- FROM content
- WHERE deleted_at IS NULL
- `).first();
- const mediaStats = await db.prepare(`
- SELECT
- COUNT(*) as total_files,
- SUM(size) as total_size
- FROM media
- WHERE deleted_at IS NULL
- `).first();
- const userStats = await db.prepare(`
- SELECT COUNT(*) as total_users
- FROM users
- `).first();
+ const user = c.get("user");
+ const formData = await c.req.formData();
+ const filesData = formData.getAll("files");
+ const files = [];
+ for (const f of filesData) {
+ if (typeof f !== "string") {
+ files.push(f);
+ }
+ }
+ if (!files || files.length === 0) {
+ return c.json({ error: "No files provided" }, 400);
+ }
+ const uploadResults = [];
+ const errors = [];
+ for (const file of files) {
+ try {
+ const validation = fileValidationSchema.safeParse({
+ name: file.name,
+ type: file.type,
+ size: file.size
+ });
+ if (!validation.success) {
+ errors.push({
+ filename: file.name,
+ error: "Validation failed",
+ details: validation.error.issues
+ });
+ continue;
+ }
+ const fileId = generateId();
+ const fileExtension = file.name.split(".").pop() || "";
+ const filename = `${fileId}.${fileExtension}`;
+ const folder = formData.get("folder") || "uploads";
+ const r2Key = `${folder}/${filename}`;
+ const arrayBuffer = await file.arrayBuffer();
+ const uploadResult = await c.env.MEDIA_BUCKET.put(r2Key, arrayBuffer, {
+ httpMetadata: {
+ contentType: file.type,
+ contentDisposition: `inline; filename="${file.name}"`
+ },
+ customMetadata: {
+ originalName: file.name,
+ uploadedBy: user.userId,
+ uploadedAt: (/* @__PURE__ */ new Date()).toISOString()
+ }
+ });
+ if (!uploadResult) {
+ errors.push({
+ filename: file.name,
+ error: "Failed to upload to storage"
+ });
+ continue;
+ }
+ const bucketName = c.env.BUCKET_NAME || "sonicjs-media-dev";
+ const publicUrl = `https://pub-${bucketName}.r2.dev/${r2Key}`;
+ let width;
+ let height;
+ if (file.type.startsWith("image/") && !file.type.includes("svg")) {
+ try {
+ const dimensions = await getImageDimensions(arrayBuffer);
+ width = dimensions.width;
+ height = dimensions.height;
+ } catch (error) {
+ console.warn("Failed to extract image dimensions:", error);
+ }
+ }
+ let thumbnailUrl;
+ if (file.type.startsWith("image/") && c.env.IMAGES_ACCOUNT_ID) {
+ thumbnailUrl = `https://imagedelivery.net/${c.env.IMAGES_ACCOUNT_ID}/${r2Key}/thumbnail`;
+ }
+ const mediaRecord = {
+ id: fileId,
+ filename,
+ original_name: file.name,
+ mime_type: file.type,
+ size: file.size,
+ width,
+ height,
+ folder,
+ r2_key: r2Key,
+ public_url: publicUrl,
+ thumbnail_url: thumbnailUrl,
+ uploaded_by: user.userId,
+ uploaded_at: Math.floor(Date.now() / 1e3)
+ };
+ const stmt = c.env.DB.prepare(`
+ INSERT INTO media (
+ id, filename, original_name, mime_type, size, width, height,
+ folder, r2_key, public_url, thumbnail_url, uploaded_by, uploaded_at
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
+ `);
+ await stmt.bind(
+ mediaRecord.id,
+ mediaRecord.filename,
+ mediaRecord.original_name,
+ mediaRecord.mime_type,
+ mediaRecord.size,
+ mediaRecord.width ?? null,
+ mediaRecord.height ?? null,
+ mediaRecord.folder,
+ mediaRecord.r2_key,
+ mediaRecord.public_url,
+ mediaRecord.thumbnail_url ?? null,
+ mediaRecord.uploaded_by,
+ mediaRecord.uploaded_at
+ ).run();
+ uploadResults.push({
+ id: mediaRecord.id,
+ filename: mediaRecord.filename,
+ originalName: mediaRecord.original_name,
+ mimeType: mediaRecord.mime_type,
+ size: mediaRecord.size,
+ width: mediaRecord.width,
+ height: mediaRecord.height,
+ r2_key: mediaRecord.r2_key,
+ publicUrl: mediaRecord.public_url,
+ thumbnailUrl: mediaRecord.thumbnail_url,
+ uploadedAt: new Date(mediaRecord.uploaded_at * 1e3).toISOString()
+ });
+ } catch (error) {
+ errors.push({
+ filename: file.name,
+ error: "Upload failed",
+ details: error instanceof Error ? error.message : "Unknown error"
+ });
+ }
+ }
+ if (uploadResults.length > 0) {
+ await emitEvent("media.upload", { count: uploadResults.length });
+ }
return c.json({
- content: {
- total: contentStats?.total_content || 0
- },
- media: {
- total_files: mediaStats?.total_files || 0,
- total_size_bytes: mediaStats?.total_size || 0,
- total_size_mb: Math.round((mediaStats?.total_size || 0) / 1024 / 1024 * 100) / 100
- },
- users: {
- total: userStats?.total_users || 0
- },
- timestamp: (/* @__PURE__ */ new Date()).toISOString()
+ success: uploadResults.length > 0,
+ uploaded: uploadResults,
+ errors,
+ summary: {
+ total: files.length,
+ successful: uploadResults.length,
+ failed: errors.length
+ }
});
} catch (error) {
- console.error("Stats query failed:", error);
- return c.json({ error: "Failed to fetch system statistics" }, 500);
+ console.error("Multiple upload error:", error);
+ return c.json({ error: "Upload failed" }, 500);
}
});
-apiSystemRoutes.get("/ping", async (c) => {
+apiMediaRoutes.post("/bulk-delete", async (c) => {
try {
- const start = Date.now();
- await c.env.DB.prepare("SELECT 1").first();
- const latency = Date.now() - start;
+ const user = c.get("user");
+ const body = await c.req.json();
+ const fileIds = body.fileIds;
+ if (!fileIds || !Array.isArray(fileIds) || fileIds.length === 0) {
+ return c.json({ error: "No file IDs provided" }, 400);
+ }
+ if (fileIds.length > 50) {
+ return c.json({ error: "Too many files selected. Maximum 50 files per operation." }, 400);
+ }
+ const results = [];
+ const errors = [];
+ for (const fileId of fileIds) {
+ try {
+ const stmt = c.env.DB.prepare("SELECT * FROM media WHERE id = ?");
+ const fileRecord = await stmt.bind(fileId).first();
+ if (!fileRecord) {
+ errors.push({ fileId, error: "File not found" });
+ continue;
+ }
+ if (fileRecord.deleted_at !== null) {
+ console.log(`File ${fileId} already deleted, skipping`);
+ results.push({
+ fileId,
+ filename: fileRecord.original_name,
+ success: true,
+ alreadyDeleted: true
+ });
+ continue;
+ }
+ if (fileRecord.uploaded_by !== user.userId && user.role !== "admin") {
+ errors.push({ fileId, error: "Permission denied" });
+ continue;
+ }
+ try {
+ await c.env.MEDIA_BUCKET.delete(fileRecord.r2_key);
+ } catch (error) {
+ console.warn(`Failed to delete from R2 for file ${fileId}:`, error);
+ }
+ const deleteStmt = c.env.DB.prepare("UPDATE media SET deleted_at = ? WHERE id = ?");
+ await deleteStmt.bind(Math.floor(Date.now() / 1e3), fileId).run();
+ results.push({
+ fileId,
+ filename: fileRecord.original_name,
+ success: true
+ });
+ } catch (error) {
+ errors.push({
+ fileId,
+ error: "Delete failed",
+ details: error instanceof Error ? error.message : "Unknown error"
+ });
+ }
+ }
+ if (results.length > 0) {
+ await emitEvent("media.delete", { count: results.length, ids: fileIds });
+ }
return c.json({
- pong: true,
- latency,
- timestamp: (/* @__PURE__ */ new Date()).toISOString()
+ success: results.length > 0,
+ deleted: results,
+ errors,
+ summary: {
+ total: fileIds.length,
+ successful: results.length,
+ failed: errors.length
+ }
});
} catch (error) {
- console.error("Ping failed:", error);
- return c.json({
- pong: false,
- error: "Database connection failed"
- }, 503);
+ console.error("Bulk delete error:", error);
+ return c.json({ error: "Bulk delete failed" }, 500);
}
});
-apiSystemRoutes.get("/env", (c) => {
- return c.json({
- environment: c.env.ENVIRONMENT || "production",
- features: {
- database: !!c.env.DB,
- cache: !!c.env.CACHE_KV,
- media_bucket: !!c.env.MEDIA_BUCKET,
- email_queue: !!c.env.EMAIL_QUEUE,
- sendgrid: !!c.env.SENDGRID_API_KEY,
- cloudflare_images: !!(c.env.IMAGES_ACCOUNT_ID && c.env.IMAGES_API_TOKEN)
- },
- timestamp: (/* @__PURE__ */ new Date()).toISOString()
- });
-});
-var api_system_default = apiSystemRoutes;
-var adminApiRoutes = new Hono();
-adminApiRoutes.use("*", requireAuth());
-adminApiRoutes.use("*", requireRole(["admin", "editor"]));
-adminApiRoutes.get("/stats", async (c) => {
+apiMediaRoutes.post("/create-folder", async (c) => {
try {
- const db = c.env.DB;
- let collectionsCount = 0;
- try {
- const collectionsStmt = db.prepare("SELECT COUNT(*) as count FROM collections WHERE is_active = 1");
- const collectionsResult = await collectionsStmt.first();
- collectionsCount = collectionsResult?.count || 0;
- } catch (error) {
- console.error("Error fetching collections count:", error);
- }
- let contentCount = 0;
- try {
- const contentStmt = db.prepare("SELECT COUNT(*) as count FROM content WHERE deleted_at IS NULL");
- const contentResult = await contentStmt.first();
- contentCount = contentResult?.count || 0;
- } catch (error) {
- console.error("Error fetching content count:", error);
+ const body = await c.req.json();
+ const folderName = body.folderName;
+ if (!folderName || typeof folderName !== "string") {
+ return c.json({ success: false, error: "No folder name provided" }, 400);
}
- let mediaCount = 0;
- let mediaSize = 0;
- try {
- const mediaStmt = db.prepare("SELECT COUNT(*) as count, COALESCE(SUM(size), 0) as total_size FROM media WHERE deleted_at IS NULL");
- const mediaResult = await mediaStmt.first();
- mediaCount = mediaResult?.count || 0;
- mediaSize = mediaResult?.total_size || 0;
- } catch (error) {
- console.error("Error fetching media count:", error);
+ const folderPattern = /^[a-z0-9-_]+$/;
+ if (!folderPattern.test(folderName)) {
+ return c.json({
+ success: false,
+ error: "Folder name can only contain lowercase letters, numbers, hyphens, and underscores"
+ }, 400);
}
- let usersCount = 0;
- try {
- const usersStmt = db.prepare("SELECT COUNT(*) as count FROM users WHERE is_active = 1");
- const usersResult = await usersStmt.first();
- usersCount = usersResult?.count || 0;
- } catch (error) {
- console.error("Error fetching users count:", error);
+ const checkStmt = c.env.DB.prepare("SELECT COUNT(*) as count FROM media WHERE folder = ? AND deleted_at IS NULL");
+ const existingFolder = await checkStmt.bind(folderName).first();
+ if (existingFolder && existingFolder.count > 0) {
+ return c.json({
+ success: false,
+ error: `Folder "${folderName}" already exists`
+ }, 400);
}
return c.json({
- collections: collectionsCount,
- contentItems: contentCount,
- mediaFiles: mediaCount,
- mediaSize,
- users: usersCount,
- timestamp: (/* @__PURE__ */ new Date()).toISOString()
+ success: true,
+ message: `Folder "${folderName}" is ready. Upload files to this folder to make it appear in the media library.`,
+ folder: folderName,
+ note: "Folders appear automatically when you upload files to them"
});
} catch (error) {
- console.error("Error fetching stats:", error);
- return c.json({ error: "Failed to fetch statistics" }, 500);
+ console.error("Create folder error:", error);
+ return c.json({ success: false, error: "Failed to create folder" }, 500);
}
});
-adminApiRoutes.get("/storage", async (c) => {
+apiMediaRoutes.post("/bulk-move", async (c) => {
try {
- const db = c.env.DB;
- let databaseSize = 0;
- try {
- const result = await db.prepare("SELECT 1").run();
- databaseSize = result?.meta?.size_after || 0;
- } catch (error) {
- console.error("Error fetching database size:", error);
+ const user = c.get("user");
+ const body = await c.req.json();
+ const fileIds = body.fileIds;
+ const targetFolder = body.folder;
+ if (!fileIds || !Array.isArray(fileIds) || fileIds.length === 0) {
+ return c.json({ error: "No file IDs provided" }, 400);
}
- let mediaSize = 0;
- try {
- const mediaStmt = db.prepare("SELECT COALESCE(SUM(size), 0) as total_size FROM media WHERE deleted_at IS NULL");
- const mediaResult = await mediaStmt.first();
- mediaSize = mediaResult?.total_size || 0;
- } catch (error) {
- console.error("Error fetching media size:", error);
+ if (!targetFolder || typeof targetFolder !== "string") {
+ return c.json({ error: "No target folder provided" }, 400);
+ }
+ if (fileIds.length > 50) {
+ return c.json({ error: "Too many files selected. Maximum 50 files per operation." }, 400);
+ }
+ const results = [];
+ const errors = [];
+ for (const fileId of fileIds) {
+ try {
+ const stmt = c.env.DB.prepare("SELECT * FROM media WHERE id = ? AND deleted_at IS NULL");
+ const fileRecord = await stmt.bind(fileId).first();
+ if (!fileRecord) {
+ errors.push({ fileId, error: "File not found" });
+ continue;
+ }
+ if (fileRecord.uploaded_by !== user.userId && user.role !== "admin") {
+ errors.push({ fileId, error: "Permission denied" });
+ continue;
+ }
+ if (fileRecord.folder === targetFolder) {
+ results.push({
+ fileId,
+ filename: fileRecord.original_name,
+ success: true,
+ skipped: true
+ });
+ continue;
+ }
+ const oldR2Key = fileRecord.r2_key;
+ const filename = oldR2Key.split("/").pop() || fileRecord.filename;
+ const newR2Key = `${targetFolder}/${filename}`;
+ try {
+ const object = await c.env.MEDIA_BUCKET.get(oldR2Key);
+ if (!object) {
+ errors.push({ fileId, error: "File not found in storage" });
+ continue;
+ }
+ await c.env.MEDIA_BUCKET.put(newR2Key, object.body, {
+ httpMetadata: object.httpMetadata,
+ customMetadata: {
+ ...object.customMetadata,
+ movedBy: user.userId,
+ movedAt: (/* @__PURE__ */ new Date()).toISOString()
+ }
+ });
+ await c.env.MEDIA_BUCKET.delete(oldR2Key);
+ } catch (error) {
+ console.warn(`Failed to move file in R2 for file ${fileId}:`, error);
+ errors.push({ fileId, error: "Failed to move file in storage" });
+ continue;
+ }
+ const bucketName = c.env.BUCKET_NAME || "sonicjs-media-dev";
+ const newPublicUrl = `https://pub-${bucketName}.r2.dev/${newR2Key}`;
+ const updateStmt = c.env.DB.prepare(`
+ UPDATE media
+ SET folder = ?, r2_key = ?, public_url = ?, updated_at = ?
+ WHERE id = ?
+ `);
+ await updateStmt.bind(
+ targetFolder,
+ newR2Key,
+ newPublicUrl,
+ Math.floor(Date.now() / 1e3),
+ fileId
+ ).run();
+ results.push({
+ fileId,
+ filename: fileRecord.original_name,
+ success: true,
+ skipped: false
+ });
+ } catch (error) {
+ errors.push({
+ fileId,
+ error: "Move failed",
+ details: error instanceof Error ? error.message : "Unknown error"
+ });
+ }
+ }
+ if (results.length > 0) {
+ await emitEvent("media.move", { count: results.length, targetFolder, ids: fileIds });
}
return c.json({
- databaseSize,
- mediaSize,
- totalSize: databaseSize + mediaSize,
- timestamp: (/* @__PURE__ */ new Date()).toISOString()
+ success: results.length > 0,
+ moved: results,
+ errors,
+ summary: {
+ total: fileIds.length,
+ successful: results.length,
+ failed: errors.length
+ }
});
} catch (error) {
- console.error("Error fetching storage usage:", error);
- return c.json({ error: "Failed to fetch storage usage" }, 500);
+ console.error("Bulk move error:", error);
+ return c.json({ error: "Bulk move failed" }, 500);
}
});
-adminApiRoutes.get("/activity", async (c) => {
+apiMediaRoutes.delete("/:id", async (c) => {
try {
- const db = c.env.DB;
- const limit = parseInt(c.req.query("limit") || "10");
- const activityStmt = db.prepare(`
- SELECT
- a.id,
- a.action,
- a.resource_type,
- a.resource_id,
- a.details,
- a.created_at,
- u.email,
- u.first_name,
- u.last_name
- FROM activity_logs a
- LEFT JOIN users u ON a.user_id = u.id
- WHERE a.resource_type IN ('content', 'collections', 'users', 'media')
- ORDER BY a.created_at DESC
- LIMIT ?
- `);
- const { results } = await activityStmt.bind(limit).all();
- const recentActivity = (results || []).map((row) => {
- const userName = row.first_name && row.last_name ? `${row.first_name} ${row.last_name}` : row.email || "System";
- let details = {};
- try {
- details = row.details ? JSON.parse(row.details) : {};
- } catch (e) {
- console.error("Error parsing activity details:", e);
- }
- return {
- id: row.id,
- type: row.resource_type,
- action: row.action,
- resource_id: row.resource_id,
- details,
- timestamp: new Date(Number(row.created_at)).toISOString(),
- user: userName
- };
- });
- return c.json({
- data: recentActivity,
- count: recentActivity.length,
- timestamp: (/* @__PURE__ */ new Date()).toISOString()
- });
+ const user = c.get("user");
+ const fileId = c.req.param("id");
+ const stmt = c.env.DB.prepare("SELECT * FROM media WHERE id = ? AND deleted_at IS NULL");
+ const fileRecord = await stmt.bind(fileId).first();
+ if (!fileRecord) {
+ return c.json({ error: "File not found" }, 404);
+ }
+ if (fileRecord.uploaded_by !== user.userId && user.role !== "admin") {
+ return c.json({ error: "Permission denied" }, 403);
+ }
+ try {
+ await c.env.MEDIA_BUCKET.delete(fileRecord.r2_key);
+ } catch (error) {
+ console.warn("Failed to delete from R2:", error);
+ }
+ const deleteStmt = c.env.DB.prepare("UPDATE media SET deleted_at = ? WHERE id = ?");
+ await deleteStmt.bind(Math.floor(Date.now() / 1e3), fileId).run();
+ await emitEvent("media.delete", { id: fileId });
+ return c.json({ success: true, message: "File deleted successfully" });
} catch (error) {
- console.error("Error fetching recent activity:", error);
- return c.json({ error: "Failed to fetch recent activity" }, 500);
+ console.error("Delete error:", error);
+ return c.json({ error: "Delete failed" }, 500);
}
});
-var createCollectionSchema = z.object({
- name: z.string().min(1).max(255).regex(/^[a-z0-9_]+$/, "Must contain only lowercase letters, numbers, and underscores"),
- displayName: z.string().min(1).max(255).optional(),
- display_name: z.string().min(1).max(255).optional(),
- description: z.string().optional()
-}).refine((data) => data.displayName || data.display_name, {
- message: "Either displayName or display_name is required",
- path: ["displayName"]
-});
-var updateCollectionSchema = z.object({
- display_name: z.string().min(1).max(255).optional(),
- description: z.string().optional(),
- is_active: z.boolean().optional()
-});
-adminApiRoutes.get("/collections", async (c) => {
+apiMediaRoutes.patch("/:id", async (c) => {
try {
- const db = c.env.DB;
- const search = c.req.query("search") || "";
- const includeInactive = c.req.query("includeInactive") === "true";
- let stmt;
- let results;
- if (search) {
- stmt = db.prepare(`
- SELECT id, name, display_name, description, created_at, updated_at, is_active, managed
- FROM collections
- WHERE ${includeInactive ? "1=1" : "is_active = 1"}
- AND (name LIKE ? OR display_name LIKE ? OR description LIKE ?)
- ORDER BY created_at DESC
- `);
- const searchParam = `%${search}%`;
- const queryResults = await stmt.bind(searchParam, searchParam, searchParam).all();
- results = queryResults.results;
- } else {
- stmt = db.prepare(`
- SELECT id, name, display_name, description, created_at, updated_at, is_active, managed
- FROM collections
- ${includeInactive ? "" : "WHERE is_active = 1"}
- ORDER BY created_at DESC
- `);
- const queryResults = await stmt.all();
- results = queryResults.results;
+ const user = c.get("user");
+ const fileId = c.req.param("id");
+ const body = await c.req.json();
+ const stmt = c.env.DB.prepare("SELECT * FROM media WHERE id = ? AND deleted_at IS NULL");
+ const fileRecord = await stmt.bind(fileId).first();
+ if (!fileRecord) {
+ return c.json({ error: "File not found" }, 404);
}
- const fieldCountStmt = db.prepare("SELECT collection_id, COUNT(*) as count FROM content_fields GROUP BY collection_id");
- const { results: fieldCountResults } = await fieldCountStmt.all();
- const fieldCounts = new Map((fieldCountResults || []).map((row) => [String(row.collection_id), Number(row.count)]));
- const collections = (results || []).map((row) => ({
- id: row.id,
- name: row.name,
- display_name: row.display_name,
- description: row.description,
- created_at: Number(row.created_at),
- updated_at: Number(row.updated_at),
- is_active: row.is_active === 1,
- managed: row.managed === 1,
- field_count: fieldCounts.get(String(row.id)) || 0
- }));
- return c.json({
- data: collections,
- count: collections.length,
- timestamp: (/* @__PURE__ */ new Date()).toISOString()
- });
+ if (fileRecord.uploaded_by !== user.userId && user.role !== "admin") {
+ return c.json({ error: "Permission denied" }, 403);
+ }
+ const allowedFields = ["alt", "caption", "tags", "folder"];
+ const updates = [];
+ const values = [];
+ for (const [key, value] of Object.entries(body)) {
+ if (allowedFields.includes(key)) {
+ updates.push(`${key} = ?`);
+ values.push(key === "tags" ? JSON.stringify(value) : value);
+ }
+ }
+ if (updates.length === 0) {
+ return c.json({ error: "No valid fields to update" }, 400);
+ }
+ updates.push("updated_at = ?");
+ values.push(Math.floor(Date.now() / 1e3));
+ values.push(fileId);
+ const updateStmt = c.env.DB.prepare(`
+ UPDATE media SET ${updates.join(", ")} WHERE id = ?
+ `);
+ await updateStmt.bind(...values).run();
+ await emitEvent("media.update", { id: fileId });
+ return c.json({ success: true, message: "File updated successfully" });
} catch (error) {
- console.error("Error fetching collections:", error);
- return c.json({ error: "Failed to fetch collections" }, 500);
+ console.error("Update error:", error);
+ return c.json({ error: "Update failed" }, 500);
}
});
-adminApiRoutes.get("/collections/:id", async (c) => {
+async function getImageDimensions(arrayBuffer) {
+ const uint8Array = new Uint8Array(arrayBuffer);
+ if (uint8Array[0] === 255 && uint8Array[1] === 216) {
+ return getJPEGDimensions(uint8Array);
+ }
+ if (uint8Array[0] === 137 && uint8Array[1] === 80 && uint8Array[2] === 78 && uint8Array[3] === 71) {
+ return getPNGDimensions(uint8Array);
+ }
+ return { width: 0, height: 0 };
+}
+function getJPEGDimensions(uint8Array) {
+ let i = 2;
+ while (i < uint8Array.length) {
+ if (i + 8 >= uint8Array.length) break;
+ if (uint8Array[i] === 255 && uint8Array[i + 1] === 192) {
+ if (i + 8 < uint8Array.length) {
+ return {
+ height: uint8Array[i + 5] << 8 | uint8Array[i + 6],
+ width: uint8Array[i + 7] << 8 | uint8Array[i + 8]
+ };
+ }
+ }
+ if (i + 3 < uint8Array.length) {
+ i += 2 + (uint8Array[i + 2] << 8 | uint8Array[i + 3]);
+ } else {
+ break;
+ }
+ }
+ return { width: 0, height: 0 };
+}
+function getPNGDimensions(uint8Array) {
+ if (uint8Array.length < 24) {
+ return { width: 0, height: 0 };
+ }
+ return {
+ width: uint8Array[16] << 24 | uint8Array[17] << 16 | uint8Array[18] << 8 | uint8Array[19],
+ height: uint8Array[20] << 24 | uint8Array[21] << 16 | uint8Array[22] << 8 | uint8Array[23]
+ };
+}
+var api_media_default = apiMediaRoutes;
+var apiSystemRoutes = new Hono();
+apiSystemRoutes.get("/health", async (c) => {
try {
- const id = c.req.param("id");
- const db = c.env.DB;
- const stmt = db.prepare("SELECT * FROM collections WHERE id = ?");
- const collection = await stmt.bind(id).first();
- if (!collection) {
- return c.json({ error: "Collection not found" }, 404);
+ const startTime = Date.now();
+ let dbStatus = "unknown";
+ let dbLatency = 0;
+ try {
+ const dbStart = Date.now();
+ await c.env.DB.prepare("SELECT 1").first();
+ dbLatency = Date.now() - dbStart;
+ dbStatus = "healthy";
+ } catch (error) {
+ console.error("Database health check failed:", error);
+ dbStatus = "unhealthy";
}
- const fieldsStmt = db.prepare(`
- SELECT * FROM content_fields
- WHERE collection_id = ?
- ORDER BY field_order ASC
- `);
- const { results: fieldsResults } = await fieldsStmt.bind(id).all();
- const fields = (fieldsResults || []).map((row) => ({
- id: row.id,
- field_name: row.field_name,
- field_type: row.field_type,
- field_label: row.field_label,
- field_options: row.field_options ? JSON.parse(row.field_options) : {},
- field_order: row.field_order,
- is_required: row.is_required === 1,
- is_searchable: row.is_searchable === 1,
- created_at: Number(row.created_at),
- updated_at: Number(row.updated_at)
- }));
+ let kvStatus = "not_configured";
+ let kvLatency = 0;
+ if (c.env.CACHE_KV) {
+ try {
+ const kvStart = Date.now();
+ await c.env.CACHE_KV.get("__health_check__");
+ kvLatency = Date.now() - kvStart;
+ kvStatus = "healthy";
+ } catch (error) {
+ console.error("KV health check failed:", error);
+ kvStatus = "unhealthy";
+ }
+ }
+ let r2Status = "not_configured";
+ if (c.env.MEDIA_BUCKET) {
+ try {
+ await c.env.MEDIA_BUCKET.head("__health_check__");
+ r2Status = "healthy";
+ } catch (error) {
+ r2Status = "healthy";
+ }
+ }
+ const totalLatency = Date.now() - startTime;
+ const overall = dbStatus === "healthy" ? "healthy" : "degraded";
return c.json({
- id: collection.id,
- name: collection.name,
- display_name: collection.display_name,
- description: collection.description,
- is_active: collection.is_active === 1,
- managed: collection.managed === 1,
- schema: collection.schema ? JSON.parse(collection.schema) : null,
- created_at: Number(collection.created_at),
- updated_at: Number(collection.updated_at),
- fields
+ status: overall,
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
+ uptime: totalLatency,
+ checks: {
+ database: {
+ status: dbStatus,
+ latency: dbLatency
+ },
+ cache: {
+ status: kvStatus,
+ latency: kvLatency
+ },
+ storage: {
+ status: r2Status
+ }
+ },
+ environment: c.env.ENVIRONMENT || "production"
});
} catch (error) {
- console.error("Error fetching collection:", error);
- return c.json({ error: "Failed to fetch collection" }, 500);
+ console.error("Health check failed:", error);
+ return c.json({
+ status: "unhealthy",
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
+ error: "Health check failed"
+ }, 503);
}
});
-adminApiRoutes.get("/references", async (c) => {
+apiSystemRoutes.get("/info", (c) => {
+ const appVersion = c.get("appVersion") || "1.0.0";
+ return c.json({
+ name: "SonicJS",
+ version: appVersion,
+ description: "Modern headless CMS built on Cloudflare Workers",
+ endpoints: {
+ api: "/api",
+ auth: "/auth",
+ health: "/api/system/health",
+ docs: "/docs"
+ },
+ features: {
+ content: true,
+ media: true,
+ auth: true,
+ collections: true,
+ caching: !!c.env.CACHE_KV,
+ storage: !!c.env.MEDIA_BUCKET
+ },
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
+ });
+});
+apiSystemRoutes.get("/stats", async (c) => {
try {
const db = c.env.DB;
- const url = new URL(c.req.url);
- const collectionParams = url.searchParams.getAll("collection").flatMap((value) => value.split(",")).map((value) => value.trim()).filter(Boolean);
- const search = c.req.query("search") || "";
- const id = c.req.query("id") || "";
- const limit = Math.min(Number.parseInt(c.req.query("limit") || "20", 10) || 20, 100);
- if (collectionParams.length === 0) {
- return c.json({ error: "Collection is required" }, 400);
+ const contentStats = await db.prepare(`
+ SELECT COUNT(*) as total_content
+ FROM content
+ WHERE deleted_at IS NULL
+ `).first();
+ const mediaStats = await db.prepare(`
+ SELECT
+ COUNT(*) as total_files,
+ SUM(size) as total_size
+ FROM media
+ WHERE deleted_at IS NULL
+ `).first();
+ const userStats = await db.prepare(`
+ SELECT COUNT(*) as total_users
+ FROM users
+ `).first();
+ return c.json({
+ content: {
+ total: contentStats?.total_content || 0
+ },
+ media: {
+ total_files: mediaStats?.total_files || 0,
+ total_size_bytes: mediaStats?.total_size || 0,
+ total_size_mb: Math.round((mediaStats?.total_size || 0) / 1024 / 1024 * 100) / 100
+ },
+ users: {
+ total: userStats?.total_users || 0
+ },
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
+ });
+ } catch (error) {
+ console.error("Stats query failed:", error);
+ return c.json({ error: "Failed to fetch system statistics" }, 500);
+ }
+});
+apiSystemRoutes.get("/ping", async (c) => {
+ try {
+ const start = Date.now();
+ await c.env.DB.prepare("SELECT 1").first();
+ const latency = Date.now() - start;
+ return c.json({
+ pong: true,
+ latency,
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
+ });
+ } catch (error) {
+ console.error("Ping failed:", error);
+ return c.json({
+ pong: false,
+ error: "Database connection failed"
+ }, 503);
+ }
+});
+apiSystemRoutes.get("/env", (c) => {
+ return c.json({
+ environment: c.env.ENVIRONMENT || "production",
+ features: {
+ database: !!c.env.DB,
+ cache: !!c.env.CACHE_KV,
+ media_bucket: !!c.env.MEDIA_BUCKET,
+ email_queue: !!c.env.EMAIL_QUEUE,
+ sendgrid: !!c.env.SENDGRID_API_KEY,
+ cloudflare_images: !!(c.env.IMAGES_ACCOUNT_ID && c.env.IMAGES_API_TOKEN)
+ },
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
+ });
+});
+var api_system_default = apiSystemRoutes;
+var adminApiRoutes = new Hono();
+adminApiRoutes.use("*", requireAuth());
+adminApiRoutes.use("*", requireRole(["admin", "editor"]));
+adminApiRoutes.get("/stats", async (c) => {
+ try {
+ const db = c.env.DB;
+ let collectionsCount = 0;
+ try {
+ const collectionsStmt = db.prepare("SELECT COUNT(*) as count FROM collections WHERE is_active = 1");
+ const collectionsResult = await collectionsStmt.first();
+ collectionsCount = collectionsResult?.count || 0;
+ } catch (error) {
+ console.error("Error fetching collections count:", error);
}
- const placeholders = collectionParams.map(() => "?").join(", ");
- const collectionStmt = db.prepare(`
- SELECT id, name, display_name
- FROM collections
- WHERE id IN (${placeholders}) OR name IN (${placeholders})
- `);
- const collectionResults = await collectionStmt.bind(...collectionParams, ...collectionParams).all();
- const collections = collectionResults.results || [];
- if (collections.length === 0) {
- return c.json({ error: "Collection not found" }, 404);
+ let contentCount = 0;
+ try {
+ const contentStmt = db.prepare("SELECT COUNT(*) as count FROM content WHERE deleted_at IS NULL");
+ const contentResult = await contentStmt.first();
+ contentCount = contentResult?.count || 0;
+ } catch (error) {
+ console.error("Error fetching content count:", error);
}
- const collectionById = Object.fromEntries(
- collections.map((entry) => [
- entry.id,
- {
- id: entry.id,
- name: entry.name,
- display_name: entry.display_name
- }
- ])
- );
- const collectionIds = collections.map((entry) => entry.id);
- if (id) {
- const idPlaceholders = collectionIds.map(() => "?").join(", ");
- const itemStmt = db.prepare(`
- SELECT id, title, slug, collection_id
- FROM content
- WHERE id = ? AND collection_id IN (${idPlaceholders})
- LIMIT 1
- `);
- const item = await itemStmt.bind(id, ...collectionIds).first();
- if (!item) {
- return c.json({ error: "Reference not found" }, 404);
- }
- return c.json({
- data: {
- id: item.id,
- title: item.title,
- slug: item.slug,
- collection: collectionById[item.collection_id]
- }
- });
+ let mediaCount = 0;
+ let mediaSize = 0;
+ try {
+ const mediaStmt = db.prepare("SELECT COUNT(*) as count, COALESCE(SUM(size), 0) as total_size FROM media WHERE deleted_at IS NULL");
+ const mediaResult = await mediaStmt.first();
+ mediaCount = mediaResult?.count || 0;
+ mediaSize = mediaResult?.total_size || 0;
+ } catch (error) {
+ console.error("Error fetching media count:", error);
}
- let stmt;
- let results;
- const listPlaceholders = collectionIds.map(() => "?").join(", ");
- const statusFilterValues = ["published"];
- const statusClause = ` AND status IN (${statusFilterValues.map(() => "?").join(", ")})`;
- if (search) {
- const searchParam = `%${search}%`;
- stmt = db.prepare(`
- SELECT id, title, slug, status, updated_at, collection_id
- FROM content
- WHERE collection_id IN (${listPlaceholders})
- AND (title LIKE ? OR slug LIKE ?)
- ${statusClause}
- ORDER BY updated_at DESC
- LIMIT ?
- `);
- const queryResults = await stmt.bind(...collectionIds, searchParam, searchParam, ...statusFilterValues, limit).all();
- results = queryResults.results;
- } else {
- stmt = db.prepare(`
- SELECT id, title, slug, status, updated_at, collection_id
- FROM content
- WHERE collection_id IN (${listPlaceholders})
- ${statusClause}
- ORDER BY updated_at DESC
- LIMIT ?
- `);
- const queryResults = await stmt.bind(...collectionIds, ...statusFilterValues, limit).all();
- results = queryResults.results;
+ let usersCount = 0;
+ try {
+ const usersStmt = db.prepare("SELECT COUNT(*) as count FROM users WHERE is_active = 1");
+ const usersResult = await usersStmt.first();
+ usersCount = usersResult?.count || 0;
+ } catch (error) {
+ console.error("Error fetching users count:", error);
}
- const items = (results || []).map((row) => ({
- id: row.id,
- title: row.title,
- slug: row.slug,
- status: row.status,
- updated_at: row.updated_at ? Number(row.updated_at) : null,
- collection: collectionById[row.collection_id]
- }));
return c.json({
- data: items,
- count: items.length
+ collections: collectionsCount,
+ contentItems: contentCount,
+ mediaFiles: mediaCount,
+ mediaSize,
+ users: usersCount,
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
});
} catch (error) {
- console.error("Error fetching reference options:", error);
- return c.json({ error: "Failed to fetch references" }, 500);
+ console.error("Error fetching stats:", error);
+ return c.json({ error: "Failed to fetch statistics" }, 500);
}
});
-adminApiRoutes.post("/collections", async (c) => {
+adminApiRoutes.get("/storage", async (c) => {
try {
- const contentType = c.req.header("Content-Type");
- if (!contentType || !contentType.includes("application/json")) {
- return c.json({ error: "Content-Type must be application/json" }, 400);
- }
- let body;
+ const db = c.env.DB;
+ let databaseSize = 0;
try {
- body = await c.req.json();
- } catch (e) {
- return c.json({ error: "Invalid JSON in request body" }, 400);
+ const result = await db.prepare("SELECT 1").run();
+ databaseSize = result?.meta?.size_after || 0;
+ } catch (error) {
+ console.error("Error fetching database size:", error);
}
- const validation = createCollectionSchema.safeParse(body);
- if (!validation.success) {
- return c.json({ error: "Validation failed", details: validation.error.issues }, 400);
+ let mediaSize = 0;
+ try {
+ const mediaStmt = db.prepare("SELECT COALESCE(SUM(size), 0) as total_size FROM media WHERE deleted_at IS NULL");
+ const mediaResult = await mediaStmt.first();
+ mediaSize = mediaResult?.total_size || 0;
+ } catch (error) {
+ console.error("Error fetching media size:", error);
}
- const validatedData = validation.data;
+ return c.json({
+ databaseSize,
+ mediaSize,
+ totalSize: databaseSize + mediaSize,
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
+ });
+ } catch (error) {
+ console.error("Error fetching storage usage:", error);
+ return c.json({ error: "Failed to fetch storage usage" }, 500);
+ }
+});
+adminApiRoutes.get("/activity", async (c) => {
+ try {
const db = c.env.DB;
- const _user = c.get("user");
- const displayName = validatedData.displayName || validatedData.display_name || "";
- const existingStmt = db.prepare("SELECT id FROM collections WHERE name = ?");
- const existing = await existingStmt.bind(validatedData.name).first();
- if (existing) {
- return c.json({ error: "A collection with this name already exists" }, 400);
- }
- const basicSchema = {
- type: "object",
- properties: {
- title: {
- type: "string",
- title: "Title",
- required: true
- },
- content: {
- type: "string",
- title: "Content",
- format: "richtext"
- },
- status: {
- type: "string",
- title: "Status",
- enum: ["draft", "published", "archived"],
- default: "draft"
- }
- },
- required: ["title"]
- };
- const collectionId = crypto.randomUUID();
- const now = Date.now();
- const insertStmt = db.prepare(`
- INSERT INTO collections (id, name, display_name, description, schema, is_active, created_at, updated_at)
- VALUES (?, ?, ?, ?, ?, ?, ?, ?)
- `);
- await insertStmt.bind(
- collectionId,
- validatedData.name,
- displayName,
- validatedData.description || null,
- JSON.stringify(basicSchema),
- 1,
- // is_active
- now,
- now
- ).run();
- try {
- await c.env.CACHE_KV.delete("cache:collections:all");
- await c.env.CACHE_KV.delete(`cache:collection:${validatedData.name}`);
- } catch (e) {
- console.error("Error clearing cache:", e);
- }
+ const limit = parseInt(c.req.query("limit") || "10");
+ const activityStmt = db.prepare(`
+ SELECT
+ a.id,
+ a.action,
+ a.resource_type,
+ a.resource_id,
+ a.details,
+ a.created_at,
+ u.email,
+ u.first_name,
+ u.last_name
+ FROM activity_logs a
+ LEFT JOIN users u ON a.user_id = u.id
+ WHERE a.resource_type IN ('content', 'collections', 'users', 'media')
+ ORDER BY a.created_at DESC
+ LIMIT ?
+ `);
+ const { results } = await activityStmt.bind(limit).all();
+ const recentActivity = (results || []).map((row) => {
+ const userName = row.first_name && row.last_name ? `${row.first_name} ${row.last_name}` : row.email || "System";
+ let details = {};
+ try {
+ details = row.details ? JSON.parse(row.details) : {};
+ } catch (e) {
+ console.error("Error parsing activity details:", e);
+ }
+ return {
+ id: row.id,
+ type: row.resource_type,
+ action: row.action,
+ resource_id: row.resource_id,
+ details,
+ timestamp: new Date(Number(row.created_at)).toISOString(),
+ user: userName
+ };
+ });
return c.json({
- id: collectionId,
- name: validatedData.name,
- displayName,
- description: validatedData.description,
- created_at: now
- }, 201);
+ data: recentActivity,
+ count: recentActivity.length,
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
+ });
} catch (error) {
- console.error("Error creating collection:", error);
- return c.json({ error: "Failed to create collection" }, 500);
+ console.error("Error fetching recent activity:", error);
+ return c.json({ error: "Failed to fetch recent activity" }, 500);
}
});
-adminApiRoutes.patch("/collections/:id", async (c) => {
+var createCollectionSchema = z.object({
+ name: z.string().min(1).max(255).regex(/^[a-z0-9_]+$/, "Must contain only lowercase letters, numbers, and underscores"),
+ displayName: z.string().min(1).max(255).optional(),
+ display_name: z.string().min(1).max(255).optional(),
+ description: z.string().optional()
+}).refine((data) => data.displayName || data.display_name, {
+ message: "Either displayName or display_name is required",
+ path: ["displayName"]
+});
+var updateCollectionSchema = z.object({
+ display_name: z.string().min(1).max(255).optional(),
+ description: z.string().optional(),
+ is_active: z.boolean().optional()
+});
+adminApiRoutes.get("/collections", async (c) => {
try {
- const id = c.req.param("id");
- const body = await c.req.json();
- const validation = updateCollectionSchema.safeParse(body);
- if (!validation.success) {
- return c.json({ error: "Validation failed", details: validation.error.issues }, 400);
- }
- const validatedData = validation.data;
const db = c.env.DB;
- const checkStmt = db.prepare("SELECT * FROM collections WHERE id = ?");
- const existing = await checkStmt.bind(id).first();
- if (!existing) {
- return c.json({ error: "Collection not found" }, 404);
- }
- const updateFields = [];
- const updateParams = [];
- if (validatedData.display_name !== void 0) {
- updateFields.push("display_name = ?");
- updateParams.push(validatedData.display_name);
- }
- if (validatedData.description !== void 0) {
- updateFields.push("description = ?");
- updateParams.push(validatedData.description);
- }
- if (validatedData.is_active !== void 0) {
- updateFields.push("is_active = ?");
- updateParams.push(validatedData.is_active ? 1 : 0);
- }
- if (updateFields.length === 0) {
- return c.json({ error: "No fields to update" }, 400);
- }
- updateFields.push("updated_at = ?");
- updateParams.push(Date.now());
- updateParams.push(id);
- const updateStmt = db.prepare(`
- UPDATE collections
- SET ${updateFields.join(", ")}
- WHERE id = ?
+ const search = c.req.query("search") || "";
+ const includeInactive = c.req.query("includeInactive") === "true";
+ let stmt;
+ let results;
+ if (search) {
+ stmt = db.prepare(`
+ SELECT id, name, display_name, description, created_at, updated_at, is_active, managed
+ FROM collections
+ WHERE ${includeInactive ? "1=1" : "is_active = 1"}
+ AND (name LIKE ? OR display_name LIKE ? OR description LIKE ?)
+ ORDER BY created_at DESC
`);
- await updateStmt.bind(...updateParams).run();
- try {
- await c.env.CACHE_KV.delete("cache:collections:all");
- await c.env.CACHE_KV.delete(`cache:collection:${existing.name}`);
- } catch (e) {
- console.error("Error clearing cache:", e);
+ const searchParam = `%${search}%`;
+ const queryResults = await stmt.bind(searchParam, searchParam, searchParam).all();
+ results = queryResults.results;
+ } else {
+ stmt = db.prepare(`
+ SELECT id, name, display_name, description, created_at, updated_at, is_active, managed
+ FROM collections
+ ${includeInactive ? "" : "WHERE is_active = 1"}
+ ORDER BY created_at DESC
+ `);
+ const queryResults = await stmt.all();
+ results = queryResults.results;
}
- return c.json({ message: "Collection updated successfully" });
+ const fieldCountStmt = db.prepare("SELECT collection_id, COUNT(*) as count FROM content_fields GROUP BY collection_id");
+ const { results: fieldCountResults } = await fieldCountStmt.all();
+ const fieldCounts = new Map((fieldCountResults || []).map((row) => [String(row.collection_id), Number(row.count)]));
+ const collections = (results || []).map((row) => ({
+ id: row.id,
+ name: row.name,
+ display_name: row.display_name,
+ description: row.description,
+ created_at: Number(row.created_at),
+ updated_at: Number(row.updated_at),
+ is_active: row.is_active === 1,
+ managed: row.managed === 1,
+ field_count: fieldCounts.get(String(row.id)) || 0
+ }));
+ return c.json({
+ data: collections,
+ count: collections.length,
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
+ });
} catch (error) {
- console.error("Error updating collection:", error);
- return c.json({ error: "Failed to update collection" }, 500);
+ console.error("Error fetching collections:", error);
+ return c.json({ error: "Failed to fetch collections" }, 500);
}
});
-adminApiRoutes.delete("/collections/:id", async (c) => {
+adminApiRoutes.get("/collections/:id", async (c) => {
try {
const id = c.req.param("id");
const db = c.env.DB;
- const collectionStmt = db.prepare("SELECT name FROM collections WHERE id = ?");
- const collection = await collectionStmt.bind(id).first();
+ const stmt = db.prepare("SELECT * FROM collections WHERE id = ?");
+ const collection = await stmt.bind(id).first();
if (!collection) {
return c.json({ error: "Collection not found" }, 404);
}
- const contentStmt = db.prepare("SELECT COUNT(*) as count FROM content WHERE collection_id = ?");
- const contentResult = await contentStmt.bind(id).first();
- if (contentResult && contentResult.count > 0) {
- return c.json({
- error: `Cannot delete collection: it contains ${contentResult.count} content item(s). Delete all content first.`
- }, 400);
- }
- const deleteFieldsStmt = db.prepare("DELETE FROM content_fields WHERE collection_id = ?");
- await deleteFieldsStmt.bind(id).run();
- const deleteStmt = db.prepare("DELETE FROM collections WHERE id = ?");
- await deleteStmt.bind(id).run();
- try {
- await c.env.CACHE_KV.delete("cache:collections:all");
- await c.env.CACHE_KV.delete(`cache:collection:${collection.name}`);
- } catch (e) {
- console.error("Error clearing cache:", e);
- }
- return c.json({ message: "Collection deleted successfully" });
+ const fieldsStmt = db.prepare(`
+ SELECT * FROM content_fields
+ WHERE collection_id = ?
+ ORDER BY field_order ASC
+ `);
+ const { results: fieldsResults } = await fieldsStmt.bind(id).all();
+ const fields = (fieldsResults || []).map((row) => ({
+ id: row.id,
+ field_name: row.field_name,
+ field_type: row.field_type,
+ field_label: row.field_label,
+ field_options: row.field_options ? JSON.parse(row.field_options) : {},
+ field_order: row.field_order,
+ is_required: row.is_required === 1,
+ is_searchable: row.is_searchable === 1,
+ created_at: Number(row.created_at),
+ updated_at: Number(row.updated_at)
+ }));
+ return c.json({
+ id: collection.id,
+ name: collection.name,
+ display_name: collection.display_name,
+ description: collection.description,
+ is_active: collection.is_active === 1,
+ managed: collection.managed === 1,
+ schema: collection.schema ? JSON.parse(collection.schema) : null,
+ created_at: Number(collection.created_at),
+ updated_at: Number(collection.updated_at),
+ fields
+ });
} catch (error) {
- console.error("Error deleting collection:", error);
- return c.json({ error: "Failed to delete collection" }, 500);
+ console.error("Error fetching collection:", error);
+ return c.json({ error: "Failed to fetch collection" }, 500);
}
});
-adminApiRoutes.get("/migrations/status", async (c) => {
+adminApiRoutes.get("/references", async (c) => {
try {
- const { MigrationService: MigrationService2 } = await import('./migrations-WJVCIKQO.js');
const db = c.env.DB;
- const migrationService = new MigrationService2(db);
- const status = await migrationService.getMigrationStatus();
- return c.json({
- success: true,
- data: status
- });
- } catch (error) {
- console.error("Error fetching migration status:", error);
+ const url = new URL(c.req.url);
+ const collectionParams = url.searchParams.getAll("collection").flatMap((value) => value.split(",")).map((value) => value.trim()).filter(Boolean);
+ const search = c.req.query("search") || "";
+ const id = c.req.query("id") || "";
+ const limit = Math.min(Number.parseInt(c.req.query("limit") || "20", 10) || 20, 100);
+ if (collectionParams.length === 0) {
+ return c.json({ error: "Collection is required" }, 400);
+ }
+ const placeholders = collectionParams.map(() => "?").join(", ");
+ const collectionStmt = db.prepare(`
+ SELECT id, name, display_name
+ FROM collections
+ WHERE id IN (${placeholders}) OR name IN (${placeholders})
+ `);
+ const collectionResults = await collectionStmt.bind(...collectionParams, ...collectionParams).all();
+ const collections = collectionResults.results || [];
+ if (collections.length === 0) {
+ return c.json({ error: "Collection not found" }, 404);
+ }
+ const collectionById = Object.fromEntries(
+ collections.map((entry) => [
+ entry.id,
+ {
+ id: entry.id,
+ name: entry.name,
+ display_name: entry.display_name
+ }
+ ])
+ );
+ const collectionIds = collections.map((entry) => entry.id);
+ if (id) {
+ const idPlaceholders = collectionIds.map(() => "?").join(", ");
+ const itemStmt = db.prepare(`
+ SELECT id, title, slug, collection_id
+ FROM content
+ WHERE id = ? AND collection_id IN (${idPlaceholders})
+ LIMIT 1
+ `);
+ const item = await itemStmt.bind(id, ...collectionIds).first();
+ if (!item) {
+ return c.json({ error: "Reference not found" }, 404);
+ }
+ return c.json({
+ data: {
+ id: item.id,
+ title: item.title,
+ slug: item.slug,
+ collection: collectionById[item.collection_id]
+ }
+ });
+ }
+ let stmt;
+ let results;
+ const listPlaceholders = collectionIds.map(() => "?").join(", ");
+ const statusFilterValues = ["published"];
+ const statusClause = ` AND status IN (${statusFilterValues.map(() => "?").join(", ")})`;
+ if (search) {
+ const searchParam = `%${search}%`;
+ stmt = db.prepare(`
+ SELECT id, title, slug, status, updated_at, collection_id
+ FROM content
+ WHERE collection_id IN (${listPlaceholders})
+ AND (title LIKE ? OR slug LIKE ?)
+ ${statusClause}
+ ORDER BY updated_at DESC
+ LIMIT ?
+ `);
+ const queryResults = await stmt.bind(...collectionIds, searchParam, searchParam, ...statusFilterValues, limit).all();
+ results = queryResults.results;
+ } else {
+ stmt = db.prepare(`
+ SELECT id, title, slug, status, updated_at, collection_id
+ FROM content
+ WHERE collection_id IN (${listPlaceholders})
+ ${statusClause}
+ ORDER BY updated_at DESC
+ LIMIT ?
+ `);
+ const queryResults = await stmt.bind(...collectionIds, ...statusFilterValues, limit).all();
+ results = queryResults.results;
+ }
+ const items = (results || []).map((row) => ({
+ id: row.id,
+ title: row.title,
+ slug: row.slug,
+ status: row.status,
+ updated_at: row.updated_at ? Number(row.updated_at) : null,
+ collection: collectionById[row.collection_id]
+ }));
return c.json({
- success: false,
- error: "Failed to fetch migration status"
- }, 500);
+ data: items,
+ count: items.length
+ });
+ } catch (error) {
+ console.error("Error fetching reference options:", error);
+ return c.json({ error: "Failed to fetch references" }, 500);
}
});
-adminApiRoutes.post("/migrations/run", async (c) => {
+adminApiRoutes.post("/collections", async (c) => {
try {
- const user = c.get("user");
- if (!user || user.role !== "admin") {
- return c.json({
- success: false,
- error: "Unauthorized. Admin access required."
- }, 403);
+ const contentType = c.req.header("Content-Type");
+ if (!contentType || !contentType.includes("application/json")) {
+ return c.json({ error: "Content-Type must be application/json" }, 400);
+ }
+ let body;
+ try {
+ body = await c.req.json();
+ } catch (e) {
+ return c.json({ error: "Invalid JSON in request body" }, 400);
+ }
+ const validation = createCollectionSchema.safeParse(body);
+ if (!validation.success) {
+ return c.json({ error: "Validation failed", details: validation.error.issues }, 400);
}
- const { MigrationService: MigrationService2 } = await import('./migrations-WJVCIKQO.js');
+ const validatedData = validation.data;
const db = c.env.DB;
- const migrationService = new MigrationService2(db);
- const result = await migrationService.runPendingMigrations();
+ const _user = c.get("user");
+ const displayName = validatedData.displayName || validatedData.display_name || "";
+ const existingStmt = db.prepare("SELECT id FROM collections WHERE name = ?");
+ const existing = await existingStmt.bind(validatedData.name).first();
+ if (existing) {
+ return c.json({ error: "A collection with this name already exists" }, 400);
+ }
+ const basicSchema = {
+ type: "object",
+ properties: {
+ title: {
+ type: "string",
+ title: "Title",
+ required: true
+ },
+ content: {
+ type: "string",
+ title: "Content",
+ format: "richtext"
+ },
+ status: {
+ type: "string",
+ title: "Status",
+ enum: ["draft", "published", "archived"],
+ default: "draft"
+ }
+ },
+ required: ["title"]
+ };
+ const collectionId = crypto.randomUUID();
+ const now = Date.now();
+ const insertStmt = db.prepare(`
+ INSERT INTO collections (id, name, display_name, description, schema, is_active, created_at, updated_at)
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?)
+ `);
+ await insertStmt.bind(
+ collectionId,
+ validatedData.name,
+ displayName,
+ validatedData.description || null,
+ JSON.stringify(basicSchema),
+ 1,
+ // is_active
+ now,
+ now
+ ).run();
+ try {
+ await c.env.CACHE_KV.delete("cache:collections:all");
+ await c.env.CACHE_KV.delete(`cache:collection:${validatedData.name}`);
+ } catch (e) {
+ console.error("Error clearing cache:", e);
+ }
return c.json({
- success: result.success,
- message: result.message,
- applied: result.applied
- });
+ id: collectionId,
+ name: validatedData.name,
+ displayName,
+ description: validatedData.description,
+ created_at: now
+ }, 201);
} catch (error) {
- console.error("Error running migrations:", error);
- return c.json({
- success: false,
- error: "Failed to run migrations"
- }, 500);
+ console.error("Error creating collection:", error);
+ return c.json({ error: "Failed to create collection" }, 500);
}
});
-adminApiRoutes.get("/migrations/validate", async (c) => {
+adminApiRoutes.patch("/collections/:id", async (c) => {
try {
- const { MigrationService: MigrationService2 } = await import('./migrations-WJVCIKQO.js');
+ const id = c.req.param("id");
+ const body = await c.req.json();
+ const validation = updateCollectionSchema.safeParse(body);
+ if (!validation.success) {
+ return c.json({ error: "Validation failed", details: validation.error.issues }, 400);
+ }
+ const validatedData = validation.data;
const db = c.env.DB;
- const migrationService = new MigrationService2(db);
- const validation = await migrationService.validateSchema();
- return c.json({
- success: true,
- data: validation
- });
+ const checkStmt = db.prepare("SELECT * FROM collections WHERE id = ?");
+ const existing = await checkStmt.bind(id).first();
+ if (!existing) {
+ return c.json({ error: "Collection not found" }, 404);
+ }
+ const updateFields = [];
+ const updateParams = [];
+ if (validatedData.display_name !== void 0) {
+ updateFields.push("display_name = ?");
+ updateParams.push(validatedData.display_name);
+ }
+ if (validatedData.description !== void 0) {
+ updateFields.push("description = ?");
+ updateParams.push(validatedData.description);
+ }
+ if (validatedData.is_active !== void 0) {
+ updateFields.push("is_active = ?");
+ updateParams.push(validatedData.is_active ? 1 : 0);
+ }
+ if (updateFields.length === 0) {
+ return c.json({ error: "No fields to update" }, 400);
+ }
+ updateFields.push("updated_at = ?");
+ updateParams.push(Date.now());
+ updateParams.push(id);
+ const updateStmt = db.prepare(`
+ UPDATE collections
+ SET ${updateFields.join(", ")}
+ WHERE id = ?
+ `);
+ await updateStmt.bind(...updateParams).run();
+ try {
+ await c.env.CACHE_KV.delete("cache:collections:all");
+ await c.env.CACHE_KV.delete(`cache:collection:${existing.name}`);
+ } catch (e) {
+ console.error("Error clearing cache:", e);
+ }
+ return c.json({ message: "Collection updated successfully" });
} catch (error) {
- console.error("Error validating schema:", error);
- return c.json({
- success: false,
- error: "Failed to validate schema"
- }, 500);
+ console.error("Error updating collection:", error);
+ return c.json({ error: "Failed to update collection" }, 500);
}
});
-var admin_api_default = adminApiRoutes;
-
-// src/templates/pages/auth-login.template.ts
-function renderLoginPage(data, demoLoginActive = false) {
+adminApiRoutes.delete("/collections/:id", async (c) => {
+ try {
+ const id = c.req.param("id");
+ const db = c.env.DB;
+ const collectionStmt = db.prepare("SELECT name FROM collections WHERE id = ?");
+ const collection = await collectionStmt.bind(id).first();
+ if (!collection) {
+ return c.json({ error: "Collection not found" }, 404);
+ }
+ const contentStmt = db.prepare("SELECT COUNT(*) as count FROM content WHERE collection_id = ?");
+ const contentResult = await contentStmt.bind(id).first();
+ if (contentResult && contentResult.count > 0) {
+ return c.json({
+ error: `Cannot delete collection: it contains ${contentResult.count} content item(s). Delete all content first.`
+ }, 400);
+ }
+ const deleteFieldsStmt = db.prepare("DELETE FROM content_fields WHERE collection_id = ?");
+ await deleteFieldsStmt.bind(id).run();
+ const deleteStmt = db.prepare("DELETE FROM collections WHERE id = ?");
+ await deleteStmt.bind(id).run();
+ try {
+ await c.env.CACHE_KV.delete("cache:collections:all");
+ await c.env.CACHE_KV.delete(`cache:collection:${collection.name}`);
+ } catch (e) {
+ console.error("Error clearing cache:", e);
+ }
+ return c.json({ message: "Collection deleted successfully" });
+ } catch (error) {
+ console.error("Error deleting collection:", error);
+ return c.json({ error: "Failed to delete collection" }, 500);
+ }
+});
+adminApiRoutes.get("/migrations/status", async (c) => {
+ try {
+ const { MigrationService: MigrationService2 } = await import('./migrations-JDDP45OR.js');
+ const db = c.env.DB;
+ const migrationService = new MigrationService2(db);
+ const status = await migrationService.getMigrationStatus();
+ return c.json({
+ success: true,
+ data: status
+ });
+ } catch (error) {
+ console.error("Error fetching migration status:", error);
+ return c.json({
+ success: false,
+ error: "Failed to fetch migration status"
+ }, 500);
+ }
+});
+adminApiRoutes.post("/migrations/run", async (c) => {
+ try {
+ const user = c.get("user");
+ if (!user || user.role !== "admin") {
+ return c.json({
+ success: false,
+ error: "Unauthorized. Admin access required."
+ }, 403);
+ }
+ const { MigrationService: MigrationService2 } = await import('./migrations-JDDP45OR.js');
+ const db = c.env.DB;
+ const migrationService = new MigrationService2(db);
+ const result = await migrationService.runPendingMigrations();
+ return c.json({
+ success: result.success,
+ message: result.message,
+ applied: result.applied
+ });
+ } catch (error) {
+ console.error("Error running migrations:", error);
+ return c.json({
+ success: false,
+ error: "Failed to run migrations"
+ }, 500);
+ }
+});
+adminApiRoutes.get("/migrations/validate", async (c) => {
+ try {
+ const { MigrationService: MigrationService2 } = await import('./migrations-JDDP45OR.js');
+ const db = c.env.DB;
+ const migrationService = new MigrationService2(db);
+ const validation = await migrationService.validateSchema();
+ return c.json({
+ success: true,
+ data: validation
+ });
+ } catch (error) {
+ console.error("Error validating schema:", error);
+ return c.json({
+ success: false,
+ error: "Failed to validate schema"
+ }, 500);
+ }
+});
+var admin_api_default = adminApiRoutes;
+
+// src/templates/pages/auth-login.template.ts
+function renderLoginPage(data, demoLoginActive = false) {
return `
@@ -8671,6 +9894,16 @@ adminContentRoutes.post("/", async (c) => {
user?.userId || "unknown",
now
).run();
+ const fts5Service = new FTS5Service(db);
+ c.executionCtx.waitUntil(
+ fts5Service.indexContent(contentId).catch(
+ (err) => console.error("[Content] FTS5 indexing failed:", err)
+ )
+ );
+ if (c.env.CACHE_KV) {
+ const searchCache = new SearchCacheService(c.env.CACHE_KV);
+ c.executionCtx.waitUntil(searchCache.invalidateAll());
+ }
const referrerParams = formData.get("referrer_params");
const redirectUrl = action === "save_and_continue" ? `/admin/content/${contentId}/edit?success=Content saved successfully!${referrerParams ? `&ref=${encodeURIComponent(referrerParams)}` : ""}` : referrerParams ? `/admin/content?${referrerParams}&success=Content created successfully!` : `/admin/content?collection=${collectionId}&success=Content created successfully!`;
const isHTMX = c.req.header("HX-Request") === "true";
@@ -8799,6 +10032,16 @@ adminContentRoutes.put("/:id", async (c) => {
now
).run();
}
+ const fts5Service = new FTS5Service(db);
+ c.executionCtx.waitUntil(
+ fts5Service.indexContent(id).catch(
+ (err) => console.error("[Content] FTS5 reindexing failed:", err)
+ )
+ );
+ if (c.env.CACHE_KV) {
+ const searchCache = new SearchCacheService(c.env.CACHE_KV);
+ c.executionCtx.waitUntil(searchCache.invalidateAll());
+ }
const referrerParams = formData.get("referrer_params");
const redirectUrl = action === "save_and_continue" ? `/admin/content/${id}/edit?success=Content updated successfully!${referrerParams ? `&ref=${encodeURIComponent(referrerParams)}` : ""}` : referrerParams ? `/admin/content?${referrerParams}&success=Content updated successfully!` : `/admin/content?collection=${existingContent.collection_id}&success=Content updated successfully!`;
const isHTMX = c.req.header("HX-Request") === "true";
@@ -9064,6 +10307,16 @@ adminContentRoutes.delete("/:id", async (c) => {
WHERE id = ?
`);
await deleteStmt.bind(now, id).run();
+ const fts5Service = new FTS5Service(db);
+ c.executionCtx.waitUntil(
+ fts5Service.removeFromIndex(id).catch(
+ (err) => console.error("[Content] FTS5 removal failed:", err)
+ )
+ );
+ if (c.env.CACHE_KV) {
+ const searchCache = new SearchCacheService(c.env.CACHE_KV);
+ c.executionCtx.waitUntil(searchCache.invalidateAll());
+ }
const cache = getCacheService(CACHE_CONFIGS.content);
await cache.delete(cache.generateKey("content", id));
await cache.invalidate("content:list:*");
@@ -10773,7 +12026,7 @@ function renderUsersListPage(data) {
sortable: true,
sortType: "string",
render: (_value, row) => {
- const escapeHtml6 = (text) => text.replace(/[&<>"']/g, (char) => ({
+ const escapeHtml7 = (text) => text.replace(/[&<>"']/g, (char) => ({
"&": "&",
"<": "<",
">": ">",
@@ -10782,9 +12035,9 @@ function renderUsersListPage(data) {
})[char] || char);
const truncatedFirstName = row.firstName.length > 25 ? row.firstName.substring(0, 25) + "..." : row.firstName;
const truncatedLastName = row.lastName.length > 25 ? row.lastName.substring(0, 25) + "..." : row.lastName;
- const fullName = escapeHtml6(`${truncatedFirstName} ${truncatedLastName}`);
+ const fullName = escapeHtml7(`${truncatedFirstName} ${truncatedLastName}`);
const truncatedUsername = row.username.length > 100 ? row.username.substring(0, 100) + "..." : row.username;
- const username = escapeHtml6(truncatedUsername);
+ const username = escapeHtml7(truncatedUsername);
const statusBadge = row.isActive ? 'Active ' : 'Inactive ';
return `
@@ -10800,14 +12053,14 @@ function renderUsersListPage(data) {
sortable: true,
sortType: "string",
render: (value) => {
- const escapeHtml6 = (text) => text.replace(/[&<>"']/g, (char) => ({
+ const escapeHtml7 = (text) => text.replace(/[&<>"']/g, (char) => ({
"&": "&",
"<": "<",
">": ">",
'"': """,
"'": "'"
})[char] || char);
- const escapedEmail = escapeHtml6(value);
+ const escapedEmail = escapeHtml7(value);
return `
${escapedEmail} `;
}
},
@@ -15763,24 +17016,8 @@ function renderSettingsTab(plugin) {
const isTurnstilePlugin = plugin.id === "turnstile" || plugin.name === "turnstile";
return `
${isSeedDataPlugin ? `
-
+
+
` : ""}
@@ -21514,8 +22751,8 @@ function renderCollectionFormPage(data) {
Select field type...
Text
URL Slug
- ${data.editorPlugins?.tinymce ? '
Rich Text (TinyMCE) ' : ""}
${data.editorPlugins?.quill ? '
Rich Text (Quill) ' : ""}
+ ${data.editorPlugins?.tinymce ? '
Rich Text (TinyMCE) ' : ""}
${data.editorPlugins?.easyMdx ? '
EasyMDX ' : ""}
Number
Boolean
@@ -22350,7 +23587,9 @@ adminCollectionsRoutes.get("/:id", async (c) => {
let fieldOrder = 0;
fields = Object.entries(schema.properties).map(([fieldName, fieldConfig]) => {
let fieldType = fieldConfig.type || "string";
- if (fieldConfig.enum) {
+ if (fieldConfig.type === "quill" || fieldConfig.type === "mdxeditor") {
+ fieldType = fieldConfig.type;
+ } else if (fieldConfig.enum) {
fieldType = "select";
} else if (fieldConfig.format === "richtext") {
fieldType = "richtext";
@@ -22696,6 +23935,12 @@ adminCollectionsRoutes.put("/:collectionId/fields/:fieldId", async (c) => {
title: fieldLabel,
searchable: isSearchable
};
+ if (fieldType === "quill" || fieldType === "mdxeditor") {
+ delete updatedFieldConfig.format;
+ } else if (fieldType === "richtext") {
+ updatedFieldConfig.type = "string";
+ updatedFieldConfig.format = "richtext";
+ }
if (isRequired) {
updatedFieldConfig.required = true;
} else {
@@ -27726,6 +28971,9699 @@ router2.get("/", async (c) => {
}
});
+// src/plugins/core-plugins/ai-search-plugin/services/embedding.service.ts
+var EmbeddingService = class {
+ constructor(ai) {
+ this.ai = ai;
+ }
+ /**
+ * Generate embedding for a single text
+ *
+ * ā Enhanced with Cloudflare Similarity-Based Caching
+ * - Automatically caches embeddings for 30 days
+ * - Similar queries share the same cache (semantic matching)
+ * - 90%+ speedup for repeated/similar queries (200ms ā 5ms)
+ * - Zero infrastructure cost (included with Workers AI)
+ *
+ * Example: "cloudflare workers" and "cloudflare worker" share cache
+ */
+ async generateEmbedding(text) {
+ try {
+ const response = await this.ai.run("@cf/baai/bge-base-en-v1.5", {
+ text: this.preprocessText(text)
+ }, {
+ // ā Enable Cloudflare's Similarity-Based Caching
+ // This provides semantic cache matching across similar queries
+ cf: {
+ cacheTtl: 2592e3,
+ // 30 days (maximum allowed)
+ cacheEverything: true
+ // Cache all AI responses
+ }
+ });
+ if (response.data && response.data.length > 0) {
+ return response.data[0];
+ }
+ throw new Error("No embedding data returned");
+ } catch (error) {
+ console.error("[EmbeddingService] Error generating embedding:", error);
+ throw error;
+ }
+ }
+ /**
+ * Generate embeddings for multiple texts using native batch API.
+ * Workers AI supports up to 100 texts per call for bge-base-en-v1.5.
+ */
+ async generateBatch(texts, onProgress) {
+ try {
+ const batchSize = 50;
+ const allEmbeddings = [];
+ for (let i = 0; i < texts.length; i += batchSize) {
+ const batch = texts.slice(i, i + batchSize);
+ const preprocessed = batch.map((t) => this.preprocessText(t));
+ const response = await this.ai.run("@cf/baai/bge-base-en-v1.5", {
+ text: preprocessed
+ });
+ if (response.data && Array.isArray(response.data)) {
+ allEmbeddings.push(...response.data);
+ } else {
+ throw new Error(`Unexpected embedding response at batch offset ${i}`);
+ }
+ if (onProgress) {
+ await onProgress(allEmbeddings.length, texts.length);
+ }
+ }
+ return allEmbeddings;
+ } catch (error) {
+ console.error("[EmbeddingService] Error generating batch embeddings:", error);
+ throw error;
+ }
+ }
+ /**
+ * Preprocess text before generating embedding
+ * - Trim whitespace
+ * - Limit length to avoid token limits
+ * - Remove special characters that might cause issues
+ */
+ preprocessText(text) {
+ if (!text) return "";
+ let processed = text.trim().replace(/\s+/g, " ");
+ if (processed.length > 8e3) {
+ processed = processed.substring(0, 8e3);
+ }
+ return processed;
+ }
+ /**
+ * Calculate cosine similarity between two embeddings
+ */
+ cosineSimilarity(a, b) {
+ if (a.length !== b.length) {
+ throw new Error("Embeddings must have same dimensions");
+ }
+ let dotProduct = 0;
+ let normA = 0;
+ let normB = 0;
+ for (let i = 0; i < a.length; i++) {
+ const aVal = a[i] ?? 0;
+ const bVal = b[i] ?? 0;
+ dotProduct += aVal * bVal;
+ normA += aVal * aVal;
+ normB += bVal * bVal;
+ }
+ return dotProduct / (Math.sqrt(normA) * Math.sqrt(normB));
+ }
+};
+
+// src/plugins/core-plugins/ai-search-plugin/services/chunking.service.ts
+var ChunkingService = class {
+ // Default chunk size (in approximate tokens)
+ CHUNK_SIZE = 500;
+ CHUNK_OVERLAP = 50;
+ /**
+ * Chunk a single content item
+ */
+ chunkContent(contentId, collectionId, title, data, metadata = {}) {
+ const text = this.extractText(data);
+ if (!text || text.trim().length === 0) {
+ console.warn(`[ChunkingService] No text found for content ${contentId}`);
+ return [];
+ }
+ const textChunks = this.splitIntoChunks(text);
+ return textChunks.map((chunkText, index) => ({
+ id: `${contentId}_chunk_${index}`,
+ content_id: contentId,
+ collection_id: collectionId,
+ title,
+ text: chunkText,
+ chunk_index: index,
+ metadata: {
+ ...metadata,
+ total_chunks: textChunks.length
+ }
+ }));
+ }
+ /**
+ * Chunk multiple content items
+ */
+ chunkContentBatch(items) {
+ const allChunks = [];
+ for (const item of items) {
+ const chunks = this.chunkContent(
+ item.id,
+ item.collection_id,
+ item.title,
+ item.data,
+ item.metadata
+ );
+ allChunks.push(...chunks);
+ }
+ return allChunks;
+ }
+ /**
+ * Extract all text from content data
+ */
+ extractText(data) {
+ const parts = [];
+ if (data.title) parts.push(String(data.title));
+ if (data.name) parts.push(String(data.name));
+ if (data.description) parts.push(String(data.description));
+ if (data.content) parts.push(String(data.content));
+ if (data.body) parts.push(String(data.body));
+ if (data.text) parts.push(String(data.text));
+ if (data.summary) parts.push(String(data.summary));
+ const extractRecursive = (obj) => {
+ if (typeof obj === "string") {
+ if (obj.length > 10 && !obj.startsWith("http")) {
+ parts.push(obj);
+ }
+ } else if (Array.isArray(obj)) {
+ obj.forEach(extractRecursive);
+ } else if (obj && typeof obj === "object") {
+ const skipKeys = ["id", "slug", "url", "image", "thumbnail", "metadata"];
+ Object.entries(obj).forEach(([key, value]) => {
+ if (!skipKeys.includes(key.toLowerCase())) {
+ extractRecursive(value);
+ }
+ });
+ }
+ };
+ extractRecursive(data);
+ return parts.join("\n\n").trim();
+ }
+ /**
+ * Split text into overlapping chunks
+ */
+ splitIntoChunks(text) {
+ const words = text.split(/\s+/);
+ if (words.length <= this.CHUNK_SIZE) {
+ return [text];
+ }
+ const chunks = [];
+ let startIndex = 0;
+ while (startIndex < words.length) {
+ const endIndex = Math.min(startIndex + this.CHUNK_SIZE, words.length);
+ const chunk = words.slice(startIndex, endIndex).join(" ");
+ chunks.push(chunk);
+ startIndex += this.CHUNK_SIZE - this.CHUNK_OVERLAP;
+ if (startIndex >= words.length - this.CHUNK_OVERLAP) {
+ break;
+ }
+ }
+ return chunks;
+ }
+ /**
+ * Get optimal chunk size based on content type
+ */
+ getOptimalChunkSize(contentType) {
+ switch (contentType) {
+ case "blog_posts":
+ case "articles":
+ return 600;
+ // Larger chunks for long-form content
+ case "products":
+ case "pages":
+ return 400;
+ // Medium chunks for structured content
+ case "messages":
+ case "comments":
+ return 200;
+ // Small chunks for short content
+ default:
+ return this.CHUNK_SIZE;
+ }
+ }
+};
+
+// src/plugins/core-plugins/ai-search-plugin/services/custom-rag.service.ts
+var CustomRAGService = class {
+ constructor(db, ai, vectorize) {
+ this.db = db;
+ this.ai = ai;
+ this.vectorize = vectorize;
+ this.embeddingService = new EmbeddingService(ai);
+ this.chunkingService = new ChunkingService();
+ }
+ embeddingService;
+ chunkingService;
+ /**
+ * Index all content from a collection.
+ * onProgress reports (phase, processedItems, totalItems) so callers can update UI.
+ * Phases: 'chunking' ā 'embedding' ā 'storing'
+ */
+ async indexCollection(collectionId, onProgress) {
+ console.log(`[CustomRAG] Starting indexing for collection: ${collectionId}`);
+ try {
+ const { results: contentItems } = await this.db.prepare(`
+ SELECT c.id, c.title, c.data, c.collection_id, c.status,
+ c.created_at, c.updated_at, c.author_id,
+ col.name as collection_name, col.display_name as collection_display_name
+ FROM content c
+ JOIN collections col ON c.collection_id = col.id
+ WHERE c.collection_id = ? AND c.status != 'deleted'
+ `).bind(collectionId).all();
+ const totalItems = contentItems?.length || 0;
+ if (totalItems === 0) {
+ console.log(`[CustomRAG] No content found in collection ${collectionId}`);
+ return { total_items: 0, total_chunks: 0, indexed_chunks: 0, errors: 0 };
+ }
+ if (onProgress) await onProgress("chunking", 0, totalItems);
+ const items = (contentItems || []).map((item) => ({
+ id: item.id,
+ collection_id: item.collection_id,
+ title: item.title || "Untitled",
+ data: typeof item.data === "string" ? JSON.parse(item.data) : item.data,
+ metadata: {
+ status: item.status,
+ created_at: item.created_at,
+ updated_at: item.updated_at,
+ author_id: item.author_id,
+ collection_name: item.collection_name,
+ collection_display_name: item.collection_display_name
+ }
+ }));
+ const chunks = this.chunkingService.chunkContentBatch(items);
+ const totalChunks = chunks.length;
+ console.log(`[CustomRAG] Generated ${totalChunks} chunks from ${totalItems} items`);
+ if (onProgress) await onProgress("embedding", 0, totalChunks);
+ const embeddings = await this.embeddingService.generateBatch(
+ chunks.map((c) => `${c.title}
+
+${c.text}`),
+ onProgress ? async (completed, total) => {
+ await onProgress("embedding", completed, total);
+ } : void 0
+ );
+ console.log(`[CustomRAG] Generated ${embeddings.length} embeddings`);
+ if (onProgress) await onProgress("storing", 0, totalChunks);
+ let indexedChunks = 0;
+ let errors = 0;
+ const batchSize = 100;
+ for (let i = 0; i < chunks.length; i += batchSize) {
+ const chunkBatch = chunks.slice(i, i + batchSize);
+ const embeddingBatch = embeddings.slice(i, i + batchSize);
+ try {
+ await this.vectorize.upsert(
+ chunkBatch.map((chunk, idx) => ({
+ id: chunk.id,
+ values: embeddingBatch[idx],
+ metadata: {
+ content_id: chunk.content_id,
+ collection_id: chunk.collection_id,
+ title: chunk.title,
+ text: chunk.text.substring(0, 500),
+ chunk_index: chunk.chunk_index,
+ ...chunk.metadata
+ }
+ }))
+ );
+ indexedChunks += chunkBatch.length;
+ if (onProgress) await onProgress("storing", indexedChunks, totalChunks);
+ } catch (error) {
+ console.error(`[CustomRAG] Error indexing batch ${i / batchSize + 1}:`, error);
+ errors += chunkBatch.length;
+ }
+ }
+ console.log(`[CustomRAG] Indexing complete: ${indexedChunks}/${totalChunks} chunks indexed`);
+ return {
+ total_items: totalItems,
+ total_chunks: totalChunks,
+ indexed_chunks: indexedChunks,
+ errors
+ };
+ } catch (error) {
+ console.error(`[CustomRAG] Error indexing collection ${collectionId}:`, error);
+ throw error;
+ }
+ }
+ /**
+ * Auto-index content in selected collections that hasn't been indexed into Vectorize yet.
+ * Mirrors FTS5's ensureCollectionsIndexed() self-healing pattern.
+ */
+ async ensureCollectionsIndexed(collections) {
+ if (collections.length === 0) return;
+ try {
+ const placeholders = collections.map(() => "?").join(", ");
+ const { results: indexedCollections } = await this.db.prepare(`
+ SELECT collection_id, status, indexed_items FROM ai_search_index_meta
+ WHERE collection_id IN (${placeholders}) AND status = 'completed' AND indexed_items > 0
+ `).bind(...collections).all();
+ const completedIds = new Set((indexedCollections || []).map((r) => r.collection_id));
+ const unindexedCollections = collections.filter((id) => !completedIds.has(id));
+ if (unindexedCollections.length === 0) return;
+ console.log(`[CustomRAG] Auto-indexing ${unindexedCollections.length} collection(s) into Vectorize...`);
+ for (const collectionId of unindexedCollections) {
+ try {
+ await this.db.prepare(`
+ INSERT OR REPLACE INTO ai_search_index_meta(collection_id, collection_name, status, total_items, indexed_items)
+ VALUES (?, ?, 'indexing', 0, 0)
+ `).bind(collectionId, collectionId).run();
+ const result = await this.indexCollection(collectionId);
+ await this.db.prepare(`
+ UPDATE ai_search_index_meta
+ SET status = 'completed', total_items = ?, indexed_items = ?, last_sync_at = ?
+ WHERE collection_id = ?
+ `).bind(result.total_items, result.indexed_chunks, Date.now(), collectionId).run();
+ console.log(`[CustomRAG] Auto-indexed collection ${collectionId}: ${result.indexed_chunks} chunks from ${result.total_items} items`);
+ } catch (error) {
+ console.error(`[CustomRAG] Error auto-indexing collection ${collectionId}:`, error);
+ await this.db.prepare(`
+ UPDATE ai_search_index_meta SET status = 'error', error_message = ?
+ WHERE collection_id = ?
+ `).bind(String(error), collectionId).run().catch(() => {
+ });
+ }
+ }
+ } catch (error) {
+ console.error("[CustomRAG] Error during auto-indexing check:", error);
+ }
+ }
+ /**
+ * Search using RAG (semantic search with Vectorize)
+ */
+ async search(query, settings) {
+ const startTime = Date.now();
+ try {
+ const collections = query.filters?.collections?.length ? query.filters.collections : settings.selected_collections;
+ await this.ensureCollectionsIndexed(collections);
+ const queryEmbedding = await this.embeddingService.generateEmbedding(query.query);
+ const filter = {};
+ if (query.filters?.collections && query.filters.collections.length > 0) {
+ filter.collection_id = { $in: query.filters.collections };
+ } else if (settings.selected_collections.length > 0) {
+ filter.collection_id = { $in: settings.selected_collections };
+ }
+ if (query.filters?.status && query.filters.status.length > 0) {
+ filter.status = { $in: query.filters.status };
+ }
+ const vectorResults = await this.vectorize.query(queryEmbedding, {
+ topK: 50,
+ // Max allowed with returnMetadata: true
+ returnMetadata: "all"
+ });
+ let filteredMatches = vectorResults.matches || [];
+ if (filter.collection_id?.$in && Array.isArray(filter.collection_id.$in)) {
+ const allowedCollections = filter.collection_id.$in;
+ const beforeCount = filteredMatches.length;
+ filteredMatches = filteredMatches.filter(
+ (match) => allowedCollections.includes(match.metadata?.collection_id)
+ );
+ }
+ if (filter.status?.$in && Array.isArray(filter.status.$in)) {
+ const allowedStatuses = filter.status.$in;
+ filteredMatches = filteredMatches.filter(
+ (match) => allowedStatuses.includes(match.metadata?.status)
+ );
+ }
+ const topK = query.limit || settings.results_limit || 20;
+ filteredMatches = filteredMatches.slice(0, topK);
+ vectorResults.matches = filteredMatches;
+ if (!vectorResults.matches || vectorResults.matches.length === 0) {
+ return {
+ results: [],
+ total: 0,
+ query_time_ms: Date.now() - startTime,
+ mode: "ai"
+ };
+ }
+ const contentIds = [...new Set(
+ vectorResults.matches.map((m) => m.metadata.content_id)
+ )];
+ const placeholders = contentIds.map(() => "?").join(",");
+ const { results: contentItems } = await this.db.prepare(`
+ SELECT c.id, c.title, c.slug, c.collection_id, c.status,
+ c.created_at, c.updated_at, c.author_id,
+ col.display_name as collection_name
+ FROM content c
+ JOIN collections col ON c.collection_id = col.id
+ WHERE c.id IN (${placeholders})
+ `).bind(...contentIds).all();
+ const d1Map = new Map((contentItems || []).map((item) => [item.id, item]));
+ const bestByContent = /* @__PURE__ */ new Map();
+ for (const match of vectorResults.matches) {
+ const cid = match.metadata?.content_id;
+ if (!cid || !d1Map.has(cid)) continue;
+ const existing = bestByContent.get(cid);
+ if (!existing || match.score > existing.score) {
+ bestByContent.set(cid, match);
+ }
+ }
+ const sortedEntries = [...bestByContent.entries()].sort((a, b) => b[1].score - a[1].score);
+ if (query.mode !== "hybrid") {
+ const MIN_RELEVANCE_SCORE = 0.45;
+ const SCORE_GAP_THRESHOLD = 0.15;
+ const filteredEntries = [];
+ for (let i = 0; i < sortedEntries.length; i++) {
+ const entry = sortedEntries[i];
+ const score = entry[1].score;
+ if (score < MIN_RELEVANCE_SCORE) break;
+ if (i > 0) {
+ const prevScore = sortedEntries[i - 1][1].score;
+ const gap = prevScore - score;
+ if (gap > SCORE_GAP_THRESHOLD) {
+ break;
+ }
+ }
+ filteredEntries.push(entry);
+ }
+ bestByContent.clear();
+ for (const [key, value] of filteredEntries) {
+ bestByContent.set(key, value);
+ }
+ }
+ const searchResults = [];
+ for (const [contentId, bestMatch] of bestByContent) {
+ const d1Item = d1Map.get(contentId);
+ searchResults.push({
+ id: d1Item.id,
+ title: d1Item.title || "Untitled",
+ slug: d1Item.slug || "",
+ collection_id: d1Item.collection_id,
+ collection_name: d1Item.collection_name,
+ snippet: bestMatch.metadata?.text || "",
+ relevance_score: bestMatch.score || 0,
+ status: d1Item.status,
+ created_at: d1Item.created_at,
+ updated_at: d1Item.updated_at
+ });
+ }
+ searchResults.sort((a, b) => (b.relevance_score || 0) - (a.relevance_score || 0));
+ const queryTime = Date.now() - startTime;
+ console.log(`[CustomRAG] Search completed in ${queryTime}ms, ${searchResults.length} results`);
+ return {
+ results: searchResults,
+ total: searchResults.length,
+ query_time_ms: queryTime,
+ mode: "ai"
+ };
+ } catch (error) {
+ console.error("[CustomRAG] Search error:", error);
+ throw error;
+ }
+ }
+ /**
+ * Update index for a single content item
+ */
+ async updateContentIndex(contentId) {
+ try {
+ const content = await this.db.prepare(`
+ SELECT c.id, c.title, c.data, c.collection_id, c.status,
+ c.created_at, c.updated_at, c.author_id,
+ col.name as collection_name, col.display_name as collection_display_name
+ FROM content c
+ JOIN collections col ON c.collection_id = col.id
+ WHERE c.id = ?
+ `).bind(contentId).first();
+ if (!content) {
+ console.warn(`[CustomRAG] Content ${contentId} not found`);
+ return;
+ }
+ if (content.status !== "published") {
+ await this.removeContentFromIndex(contentId);
+ return;
+ }
+ const chunks = this.chunkingService.chunkContent(
+ content.id,
+ content.collection_id,
+ content.title || "Untitled",
+ typeof content.data === "string" ? JSON.parse(content.data) : content.data,
+ {
+ status: content.status,
+ created_at: content.created_at,
+ updated_at: content.updated_at,
+ author_id: content.author_id,
+ collection_name: content.collection_name,
+ collection_display_name: content.collection_display_name
+ }
+ );
+ const embeddings = await this.embeddingService.generateBatch(
+ chunks.map((c) => `${c.title}
+
+${c.text}`)
+ );
+ await this.vectorize.upsert(
+ chunks.map((chunk, idx) => ({
+ id: chunk.id,
+ values: embeddings[idx],
+ metadata: {
+ content_id: chunk.content_id,
+ collection_id: chunk.collection_id,
+ title: chunk.title,
+ text: chunk.text.substring(0, 500),
+ chunk_index: chunk.chunk_index,
+ ...chunk.metadata
+ }
+ }))
+ );
+ console.log(`[CustomRAG] Updated index for content ${contentId}: ${chunks.length} chunks`);
+ } catch (error) {
+ console.error(`[CustomRAG] Error updating index for ${contentId}:`, error);
+ throw error;
+ }
+ }
+ /**
+ * Remove content from index
+ */
+ async removeContentFromIndex(contentId) {
+ try {
+ console.log(`[CustomRAG] Removing content ${contentId} from index`);
+ } catch (error) {
+ console.error(`[CustomRAG] Error removing content ${contentId}:`, error);
+ throw error;
+ }
+ }
+ /**
+ * Get search suggestions based on query
+ */
+ async getSuggestions(partialQuery, limit = 5) {
+ try {
+ const queryEmbedding = await this.embeddingService.generateEmbedding(partialQuery);
+ const results = await this.vectorize.query(queryEmbedding, {
+ topK: limit * 2,
+ // Get more to filter
+ returnMetadata: true
+ });
+ const suggestions = [...new Set(
+ results.matches?.map((m) => m.metadata.title).filter(Boolean) || []
+ )].slice(0, limit);
+ return suggestions;
+ } catch (error) {
+ console.error("[CustomRAG] Error getting suggestions:", error);
+ return [];
+ }
+ }
+ /**
+ * Check if Vectorize is available and configured
+ */
+ isAvailable() {
+ return !!this.vectorize && !!this.ai;
+ }
+};
+
+// src/plugins/core-plugins/ai-search-plugin/services/hybrid-search.service.ts
+var RRF_K = 60;
+var HybridSearchService = class {
+ constructor(fts5Service, customRAG) {
+ this.fts5Service = fts5Service;
+ this.customRAG = customRAG;
+ }
+ /**
+ * Run FTS5 + AI searches in parallel, merge with RRF
+ * Uses Promise.allSettled for partial failure tolerance
+ *
+ * Each sub-search retrieves 3x the final limit to give RRF a larger
+ * candidate pool. This prevents relevant docs from one system being
+ * displaced by irrelevant docs from the other when results are sliced.
+ */
+ async search(query, settings) {
+ const startTime = Date.now();
+ const finalLimit = query.limit || settings.results_limit || 20;
+ const candidateLimit = finalLimit * 3;
+ const expandedQuery = { ...query, limit: candidateLimit };
+ const fts5Weights = {
+ titleBoost: settings.fts5_title_boost,
+ slugBoost: settings.fts5_slug_boost,
+ bodyBoost: settings.fts5_body_boost
+ };
+ const searches = [
+ this.fts5Service.search(expandedQuery, settings, fts5Weights)
+ ];
+ if (this.customRAG?.isAvailable()) {
+ searches.push(this.customRAG.search(expandedQuery, settings));
+ }
+ const settled = await Promise.allSettled(searches);
+ const fulfilled = [];
+ for (const result of settled) {
+ if (result.status === "fulfilled") {
+ fulfilled.push(result.value);
+ } else {
+ console.error("[HybridSearch] One search leg failed:", result.reason);
+ }
+ }
+ if (fulfilled.length === 0) {
+ return {
+ results: [],
+ total: 0,
+ query_time_ms: Date.now() - startTime,
+ mode: "hybrid"
+ };
+ }
+ if (fulfilled.length === 1) {
+ const single = fulfilled[0];
+ return {
+ results: single.results,
+ total: single.total,
+ suggestions: single.suggestions,
+ mode: "hybrid",
+ query_time_ms: Date.now() - startTime
+ };
+ }
+ return this.mergeWithRRF(fulfilled[0], fulfilled[1], query, settings, startTime);
+ }
+ /**
+ * Reciprocal Rank Fusion (RRF)
+ *
+ * For each document d, compute:
+ * RRF_score(d) = Σ 1/(k + rank_i(d))
+ * where rank_i(d) is the 1-based rank of d in system i.
+ *
+ * Docs found by both systems get two contributions (higher score).
+ * k=60 smooths out rank differences (standard value).
+ */
+ mergeWithRRF(fts5Response, aiResponse, query, settings, startTime) {
+ const rrfScores = /* @__PURE__ */ new Map();
+ const docData = /* @__PURE__ */ new Map();
+ aiResponse.results.forEach((doc, i) => {
+ const rank = i + 1;
+ const score = 1 / (RRF_K + rank);
+ rrfScores.set(doc.id, (rrfScores.get(doc.id) || 0) + score);
+ docData.set(doc.id, { ...doc });
+ });
+ fts5Response.results.forEach((doc, i) => {
+ const rank = i + 1;
+ const score = 1 / (RRF_K + rank);
+ rrfScores.set(doc.id, (rrfScores.get(doc.id) || 0) + score);
+ const existing = docData.get(doc.id);
+ if (existing) {
+ if (doc.highlights) existing.highlights = doc.highlights;
+ if (doc.bm25_score) existing.bm25_score = doc.bm25_score;
+ } else {
+ docData.set(doc.id, { ...doc });
+ }
+ });
+ const sorted = [...rrfScores.entries()].sort((a, b) => b[1] - a[1]);
+ const limit = query.limit || settings.results_limit || 20;
+ const results = sorted.slice(0, limit).map(([id, score]) => ({
+ ...docData.get(id),
+ relevance_score: score
+ }));
+ return {
+ mode: "hybrid",
+ results,
+ total: rrfScores.size,
+ query_time_ms: Date.now() - startTime
+ };
+ }
+};
+
+// src/plugins/core-plugins/ai-search-plugin/services/query-rewriter.service.ts
+var REWRITE_SYSTEM_PROMPT = `You are a search query optimizer. Given a user's search query, rewrite it to improve search results by:
+- Adding relevant synonyms or related terms
+- Expanding abbreviations
+- Keeping the core intent intact
+
+Rules:
+- Return ONLY the rewritten query, nothing else
+- Keep it concise (under 100 characters)
+- Do not add explanations or formatting
+- Do not wrap in quotes
+- If the query is already precise, return it unchanged`;
+var QueryRewriterService = class {
+ constructor(ai) {
+ this.ai = ai;
+ }
+ /**
+ * Rewrite a query using LLM expansion
+ * Returns original query on any failure
+ */
+ async rewrite(originalQuery) {
+ try {
+ const response = await this.ai.run(
+ "@cf/meta/llama-3.1-8b-instruct-fp8-fast",
+ {
+ messages: [
+ { role: "system", content: REWRITE_SYSTEM_PROMPT },
+ { role: "user", content: originalQuery }
+ ],
+ max_tokens: 100
+ }
+ );
+ const rewritten = response.response?.trim();
+ if (!rewritten) return originalQuery;
+ if (rewritten.length > originalQuery.length * 3) return originalQuery;
+ if (rewritten.length > 200) return originalQuery;
+ if (rewritten.includes("\n")) return originalQuery;
+ return rewritten;
+ } catch (error) {
+ console.error("[QueryRewriter] LLM call failed, using original query:", error);
+ return originalQuery;
+ }
+ }
+ /**
+ * Check if a query should be rewritten
+ * Short/precise queries don't benefit from rewriting
+ */
+ static shouldRewrite(query) {
+ return query.length >= 15;
+ }
+};
+
+// src/plugins/core-plugins/ai-search-plugin/services/query-rules.service.ts
+var QueryRulesService = class {
+ constructor(db) {
+ this.db = db;
+ }
+ // === CRUD ===
+ async getAll() {
+ try {
+ const { results } = await this.db.prepare("SELECT id, match_pattern, match_type, substitute_query, enabled, priority, created_at, updated_at FROM ai_search_query_rules ORDER BY priority DESC, created_at DESC").all();
+ return (results || []).map((row) => ({
+ id: row.id,
+ match_pattern: row.match_pattern,
+ match_type: row.match_type,
+ substitute_query: row.substitute_query,
+ enabled: row.enabled === 1,
+ priority: row.priority,
+ created_at: row.created_at,
+ updated_at: row.updated_at
+ }));
+ } catch {
+ return [];
+ }
+ }
+ async getById(id) {
+ try {
+ const row = await this.db.prepare("SELECT id, match_pattern, match_type, substitute_query, enabled, priority, created_at, updated_at FROM ai_search_query_rules WHERE id = ?").bind(id).first();
+ if (!row) return null;
+ return {
+ id: row.id,
+ match_pattern: row.match_pattern,
+ match_type: row.match_type,
+ substitute_query: row.substitute_query,
+ enabled: row.enabled === 1,
+ priority: row.priority,
+ created_at: row.created_at,
+ updated_at: row.updated_at
+ };
+ } catch {
+ return null;
+ }
+ }
+ async create(data) {
+ const pattern = data.match_pattern.trim();
+ const substitute = data.substitute_query.trim();
+ if (!pattern) throw new Error("match_pattern is required");
+ if (!substitute) throw new Error("substitute_query is required");
+ const id = crypto.randomUUID().replace(/-/g, "");
+ const matchType = data.match_type || "exact";
+ const enabled = data.enabled !== false;
+ const priority = data.priority ?? 0;
+ await this.db.prepare("INSERT INTO ai_search_query_rules (id, match_pattern, match_type, substitute_query, enabled, priority) VALUES (?, ?, ?, ?, ?, ?)").bind(id, pattern, matchType, substitute, enabled ? 1 : 0, priority).run();
+ const created = await this.getById(id);
+ if (!created) throw new Error("Failed to create query rule");
+ return created;
+ }
+ async update(id, data) {
+ const existing = await this.getById(id);
+ if (!existing) return null;
+ const pattern = data.match_pattern !== void 0 ? data.match_pattern.trim() : existing.match_pattern;
+ const matchType = data.match_type !== void 0 ? data.match_type : existing.match_type;
+ const substitute = data.substitute_query !== void 0 ? data.substitute_query.trim() : existing.substitute_query;
+ const enabled = data.enabled !== void 0 ? data.enabled : existing.enabled;
+ const priority = data.priority !== void 0 ? data.priority : existing.priority;
+ if (!pattern) throw new Error("match_pattern cannot be empty");
+ if (!substitute) throw new Error("substitute_query cannot be empty");
+ await this.db.prepare("UPDATE ai_search_query_rules SET match_pattern = ?, match_type = ?, substitute_query = ?, enabled = ?, priority = ?, updated_at = unixepoch() WHERE id = ?").bind(pattern, matchType, substitute, enabled ? 1 : 0, priority, id).run();
+ return this.getById(id);
+ }
+ async delete(id) {
+ const result = await this.db.prepare("DELETE FROM ai_search_query_rules WHERE id = ?").bind(id).run();
+ return (result.meta?.changes ?? 0) > 0;
+ }
+ // === Query Substitution ===
+ /**
+ * Apply substitution rules to a query string.
+ * Loads enabled rules (priority DESC), first match wins.
+ * - Exact: LOWER(query) === LOWER(pattern)
+ * - Prefix: LOWER(query).startsWith(LOWER(pattern)) ā preserves suffix
+ * Returns the (possibly modified) query plus metadata.
+ */
+ async applyRules(query) {
+ try {
+ const rules = await this.getEnabled();
+ if (rules.length === 0) return { query };
+ const queryLower = query.toLowerCase().trim();
+ for (const rule of rules) {
+ const patternLower = rule.match_pattern.toLowerCase().trim();
+ if (rule.match_type === "exact") {
+ if (queryLower === patternLower) {
+ return {
+ query: rule.substitute_query,
+ ruleId: rule.id,
+ originalQuery: query
+ };
+ }
+ } else if (rule.match_type === "prefix") {
+ if (queryLower.startsWith(patternLower)) {
+ const suffix = query.substring(rule.match_pattern.trim().length);
+ return {
+ query: rule.substitute_query + suffix,
+ ruleId: rule.id,
+ originalQuery: query
+ };
+ }
+ }
+ }
+ return { query };
+ } catch (error) {
+ console.warn("[QueryRulesService] applyRules error (returning original query):", error);
+ return { query };
+ }
+ }
+ // === Helpers ===
+ async getEnabled() {
+ try {
+ const { results } = await this.db.prepare("SELECT id, match_pattern, match_type, substitute_query, enabled, priority, created_at, updated_at FROM ai_search_query_rules WHERE enabled = 1 ORDER BY priority DESC").all();
+ return (results || []).map((row) => ({
+ id: row.id,
+ match_pattern: row.match_pattern,
+ match_type: row.match_type,
+ substitute_query: row.substitute_query,
+ enabled: row.enabled === 1,
+ priority: row.priority,
+ created_at: row.created_at,
+ updated_at: row.updated_at
+ }));
+ } catch {
+ return [];
+ }
+ }
+};
+
+// src/plugins/core-plugins/ai-search-plugin/types.ts
+var DEFAULT_RANKING_PIPELINE = [
+ { type: "exactMatch", weight: 10, enabled: true },
+ { type: "bm25", weight: 5, enabled: true },
+ { type: "semantic", weight: 3, enabled: true },
+ { type: "recency", weight: 1, enabled: true, config: { half_life_days: 30 } },
+ { type: "popularity", weight: 0, enabled: false },
+ { type: "custom", weight: 0, enabled: false }
+];
+
+// src/plugins/core-plugins/ai-search-plugin/services/ranking-pipeline.service.ts
+function clampWeight(val, fallback) {
+ const n = Number(val);
+ return isNaN(n) || !isFinite(n) ? fallback : Math.round(Math.min(10, Math.max(0, n)) * 10) / 10;
+}
+var VALID_STAGE_TYPES = /* @__PURE__ */ new Set(["exactMatch", "bm25", "semantic", "recency", "popularity", "custom"]);
+var RankingPipelineService = class {
+ constructor(db) {
+ this.db = db;
+ }
+ // === Config CRUD ===
+ async getConfig() {
+ try {
+ const row = await this.db.prepare("SELECT pipeline_json FROM ai_search_ranking_config WHERE id = 'default' LIMIT 1").first();
+ if (!row?.pipeline_json) {
+ return structuredClone(DEFAULT_RANKING_PIPELINE);
+ }
+ return this.validateStages(JSON.parse(row.pipeline_json));
+ } catch {
+ return structuredClone(DEFAULT_RANKING_PIPELINE);
+ }
+ }
+ async saveConfig(stages) {
+ const validated = this.validateStages(stages);
+ await this.db.prepare(`
+ INSERT INTO ai_search_ranking_config (id, pipeline_json, updated_at)
+ VALUES ('default', ?, unixepoch())
+ ON CONFLICT(id) DO UPDATE SET pipeline_json = excluded.pipeline_json, updated_at = excluded.updated_at
+ `).bind(JSON.stringify(validated)).run();
+ }
+ validateStages(stages) {
+ if (!Array.isArray(stages)) return structuredClone(DEFAULT_RANKING_PIPELINE);
+ return stages.filter((s) => VALID_STAGE_TYPES.has(s.type)).map((s) => ({
+ type: s.type,
+ weight: clampWeight(s.weight, 0),
+ enabled: Boolean(s.enabled),
+ config: s.config || void 0
+ }));
+ }
+ // === Pipeline Execution ===
+ async apply(response, query) {
+ const results = response.results;
+ if (results.length === 0) return response;
+ const stages = await this.getConfig();
+ const activeStages = stages.filter((s) => s.enabled && s.weight > 0);
+ if (activeStages.length === 0) return response;
+ const totalWeight = activeStages.reduce((sum, s) => sum + s.weight, 0);
+ if (totalWeight === 0) return response;
+ let minBM25 = Infinity;
+ let maxBM25 = -Infinity;
+ const hasBM25 = activeStages.some((s) => s.type === "bm25");
+ if (hasBM25) {
+ for (const r of results) {
+ if (r.bm25_score != null) {
+ if (r.bm25_score < minBM25) minBM25 = r.bm25_score;
+ if (r.bm25_score > maxBM25) maxBM25 = r.bm25_score;
+ }
+ }
+ if (minBM25 === Infinity) {
+ minBM25 = 0;
+ maxBM25 = 0;
+ }
+ }
+ const contentIds = results.map((r) => r.id);
+ let popularityScores = /* @__PURE__ */ new Map();
+ let customScores = /* @__PURE__ */ new Map();
+ const needsPopularity = activeStages.some((s) => s.type === "popularity");
+ const needsCustom = activeStages.some((s) => s.type === "custom");
+ if (needsPopularity) {
+ popularityScores = await this.getContentScores(contentIds, "popularity");
+ this.normalizeScoresMinMax(popularityScores);
+ }
+ if (needsCustom) {
+ customScores = await this.getContentScores(contentIds, "custom");
+ }
+ for (const result of results) {
+ let weightedSum = 0;
+ for (const stage of activeStages) {
+ let score = 0;
+ switch (stage.type) {
+ case "exactMatch":
+ score = this.scoreExactMatch(result, query);
+ break;
+ case "bm25":
+ score = this.scoreBM25(result, minBM25, maxBM25);
+ break;
+ case "semantic":
+ score = this.scoreSemantic(result);
+ break;
+ case "recency":
+ score = this.scoreRecency(result, stage.config?.half_life_days ?? 30);
+ break;
+ case "popularity":
+ score = popularityScores.get(result.id) ?? 0;
+ break;
+ case "custom":
+ score = Math.max(0, Math.min(1, customScores.get(result.id) ?? 0));
+ break;
+ }
+ weightedSum += stage.weight * score;
+ }
+ result.pipeline_score = weightedSum / totalWeight;
+ }
+ results.sort((a, b) => (b.pipeline_score ?? 0) - (a.pipeline_score ?? 0));
+ return { ...response, results };
+ }
+ // === Content Scores CRUD ===
+ async getContentScores(contentIds, scoreType) {
+ if (contentIds.length === 0) return /* @__PURE__ */ new Map();
+ try {
+ const placeholders = contentIds.map(() => "?").join(",");
+ const { results } = await this.db.prepare(`SELECT content_id, score FROM ai_search_content_scores WHERE content_id IN (${placeholders}) AND score_type = ?`).bind(...contentIds, scoreType).all();
+ const map = /* @__PURE__ */ new Map();
+ for (const row of results || []) {
+ map.set(row.content_id, row.score);
+ }
+ return map;
+ } catch {
+ return /* @__PURE__ */ new Map();
+ }
+ }
+ async setContentScore(contentId, scoreType, score) {
+ const clamped = Math.max(0, Math.min(1, score));
+ await this.db.prepare(`
+ INSERT INTO ai_search_content_scores (content_id, score_type, score, updated_at)
+ VALUES (?, ?, ?, unixepoch())
+ ON CONFLICT(content_id, score_type) DO UPDATE SET score = excluded.score, updated_at = excluded.updated_at
+ `).bind(contentId, scoreType, clamped).run();
+ }
+ async deleteContentScore(contentId, scoreType) {
+ await this.db.prepare("DELETE FROM ai_search_content_scores WHERE content_id = ? AND score_type = ?").bind(contentId, scoreType).run();
+ }
+ // === Scoring Functions ===
+ scoreExactMatch(result, query) {
+ if (!query || !result.title) return 0;
+ return result.title.toLowerCase().includes(query.toLowerCase()) ? 1 : 0;
+ }
+ scoreBM25(result, minBM25, maxBM25) {
+ if (result.bm25_score == null) return 0;
+ if (maxBM25 === minBM25) return 1;
+ return (result.bm25_score - minBM25) / (maxBM25 - minBM25);
+ }
+ scoreSemantic(result) {
+ return result.relevance_score ?? 0;
+ }
+ scoreRecency(result, halfLifeDays) {
+ if (!result.created_at) return 0;
+ const nowMs = Date.now();
+ const createdMs = result.created_at > 1e12 ? result.created_at : result.created_at * 1e3;
+ const ageDays = (nowMs - createdMs) / (1e3 * 60 * 60 * 24);
+ if (ageDays <= 0) return 1;
+ if (halfLifeDays <= 0) return 0;
+ return Math.exp(-Math.LN2 * ageDays / halfLifeDays);
+ }
+ /** Min-max normalize a map of scores in-place */
+ normalizeScoresMinMax(scores) {
+ if (scores.size === 0) return;
+ let min = Infinity;
+ let max = -Infinity;
+ for (const v of scores.values()) {
+ if (v < min) min = v;
+ if (v > max) max = v;
+ }
+ if (max === min) {
+ for (const k of scores.keys()) scores.set(k, scores.size > 0 ? 1 : 0);
+ return;
+ }
+ for (const [k, v] of scores) {
+ scores.set(k, (v - min) / (max - min));
+ }
+ }
+};
+
+// src/plugins/core-plugins/ai-search-plugin/services/synonym.service.ts
+var SynonymService = class {
+ constructor(db) {
+ this.db = db;
+ }
+ // === CRUD ===
+ async getAll() {
+ try {
+ const { results } = await this.db.prepare("SELECT id, terms, enabled, created_at, updated_at FROM ai_search_synonyms ORDER BY created_at DESC").all();
+ return (results || []).map((row) => ({
+ id: row.id,
+ terms: JSON.parse(row.terms),
+ enabled: row.enabled === 1,
+ created_at: row.created_at,
+ updated_at: row.updated_at
+ }));
+ } catch {
+ return [];
+ }
+ }
+ async getById(id) {
+ try {
+ const row = await this.db.prepare("SELECT id, terms, enabled, created_at, updated_at FROM ai_search_synonyms WHERE id = ?").bind(id).first();
+ if (!row) return null;
+ return {
+ id: row.id,
+ terms: JSON.parse(row.terms),
+ enabled: row.enabled === 1,
+ created_at: row.created_at,
+ updated_at: row.updated_at
+ };
+ } catch {
+ return null;
+ }
+ }
+ async create(terms, enabled = true) {
+ const sanitized = this.sanitizeTerms(terms);
+ if (sanitized.length < 2) {
+ throw new Error("A synonym group must have at least 2 terms");
+ }
+ const id = crypto.randomUUID().replace(/-/g, "");
+ await this.db.prepare("INSERT INTO ai_search_synonyms (id, terms, enabled) VALUES (?, ?, ?)").bind(id, JSON.stringify(sanitized), enabled ? 1 : 0).run();
+ const created = await this.getById(id);
+ if (!created) throw new Error("Failed to create synonym group");
+ return created;
+ }
+ async update(id, data) {
+ const existing = await this.getById(id);
+ if (!existing) return null;
+ const terms = data.terms !== void 0 ? this.sanitizeTerms(data.terms) : existing.terms;
+ if (terms.length < 2) {
+ throw new Error("A synonym group must have at least 2 terms");
+ }
+ const enabled = data.enabled !== void 0 ? data.enabled : existing.enabled;
+ await this.db.prepare("UPDATE ai_search_synonyms SET terms = ?, enabled = ?, updated_at = unixepoch() WHERE id = ?").bind(JSON.stringify(terms), enabled ? 1 : 0, id).run();
+ return this.getById(id);
+ }
+ async delete(id) {
+ const result = await this.db.prepare("DELETE FROM ai_search_synonyms WHERE id = ?").bind(id).run();
+ return (result.meta?.changes ?? 0) > 0;
+ }
+ // === Query Expansion ===
+ /**
+ * Expand an array of sanitized search terms using enabled synonym groups.
+ * For each input term, if it appears in a group, all other terms from
+ * that group are added. Returns deduplicated expanded term list.
+ */
+ async expandQuery(terms) {
+ const groups = await this.getEnabled();
+ if (groups.length === 0) return terms;
+ const synonymMap = /* @__PURE__ */ new Map();
+ for (const group of groups) {
+ const lowerTerms = group.terms.map((t) => t.toLowerCase());
+ for (const term of lowerTerms) {
+ if (!synonymMap.has(term)) {
+ synonymMap.set(term, /* @__PURE__ */ new Set());
+ }
+ for (const synonym of lowerTerms) {
+ synonymMap.get(term).add(synonym);
+ }
+ }
+ }
+ const expanded = /* @__PURE__ */ new Set();
+ for (const term of terms) {
+ expanded.add(term.toLowerCase());
+ const synonyms = synonymMap.get(term.toLowerCase());
+ if (synonyms) {
+ for (const syn of synonyms) {
+ expanded.add(syn);
+ }
+ }
+ }
+ return Array.from(expanded);
+ }
+ // === Helpers ===
+ async getEnabled() {
+ try {
+ const { results } = await this.db.prepare("SELECT id, terms, enabled, created_at, updated_at FROM ai_search_synonyms WHERE enabled = 1").all();
+ return (results || []).map((row) => ({
+ id: row.id,
+ terms: JSON.parse(row.terms),
+ enabled: row.enabled === 1,
+ created_at: row.created_at,
+ updated_at: row.updated_at
+ }));
+ } catch {
+ return [];
+ }
+ }
+ /** Sanitize terms: trim, lowercase, deduplicate, remove empties */
+ sanitizeTerms(terms) {
+ const seen = /* @__PURE__ */ new Set();
+ const result = [];
+ for (const raw2 of terms) {
+ const term = raw2.trim().toLowerCase();
+ if (term && !seen.has(term)) {
+ seen.add(term);
+ result.push(term);
+ }
+ }
+ return result;
+ }
+};
+
+// src/plugins/core-plugins/ai-search-plugin/services/reranker.service.ts
+var RerankerService = class {
+ constructor(ai) {
+ this.ai = ai;
+ }
+ /**
+ * Rerank results using cross-encoder scoring
+ * Returns results sorted by reranker score with rerank_score field added
+ */
+ async rerank(query, results, topK) {
+ if (results.length <= 1) return results;
+ const limit = topK || results.length;
+ try {
+ const contexts = results.map((r) => ({
+ text: `${r.title}. ${r.snippet || ""}`
+ }));
+ const response = await this.ai.run("@cf/baai/bge-reranker-base", {
+ query,
+ contexts,
+ top_k: limit
+ });
+ const scores = Array.isArray(response) ? response : response.response;
+ if (!Array.isArray(scores) || scores.length === 0) {
+ console.warn("[Reranker] Unexpected response format, returning original order");
+ return results.slice(0, limit);
+ }
+ const reranked = scores.filter((s) => s.id >= 0 && s.id < results.length).map((s) => {
+ const result = results[s.id];
+ return { ...result, rerank_score: s.score };
+ });
+ return reranked.slice(0, limit);
+ } catch (error) {
+ console.error("[Reranker] Cross-encoder failed, returning original order:", error);
+ return results.slice(0, limit);
+ }
+ }
+};
+
+// src/plugins/core-plugins/ai-search-plugin/services/trending-search.service.ts
+var TrendingSearchService = class {
+ constructor(db, kv) {
+ this.db = db;
+ this.kv = kv;
+ }
+ /**
+ * Get trending searches ā returns from KV cache if available, otherwise computes.
+ */
+ async getTrending(limit = 10, periodDays = 7) {
+ const cacheKey = `trending:${periodDays}d:${limit}`;
+ if (this.kv) {
+ try {
+ const cached = await this.kv.get(cacheKey, "json");
+ if (cached) {
+ return { items: cached, cached: true };
+ }
+ } catch {
+ }
+ }
+ const items = await this.computeTrending(limit, periodDays);
+ if (this.kv) {
+ try {
+ await this.kv.put(cacheKey, JSON.stringify(items), { expirationTtl: 900 });
+ } catch {
+ }
+ }
+ return { items, cached: false };
+ }
+ /**
+ * Compute trending searches using time-decay bucket scoring.
+ * Precomputes all thresholds in TypeScript for clean parameter binding.
+ */
+ async computeTrending(limit, periodDays) {
+ const now = Date.now();
+ const t1h = now - 36e5;
+ const t6h = now - 216e5;
+ const t24h = now - 864e5;
+ const t7d = now - 6048e5;
+ const lookback = now - periodDays * 864e5;
+ try {
+ const sql = `
+ SELECT
+ LOWER(query) as q,
+ SUM(
+ CASE
+ WHEN created_at > ?1 THEN 4.0
+ WHEN created_at > ?2 THEN 2.0
+ WHEN created_at > ?3 THEN 1.0
+ WHEN created_at > ?4 THEN 0.5
+ ELSE 0.25
+ END
+ ) as trend_score,
+ COUNT(*) as raw_count
+ FROM ai_search_history
+ WHERE created_at > ?5
+ AND results_count > 0
+ AND query IS NOT NULL
+ AND LENGTH(TRIM(query)) >= 2
+ GROUP BY LOWER(query)
+ HAVING COUNT(*) >= 3
+ ORDER BY trend_score DESC
+ LIMIT ?6
+ `;
+ const fetchLimit = Math.min(limit * 2, 40);
+ const { results } = await this.db.prepare(sql).bind(t1h, t6h, t24h, t7d, lookback, fetchLimit).all();
+ if (!results || results.length === 0) return [];
+ return results.filter((r) => this.isValidQuery(r.q)).slice(0, limit).map((r) => ({
+ query: r.q,
+ trend_score: Math.round(r.trend_score * 100) / 100,
+ search_count: r.raw_count
+ }));
+ } catch (error) {
+ console.log("[TrendingSearchService] Query failed:", error);
+ return [];
+ }
+ }
+ /**
+ * Post-filter: reject garbage queries that slip through SQL filters.
+ */
+ isValidQuery(q) {
+ if (q.length < 3) return false;
+ if (q.length > 100) return false;
+ if (/^\d+$/.test(q)) return false;
+ if (/^[0-9a-f-]{8,}$/i.test(q)) return false;
+ return true;
+ }
+ /**
+ * Invalidate all trending KV cache keys.
+ */
+ async invalidateCache() {
+ if (!this.kv) return;
+ const periods = [1, 7, 14, 30];
+ const limits = [5, 10, 15, 20];
+ const deletes = periods.flatMap(
+ (p) => limits.map((l) => this.kv.delete(`trending:${p}d:${l}`))
+ );
+ await Promise.allSettled(deletes);
+ }
+};
+
+// src/plugins/core-plugins/ai-search-plugin/services/related-search.service.ts
+var RelatedSearchService = class {
+ constructor(db, kv) {
+ this.db = db;
+ this.kv = kv;
+ }
+ // =============================================
+ // Main Entry Point
+ // =============================================
+ /**
+ * Get related searches for a query ā merges manual + agent (D1) + auto (KV/compute).
+ * Returns deduplicated results with manual first, then agent, then auto, up to limit.
+ */
+ async getRelatedSearches(query, limit = 5) {
+ const normalized = this.normalize(query);
+ if (!normalized) return [];
+ const stored = await this.getStoredRelated(normalized);
+ const results = stored.map((r) => ({
+ query: r.related_query,
+ source: r.source
+ }));
+ if (results.length >= limit) {
+ return results.slice(0, limit);
+ }
+ const remaining = limit - results.length;
+ const autoResults = await this.getAutoRelated(normalized, remaining, results);
+ results.push(...autoResults);
+ return results.slice(0, limit);
+ }
+ // =============================================
+ // Stored Entries (Manual + Agent)
+ // =============================================
+ async getStoredRelated(normalizedQuery) {
+ try {
+ const { results } = await this.db.prepare(`
+ SELECT * FROM ai_search_related
+ WHERE source_query = ? AND enabled = 1
+ ORDER BY
+ CASE source WHEN 'manual' THEN 0 WHEN 'agent' THEN 1 END,
+ position ASC
+ `).bind(normalizedQuery).all();
+ return (results || []).map((row) => this.mapRow(row));
+ } catch {
+ return [];
+ }
+ }
+ // =============================================
+ // Auto-Generated (Click Overlap + Session Co-occurrence)
+ // =============================================
+ async getAutoRelated(normalizedQuery, limit, existingResults) {
+ if (!this.kv || limit <= 0) return [];
+ const cacheKey = `related:auto:${normalizedQuery}`;
+ try {
+ const cached = await this.kv.get(cacheKey, "json");
+ if (cached) {
+ const existingQueries2 = new Set(existingResults.map((r) => r.query.toLowerCase()));
+ return cached.filter((r) => !existingQueries2.has(r.query.toLowerCase())).slice(0, limit);
+ }
+ } catch {
+ }
+ const thirtyDaysAgo = Date.now() - 30 * 24 * 60 * 60 * 1e3;
+ try {
+ const countRow = await this.db.prepare("SELECT COUNT(*) as cnt FROM ai_search_history WHERE created_at >= ?").bind(thirtyDaysAgo).first();
+ if (!countRow || countRow.cnt < 100) return [];
+ } catch {
+ return [];
+ }
+ const existingQueries = new Set(existingResults.map((r) => r.query.toLowerCase()));
+ const scoreMap = /* @__PURE__ */ new Map();
+ try {
+ const { results: clickRows } = await this.db.prepare(`
+ WITH target_clicks AS (
+ SELECT DISTINCT c.clicked_content_id
+ FROM ai_search_clicks c
+ JOIN ai_search_history h ON c.search_id = CAST(h.id AS TEXT)
+ WHERE LOWER(h.query) = ?
+ AND h.created_at >= ?
+ ),
+ related AS (
+ SELECT LOWER(h.query) as related_query,
+ COUNT(DISTINCT c.clicked_content_id) as shared_clicks
+ FROM ai_search_clicks c
+ JOIN ai_search_history h ON c.search_id = CAST(h.id AS TEXT)
+ JOIN target_clicks t ON c.clicked_content_id = t.clicked_content_id
+ WHERE LOWER(h.query) != ?
+ AND LENGTH(TRIM(h.query)) >= 2
+ AND h.results_count > 0
+ GROUP BY LOWER(h.query)
+ HAVING shared_clicks >= 2
+ )
+ SELECT related_query, shared_clicks
+ FROM related
+ ORDER BY shared_clicks DESC
+ LIMIT 20
+ `).bind(normalizedQuery, thirtyDaysAgo, normalizedQuery).all();
+ for (const row of clickRows || []) {
+ if (!existingQueries.has(row.related_query)) {
+ scoreMap.set(row.related_query, (scoreMap.get(row.related_query) || 0) + row.shared_clicks);
+ }
+ }
+ } catch (error) {
+ console.warn("[RelatedSearchService] Click overlap query failed:", error);
+ }
+ try {
+ const { results: sessionRows } = await this.db.prepare(`
+ WITH target_searches AS (
+ SELECT user_id, created_at
+ FROM ai_search_history
+ WHERE LOWER(query) = ?
+ AND created_at >= ?
+ AND results_count > 0
+ AND user_id IS NOT NULL
+ ),
+ co_occurring AS (
+ SELECT LOWER(h.query) as related_query, COUNT(*) as co_count
+ FROM ai_search_history h
+ JOIN target_searches t ON h.user_id = t.user_id
+ AND ABS(h.created_at - t.created_at) <= 1800000
+ WHERE LOWER(h.query) != ?
+ AND h.results_count > 0
+ AND h.user_id IS NOT NULL
+ AND LENGTH(TRIM(h.query)) >= 2
+ GROUP BY LOWER(h.query)
+ HAVING co_count >= 2
+ )
+ SELECT related_query, co_count
+ FROM co_occurring
+ ORDER BY co_count DESC
+ LIMIT 20
+ `).bind(normalizedQuery, thirtyDaysAgo, normalizedQuery).all();
+ for (const row of sessionRows || []) {
+ if (!existingQueries.has(row.related_query)) {
+ scoreMap.set(row.related_query, (scoreMap.get(row.related_query) || 0) + row.co_count);
+ }
+ }
+ } catch (error) {
+ console.warn("[RelatedSearchService] Session co-occurrence query failed:", error);
+ }
+ const autoResults = Array.from(scoreMap.entries()).sort((a, b) => b[1] - a[1]).slice(0, limit + 5).map(([query]) => ({ query, source: "auto" }));
+ try {
+ await this.kv.put(cacheKey, JSON.stringify(autoResults), { expirationTtl: 3600 });
+ } catch {
+ }
+ return autoResults.slice(0, limit);
+ }
+ // =============================================
+ // CRUD
+ // =============================================
+ async create(sourceQuery, relatedQuery, opts) {
+ const source = opts?.source || "manual";
+ const position = opts?.position ?? 0;
+ const bidirectional = opts?.bidirectional ? 1 : 0;
+ const normalizedSource = this.normalize(sourceQuery);
+ const normalizedRelated = this.normalize(relatedQuery);
+ const id = crypto.randomUUID().replace(/-/g, "");
+ await this.db.prepare(`
+ INSERT INTO ai_search_related (id, source_query, related_query, source, position, bidirectional, enabled)
+ VALUES (?, ?, ?, ?, ?, ?, 1)
+ `).bind(id, normalizedSource, normalizedRelated, source, position, bidirectional).run();
+ if (opts?.bidirectional) {
+ const reverseId = crypto.randomUUID().replace(/-/g, "");
+ try {
+ await this.db.prepare(`
+ INSERT INTO ai_search_related (id, source_query, related_query, source, position, bidirectional, enabled)
+ VALUES (?, ?, ?, ?, ?, ?, 1)
+ `).bind(reverseId, normalizedRelated, normalizedSource, source, position, bidirectional).run();
+ } catch {
+ }
+ }
+ return {
+ id,
+ source_query: normalizedSource,
+ related_query: normalizedRelated,
+ source,
+ position,
+ bidirectional: !!opts?.bidirectional,
+ enabled: true,
+ created_at: Math.floor(Date.now() / 1e3),
+ updated_at: Math.floor(Date.now() / 1e3)
+ };
+ }
+ async update(id, fields) {
+ const setClauses = ["updated_at = unixepoch()"];
+ const params = [];
+ if (fields.related_query !== void 0) {
+ setClauses.push("related_query = ?");
+ params.push(this.normalize(fields.related_query));
+ }
+ if (fields.position !== void 0) {
+ setClauses.push("position = ?");
+ params.push(fields.position);
+ }
+ if (fields.enabled !== void 0) {
+ setClauses.push("enabled = ?");
+ params.push(fields.enabled ? 1 : 0);
+ }
+ params.push(id);
+ await this.db.prepare(`UPDATE ai_search_related SET ${setClauses.join(", ")} WHERE id = ?`).bind(...params).run();
+ return this.getById(id);
+ }
+ async delete(id) {
+ const result = await this.db.prepare("DELETE FROM ai_search_related WHERE id = ?").bind(id).run();
+ return (result?.meta?.changes ?? 0) > 0;
+ }
+ async getById(id) {
+ try {
+ const row = await this.db.prepare("SELECT * FROM ai_search_related WHERE id = ?").bind(id).first();
+ return row ? this.mapRow(row) : null;
+ } catch {
+ return null;
+ }
+ }
+ async getAll(opts) {
+ const conditions = [];
+ const params = [];
+ if (opts?.source_query) {
+ conditions.push("source_query = ?");
+ params.push(this.normalize(opts.source_query));
+ }
+ if (opts?.source) {
+ conditions.push("source = ?");
+ params.push(opts.source);
+ }
+ if (opts?.enabled !== void 0) {
+ conditions.push("enabled = ?");
+ params.push(opts.enabled ? 1 : 0);
+ }
+ const where = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
+ const limit = opts?.limit || 100;
+ const offset = opts?.offset || 0;
+ try {
+ const { results } = await this.db.prepare(`SELECT * FROM ai_search_related ${where} ORDER BY source_query ASC, position ASC LIMIT ? OFFSET ?`).bind(...params, limit, offset).all();
+ return (results || []).map((row) => this.mapRow(row));
+ } catch {
+ return [];
+ }
+ }
+ async bulkCreate(entries) {
+ let count = 0;
+ for (const entry of entries) {
+ try {
+ await this.create(entry.source_query, entry.related_query, {
+ source: entry.source,
+ position: entry.position,
+ bidirectional: entry.bidirectional
+ });
+ count++;
+ } catch {
+ }
+ }
+ return count;
+ }
+ async invalidateCache(query) {
+ if (!this.kv) return;
+ if (query) {
+ await this.kv.delete(`related:auto:${this.normalize(query)}`);
+ } else {
+ try {
+ const list = await this.kv.list({ prefix: "related:auto:" });
+ for (const key of list.keys) {
+ await this.kv.delete(key.name);
+ }
+ } catch {
+ }
+ }
+ }
+ // =============================================
+ // Helpers
+ // =============================================
+ normalize(query) {
+ return query.toLowerCase().trim();
+ }
+ mapRow(row) {
+ return {
+ id: row.id,
+ source_query: row.source_query,
+ related_query: row.related_query,
+ source: row.source,
+ position: row.position,
+ bidirectional: row.bidirectional === 1,
+ enabled: row.enabled === 1,
+ created_at: row.created_at,
+ updated_at: row.updated_at
+ };
+ }
+};
+
+// src/plugins/core-plugins/ai-search-plugin/services/ai-search.ts
+var AISearchService = class {
+ constructor(db, ai, vectorize, kv) {
+ this.db = db;
+ this.ai = ai;
+ this.vectorize = vectorize;
+ this.kv = kv;
+ if (this.ai && this.vectorize) {
+ this.customRAG = new CustomRAGService(db, ai, vectorize);
+ console.log("[AISearchService] Custom RAG initialized");
+ } else {
+ console.log("[AISearchService] Custom RAG not available, using keyword search only");
+ }
+ this.fts5Service = new FTS5Service(db);
+ console.log("[AISearchService] FTS5 service initialized");
+ this.hybridService = new HybridSearchService(this.fts5Service, this.customRAG);
+ console.log("[AISearchService] Hybrid search service initialized");
+ if (this.ai) {
+ this.queryRewriter = new QueryRewriterService(this.ai);
+ this.reranker = new RerankerService(this.ai);
+ console.log("[AISearchService] Query rewriter and reranker initialized");
+ }
+ this.synonymService = new SynonymService(db);
+ if (this.fts5Service) {
+ this.fts5Service.setSynonymService(this.synonymService);
+ }
+ this.queryRulesService = new QueryRulesService(db);
+ this.rankingPipeline = new RankingPipelineService(db);
+ if (this.kv) {
+ this.searchCache = new SearchCacheService(this.kv);
+ }
+ }
+ customRAG;
+ fts5Service;
+ hybridService;
+ queryRewriter;
+ reranker;
+ rankingPipeline;
+ synonymService;
+ queryRulesService;
+ searchCache;
+ /**
+ * Get plugin settings
+ */
+ async getSettings() {
+ try {
+ const plugin = await this.db.prepare(`SELECT settings FROM plugins WHERE id = ? LIMIT 1`).bind("ai-search").first();
+ if (!plugin || !plugin.settings) {
+ return this.getDefaultSettings();
+ }
+ return JSON.parse(plugin.settings);
+ } catch (error) {
+ console.error("Error fetching AI Search settings:", error);
+ return this.getDefaultSettings();
+ }
+ }
+ /**
+ * Get default settings
+ */
+ getDefaultSettings() {
+ return {
+ enabled: true,
+ ai_mode_enabled: true,
+ selected_collections: [],
+ dismissed_collections: [],
+ autocomplete_enabled: true,
+ cache_duration: 1,
+ results_limit: 20,
+ index_media: false,
+ query_rewriting_enabled: false,
+ reranking_enabled: true,
+ fts5_title_boost: 5,
+ fts5_slug_boost: 2,
+ fts5_body_boost: 1
+ };
+ }
+ /**
+ * Update plugin settings
+ */
+ async updateSettings(settings) {
+ const existing = await this.getSettings();
+ const updated = {
+ ...existing,
+ ...settings
+ };
+ try {
+ await this.db.prepare(`
+ UPDATE plugins
+ SET settings = ?,
+ updated_at = unixepoch()
+ WHERE id = 'ai-search'
+ `).bind(JSON.stringify(updated)).run();
+ return updated;
+ } catch (error) {
+ console.error("Error updating AI Search settings:", error);
+ throw error;
+ }
+ }
+ /**
+ * Detect new collections that aren't indexed or dismissed
+ */
+ async detectNewCollections() {
+ try {
+ const collectionsStmt = this.db.prepare(
+ "SELECT id, name, display_name, description FROM collections WHERE is_active = 1"
+ );
+ const { results: allCollections } = await collectionsStmt.all();
+ const collections = (allCollections || []).filter(
+ (col) => {
+ if (!col.name) return false;
+ const name = col.name.toLowerCase();
+ return !name.startsWith("test_") && !name.endsWith("_test") && name !== "test_collection" && !name.includes("_test_") && name !== "large_payload_test" && name !== "concurrent_test";
+ }
+ );
+ const settings = await this.getSettings();
+ const selected = settings?.selected_collections || [];
+ const dismissed = settings?.dismissed_collections || [];
+ const notifications = [];
+ for (const collection of collections || []) {
+ const collectionId = String(collection.id);
+ if (selected.includes(collectionId) || dismissed.includes(collectionId)) {
+ continue;
+ }
+ const countStmt = this.db.prepare(
+ "SELECT COUNT(*) as count FROM content WHERE collection_id = ?"
+ );
+ const countResult = await countStmt.bind(collectionId).first();
+ const itemCount = countResult?.count || 0;
+ notifications.push({
+ collection: {
+ id: collectionId,
+ name: collection.name,
+ display_name: collection.display_name,
+ description: collection.description,
+ item_count: itemCount,
+ is_indexed: false,
+ is_dismissed: false,
+ is_new: true
+ },
+ message: `New collection "${collection.display_name}" with ${itemCount} items available for indexing`
+ });
+ }
+ return notifications;
+ } catch (error) {
+ console.error("Error detecting new collections:", error);
+ return [];
+ }
+ }
+ /**
+ * Get all collections with indexing status
+ */
+ async getAllCollections() {
+ try {
+ const collectionsStmt = this.db.prepare(
+ "SELECT id, name, display_name, description FROM collections WHERE is_active = 1 ORDER BY display_name"
+ );
+ const { results: allCollections } = await collectionsStmt.all();
+ console.log("[AISearchService.getAllCollections] Raw collections from DB:", allCollections?.length || 0);
+ const firstCollection = allCollections?.[0];
+ if (firstCollection) {
+ console.log("[AISearchService.getAllCollections] Sample collection:", {
+ id: firstCollection.id,
+ name: firstCollection.name,
+ display_name: firstCollection.display_name
+ });
+ }
+ const collections = (allCollections || []).filter(
+ (col) => col.id && col.name
+ );
+ console.log("[AISearchService.getAllCollections] After filtering test collections:", collections.length);
+ console.log("[AISearchService.getAllCollections] Remaining collections:", collections.map((c) => c.name).join(", "));
+ const settings = await this.getSettings();
+ const selected = settings?.selected_collections || [];
+ const dismissed = settings?.dismissed_collections || [];
+ console.log("[AISearchService.getAllCollections] Settings:", {
+ selected_count: selected.length,
+ dismissed_count: dismissed.length,
+ selected
+ });
+ const collectionInfos = [];
+ for (const collection of collections) {
+ if (!collection.id || !collection.name) continue;
+ const collectionId = String(collection.id);
+ if (!collectionId) {
+ console.warn("[AISearchService] Skipping invalid collection:", collection);
+ continue;
+ }
+ const countStmt = this.db.prepare(
+ "SELECT COUNT(*) as count FROM content WHERE collection_id = ?"
+ );
+ const countResult = await countStmt.bind(collectionId).first();
+ const itemCount = countResult?.count || 0;
+ collectionInfos.push({
+ id: collectionId,
+ name: collection.name,
+ display_name: collection.display_name || collection.name,
+ description: collection.description,
+ item_count: itemCount,
+ is_indexed: selected.includes(collectionId),
+ is_dismissed: dismissed.includes(collectionId),
+ is_new: !selected.includes(collectionId) && !dismissed.includes(collectionId)
+ });
+ }
+ console.log("[AISearchService.getAllCollections] Returning collectionInfos:", collectionInfos.length);
+ const firstInfo = collectionInfos[0];
+ if (collectionInfos.length > 0 && firstInfo) {
+ console.log("[AISearchService.getAllCollections] First collectionInfo:", {
+ id: firstInfo.id,
+ name: firstInfo.name,
+ display_name: firstInfo.display_name,
+ item_count: firstInfo.item_count
+ });
+ }
+ return collectionInfos;
+ } catch (error) {
+ console.error("[AISearchService] Error fetching collections:", error);
+ return [];
+ }
+ }
+ /**
+ * Execute search query
+ * Supports three modes: 'ai' (semantic), 'fts5' (full-text), 'keyword' (basic)
+ */
+ async search(query) {
+ const startTime = Date.now();
+ const settings = await this.getSettings();
+ if (!settings?.enabled) {
+ return {
+ results: [],
+ total: 0,
+ query_time_ms: 0,
+ mode: query.mode
+ };
+ }
+ let originalQuery;
+ let appliedRuleId;
+ const ruleResult = await this.queryRulesService.applyRules(query.query);
+ if (ruleResult.originalQuery) {
+ originalQuery = ruleResult.originalQuery;
+ appliedRuleId = ruleResult.ruleId;
+ query = { ...query, query: ruleResult.query };
+ }
+ if (this.searchCache) {
+ const cacheKey = await this.searchCache.buildKey(query);
+ if (cacheKey) {
+ const cached = await this.searchCache.get(cacheKey);
+ if (cached) {
+ const elapsed = Date.now() - startTime;
+ const [searchId, relatedSearches2] = await Promise.all([
+ this.logSearch(query.query, query.mode, cached.results.length, elapsed, true),
+ settings.related_searches_enabled !== false ? new RelatedSearchService(this.db, this.kv).getRelatedSearches(query.query, 5).catch(() => void 0) : Promise.resolve(void 0)
+ ]);
+ return {
+ ...cached,
+ query_time_ms: elapsed,
+ search_id: searchId,
+ cached: true,
+ ...relatedSearches2 ? { related_searches: relatedSearches2 } : {},
+ // Re-attach rule metadata (not cached)
+ ...originalQuery ? { original_query: originalQuery, applied_rule_id: appliedRuleId } : {}
+ };
+ }
+ }
+ }
+ const shouldComputeFacets = query.facets && settings.facets_enabled;
+ if (shouldComputeFacets && (!settings.facet_config || settings.facet_config.length === 0)) {
+ try {
+ const facetService = new FacetService(this.db);
+ const discovered = await facetService.discoverFields();
+ const config = facetService.autoGenerateConfig(discovered);
+ if (config.length > 0) {
+ await this.updateSettings({ facet_config: config });
+ settings.facet_config = config;
+ }
+ } catch (error) {
+ console.warn("[AISearchService] Auto-generate facet config failed:", error);
+ }
+ }
+ let searchPromise;
+ if (query.mode === "hybrid") {
+ searchPromise = this.searchHybrid(query, settings);
+ } else if (query.mode === "fts5") {
+ searchPromise = this.searchFTS5(query, settings);
+ } else if (query.mode === "ai" && settings.ai_mode_enabled && this.customRAG?.isAvailable()) {
+ searchPromise = this.searchAI(query, settings);
+ } else {
+ searchPromise = this.searchKeyword(query, settings);
+ }
+ let facetPromise = null;
+ if (shouldComputeFacets && settings.facet_config && settings.facet_config.length > 0) {
+ facetPromise = this.computeFacets(query, settings);
+ }
+ const [result, facets] = await Promise.all([
+ searchPromise,
+ facetPromise || Promise.resolve(null)
+ ]);
+ if (query.filters?.custom && Object.keys(query.filters.custom).length > 0 && (query.mode === "ai" || query.mode === "hybrid")) {
+ result.results = this.filterResultsByFacets(result.results, query.filters.custom);
+ result.total = result.results.length;
+ }
+ if (facets && facets.length > 0) {
+ result.facets = facets;
+ }
+ if (shouldComputeFacets && query.mode === "ai" && result.results.length > 0 && settings.facet_config?.length) {
+ try {
+ const facetService = new FacetService(this.db);
+ const contentIds = result.results.map((r) => r.id).slice(0, 50);
+ result.facets = await facetService.computeFacetsFromIds(
+ settings.facet_config,
+ contentIds,
+ settings.facet_max_values || 20
+ );
+ } catch (error) {
+ console.warn("[AISearchService] AI mode facet computation failed:", error);
+ }
+ }
+ if (originalQuery) {
+ result.original_query = originalQuery;
+ result.applied_rule_id = appliedRuleId;
+ }
+ let finalResult;
+ try {
+ finalResult = await this.rankingPipeline.apply(result, query.query);
+ } catch (error) {
+ console.warn("[AISearchService] Ranking pipeline error (preserving original order):", error);
+ finalResult = result;
+ }
+ const cachePromise = this.searchCache && settings.cache_duration > 0 ? this.searchCache.buildKey(query).then(async (cacheKey) => {
+ if (cacheKey) {
+ const ttlSeconds = settings.cache_duration * 3600;
+ await this.searchCache.put(cacheKey, finalResult, ttlSeconds).catch((err) => {
+ console.warn("[AISearchService] Cache write failed:", err);
+ });
+ }
+ }) : Promise.resolve();
+ const relatedPromise = settings.related_searches_enabled !== false ? new RelatedSearchService(this.db, this.kv).getRelatedSearches(query.query, 5).catch(() => void 0) : Promise.resolve(void 0);
+ const [, relatedSearches] = await Promise.all([cachePromise, relatedPromise]);
+ if (relatedSearches) {
+ finalResult.related_searches = relatedSearches;
+ }
+ return finalResult;
+ }
+ /**
+ * Execute search with experiment variant overrides applied.
+ * Phase 1: flat AISearchSettings merge only (no pipeline weight overrides).
+ * Used by A/B testing to run control/treatment searches with different configs.
+ */
+ async searchWithOverrides(query, overrides) {
+ const startTime = Date.now();
+ const baseSettings = await this.getSettings();
+ if (!baseSettings?.enabled) {
+ return { results: [], total: 0, query_time_ms: 0, mode: query.mode };
+ }
+ const settings = { ...baseSettings, ...overrides };
+ let originalQuery;
+ let appliedRuleId;
+ const ruleResult = await this.queryRulesService.applyRules(query.query);
+ if (ruleResult.originalQuery) {
+ originalQuery = ruleResult.originalQuery;
+ appliedRuleId = ruleResult.ruleId;
+ query = { ...query, query: ruleResult.query };
+ }
+ let searchPromise;
+ if (query.mode === "hybrid") {
+ searchPromise = this.searchHybrid(query, settings);
+ } else if (query.mode === "fts5") {
+ searchPromise = this.searchFTS5(query, settings);
+ } else if (query.mode === "ai" && settings.ai_mode_enabled && this.customRAG?.isAvailable()) {
+ searchPromise = this.searchAI(query, settings);
+ } else {
+ searchPromise = this.searchKeyword(query, settings);
+ }
+ const result = await searchPromise;
+ if (originalQuery) {
+ result.original_query = originalQuery;
+ result.applied_rule_id = appliedRuleId;
+ }
+ try {
+ const ranked = await this.rankingPipeline.apply(result, query.query);
+ ranked.query_time_ms = Date.now() - startTime;
+ return ranked;
+ } catch {
+ result.query_time_ms = Date.now() - startTime;
+ return result;
+ }
+ }
+ /**
+ * Compute facets for the current search query.
+ * Delegates to FacetService with mode-appropriate strategy.
+ */
+ async computeFacets(query, settings) {
+ const facetService = new FacetService(this.db);
+ const config = settings.facet_config;
+ const maxValues = settings.facet_max_values || 20;
+ const collectionIds = query.filters?.collections?.length ? query.filters.collections : settings.selected_collections;
+ const activeFilters = query.filters?.custom;
+ try {
+ if (query.mode === "fts5" || query.mode === "hybrid") {
+ const matchQuery = FacetService.sanitizeFTS5Query(query.query);
+ return await facetService.computeFacetsFts(config, matchQuery, collectionIds, maxValues, activeFilters);
+ }
+ if (query.mode === "keyword") {
+ return await facetService.computeFacetsKeyword(config, query.query, collectionIds, maxValues, activeFilters);
+ }
+ return [];
+ } catch (error) {
+ console.warn("[AISearchService] Facet computation failed:", error);
+ return [];
+ }
+ }
+ /**
+ * FTS5 full-text search with BM25 ranking, stemming, and highlighting
+ */
+ async searchFTS5(query, settings) {
+ const startTime = Date.now();
+ try {
+ if (!this.fts5Service) {
+ console.warn("[AISearchService] FTS5 service not initialized, falling back to keyword search");
+ return this.searchKeyword(query, settings);
+ }
+ if (!await this.fts5Service.isAvailable()) {
+ console.warn("[AISearchService] FTS5 table not available, falling back to keyword search");
+ return this.searchKeyword(query, settings);
+ }
+ const result = await this.fts5Service.search(query, settings, {
+ titleBoost: settings.fts5_title_boost,
+ slugBoost: settings.fts5_slug_boost,
+ bodyBoost: settings.fts5_body_boost
+ });
+ const elapsed = Date.now() - startTime;
+ const searchId = await this.logSearch(query.query, "fts5", result.results.length, elapsed);
+ result.search_id = searchId;
+ return result;
+ } catch (error) {
+ console.error("[AISearchService] FTS5 search error, falling back to keyword:", error);
+ return this.searchKeyword(query, settings);
+ }
+ }
+ /**
+ * Hybrid search: FTS5 + AI combined with RRF, optional query rewriting + reranking
+ */
+ async searchHybrid(query, settings) {
+ const startTime = Date.now();
+ try {
+ if (!this.hybridService || !this.fts5Service) {
+ console.warn("[AISearchService] Hybrid service not available, falling back to keyword search");
+ return this.searchKeyword(query, settings);
+ }
+ if (!await this.fts5Service.isAvailable()) {
+ console.warn("[AISearchService] FTS5 not available for hybrid, falling back to keyword search");
+ return this.searchKeyword(query, settings);
+ }
+ let searchQuery = query;
+ const rewritingEnabled = settings.query_rewriting_enabled ?? false;
+ if (rewritingEnabled && this.queryRewriter && QueryRewriterService.shouldRewrite(query.query)) {
+ const rewritten = await this.queryRewriter.rewrite(query.query);
+ if (rewritten !== query.query) {
+ console.log(`[AISearchService] Query rewritten: "${query.query}" \u2192 "${rewritten}"`);
+ searchQuery = { ...query, query: rewritten };
+ }
+ }
+ let result = await this.hybridService.search(searchQuery, settings);
+ const elapsed = Date.now() - startTime;
+ const searchId = await this.logSearch(query.query, "hybrid", result.results.length, elapsed);
+ result.search_id = searchId;
+ return result;
+ } catch (error) {
+ console.error("[AISearchService] Hybrid search error, falling back to keyword:", error);
+ return this.searchKeyword(query, settings);
+ }
+ }
+ /**
+ * AI-powered semantic search using Custom RAG
+ */
+ async searchAI(query, settings) {
+ const startTime = Date.now();
+ try {
+ if (!this.customRAG) {
+ console.warn("[AISearchService] CustomRAG not available, falling back to keyword search");
+ return this.searchKeyword(query, settings);
+ }
+ const result = await this.customRAG.search(query, settings);
+ const elapsed = Date.now() - startTime;
+ const searchId = await this.logSearch(query.query, "ai", result.results.length, elapsed);
+ result.search_id = searchId;
+ return result;
+ } catch (error) {
+ console.error("[AISearchService] AI search error, falling back to keyword:", error);
+ return this.searchKeyword(query, settings);
+ }
+ }
+ /**
+ * Traditional keyword search
+ */
+ async searchKeyword(query, settings) {
+ const startTime = Date.now();
+ try {
+ const conditions = [];
+ const params = [];
+ if (query.query) {
+ conditions.push("(c.title LIKE ? OR c.slug LIKE ? OR c.data LIKE ?)");
+ const searchTerm = `%${query.query}%`;
+ params.push(searchTerm, searchTerm, searchTerm);
+ }
+ if (query.filters?.collections && query.filters.collections.length > 0) {
+ const placeholders = query.filters.collections.map(() => "?").join(",");
+ conditions.push(`c.collection_id IN (${placeholders})`);
+ params.push(...query.filters.collections);
+ } else if (settings.selected_collections.length > 0) {
+ const placeholders = settings.selected_collections.map(() => "?").join(",");
+ conditions.push(`c.collection_id IN (${placeholders})`);
+ params.push(...settings.selected_collections);
+ }
+ if (query.filters?.status && query.filters.status.length > 0) {
+ const placeholders = query.filters.status.map(() => "?").join(",");
+ conditions.push(`c.status IN (${placeholders})`);
+ params.push(...query.filters.status);
+ } else {
+ conditions.push("c.status != 'deleted'");
+ }
+ if (query.filters?.dateRange) {
+ const field = query.filters.dateRange.field || "created_at";
+ if (query.filters.dateRange.start) {
+ conditions.push(`c.${field} >= ?`);
+ params.push(query.filters.dateRange.start.getTime());
+ }
+ if (query.filters.dateRange.end) {
+ conditions.push(`c.${field} <= ?`);
+ params.push(query.filters.dateRange.end.getTime());
+ }
+ }
+ if (query.filters?.author) {
+ conditions.push("c.author_id = ?");
+ params.push(query.filters.author);
+ }
+ if (query.filters?.custom && settings.facet_config?.length) {
+ const { conditions: filterConditions, params: filterParams } = FacetService.buildFacetFilterSQL(
+ query.filters.custom,
+ settings.facet_config
+ );
+ conditions.push(...filterConditions);
+ params.push(...filterParams);
+ }
+ const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(" AND ")}` : "";
+ const countStmt = this.db.prepare(`
+ SELECT COUNT(*) as count
+ FROM content c
+ ${whereClause}
+ `);
+ const countResult = await countStmt.bind(...params).first();
+ const total = countResult?.count || 0;
+ const limit = query.limit || settings.results_limit;
+ const offset = query.offset || 0;
+ const resultsStmt = this.db.prepare(`
+ SELECT
+ c.id, c.title, c.slug, c.collection_id, c.status,
+ c.created_at, c.updated_at, c.author_id, c.data,
+ col.name as collection_name, col.display_name as collection_display_name,
+ u.email as author_email
+ FROM content c
+ JOIN collections col ON c.collection_id = col.id
+ LEFT JOIN users u ON c.author_id = u.id
+ ${whereClause}
+ ORDER BY c.updated_at DESC
+ LIMIT ? OFFSET ?
+ `);
+ const { results } = await resultsStmt.bind(...params, limit, offset).all();
+ const searchResults = (results || []).map((row) => {
+ const snippet = this.extractSnippet(row.data, query.query);
+ const titleHighlight = this.highlightText(row.title || "Untitled", query.query);
+ return {
+ id: String(row.id),
+ title: row.title || "Untitled",
+ slug: row.slug || "",
+ collection_id: String(row.collection_id),
+ collection_name: row.collection_display_name || row.collection_name,
+ snippet,
+ highlights: {
+ title: titleHighlight,
+ body: snippet
+ },
+ status: row.status,
+ created_at: Number(row.created_at),
+ updated_at: Number(row.updated_at),
+ author_name: row.author_email
+ };
+ });
+ const queryTime = Date.now() - startTime;
+ const searchId = await this.logSearch(query.query, query.mode, searchResults.length, queryTime);
+ return {
+ results: searchResults,
+ total,
+ query_time_ms: queryTime,
+ mode: query.mode,
+ search_id: searchId
+ };
+ } catch (error) {
+ console.error("Keyword search error:", error);
+ return {
+ results: [],
+ total: 0,
+ query_time_ms: Date.now() - startTime,
+ mode: query.mode
+ };
+ }
+ }
+ /**
+ * Extract snippet from content data
+ * Pulls human-readable text from JSON data fields instead of raw JSON
+ */
+ extractSnippet(data, query) {
+ try {
+ const parsed = typeof data === "string" ? JSON.parse(data) : data;
+ const textParts = [];
+ const textFields = ["description", "content", "body", "text", "summary", "excerpt"];
+ for (const field of textFields) {
+ if (parsed[field] && typeof parsed[field] === "string") {
+ textParts.push(parsed[field]);
+ }
+ }
+ if (textParts.length === 0) {
+ for (const value of Object.values(parsed)) {
+ if (typeof value === "string" && value.length > 20) {
+ textParts.push(value);
+ }
+ }
+ }
+ const text = textParts.join(" ").replace(/\s+/g, " ").trim();
+ if (!text) {
+ return "No preview available";
+ }
+ const queryLower = query.toLowerCase();
+ const textLower = text.toLowerCase();
+ const index = textLower.indexOf(queryLower);
+ if (index === -1) {
+ return text.substring(0, 200) + (text.length > 200 ? "..." : "");
+ }
+ const start = Math.max(0, index - 80);
+ const end = Math.min(text.length, index + query.length + 120);
+ const prefix = start > 0 ? "..." : "";
+ const suffix = end < text.length ? "..." : "";
+ const excerpt = text.substring(start, end);
+ return prefix + this.highlightText(excerpt, query) + suffix;
+ } catch {
+ return data.substring(0, 200) + "...";
+ }
+ }
+ /**
+ * Highlight query terms in text with
tags
+ * Case-insensitive, highlights all occurrences
+ */
+ highlightText(text, query) {
+ if (!text || !query) return text;
+ try {
+ const words = query.trim().split(/\s+/).filter((w) => w.length > 1);
+ if (words.length === 0) return text;
+ const escaped = words.map((w) => w.replace(/[.*+?^${}()|[\]\\]/g, "\\$&"));
+ const pattern = new RegExp(`(${escaped.join("|")})`, "gi");
+ return text.replace(pattern, "$1 ");
+ } catch {
+ return text;
+ }
+ }
+ /**
+ * Filter search results in-memory by active facet selections.
+ * Used for AI/hybrid modes where SQL-level filtering isn't possible.
+ */
+ filterResultsByFacets(results, customFilters) {
+ if (!customFilters || Object.keys(customFilters).length === 0) return results;
+ return results.filter((result) => {
+ for (const [field, values] of Object.entries(customFilters)) {
+ if (!values || Array.isArray(values) && values.length === 0) continue;
+ const valueArr = Array.isArray(values) ? values : [values];
+ if (valueArr.length === 0) continue;
+ switch (field) {
+ case "collection_name":
+ if (!valueArr.includes(result.collection_name)) return false;
+ break;
+ case "status":
+ if (!valueArr.includes(result.status)) return false;
+ break;
+ case "author":
+ if (!result.author_name || !valueArr.includes(result.author_name)) return false;
+ break;
+ }
+ }
+ return true;
+ });
+ }
+ /**
+ * Get search suggestions (autocomplete)
+ * Routes to trending queries (empty/short input) or prefix suggestions (2+ chars)
+ */
+ async getSearchSuggestions(partial) {
+ try {
+ const settings = await this.getSettings();
+ if (!settings?.autocomplete_enabled) {
+ return [];
+ }
+ const trimmed = partial.trim();
+ if (trimmed.length < 2) {
+ return this.getTrendingQueries();
+ }
+ return this.getPrefixSuggestions(trimmed);
+ } catch (error) {
+ console.error("Error getting suggestions:", error);
+ return [];
+ }
+ }
+ /**
+ * Get trending queries using TrendingSearchService (time-decay scoring + KV cache).
+ * Delegates to the dedicated service for consistent behavior across suggest and trending endpoints.
+ */
+ async getTrendingQueries() {
+ try {
+ const service = new TrendingSearchService(this.db, this.kv);
+ const result = await service.getTrending(10, 7);
+ return result.items.map((r) => r.query);
+ } catch (error) {
+ console.log("[AISearchService] Trending queries unavailable:", error);
+ return [];
+ }
+ }
+ /**
+ * Get prefix suggestions by blending popular query prefixes (30d) + FTS5 content title prefixes.
+ * Popular queries appear first (real user intent), content titles fill remaining slots.
+ */
+ async getPrefixSuggestions(prefix) {
+ const [popularQueries, contentTitles] = await Promise.all([
+ this.getPopularQueryPrefixes(prefix, 5),
+ this.getContentTitlePrefixes(prefix, 5)
+ ]);
+ const seen = new Set(popularQueries.map((q) => q.toLowerCase()));
+ const merged = [...popularQueries];
+ for (const title of contentTitles) {
+ if (!seen.has(title.toLowerCase())) {
+ merged.push(title);
+ seen.add(title.toLowerCase());
+ }
+ if (merged.length >= 10) break;
+ }
+ return merged;
+ }
+ /**
+ * Popular query prefixes from search history (last 30 days).
+ * Ranked by frequency, excludes zero-result queries.
+ */
+ async getPopularQueryPrefixes(prefix, limit) {
+ try {
+ const thirtyDaysAgo = Date.now() - 30 * 24 * 60 * 60 * 1e3;
+ const stmt = this.db.prepare(`
+ SELECT query, COUNT(*) as cnt, AVG(results_count) as avg_res
+ FROM ai_search_history
+ WHERE created_at >= ? AND LOWER(query) LIKE ?
+ GROUP BY LOWER(query)
+ HAVING avg_res >= 0.5
+ ORDER BY cnt DESC
+ LIMIT ?
+ `);
+ const { results } = await stmt.bind(thirtyDaysAgo, `${prefix.toLowerCase()}%`, limit).all();
+ return (results || []).map((r) => r.query).filter(Boolean);
+ } catch (error) {
+ console.log("[AISearchService] Popular query prefixes unavailable:", error);
+ return [];
+ }
+ }
+ /**
+ * Content title prefixes via FTS5 prefix matching.
+ * Falls back to ai_search_index LIKE if FTS5 is unavailable.
+ */
+ async getContentTitlePrefixes(prefix, limit) {
+ try {
+ const sanitized = prefix.replace(/[^\w\s]/g, "").trim();
+ if (!sanitized) return [];
+ const stmt = this.db.prepare(`
+ SELECT DISTINCT title FROM content_fts
+ WHERE content_fts MATCH ?
+ ORDER BY bm25(content_fts, 5.0, 2.0, 1.0)
+ LIMIT ?
+ `);
+ const { results } = await stmt.bind(`${sanitized}*`, limit).all();
+ return (results || []).map((r) => r.title).filter(Boolean);
+ } catch {
+ }
+ try {
+ const stmt = this.db.prepare(`
+ SELECT DISTINCT title FROM ai_search_index
+ WHERE LOWER(title) LIKE ?
+ ORDER BY title
+ LIMIT ?
+ `);
+ const { results } = await stmt.bind(`${prefix.toLowerCase()}%`, limit).all();
+ return (results || []).map((r) => r.title).filter(Boolean);
+ } catch {
+ return [];
+ }
+ }
+ /**
+ * Log search query to history, returns the generated search_id
+ */
+ async logSearch(query, mode, resultsCount, responseTimeMs, cached) {
+ try {
+ const result = await this.db.prepare(`
+ INSERT INTO ai_search_history (query, mode, results_count, response_time_ms, cached, created_at)
+ VALUES (?, ?, ?, ?, ?, ?)
+ `).bind(query, mode, resultsCount, responseTimeMs ?? null, cached ? 1 : 0, Date.now()).run();
+ const rowId = result?.meta?.last_row_id;
+ return rowId ? String(rowId) : void 0;
+ } catch (error) {
+ console.error("Error logging search:", error);
+ return void 0;
+ }
+ }
+ /**
+ * Get search analytics
+ */
+ async getSearchAnalytics() {
+ try {
+ const totalStmt = this.db.prepare(`
+ SELECT COUNT(*) as count
+ FROM ai_search_history
+ WHERE created_at >= ?
+ `);
+ const thirtyDaysAgo = Date.now() - 30 * 24 * 60 * 60 * 1e3;
+ const totalResult = await totalStmt.bind(thirtyDaysAgo).first();
+ const modeStmt = this.db.prepare(`
+ SELECT mode, COUNT(*) as count
+ FROM ai_search_history
+ WHERE created_at >= ?
+ GROUP BY mode
+ `);
+ const { results: modeResults } = await modeStmt.bind(thirtyDaysAgo).all();
+ const aiCount = modeResults?.find((r) => r.mode === "ai")?.count || 0;
+ const keywordCount = modeResults?.find((r) => r.mode === "keyword")?.count || 0;
+ const fts5Count = modeResults?.find((r) => r.mode === "fts5")?.count || 0;
+ const hybridCount = modeResults?.find((r) => r.mode === "hybrid")?.count || 0;
+ const popularStmt = this.db.prepare(`
+ SELECT query, COUNT(*) as count
+ FROM ai_search_history
+ WHERE created_at >= ?
+ GROUP BY query
+ ORDER BY count DESC
+ LIMIT 10
+ `);
+ const { results: popularResults } = await popularStmt.bind(thirtyDaysAgo).all();
+ return {
+ total_queries: totalResult?.count || 0,
+ ai_queries: aiCount,
+ keyword_queries: keywordCount,
+ fts5_queries: fts5Count,
+ hybrid_queries: hybridCount,
+ popular_queries: (popularResults || []).map((r) => ({
+ query: r.query,
+ count: r.count
+ })),
+ average_query_time: 0
+ // TODO: Track query times
+ };
+ } catch (error) {
+ console.error("Error getting analytics:", error);
+ return {
+ total_queries: 0,
+ ai_queries: 0,
+ keyword_queries: 0,
+ fts5_queries: 0,
+ hybrid_queries: 0,
+ popular_queries: [],
+ average_query_time: 0
+ };
+ }
+ }
+ /**
+ * Get extended analytics for the Analytics tab
+ */
+ async getAnalyticsExtended() {
+ const thirtyDaysAgo = Date.now() - 30 * 24 * 60 * 60 * 1e3;
+ const todayStart = /* @__PURE__ */ new Date();
+ todayStart.setHours(0, 0, 0, 0);
+ const todayStartMs = todayStart.getTime();
+ try {
+ const [
+ totalResult,
+ todayResult,
+ modeResults,
+ avgResults,
+ zeroCountResult,
+ avgTimeResult,
+ popularResults,
+ zeroResultResults,
+ recentResults,
+ dailyResults,
+ // Click analytics
+ clickCountResult,
+ avgClickPosResult,
+ ctrOverTimeResults,
+ mostClickedResults,
+ noClickResults,
+ // Facet analytics
+ facetClickCountResult,
+ topFacetFieldsResult,
+ topFacetValuesResult,
+ facetClicksOverTimeResult
+ ] = await Promise.all([
+ // Total queries (30 days)
+ this.db.prepare("SELECT COUNT(*) as count FROM ai_search_history WHERE created_at >= ?").bind(thirtyDaysAgo).first(),
+ // Queries today
+ this.db.prepare("SELECT COUNT(*) as count FROM ai_search_history WHERE created_at >= ?").bind(todayStartMs).first(),
+ // Mode breakdown
+ this.db.prepare("SELECT mode, COUNT(*) as count FROM ai_search_history WHERE created_at >= ? GROUP BY mode").bind(thirtyDaysAgo).all(),
+ // Average results per query
+ this.db.prepare("SELECT AVG(results_count) as avg_results FROM ai_search_history WHERE created_at >= ?").bind(thirtyDaysAgo).first(),
+ // Zero result count
+ this.db.prepare("SELECT COUNT(*) as count FROM ai_search_history WHERE created_at >= ? AND results_count = 0").bind(thirtyDaysAgo).first(),
+ // Average response time
+ this.db.prepare("SELECT AVG(response_time_ms) as avg_time FROM ai_search_history WHERE created_at >= ? AND response_time_ms IS NOT NULL").bind(thirtyDaysAgo).first(),
+ // Popular queries (top 15)
+ this.db.prepare("SELECT query, COUNT(*) as count FROM ai_search_history WHERE created_at >= ? GROUP BY query ORDER BY count DESC LIMIT 15").bind(thirtyDaysAgo).all(),
+ // Zero-result queries (top 20)
+ this.db.prepare("SELECT query, COUNT(*) as count FROM ai_search_history WHERE created_at >= ? AND results_count = 0 GROUP BY query ORDER BY count DESC LIMIT 20").bind(thirtyDaysAgo).all(),
+ // Recent queries (last 25)
+ this.db.prepare("SELECT query, mode, results_count, response_time_ms, created_at FROM ai_search_history ORDER BY created_at DESC LIMIT 25").all(),
+ // Daily counts for last 30 days
+ this.db.prepare(`
+ SELECT date(created_at / 1000, 'unixepoch') as date, COUNT(*) as count
+ FROM ai_search_history
+ WHERE created_at >= ?
+ GROUP BY date(created_at / 1000, 'unixepoch')
+ ORDER BY date ASC
+ `).bind(thirtyDaysAgo).all(),
+ // Click analytics: total clicks (30 days)
+ this.db.prepare("SELECT COUNT(*) as count FROM ai_search_clicks WHERE created_at > datetime('now', '-30 days')").first().catch(() => ({ count: 0 })),
+ // Click analytics: average click position (30 days)
+ this.db.prepare("SELECT AVG(click_position) as avg_pos FROM ai_search_clicks WHERE created_at > datetime('now', '-30 days')").first().catch(() => ({ avg_pos: null })),
+ // Click analytics: CTR over time (daily, 30 days)
+ this.db.prepare(`
+ SELECT
+ date(h.created_at / 1000, 'unixepoch') as date,
+ COUNT(DISTINCT h.id) as searches,
+ COUNT(c.id) as clicks
+ FROM ai_search_history h
+ LEFT JOIN ai_search_clicks c ON c.search_id = h.id
+ WHERE h.created_at >= ?
+ GROUP BY date(h.created_at / 1000, 'unixepoch')
+ ORDER BY date ASC
+ `).bind(thirtyDaysAgo).all().catch(() => ({ results: [] })),
+ // Click analytics: most clicked content (top 20)
+ this.db.prepare(`
+ SELECT clicked_content_id as content_id, clicked_content_title as content_title, COUNT(*) as click_count
+ FROM ai_search_clicks
+ WHERE created_at > datetime('now', '-30 days')
+ GROUP BY clicked_content_id
+ ORDER BY click_count DESC
+ LIMIT 20
+ `).all().catch(() => ({ results: [] })),
+ // Click analytics: searches with no clicks (top 20)
+ this.db.prepare(`
+ SELECT h.query, COUNT(DISTINCT h.id) as search_count, CAST(AVG(h.results_count) AS INTEGER) as results_count_avg
+ FROM ai_search_history h
+ LEFT JOIN ai_search_clicks c ON c.search_id = h.id
+ WHERE h.created_at >= ?
+ AND h.results_count > 0
+ AND c.id IS NULL
+ GROUP BY h.query
+ ORDER BY search_count DESC
+ LIMIT 20
+ `).bind(thirtyDaysAgo).all().catch(() => ({ results: [] })),
+ // Facet analytics: total facet clicks (30 days)
+ this.db.prepare("SELECT COUNT(*) as count FROM ai_search_facet_clicks WHERE created_at > datetime('now', '-30 days')").first().catch(() => ({ count: 0 })),
+ // Facet analytics: top facet fields by click count (30 days)
+ this.db.prepare(`
+ SELECT facet_field, COUNT(*) as click_count
+ FROM ai_search_facet_clicks
+ WHERE created_at > datetime('now', '-30 days')
+ GROUP BY facet_field
+ ORDER BY click_count DESC
+ LIMIT 10
+ `).all().catch(() => ({ results: [] })),
+ // Facet analytics: top facet values by click count (30 days)
+ this.db.prepare(`
+ SELECT facet_field, facet_value, COUNT(*) as click_count
+ FROM ai_search_facet_clicks
+ WHERE created_at > datetime('now', '-30 days')
+ GROUP BY facet_field, facet_value
+ ORDER BY click_count DESC
+ LIMIT 15
+ `).all().catch(() => ({ results: [] })),
+ // Facet analytics: facet clicks over time (daily, 30 days)
+ this.db.prepare(`
+ SELECT date(created_at) as date, COUNT(*) as count
+ FROM ai_search_facet_clicks
+ WHERE created_at > datetime('now', '-30 days')
+ GROUP BY date(created_at)
+ ORDER BY date ASC
+ `).all().catch(() => ({ results: [] }))
+ ]);
+ const totalQueries = totalResult?.count || 0;
+ const zeroCount = zeroCountResult?.count || 0;
+ const modes = modeResults?.results || [];
+ const totalClicks = clickCountResult?.count || 0;
+ const avgClickPos = avgClickPosResult?.avg_pos;
+ const ctrRaw = ctrOverTimeResults?.results || [];
+ const ctrOverTime = ctrRaw.map((r) => ({
+ date: r.date,
+ searches: r.searches,
+ clicks: r.clicks,
+ ctr: r.searches > 0 ? Math.round(r.clicks / r.searches * 1e3) / 10 : 0
+ }));
+ return {
+ total_queries: totalQueries,
+ queries_today: todayResult?.count || 0,
+ ai_queries: modes.find((r) => r.mode === "ai")?.count || 0,
+ keyword_queries: modes.find((r) => r.mode === "keyword")?.count || 0,
+ fts5_queries: modes.find((r) => r.mode === "fts5")?.count || 0,
+ hybrid_queries: modes.find((r) => r.mode === "hybrid")?.count || 0,
+ avg_results_per_query: Math.round((avgResults?.avg_results ?? 0) * 10) / 10,
+ zero_result_rate: totalQueries > 0 ? Math.round(zeroCount / totalQueries * 1e3) / 10 : 0,
+ avg_response_time_ms: Math.round(avgTimeResult?.avg_time ?? 0),
+ popular_queries: (popularResults?.results || []).map((r) => ({ query: r.query, count: r.count })),
+ zero_result_queries: (zeroResultResults?.results || []).map((r) => ({ query: r.query, count: r.count })),
+ recent_queries: (recentResults?.results || []).map((r) => ({
+ query: r.query,
+ mode: r.mode,
+ results_count: r.results_count,
+ response_time_ms: r.response_time_ms,
+ created_at: r.created_at
+ })),
+ daily_counts: (dailyResults?.results || []).map((r) => ({ date: r.date, count: r.count })),
+ // Click analytics
+ total_clicks_30d: totalClicks,
+ ctr_30d: totalQueries > 0 ? Math.round(totalClicks / totalQueries * 1e3) / 10 : 0,
+ avg_click_position_30d: avgClickPos != null ? Math.round(avgClickPos * 10) / 10 : 0,
+ ctr_over_time: ctrOverTime,
+ most_clicked_content: (mostClickedResults?.results || []).map((r) => ({
+ content_id: r.content_id,
+ content_title: r.content_title || "Untitled",
+ click_count: r.click_count
+ })),
+ no_click_searches: (noClickResults?.results || []).map((r) => ({
+ query: r.query,
+ search_count: r.search_count,
+ results_count_avg: r.results_count_avg
+ })),
+ // Facet analytics
+ total_facet_clicks_30d: facetClickCountResult?.count || 0,
+ top_facet_fields: (topFacetFieldsResult?.results || []).map((r) => ({
+ facet_field: r.facet_field,
+ click_count: r.click_count
+ })),
+ top_facet_values: (topFacetValuesResult?.results || []).map((r) => ({
+ facet_field: r.facet_field,
+ facet_value: r.facet_value,
+ click_count: r.click_count
+ })),
+ facet_clicks_over_time: (facetClicksOverTimeResult?.results || []).map((r) => ({
+ date: r.date,
+ count: r.count
+ }))
+ };
+ } catch (error) {
+ console.error("Error getting extended analytics:", error);
+ return {
+ total_queries: 0,
+ queries_today: 0,
+ ai_queries: 0,
+ keyword_queries: 0,
+ fts5_queries: 0,
+ hybrid_queries: 0,
+ avg_results_per_query: 0,
+ zero_result_rate: 0,
+ avg_response_time_ms: 0,
+ popular_queries: [],
+ zero_result_queries: [],
+ recent_queries: [],
+ daily_counts: [],
+ total_clicks_30d: 0,
+ ctr_30d: 0,
+ avg_click_position_30d: 0,
+ ctr_over_time: [],
+ most_clicked_content: [],
+ no_click_searches: [],
+ total_facet_clicks_30d: 0,
+ top_facet_fields: [],
+ top_facet_values: [],
+ facet_clicks_over_time: []
+ };
+ }
+ }
+ /**
+ * Verify Custom RAG is available
+ */
+ verifyBinding() {
+ return this.customRAG?.isAvailable() ?? false;
+ }
+ /**
+ * Get Custom RAG service instance (for indexer)
+ */
+ getCustomRAG() {
+ return this.customRAG;
+ }
+ /**
+ * Get FTS5 service instance (for content sync and admin operations)
+ */
+ getFTS5Service() {
+ return this.fts5Service;
+ }
+ /**
+ * Get ranking pipeline service instance (for admin routes)
+ */
+ getRankingPipeline() {
+ return this.rankingPipeline;
+ }
+ /**
+ * Get synonym service instance (for admin routes)
+ */
+ getSynonymService() {
+ return this.synonymService;
+ }
+ /**
+ * Get query rules service instance (for admin routes)
+ */
+ getQueryRulesService() {
+ return this.queryRulesService;
+ }
+ /**
+ * Get search cache service instance (for cache invalidation from content CRUD hooks)
+ */
+ getSearchCache() {
+ return this.searchCache;
+ }
+};
+
+// src/plugins/core-plugins/ai-search-plugin/services/indexer.ts
+var IndexManager = class {
+ constructor(db, ai, vectorize) {
+ this.db = db;
+ this.ai = ai;
+ this.vectorize = vectorize;
+ this.fts5Service = new FTS5Service(db);
+ if (this.ai && this.vectorize) {
+ this.customRAG = new CustomRAGService(db, ai, vectorize);
+ console.log("[IndexManager] Custom RAG initialized");
+ }
+ }
+ customRAG;
+ fts5Service;
+ /**
+ * Index all content items within a collection using Custom RAG
+ */
+ async indexCollection(collectionId) {
+ try {
+ const collectionStmt = this.db.prepare(
+ "SELECT id, name, display_name FROM collections WHERE id = ?"
+ );
+ const collection = await collectionStmt.bind(collectionId).first();
+ if (!collection) {
+ throw new Error(`Collection ${collectionId} not found`);
+ }
+ const countResult = await this.db.prepare(
+ "SELECT COUNT(*) as cnt FROM content WHERE collection_id = ? AND status != 'deleted'"
+ ).bind(collectionId).first();
+ const totalItems = countResult?.cnt || 0;
+ await this.updateIndexStatus(collectionId, {
+ collection_id: collectionId,
+ collection_name: collection.display_name,
+ total_items: totalItems,
+ indexed_items: 0,
+ status: "indexing"
+ });
+ if (this.customRAG?.isAvailable()) {
+ console.log(`[IndexManager] Using Custom RAG to index collection ${collectionId}`);
+ let highWaterMark = 0;
+ let result;
+ try {
+ result = await this.customRAG.indexCollection(
+ collectionId,
+ async (phase, processed, total) => {
+ let itemProgress;
+ if (phase === "chunking") {
+ itemProgress = 0;
+ } else if (phase === "embedding") {
+ itemProgress = Math.round(processed / Math.max(total, 1) * totalItems * 0.9);
+ } else {
+ itemProgress = Math.round(totalItems * 0.9 + processed / Math.max(total, 1) * totalItems * 0.1);
+ }
+ itemProgress = Math.min(totalItems, itemProgress);
+ if (itemProgress > highWaterMark) {
+ highWaterMark = itemProgress;
+ }
+ await this.updateIndexStatus(collectionId, {
+ collection_id: collectionId,
+ collection_name: collection.display_name,
+ total_items: totalItems,
+ indexed_items: highWaterMark,
+ status: "indexing"
+ });
+ }
+ );
+ } catch (ragError) {
+ console.error(`[IndexManager] CustomRAG indexing failed for ${collectionId}:`, ragError);
+ await this.updateIndexStatus(collectionId, {
+ collection_id: collectionId,
+ collection_name: collection.display_name,
+ total_items: totalItems,
+ indexed_items: highWaterMark,
+ status: "error",
+ error_message: ragError instanceof Error ? ragError.message : String(ragError)
+ });
+ return {
+ collection_id: collectionId,
+ collection_name: collection.display_name,
+ total_items: totalItems,
+ indexed_items: highWaterMark,
+ status: "error",
+ error_message: ragError instanceof Error ? ragError.message : String(ragError)
+ };
+ }
+ const finalStatus = {
+ collection_id: collectionId,
+ collection_name: collection.display_name,
+ total_items: result.total_items,
+ indexed_items: result.total_items,
+ // Use total_items, not chunks, for final display
+ last_sync_at: Date.now(),
+ status: result.errors > 0 ? "error" : "completed",
+ error_message: result.errors > 0 ? `${result.errors} errors during indexing` : void 0
+ };
+ await this.updateIndexStatus(collectionId, finalStatus);
+ return finalStatus;
+ }
+ console.log(`[IndexManager] Using FTS5 to index collection ${collectionId}`);
+ const fts5Available = await this.fts5Service.isAvailable();
+ if (fts5Available) {
+ const fts5Result = await this.fts5Service.indexCollection(
+ collectionId,
+ async (indexed, total) => {
+ await this.updateIndexStatus(collectionId, {
+ collection_id: collectionId,
+ collection_name: collection.display_name,
+ total_items: total,
+ indexed_items: indexed,
+ status: "indexing"
+ });
+ }
+ );
+ const fallbackStatus2 = {
+ collection_id: collectionId,
+ collection_name: collection.display_name,
+ total_items: fts5Result.total_items,
+ indexed_items: fts5Result.indexed_items,
+ last_sync_at: Date.now(),
+ status: fts5Result.errors > 0 ? "error" : "completed",
+ error_message: fts5Result.errors > 0 ? `${fts5Result.errors} errors during FTS5 indexing` : void 0
+ };
+ await this.updateIndexStatus(collectionId, fallbackStatus2);
+ return fallbackStatus2;
+ }
+ console.warn(`[IndexManager] No FTS5 available, counting content items for ${collectionId}`);
+ const fallbackCount = await this.db.prepare(
+ "SELECT COUNT(*) as cnt FROM content WHERE collection_id = ?"
+ ).bind(collectionId).first();
+ const fallbackStatus = {
+ collection_id: collectionId,
+ collection_name: collection.display_name,
+ total_items: fallbackCount?.cnt || 0,
+ indexed_items: 0,
+ last_sync_at: Date.now(),
+ status: "completed",
+ error_message: "No search index available (Vectorize and FTS5 both unavailable)"
+ };
+ await this.updateIndexStatus(collectionId, fallbackStatus);
+ return fallbackStatus;
+ } catch (error) {
+ console.error(`[IndexManager] Error indexing collection ${collectionId}:`, error);
+ const errorStatus = {
+ collection_id: collectionId,
+ collection_name: "Unknown",
+ total_items: 0,
+ indexed_items: 0,
+ status: "error",
+ error_message: error instanceof Error ? error.message : String(error)
+ };
+ await this.updateIndexStatus(collectionId, errorStatus);
+ return errorStatus;
+ }
+ }
+ /**
+ * Index a single content item
+ */
+ async indexContentItem(item, collectionId) {
+ try {
+ let parsedData = {};
+ try {
+ parsedData = typeof item.data === "string" ? JSON.parse(item.data) : item.data;
+ } catch {
+ parsedData = {};
+ }
+ const document = {
+ id: `content_${item.id}`,
+ title: item.title || "Untitled",
+ slug: item.slug || "",
+ content: this.extractSearchableText(parsedData),
+ metadata: {
+ collection_id: collectionId,
+ collection_name: item.collection_name,
+ collection_display_name: item.collection_display_name,
+ status: item.status,
+ created_at: item.created_at,
+ updated_at: item.updated_at,
+ author_id: item.author_id
+ }
+ };
+ console.log(`Indexed content item: ${item.id}`);
+ } catch (error) {
+ console.error(`Error indexing content item ${item.id}:`, error);
+ throw error;
+ }
+ }
+ /**
+ * Extract searchable text from content data
+ */
+ extractSearchableText(data) {
+ const parts = [];
+ if (data.title) parts.push(String(data.title));
+ if (data.name) parts.push(String(data.name));
+ if (data.description) parts.push(String(data.description));
+ if (data.content) parts.push(String(data.content));
+ if (data.body) parts.push(String(data.body));
+ if (data.text) parts.push(String(data.text));
+ const extractStrings = (obj) => {
+ if (typeof obj === "string") {
+ parts.push(obj);
+ } else if (Array.isArray(obj)) {
+ obj.forEach(extractStrings);
+ } else if (obj && typeof obj === "object") {
+ Object.values(obj).forEach(extractStrings);
+ }
+ };
+ extractStrings(data);
+ return parts.join(" ");
+ }
+ /**
+ * Update a single content item in the index
+ */
+ async updateIndex(collectionId, contentId) {
+ try {
+ const stmt = this.db.prepare(`
+ SELECT
+ c.id, c.title, c.slug, c.data, c.status,
+ c.created_at, c.updated_at, c.author_id,
+ col.name as collection_name, col.display_name as collection_display_name
+ FROM content c
+ JOIN collections col ON c.collection_id = col.id
+ WHERE c.id = ? AND c.collection_id = ?
+ `);
+ const item = await stmt.bind(contentId, collectionId).first();
+ if (!item) {
+ throw new Error(`Content item ${contentId} not found`);
+ }
+ await this.indexContentItem(item, String(collectionId));
+ const status = await this.getIndexStatus(String(collectionId));
+ if (status) {
+ await this.updateIndexStatus(String(collectionId), {
+ ...status,
+ last_sync_at: Date.now()
+ });
+ }
+ } catch (error) {
+ console.error(`Error updating index for content ${contentId}:`, error);
+ throw error;
+ }
+ }
+ /**
+ * Remove a content item from the index using Custom RAG
+ */
+ async removeFromIndex(collectionId, contentId) {
+ try {
+ if (this.customRAG?.isAvailable()) {
+ console.log(`[IndexManager] Removing content ${contentId} from index`);
+ await this.customRAG.removeContentFromIndex(contentId);
+ } else {
+ console.warn(`[IndexManager] Custom RAG not available, skipping removal for ${contentId}`);
+ }
+ } catch (error) {
+ console.error(`[IndexManager] Error removing content ${contentId} from index:`, error);
+ throw error;
+ }
+ }
+ /**
+ * Get indexing status for a collection
+ */
+ async getIndexStatus(collectionId) {
+ try {
+ const stmt = this.db.prepare(
+ "SELECT * FROM ai_search_index_meta WHERE collection_id = ?"
+ );
+ const result = await stmt.bind(collectionId).first();
+ if (!result) {
+ return null;
+ }
+ return {
+ collection_id: String(result.collection_id),
+ collection_name: result.collection_name,
+ total_items: result.total_items,
+ indexed_items: result.indexed_items,
+ last_sync_at: result.last_sync_at,
+ status: result.status,
+ error_message: result.error_message
+ };
+ } catch (error) {
+ console.error(`Error getting index status for collection ${collectionId}:`, error);
+ return null;
+ }
+ }
+ /**
+ * Get indexing status for all collections
+ */
+ async getAllIndexStatus() {
+ try {
+ const stmt = this.db.prepare("SELECT * FROM ai_search_index_meta");
+ const { results } = await stmt.all();
+ const statusMap = {};
+ for (const row of results || []) {
+ const collectionId = String(row.collection_id);
+ statusMap[collectionId] = {
+ collection_id: collectionId,
+ collection_name: row.collection_name,
+ total_items: row.total_items,
+ indexed_items: row.indexed_items,
+ last_sync_at: row.last_sync_at,
+ status: row.status,
+ error_message: row.error_message
+ };
+ }
+ return statusMap;
+ } catch (error) {
+ console.error("Error getting all index status:", error);
+ return {};
+ }
+ }
+ /**
+ * Update index status in database
+ */
+ async updateIndexStatus(collectionId, status) {
+ try {
+ const checkStmt = this.db.prepare(
+ "SELECT id FROM ai_search_index_meta WHERE collection_id = ?"
+ );
+ const existing = await checkStmt.bind(collectionId).first();
+ if (existing) {
+ const stmt = this.db.prepare(`
+ UPDATE ai_search_index_meta
+ SET collection_name = ?,
+ total_items = ?,
+ indexed_items = ?,
+ last_sync_at = ?,
+ status = ?,
+ error_message = ?
+ WHERE collection_id = ?
+ `);
+ await stmt.bind(
+ status.collection_name,
+ status.total_items,
+ status.indexed_items,
+ status.last_sync_at || null,
+ status.status,
+ status.error_message || null,
+ String(collectionId)
+ ).run();
+ } else {
+ const stmt = this.db.prepare(`
+ INSERT INTO ai_search_index_meta (
+ collection_id, collection_name, total_items, indexed_items,
+ last_sync_at, status, error_message
+ ) VALUES (?, ?, ?, ?, ?, ?, ?)
+ `);
+ await stmt.bind(
+ String(status.collection_id),
+ status.collection_name,
+ status.total_items,
+ status.indexed_items,
+ status.last_sync_at || null,
+ status.status,
+ status.error_message || null
+ ).run();
+ }
+ } catch (error) {
+ console.error(`Error updating index status for collection ${collectionId}:`, error);
+ throw error;
+ }
+ }
+ /**
+ * Sync all selected collections
+ */
+ async syncAll(selectedCollections) {
+ for (const collectionId of selectedCollections) {
+ try {
+ await this.indexCollection(collectionId);
+ } catch (error) {
+ console.error(`Error syncing collection ${collectionId}:`, error);
+ }
+ }
+ }
+};
+
+// src/plugins/core-plugins/ai-search-plugin/data/benchmark-datasets.ts
+var BENCHMARK_DATASETS = [
+ {
+ id: "scifact",
+ name: "BEIR SciFact",
+ description: "Scientific fact verification \u2014 abstracts from S2ORC",
+ corpus_size: 5183,
+ query_count: 1109,
+ avg_qrels_per_query: 1.1,
+ license: "CC BY-SA 4.0"
+ },
+ {
+ id: "nfcorpus",
+ name: "BEIR NFCorpus",
+ description: "Bio-medical IR \u2014 NutritionFacts clinical documents",
+ corpus_size: 3633,
+ query_count: 323,
+ avg_qrels_per_query: 38.2,
+ license: "Mixed (see dataset)"
+ },
+ {
+ id: "fiqa",
+ name: "BEIR FiQA-2018",
+ description: "Financial Q&A \u2014 opinion-based questions from StackExchange/Reddit",
+ corpus_size: 57638,
+ query_count: 648,
+ avg_qrels_per_query: 2.6,
+ license: "Mixed (see dataset)"
+ }
+];
+
+// src/plugins/core-plugins/ai-search-plugin/services/benchmark.service.ts
+var BenchmarkService = class {
+ constructor(db, kv, vectorize, dataset = "scifact") {
+ this.db = db;
+ this.kv = kv;
+ this.vectorize = vectorize;
+ this.dataset = dataset;
+ this.idPrefix = `beir-${dataset}-`;
+ this.collectionId = `benchmark-${dataset}-collection`;
+ if (!BENCHMARK_DATASETS.find((d) => d.id === dataset)) {
+ throw new Error(`Unknown benchmark dataset: ${dataset}`);
+ }
+ }
+ dataset;
+ data = null;
+ idPrefix;
+ collectionId;
+ /**
+ * Load dataset from KV on first access. Cached for lifetime of the service instance.
+ *
+ * Corpus data may be stored as a single key or chunked across multiple keys
+ * (for datasets that exceed the 25 MiB KV value limit). Chunked data uses:
+ * benchmark:{dataset}:corpus:meta ā { chunks: N, total: M }
+ * benchmark:{dataset}:corpus:0 ā first slice
+ * benchmark:{dataset}:corpus:1 ā second slice
+ * ...
+ */
+ async loadData() {
+ if (this.data) return this.data;
+ const corpusKey = `benchmark:${this.dataset}:corpus`;
+ const [corpus, queries, qrels, corpusMeta] = await Promise.all([
+ this.kv.get(corpusKey, "json"),
+ this.kv.get(
+ `benchmark:${this.dataset}:queries`,
+ "json"
+ ),
+ this.kv.get(
+ `benchmark:${this.dataset}:qrels`,
+ "json"
+ ),
+ this.kv.get(
+ `${corpusKey}:meta`,
+ "json"
+ )
+ ]);
+ let resolvedCorpus = corpus;
+ if (!resolvedCorpus && corpusMeta) {
+ console.log(
+ `[BenchmarkService] Loading chunked corpus: ${corpusMeta.chunks} chunks, ${corpusMeta.total} docs`
+ );
+ const chunkPromises = [];
+ for (let i = 0; i < corpusMeta.chunks; i++) {
+ chunkPromises.push(
+ this.kv.get(`${corpusKey}:${i}`, "json")
+ );
+ }
+ const chunks = await Promise.all(chunkPromises);
+ resolvedCorpus = [];
+ for (const chunk of chunks) {
+ if (!chunk) {
+ throw new Error(
+ `Missing corpus chunk for dataset "${this.dataset}". Re-upload with: npx tsx scripts/generate-benchmark-data.ts --dataset ${this.dataset}`
+ );
+ }
+ resolvedCorpus.push(...chunk);
+ }
+ console.log(
+ `[BenchmarkService] Reassembled ${resolvedCorpus.length} docs from ${corpusMeta.chunks} chunks`
+ );
+ }
+ if (!resolvedCorpus || !queries || !qrels) {
+ throw new Error(
+ `Benchmark dataset "${this.dataset}" not found in KV. Run: npx tsx scripts/generate-benchmark-data.ts --dataset ${this.dataset}`
+ );
+ }
+ this.data = { corpus: resolvedCorpus, queries, qrels };
+ return this.data;
+ }
+ /**
+ * Get the subset of corpus documents: only those referenced in qrels + noise.
+ * Deterministic selection (sorted by ID) so results are reproducible.
+ */
+ async getSubsetCorpus() {
+ const { corpus, qrels } = await this.loadData();
+ const relevantDocIds = new Set(qrels.map((qr) => qr.doc_id));
+ const relevantDocs = corpus.filter((doc) => relevantDocIds.has(doc._id));
+ const noiseDocs = corpus.filter((doc) => !relevantDocIds.has(doc._id)).slice(0, 200);
+ return [...relevantDocs, ...noiseDocs];
+ }
+ /**
+ * Seed benchmark documents into the content table.
+ * Uses a dedicated collection per dataset created on-the-fly.
+ * Idempotent ā skips if data already exists.
+ */
+ async seed(authorId, useSubset = true, onProgress) {
+ const existing = await this.db.prepare(
+ `SELECT COUNT(*) as count FROM content WHERE id LIKE '${this.idPrefix}%'`
+ ).first();
+ if (existing && existing.count > 0) {
+ return { seeded: existing.count, skipped: true };
+ }
+ const collectionId = await this.ensureBenchmarkCollection();
+ const { corpus: fullCorpus } = await this.loadData();
+ const corpus = useSubset ? await this.getSubsetCorpus() : fullCorpus;
+ const now = Date.now();
+ const batchSize = 50;
+ let inserted = 0;
+ for (let i = 0; i < corpus.length; i += batchSize) {
+ const batch = corpus.slice(i, i + batchSize);
+ const batchOps = batch.map((doc) => {
+ const id = `${this.idPrefix}${doc._id}`;
+ const slug = `${this.idPrefix}${doc._id}`;
+ const safeText = doc.text.replace(/&/g, "&").replace(//g, ">");
+ const data = JSON.stringify({
+ content: `${safeText}
`,
+ excerpt: doc.text.substring(0, 200),
+ tags: [`beir-${this.dataset}`, "benchmark"]
+ });
+ return this.db.prepare(
+ `INSERT OR IGNORE INTO content
+ (id, collection_id, slug, title, data, status, author_id, created_at, updated_at)
+ VALUES (?, ?, ?, ?, ?, 'published', ?, ?, ?)`
+ ).bind(id, collectionId, slug, doc.title, data, authorId, now, now);
+ });
+ await this.db.batch(batchOps);
+ inserted += batch.length;
+ if (onProgress) {
+ onProgress({
+ phase: "inserting",
+ inserted,
+ total: corpus.length
+ });
+ }
+ }
+ if (onProgress) {
+ onProgress({
+ phase: "complete",
+ inserted: corpus.length,
+ total: corpus.length
+ });
+ }
+ return { seeded: corpus.length, skipped: false };
+ }
+ /**
+ * Remove all benchmark documents and related index entries for this dataset.
+ */
+ async purge() {
+ const result = await this.db.prepare(
+ `DELETE FROM content WHERE id LIKE '${this.idPrefix}%'`
+ ).run();
+ try {
+ await this.db.batch([
+ this.db.prepare(
+ `DELETE FROM content_fts WHERE content_id LIKE '${this.idPrefix}%'`
+ ),
+ this.db.prepare(
+ `DELETE FROM content_fts_sync WHERE content_id LIKE '${this.idPrefix}%'`
+ )
+ ]);
+ } catch (error) {
+ console.warn("[BenchmarkService] FTS5 cleanup skipped:", error);
+ }
+ try {
+ await this.db.prepare("DELETE FROM collections WHERE id = ?").bind(this.collectionId).run();
+ } catch (error) {
+ console.warn("[BenchmarkService] Collection cleanup skipped:", error);
+ }
+ try {
+ await this.db.prepare(
+ "DELETE FROM ai_search_index_meta WHERE collection_id = ?"
+ ).bind(this.collectionId).run();
+ } catch (error) {
+ }
+ if (this.vectorize) {
+ try {
+ const { corpus } = await this.loadData();
+ const vectorIds = [];
+ for (const doc of corpus) {
+ for (let i = 0; i < 5; i++) {
+ vectorIds.push(`${this.idPrefix}${doc._id}-chunk-${i}`);
+ }
+ }
+ const batchSize = 1e3;
+ for (let i = 0; i < vectorIds.length; i += batchSize) {
+ const batch = vectorIds.slice(i, i + batchSize);
+ await this.vectorize.deleteByIds(batch);
+ }
+ console.log(
+ `[BenchmarkService] Deleted up to ${vectorIds.length} vectors from Vectorize`
+ );
+ } catch (error) {
+ console.warn(
+ "[BenchmarkService] Vectorize cleanup error (non-fatal):",
+ error
+ );
+ }
+ }
+ return result.meta?.changes || 0;
+ }
+ /**
+ * Run benchmark queries against a search function and compute IR metrics.
+ */
+ async evaluate(searchFn, mode = "fts5", limit = 10, maxQueries = 0) {
+ const { corpus, queries, qrels } = await this.loadData();
+ const startTime = Date.now();
+ const perQuery = [];
+ const qrelsMap = /* @__PURE__ */ new Map();
+ for (const qrel of qrels) {
+ if (!qrelsMap.has(qrel.query_id))
+ qrelsMap.set(qrel.query_id, /* @__PURE__ */ new Map());
+ qrelsMap.get(qrel.query_id).set(qrel.doc_id, qrel.score);
+ }
+ const queriesWithJudgments = queries.filter(
+ (q) => qrelsMap.has(q._id) && qrelsMap.get(q._id).size > 0
+ );
+ const queriesToRun = maxQueries > 0 ? queriesWithJudgments.slice(0, maxQueries) : queriesWithJudgments;
+ let totalNDCG = 0;
+ let totalPrecision = 0;
+ let totalRecall = 0;
+ let totalMRR = 0;
+ for (const query of queriesToRun) {
+ const relevantDocs = qrelsMap.get(query._id);
+ const queryStart = Date.now();
+ let response;
+ try {
+ response = await searchFn(query.text, mode, limit);
+ } catch (error) {
+ console.error(
+ `[BenchmarkService] Search error for query ${query._id}:`,
+ error
+ );
+ perQuery.push({
+ query_id: query._id,
+ query_text: query.text,
+ ndcg: 0,
+ precision: 0,
+ recall: 0,
+ mrr: 0,
+ hits: 0,
+ expected: relevantDocs.size,
+ returned: 0,
+ query_time_ms: Date.now() - queryStart
+ });
+ continue;
+ }
+ const queryTime = Date.now() - queryStart;
+ const rankedDocIds = response.results.map(
+ (r) => r.id.startsWith(this.idPrefix) ? r.id.slice(this.idPrefix.length) : r.id
+ );
+ const ndcg = computeNDCG(rankedDocIds, relevantDocs, limit);
+ const precision = computePrecision(rankedDocIds, relevantDocs, limit);
+ const recall = computeRecall(rankedDocIds, relevantDocs);
+ const mrr = computeMRR(rankedDocIds, relevantDocs);
+ totalNDCG += ndcg;
+ totalPrecision += precision;
+ totalRecall += recall;
+ totalMRR += mrr;
+ perQuery.push({
+ query_id: query._id,
+ query_text: query.text,
+ ndcg,
+ precision,
+ recall,
+ mrr,
+ hits: rankedDocIds.filter((id) => relevantDocs.has(id)).length,
+ expected: relevantDocs.size,
+ returned: rankedDocIds.length,
+ query_time_ms: queryTime
+ });
+ }
+ const totalTime = Date.now() - startTime;
+ const evaluated = queriesToRun.length;
+ return {
+ mode,
+ limit,
+ corpus_size: corpus.length,
+ queries_evaluated: evaluated,
+ total_time_ms: totalTime,
+ avg_query_time_ms: evaluated > 0 ? Math.round(totalTime / evaluated) : 0,
+ metrics: {
+ ndcg_at_k: evaluated > 0 ? totalNDCG / evaluated : 0,
+ precision_at_k: evaluated > 0 ? totalPrecision / evaluated : 0,
+ recall_at_k: evaluated > 0 ? totalRecall / evaluated : 0,
+ mrr: evaluated > 0 ? totalMRR / evaluated : 0
+ },
+ per_query: perQuery
+ };
+ }
+ /**
+ * Get the list of query IDs that have relevance judgments, optionally limited.
+ */
+ async getEvaluableQueryIds(maxQueries = 0) {
+ const { queries, qrels } = await this.loadData();
+ const qrelsMap = /* @__PURE__ */ new Map();
+ for (const qrel of qrels) {
+ if (!qrelsMap.has(qrel.query_id))
+ qrelsMap.set(qrel.query_id, /* @__PURE__ */ new Map());
+ qrelsMap.get(qrel.query_id).set(qrel.doc_id, qrel.score);
+ }
+ const ids = queries.filter((q) => qrelsMap.has(q._id) && qrelsMap.get(q._id).size > 0).map((q) => q._id);
+ return maxQueries > 0 ? ids.slice(0, maxQueries) : ids;
+ }
+ /**
+ * Evaluate a batch of queries by their IDs.
+ * Returns per-query results for the batch so the client can accumulate and compute aggregates.
+ */
+ async evaluateBatch(searchFn, mode, limit, queryIds) {
+ const { queries, qrels } = await this.loadData();
+ const qrelsMap = /* @__PURE__ */ new Map();
+ for (const qrel of qrels) {
+ if (!qrelsMap.has(qrel.query_id))
+ qrelsMap.set(qrel.query_id, /* @__PURE__ */ new Map());
+ qrelsMap.get(qrel.query_id).set(qrel.doc_id, qrel.score);
+ }
+ const queryMap = new Map(queries.map((q) => [q._id, q]));
+ const results = [];
+ for (const qid of queryIds) {
+ const query = queryMap.get(qid);
+ const relevantDocs = qrelsMap.get(qid);
+ if (!query || !relevantDocs) continue;
+ const queryStart = Date.now();
+ let response;
+ try {
+ response = await searchFn(query.text, mode, limit);
+ } catch (error) {
+ console.error(
+ `[BenchmarkService] Search error for query ${qid}:`,
+ error
+ );
+ results.push({
+ query_id: qid,
+ query_text: query.text,
+ ndcg: 0,
+ precision: 0,
+ recall: 0,
+ mrr: 0,
+ hits: 0,
+ expected: relevantDocs.size,
+ returned: 0,
+ query_time_ms: Date.now() - queryStart
+ });
+ continue;
+ }
+ const queryTime = Date.now() - queryStart;
+ const rankedDocIds = response.results.map(
+ (r) => r.id.startsWith(this.idPrefix) ? r.id.slice(this.idPrefix.length) : r.id
+ );
+ const ndcg = computeNDCG(rankedDocIds, relevantDocs, limit);
+ const precision = computePrecision(rankedDocIds, relevantDocs, limit);
+ const recall = computeRecall(rankedDocIds, relevantDocs);
+ const mrr = computeMRR(rankedDocIds, relevantDocs);
+ results.push({
+ query_id: qid,
+ query_text: query.text,
+ ndcg,
+ precision,
+ recall,
+ mrr,
+ hits: rankedDocIds.filter((id) => relevantDocs.has(id)).length,
+ expected: relevantDocs.size,
+ returned: rankedDocIds.length,
+ query_time_ms: queryTime
+ });
+ }
+ return results;
+ }
+ /**
+ * Get dataset metadata from the compiled-in registry (no KV needed).
+ */
+ getMeta() {
+ return BENCHMARK_DATASETS.find((d) => d.id === this.dataset);
+ }
+ getCorpusSize() {
+ return this.getMeta().corpus_size;
+ }
+ getQueryCount() {
+ return this.getMeta().query_count;
+ }
+ getDatasetId() {
+ return this.dataset;
+ }
+ getIdPrefix() {
+ return this.idPrefix;
+ }
+ getCollectionId() {
+ return this.collectionId;
+ }
+ async getSubsetSize() {
+ const subset = await this.getSubsetCorpus();
+ return subset.length;
+ }
+ /**
+ * Check if benchmark data is currently seeded for this dataset.
+ */
+ async isSeeded() {
+ const result = await this.db.prepare(
+ `SELECT COUNT(*) as count FROM content WHERE id LIKE '${this.idPrefix}%'`
+ ).first();
+ const count = result?.count || 0;
+ return { seeded: count > 0, count };
+ }
+ /**
+ * Check if dataset data exists in KV.
+ */
+ async isDataAvailable() {
+ const queries = await this.kv.get(
+ `benchmark:${this.dataset}:queries`
+ );
+ return queries !== null;
+ }
+ /**
+ * Ensure a benchmark collection exists in the collections table.
+ * Returns the collection ID.
+ */
+ async ensureBenchmarkCollection() {
+ const existing = await this.db.prepare("SELECT id FROM collections WHERE id = ?").bind(this.collectionId).first();
+ if (existing) {
+ return this.collectionId;
+ }
+ const meta = this.getMeta();
+ const schema = JSON.stringify({
+ type: "object",
+ properties: {
+ title: { type: "string", title: "Title", required: true },
+ content: { type: "string", title: "Content", format: "richtext" },
+ excerpt: { type: "string", title: "Excerpt" },
+ tags: { type: "array", title: "Tags", items: { type: "string" } }
+ },
+ required: ["title"]
+ });
+ await this.db.prepare(
+ `INSERT OR IGNORE INTO collections (id, name, display_name, description, schema, is_active, created_at, updated_at)
+ VALUES (?, ?, ?, ?, ?, 1, unixepoch(), unixepoch())`
+ ).bind(
+ this.collectionId,
+ `benchmark_${this.dataset}`,
+ `${meta.name} Benchmark`,
+ meta.description,
+ schema
+ ).run();
+ return this.collectionId;
+ }
+};
+function computeNDCG(ranked, qrels, k) {
+ let dcg = 0;
+ for (let i = 0; i < Math.min(ranked.length, k); i++) {
+ const rel = qrels.get(ranked[i]) || 0;
+ dcg += rel / Math.log2(i + 2);
+ }
+ const ideal = Array.from(qrels.values()).sort((a, b) => b - a).slice(0, k);
+ let idcg = 0;
+ for (let i = 0; i < ideal.length; i++) {
+ idcg += ideal[i] / Math.log2(i + 2);
+ }
+ return idcg === 0 ? 0 : dcg / idcg;
+}
+function computePrecision(ranked, qrels, k) {
+ const topK = ranked.slice(0, k);
+ const hits = topK.filter((id) => (qrels.get(id) || 0) > 0).length;
+ return hits / k;
+}
+function computeRecall(ranked, qrels) {
+ const totalRelevant = Array.from(qrels.values()).filter(
+ (v) => v > 0
+ ).length;
+ if (totalRelevant === 0) return 0;
+ const hits = ranked.filter((id) => (qrels.get(id) || 0) > 0).length;
+ return hits / totalRelevant;
+}
+function computeMRR(ranked, qrels) {
+ for (let i = 0; i < ranked.length; i++) {
+ if ((qrels.get(ranked[i]) || 0) > 0) return 1 / (i + 1);
+ }
+ return 0;
+}
+
+// src/templates/pages/admin-search.template.ts
+init_admin_layout_catalyst_template();
+
+// src/templates/pages/admin-search-overview.template.ts
+function renderOverviewTab(props) {
+ const {
+ fts5TotalIndexed,
+ queriesToday,
+ avgQueryTime,
+ ctr,
+ enabled,
+ aiModeEnabled,
+ facetsEnabled,
+ settings,
+ totalQueries,
+ totalClicks30d,
+ zeroResults30d,
+ popularQueries,
+ fts5Available,
+ vectorizeIndexedItems,
+ selectedCollections,
+ collections
+ } = props;
+ return `
+
+
+
+ ${renderStatCard("Indexed Documents", String(fts5TotalIndexed), "lime", `
+
+
+
+ `)}
+
+ ${renderStatCard("Queries Today", String(queriesToday), "sky", `
+
+
+
+ `)}
+
+ ${renderStatCard("Avg Response Time", avgQueryTime > 0 ? avgQueryTime + "ms" : "N/A", "purple", `
+
+
+
+ `)}
+
+ ${renderStatCard("Click-Through Rate", ctr !== null ? ctr + "%" : "N/A", "amber", `
+
+
+
+ `)}
+
+
+
+
+
+
+
+
Feature Status
+
+
+
+ ${renderFeatureToggle("Search", enabled)}
+ ${renderFeatureToggle("AI Mode", aiModeEnabled)}
+ ${renderFeatureToggle("Faceted Search", facetsEnabled)}
+ ${renderFeatureToggle("Query Rewriting", settings.query_rewriting_enabled === true)}
+ ${renderFeatureToggle("Reranking", settings.reranking_enabled === true)}
+ ${renderFeatureToggle("Synonyms", settings.query_synonyms_enabled !== false)}
+
+
+
+
+
+
+
+
Search Activity
+
+
+
+
+
+
Quick Stats
+
+
+ Total Queries (30d)
+ ${totalQueries}
+
+
+ Queries Today
+ ${queriesToday}
+
+
+ Total Clicks (30d)
+ ${totalClicks30d}
+
+
+ Zero-Result Queries
+ ${zeroResults30d}
+
+
+
+
+
+
Popular Queries
+ ${popularQueries.length > 0 ? `
+
+ ${popularQueries.slice(0, 5).map((q) => `
+
+ ${escapeHtml6(q.query)}
+ ${q.count}
+
+ `).join("")}
+
+ View all in Analytics →
+
+
+ ` : `
+
No queries recorded yet.
+ `}
+
+
+
+
+
+
+
+
+
+
Index Health
+
+
+
+
+
FTS5
+
+ ${fts5Available ? "Available" : "Unavailable"}
+ ${fts5TotalIndexed} docs
+
+
+
+
Vectorize
+
+ ${aiModeEnabled ? "Enabled" : "Disabled"}
+ ${vectorizeIndexedItems} items
+
+
+
+ Collections
+ ${selectedCollections.length} selected / ${collections.length} total
+
+
+
+
+
+ `;
+}
+
+// src/templates/pages/admin-search-config.template.ts
+function renderConfigTab(props) {
+ const {
+ collections,
+ selectedCollectionIds,
+ dismissedCollectionIds,
+ enabled,
+ aiModeEnabled,
+ autocompleteEnabled,
+ indexMedia,
+ settings,
+ vectorizeStatusText,
+ data
+ } = props;
+ return `
+
+ `;
+}
+function renderConfigScript() {
+ return `
+ // =============================================
+ // Form submission with error handling
+ // =============================================
+ document.getElementById('settingsForm').addEventListener('submit', async function(e) {
+ e.preventDefault();
+ console.log('[AI Search Client] Form submitted');
+
+ try {
+ var btn = e.submitter;
+ btn.innerText = 'Saving...';
+ btn.disabled = true;
+
+ var formData = new FormData(e.target);
+ var selectedCollections = Array.from(formData.getAll('selected_collections')).map(String);
+
+ var data = {
+ enabled: document.getElementById('enabled').checked,
+ ai_mode_enabled: document.getElementById('ai_mode_enabled').checked,
+ selected_collections: selectedCollections,
+ autocomplete_enabled: document.getElementById('autocomplete_enabled').checked,
+ cache_duration: Number(formData.get('cache_duration')),
+ results_limit: Number(formData.get('results_limit')),
+ index_media: document.getElementById('index_media').checked,
+ reranking_enabled: document.getElementById('reranking_enabled').checked,
+ query_rewriting_enabled: document.getElementById('query_rewriting_enabled').checked,
+ facets_enabled: document.getElementById('facets_enabled').checked,
+ facet_config: facetConfigData.length > 0 ? facetConfigData : undefined,
+ };
+
+ console.log('[AI Search Client] Sending data:', data);
+ console.log('[AI Search Client] Selected collections:', selectedCollections);
+
+ var res = await fetch('/admin/plugins/ai-search', {
+ method: 'POST',
+ headers: {'Content-Type': 'application/json'},
+ body: JSON.stringify(data)
+ });
+
+ console.log('[AI Search Client] Response status:', res.status);
+
+ if (res.ok) {
+ var result = await res.json();
+ console.log('[AI Search Client] Save successful:', result);
+ document.getElementById('msg').classList.remove('hidden');
+ setTimeout(function() {
+ document.getElementById('msg').classList.add('hidden');
+ location.reload();
+ }, 2000);
+ } else {
+ var error = await res.text();
+ console.error('[AI Search Client] Save failed:', error);
+ alert('Failed to save settings: ' + error);
+ }
+
+ btn.innerText = 'Save Settings';
+ btn.disabled = false;
+ } catch (error) {
+ console.error('[AI Search Client] Error:', error);
+ alert('Error saving settings: ' + error.message);
+ }
+ });
+
+ // =============================================
+ // Add collection to index
+ // =============================================
+ async function addCollectionToIndex(collectionId) {
+ var form = document.getElementById('settingsForm');
+ var checkbox = document.getElementById('collection_' + collectionId);
+ if (checkbox) {
+ checkbox.checked = true;
+ form.dispatchEvent(new Event('submit'));
+ }
+ }
+
+ // =============================================
+ // Dismiss collection
+ // =============================================
+ async function dismissCollection(collectionId) {
+ var res = await fetch('/admin/plugins/ai-search', {
+ method: 'POST',
+ headers: {'Content-Type': 'application/json'},
+ body: JSON.stringify({
+ dismissed_collections: [collectionId]
+ })
+ });
+ if (res.ok) {
+ location.reload();
+ }
+ }
+
+ // =============================================
+ // FTS5 status check on load
+ // =============================================
+ (async function checkFTS5Status() {
+ try {
+ var res = await fetch('/admin/plugins/ai-search/api/fts5/status');
+ if (res.ok) {
+ var body = await res.json();
+ var data = body.data;
+ var statusText = document.getElementById('fts5-status-text');
+ var statsText = document.getElementById('fts5-stats-text');
+ var reindexBtn = document.getElementById('fts5-reindex-btn');
+ if (data.available) {
+ statusText.textContent = 'FTS5 is available';
+ statsText.textContent = data.total_indexed + ' items indexed across ' + Object.keys(data.by_collection || {}).length + ' collections';
+ reindexBtn.disabled = false;
+ } else {
+ statusText.textContent = 'FTS5 tables not created yet';
+ statsText.textContent = 'Run migrations to enable FTS5 full-text search.';
+ }
+ }
+ } catch (e) {
+ console.error('FTS5 status check failed:', e);
+ }
+ })();
+
+ // =============================================
+ // Reindex all collections for FTS5
+ // =============================================
+ async function reindexFTS5All() {
+ var btn = document.getElementById('fts5-reindex-btn');
+ btn.disabled = true;
+ btn.textContent = 'Reindexing...';
+ try {
+ var res = await fetch('/admin/plugins/ai-search/api/fts5/reindex-all', {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/json' }
+ });
+ if (res.ok) {
+ var result = await res.json();
+ alert('FTS5 reindex started for ' + (result.collections ? result.collections.length : 0) + ' collections');
+ setTimeout(function() { location.reload(); }, 3000);
+ } else {
+ alert('Failed to start FTS5 reindex');
+ btn.disabled = false;
+ btn.textContent = 'Reindex FTS5';
+ }
+ } catch (e) {
+ alert('Error: ' + e.message);
+ btn.disabled = false;
+ btn.textContent = 'Reindex FTS5';
+ }
+ }
+
+ // =============================================
+ // Reindex all collections for Vectorize
+ // =============================================
+ var vectorizePollTimer = null;
+
+ async function reindexVectorizeAll() {
+ var btn = document.getElementById('vectorize-reindex-btn');
+ btn.disabled = true;
+ btn.textContent = 'Reindexing...';
+ var statsText = document.getElementById('vectorize-stats-text');
+ var progressWrap = document.getElementById('vectorize-progress-wrap');
+ try {
+ var res = await fetch('/admin/plugins/ai-search/api/vectorize/reindex-all', {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/json' }
+ });
+ if (res.ok) {
+ var result = await res.json();
+ var count = result.collections ? result.collections.length : 0;
+ if (statsText) statsText.textContent = 'Reindexing ' + count + ' collection(s)...';
+ if (progressWrap) progressWrap.classList.remove('hidden');
+ startVectorizePoll();
+ } else {
+ var error = await res.json().catch(function() { return {}; });
+ alert('Failed to start Vectorize reindex: ' + (error.error || 'Unknown error'));
+ btn.disabled = false;
+ btn.textContent = 'Reindex Vectorize';
+ }
+ } catch (e) {
+ alert('Error: ' + e.message);
+ btn.disabled = false;
+ btn.textContent = 'Reindex Vectorize';
+ }
+ }
+
+ function startVectorizePoll() {
+ if (vectorizePollTimer) clearTimeout(vectorizePollTimer);
+ pollVectorizeStatus();
+ }
+
+ async function pollVectorizeStatus() {
+ try {
+ var res = await fetch('/admin/plugins/ai-search/api/status');
+ if (!res.ok) { vectorizePollTimer = setTimeout(pollVectorizeStatus, 3000); return; }
+ var json = await res.json();
+ var data = json.data || {};
+ var totalItems = 0, indexedItems = 0, hasIndexing = false, hasCompleted = false;
+ for (var colId in data) {
+ var s = data[colId];
+ totalItems += (s.total_items || 0);
+ indexedItems += (s.indexed_items || 0);
+ if (s.status === 'indexing') hasIndexing = true;
+ if (s.status === 'completed') hasCompleted = true;
+ }
+ var pct = totalItems > 0 ? Math.round((indexedItems / totalItems) * 100) : 0;
+ var bar = document.getElementById('vectorize-progress-bar');
+ var label = document.getElementById('vectorize-progress-label');
+ var countEl = document.getElementById('vectorize-progress-count');
+ var statsText = document.getElementById('vectorize-stats-text');
+ if (bar) bar.style.width = pct + '%';
+ if (countEl) countEl.textContent = indexedItems + '/' + totalItems;
+ if (label) label.textContent = hasIndexing ? 'Embedding & indexing...' : 'Complete';
+
+ if (hasIndexing) {
+ if (statsText) statsText.textContent = 'Indexing: ' + indexedItems + '/' + totalItems + ' items (' + pct + '%)';
+ vectorizePollTimer = setTimeout(pollVectorizeStatus, 3000);
+ } else {
+ // Done
+ var btn = document.getElementById('vectorize-reindex-btn');
+ btn.disabled = false;
+ btn.textContent = 'Reindex Vectorize';
+ if (bar) bar.style.width = '100%';
+ if (label) label.textContent = 'Complete';
+ if (countEl) countEl.textContent = indexedItems + '/' + totalItems;
+ if (statsText) statsText.textContent = 'Vectorize index: ' + totalItems + ' items indexed';
+ setTimeout(function() {
+ var wrap = document.getElementById('vectorize-progress-wrap');
+ if (wrap) wrap.classList.add('hidden');
+ }, 5000);
+ }
+ } catch (e) {
+ vectorizePollTimer = setTimeout(pollVectorizeStatus, 5000);
+ }
+ }
+
+ // Auto-start Vectorize polling if indexing is already in progress
+ (async function checkVectorizeOnLoad() {
+ try {
+ var res = await fetch('/admin/plugins/ai-search/api/status');
+ if (res.ok) {
+ var json = await res.json();
+ var data = json.data || {};
+ var hasIndexing = false;
+ for (var colId in data) {
+ if (data[colId].status === 'indexing') hasIndexing = true;
+ }
+ if (hasIndexing) {
+ var wrap = document.getElementById('vectorize-progress-wrap');
+ var btn = document.getElementById('vectorize-reindex-btn');
+ if (wrap) wrap.classList.remove('hidden');
+ if (btn) { btn.disabled = true; btn.textContent = 'Reindexing...'; }
+ startVectorizePoll();
+ }
+ }
+ } catch (e) { /* ignore */ }
+ })();
+
+ // ==========================================
+ // Faceted Search Configuration
+ // ==========================================
+ var facetConfigData = []; // Current facet config array
+
+ var facetConfigLoaded = false;
+
+ function toggleFacetsEnabled(enabled) {
+ var section = document.getElementById('facet-config-section');
+ if (enabled) {
+ section.classList.remove('hidden');
+ if (!facetConfigLoaded) {
+ loadFacetConfig(true);
+ }
+ } else {
+ section.classList.add('hidden');
+ }
+ }
+
+ async function loadFacetConfig(keepToggleState) {
+ try {
+ var res = await fetch('/admin/plugins/ai-search/api/facets/config');
+ var json = await res.json();
+ if (!json.success) throw new Error('Failed to load config');
+
+ var toggle = document.getElementById('facets_enabled');
+
+ // Only set the toggle from DB on initial page load, not when
+ // the user just clicked it (keepToggleState = true)
+ if (!keepToggleState) {
+ toggle.checked = json.data.enabled;
+ if (json.data.enabled) {
+ document.getElementById('facet-config-section').classList.remove('hidden');
+ }
+ }
+
+ facetConfigData = json.data.config || [];
+ facetConfigLoaded = true;
+
+ if (facetConfigData.length === 0 && (toggle.checked || json.data.enabled)) {
+ // Auto-generate on first load
+ await autoGenerateFacets();
+ return;
+ }
+
+ renderFacetConfigTable(facetConfigData);
+ } catch (error) {
+ console.error('Error loading facet config:', error);
+ document.getElementById('facet-config-status').textContent = 'Error loading facet configuration';
+ }
+ }
+
+ async function autoGenerateFacets() {
+ try {
+ document.getElementById('facet-config-status').textContent = 'Auto-discovering fields...';
+ var res = await fetch('/admin/plugins/ai-search/api/facets/auto-generate', { method: 'POST' });
+ var json = await res.json();
+ if (!json.success) throw new Error('Failed to auto-generate');
+
+ facetConfigData = json.data.config || [];
+ document.getElementById('facet-config-status').textContent =
+ 'Discovered ' + json.data.discovered_count + ' fields, auto-enabled ' + json.data.auto_enabled_count;
+ renderFacetConfigTable(facetConfigData);
+ } catch (error) {
+ console.error('Error auto-generating facets:', error);
+ document.getElementById('facet-config-status').textContent = 'Error: ' + error.message;
+ }
+ }
+
+ async function rediscoverFacets() {
+ try {
+ document.getElementById('facet-config-status').textContent = 'Re-discovering fields...';
+ var res = await fetch('/admin/plugins/ai-search/api/facets/discover');
+ var json = await res.json();
+ if (!json.success) throw new Error('Failed to discover');
+
+ var discovered = json.data || [];
+ // Merge: keep existing config, add new discovered fields
+ var existingFields = new Set(facetConfigData.map(function(f) { return f.field; }));
+ var newFields = discovered.filter(function(d) { return !existingFields.has(d.field); });
+
+ for (var i = 0; i < newFields.length; i++) {
+ facetConfigData.push({
+ name: newFields[i].title,
+ field: newFields[i].field,
+ type: newFields[i].type,
+ collections: newFields[i].collections.map(function(c) { return c.id; }),
+ enabled: newFields[i].recommended,
+ source: 'auto',
+ position: facetConfigData.length
+ });
+ }
+
+ document.getElementById('facet-config-status').textContent =
+ discovered.length + ' fields found' + (newFields.length > 0 ? ', ' + newFields.length + ' new' : '');
+ renderFacetConfigTable(facetConfigData);
+ } catch (error) {
+ console.error('Error re-discovering facets:', error);
+ document.getElementById('facet-config-status').textContent = 'Error: ' + error.message;
+ }
+ }
+
+ function renderFacetConfigTable(config) {
+ var tbody = document.getElementById('facet-config-body');
+ if (!config || config.length === 0) {
+ tbody.innerHTML = 'No facets configured. Click "Re-discover Fields" to scan collection schemas. ';
+ return;
+ }
+
+ var typeBadge = function(type) {
+ switch (type) {
+ case 'builtin': return 'built-in ';
+ case 'json_array': return 'array ';
+ case 'json_scalar': return 'scalar ';
+ default: return '' + type + ' ';
+ }
+ };
+ var sourceBadge = function(source) {
+ switch (source) {
+ case 'auto': return 'auto ';
+ case 'manual': return 'manual ';
+ case 'agent': return 'agent ';
+ default: return '' + (source || 'auto') + ' ';
+ }
+ };
+
+ var html = '';
+ for (var i = 0; i < config.length; i++) {
+ var f = config[i];
+ html += '' +
+ ' ' +
+ '' + (f.name || f.field) + ' ' +
+ '' + f.field + ' ' +
+ '' + typeBadge(f.type) + ' ' +
+ '' + sourceBadge(f.source) + ' ' +
+ ' ';
+ }
+ tbody.innerHTML = html;
+ document.getElementById('facet-config-status').textContent = config.length + ' facets configured, ' + config.filter(function(f) { return f.enabled; }).length + ' enabled';
+ }
+
+ function toggleFacetConfig(index, enabled) {
+ if (facetConfigData[index]) {
+ facetConfigData[index].enabled = enabled;
+ // If manually changed, update source
+ if (facetConfigData[index].source !== 'manual') {
+ facetConfigData[index].source = 'manual';
+ }
+ renderFacetConfigTable(facetConfigData);
+ }
+ }
+
+ async function saveFacetConfig() {
+ try {
+ var res = await fetch('/admin/plugins/ai-search/api/facets/config', {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify({
+ enabled: document.getElementById('facets_enabled').checked,
+ config: facetConfigData
+ })
+ });
+ var json = await res.json();
+ if (json.success) {
+ document.getElementById('facet-config-status').textContent = 'Facet configuration saved!';
+ setTimeout(function() {
+ renderFacetConfigTable(facetConfigData);
+ }, 2000);
+ } else {
+ document.getElementById('facet-config-status').textContent = 'Error saving: ' + (json.error || 'Unknown error');
+ }
+ } catch (error) {
+ console.error('Error saving facet config:', error);
+ document.getElementById('facet-config-status').textContent = 'Error: ' + error.message;
+ }
+ }
+
+ // Load facet config on page load (if on configuration tab)
+ if (initTab === 'configuration') {
+ loadFacetConfig();
+ }
+ `;
+}
+
+// src/templates/pages/admin-search-benchmark.template.ts
+function renderBenchmarkTab() {
+ return `
+
+
+
Search Benchmark
+
+ BEIR benchmark datasets with ground-truth relevance judgments.
+ Seed the data, index it, then evaluate search quality with standard IR metrics (nDCG@10, Precision, Recall, MRR).
+
+
+
+
+
+ Dataset:
+
+ SciFact (5,183 docs, scientific)
+ NFCorpus (3,633 docs, biomedical)
+ FiQA-2018 (57,638 docs, financial Q&A)
+
+
+
+ Data not uploaded to KV
+
+
+
+
Checking benchmark status...
+
+
+
+
+ Corpus:
+
+ Subset
+ Full corpus
+
+
+
+ Seed Data
+
+
+ Index (FTS5)
+
+
+ Index (Vectorize)
+
+
+ Purge Data
+
+
+
+
+
+
Evaluate:
+
+ Queries:
+
+ 15
+ 50
+ 100
+ All
+
+
+
+ FTS5
+
+
+ Keyword
+
+
+ Hybrid
+
+
+ AI (Vectorize)
+
+
+
+ Hybrid and AI modes require Vectorize index binding. If unavailable, they will return an error.
+
+
+
+
+
+
+ `;
+}
+function renderBenchmarkScript() {
+ return `
+ // =============================================
+ // Benchmark Functions
+ // =============================================
+
+ var benchDescriptions = {
+ scifact: 'BEIR SciFact \u2014 scientific abstracts with 300+ test queries and ground-truth relevance judgments.',
+ nfcorpus: 'BEIR NFCorpus \u2014 biomedical IR from NutritionFacts with 323 queries and rich multi-level relevance (38 qrels/query).',
+ fiqa: 'BEIR FiQA-2018 \u2014 financial opinion Q&A from StackExchange/Reddit with 648 test queries.'
+ };
+
+ function getBenchDataset() {
+ return document.getElementById('bench-dataset').value;
+ }
+
+ async function switchBenchmarkDataset() {
+ var dataset = getBenchDataset();
+ // Update description
+ document.getElementById('bench-description').textContent = benchDescriptions[dataset] ||
+ 'BEIR benchmark dataset. Seed, index, then evaluate with IR metrics.';
+ // Reset UI
+ document.getElementById('benchmark-status').textContent = 'Checking benchmark status...';
+ document.getElementById('benchmark-results').classList.add('hidden');
+ ['seed','index','vectorize','fts5','keyword','hybrid','ai','purge'].forEach(function(id) {
+ var btn = document.getElementById('bench-' + id + '-btn');
+ if (btn) btn.disabled = true;
+ });
+ document.getElementById('bench-seed-btn').disabled = false;
+ document.getElementById('bench-seed-btn').textContent = 'Seed Data';
+ document.getElementById('bench-data-badge').classList.add('hidden');
+ await checkBenchmarkStatus(dataset);
+ // Re-render saved results (filtered to selected dataset)
+ renderAllBenchmarkRuns();
+ }
+
+ // Check benchmark status on page load
+ // Cached status data for reactive UI updates
+ var _lastBenchStatus = null;
+
+ function updateBenchmarkStatusText() {
+ var d = _lastBenchStatus;
+ if (!d) return;
+ var statusEl = document.getElementById('benchmark-status');
+ var corpusSelect = document.getElementById('bench-corpus-size');
+ var evalCount = d.evaluable_queries || d.query_count;
+ var selectedSize = corpusSelect.value;
+
+ if (d.seeded) {
+ // Determine expected doc count for the selected corpus option
+ var expectedCount = selectedSize === 'full' ? d.corpus_size : d.subset_size;
+ if (expectedCount && d.seeded_count !== expectedCount) {
+ statusEl.textContent = 'Seeded: ' + d.seeded_count.toLocaleString() + ' docs \u2014 selected: ' +
+ corpusSelect.options[corpusSelect.selectedIndex].textContent +
+ '. Click "Re-seed Data" to update.';
+ } else {
+ statusEl.textContent = 'Benchmark data seeded: ' + d.seeded_count.toLocaleString() + ' documents (' + evalCount + ' evaluable queries)';
+ }
+ } else {
+ statusEl.textContent = 'Dataset: ' + d.dataset + ' (' + d.corpus_size.toLocaleString() + ' docs, ' + evalCount + ' evaluable queries) \u2014 Not yet seeded';
+ }
+ }
+
+ async function checkBenchmarkStatus(dataset) {
+ if (!dataset) dataset = getBenchDataset();
+ try {
+ var res = await fetch('/admin/plugins/ai-search/api/benchmark/status?dataset=' + dataset);
+ if (res.ok) {
+ var body = await res.json();
+ var d = body.data;
+ _lastBenchStatus = d;
+ var statusEl = document.getElementById('benchmark-status');
+ var corpusSelect = document.getElementById('bench-corpus-size');
+ var dataBadge = document.getElementById('bench-data-badge');
+
+ // Show/hide KV data badge
+ if (d.data_available) {
+ dataBadge.classList.add('hidden');
+ } else {
+ dataBadge.classList.remove('hidden');
+ statusEl.textContent = 'Dataset data not uploaded to KV. Run: npx tsx scripts/generate-benchmark-data.ts --dataset ' + dataset;
+ return;
+ }
+
+ // Update corpus size options with actual counts
+ if (d.subset_size && d.corpus_size) {
+ corpusSelect.options[0].textContent = 'Subset (' + d.subset_size.toLocaleString() + ' docs)';
+ corpusSelect.options[1].textContent = 'Full corpus (' + d.corpus_size.toLocaleString() + ' docs)';
+ } else if (d.corpus_size) {
+ corpusSelect.options[1].textContent = 'Full corpus (' + d.corpus_size.toLocaleString() + ' docs)';
+ }
+
+ // Auto-select the corpus option matching what's currently seeded
+ if (d.seeded && d.subset_size && d.seeded_count <= d.subset_size) {
+ corpusSelect.value = 'subset';
+ } else if (d.seeded) {
+ corpusSelect.value = 'full';
+ }
+
+ // Update Queries dropdown "All" option with actual evaluable count
+ var querySelect = document.getElementById('bench-query-count');
+ var evalCount = d.evaluable_queries || d.query_count;
+ var allOption = querySelect.options[querySelect.options.length - 1];
+ allOption.textContent = 'All (' + evalCount.toLocaleString() + ')';
+
+ if (d.seeded) {
+ document.getElementById('bench-seed-btn').textContent = 'Re-seed Data';
+ document.getElementById('bench-index-btn').disabled = false;
+ document.getElementById('bench-vectorize-btn').disabled = false;
+ document.getElementById('bench-fts5-btn').disabled = false;
+ document.getElementById('bench-keyword-btn').disabled = false;
+ document.getElementById('bench-hybrid-btn').disabled = false;
+ document.getElementById('bench-ai-btn').disabled = false;
+ document.getElementById('bench-purge-btn').disabled = false;
+ }
+
+ // Set status text (uses cached _lastBenchStatus)
+ updateBenchmarkStatusText();
+ }
+ } catch (e) {
+ document.getElementById('benchmark-status').textContent = 'Could not check benchmark status: ' + e.message;
+ }
+ }
+ checkBenchmarkStatus();
+
+ async function seedBenchmark() {
+ var btn = document.getElementById('bench-seed-btn');
+ var corpusSize = document.getElementById('bench-corpus-size').value;
+ var dataset = getBenchDataset();
+ btn.textContent = 'Seeding (' + corpusSize + ')...';
+ btn.disabled = true;
+ try {
+ var res = await fetch('/admin/plugins/ai-search/api/benchmark/seed', {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify({ corpus_size: corpusSize, dataset: dataset })
+ });
+ var data = await res.json();
+ if (data.success) {
+ document.getElementById('benchmark-status').textContent = data.message;
+ btn.textContent = 'Re-seed Data';
+ document.getElementById('bench-index-btn').disabled = false;
+ document.getElementById('bench-vectorize-btn').disabled = false;
+ document.getElementById('bench-fts5-btn').disabled = false;
+ document.getElementById('bench-keyword-btn').disabled = false;
+ document.getElementById('bench-hybrid-btn').disabled = false;
+ document.getElementById('bench-ai-btn').disabled = false;
+ document.getElementById('bench-purge-btn').disabled = false;
+ } else {
+ alert('Seed failed: ' + (data.error || 'Unknown error'));
+ btn.textContent = 'Seed Data';
+ }
+ } catch (e) {
+ alert('Error: ' + e.message);
+ btn.textContent = 'Seed Data';
+ }
+ btn.disabled = false;
+ }
+
+ async function indexBenchmark() {
+ var btn = document.getElementById('bench-index-btn');
+ btn.disabled = true;
+ var statusEl = document.getElementById('benchmark-status');
+ var dataset = getBenchDataset();
+
+ var totalIndexed = 0;
+ var remaining = 1;
+ var batchNum = 0;
+
+ while (remaining > 0) {
+ batchNum++;
+ btn.textContent = 'Indexing batch ' + batchNum + '...';
+ try {
+ var res = await fetch('/admin/plugins/ai-search/api/benchmark/index-fts5-batch', {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify({ batch_size: 200, dataset: dataset })
+ });
+ var data = await res.json();
+ if (!data.success) {
+ alert('FTS5 indexing failed: ' + (data.error || 'Unknown error'));
+ break;
+ }
+ totalIndexed += data.indexed;
+ remaining = data.remaining;
+ var done = data.total - remaining;
+ statusEl.textContent = 'FTS5 indexing: ' + done + '/' + data.total + ' docs indexed...';
+ btn.textContent = 'Indexing... (' + done + '/' + data.total + ')';
+ } catch (e) {
+ alert('FTS5 indexing error: ' + e.message);
+ break;
+ }
+ }
+
+ statusEl.textContent = 'FTS5 indexing complete: ' + totalIndexed + ' docs indexed in ' + batchNum + ' batches.';
+ btn.textContent = 'Index (FTS5)';
+ btn.disabled = false;
+ }
+
+ async function indexBenchmarkVectorize() {
+ var btn = document.getElementById('bench-vectorize-btn');
+ btn.disabled = true;
+ var statusEl = document.getElementById('benchmark-status');
+ var dataset = getBenchDataset();
+
+ // Reset index meta first
+ try {
+ await fetch('/admin/plugins/ai-search/api/benchmark/index-vectorize', {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify({ dataset: dataset })
+ });
+ } catch (e) { /* continue anyway */ }
+
+ var offset = 0;
+ var remaining = 1;
+ var batchNum = 0;
+ var totalChunks = 0;
+
+ while (remaining > 0) {
+ batchNum++;
+ btn.textContent = 'Embedding batch ' + batchNum + '...';
+ try {
+ var res = await fetch('/admin/plugins/ai-search/api/benchmark/index-vectorize-batch', {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify({ batch_size: 25, offset: offset, dataset: dataset })
+ });
+ var data = await res.json();
+ if (!data.success) {
+ alert('Vectorize indexing failed: ' + (data.error || 'Unknown error'));
+ break;
+ }
+ totalChunks += data.indexed;
+ offset = data.offset;
+ remaining = data.remaining;
+ var done = data.total - remaining;
+ statusEl.textContent = 'Vectorize: ' + done + '/' + data.total + ' docs embedded (' + totalChunks + ' chunks)...';
+ btn.textContent = 'Embedding... (' + done + '/' + data.total + ')';
+ } catch (e) {
+ alert('Vectorize indexing error: ' + e.message);
+ break;
+ }
+ }
+
+ statusEl.textContent = 'Vectorize indexing complete: ' + totalChunks + ' chunks indexed in ' + batchNum + ' batches.';
+ btn.textContent = 'Index (Vectorize)';
+ btn.disabled = false;
+ }
+
+ async function runBenchmark(mode) {
+ var btn = document.getElementById('bench-' + mode + '-btn');
+ var origText = btn.textContent;
+ btn.textContent = 'Running...';
+ btn.disabled = true;
+
+ var progressDiv = document.getElementById('benchmark-progress');
+ var progressText = document.getElementById('benchmark-progress-text');
+ var progressBar = document.getElementById('benchmark-progress-bar');
+ progressDiv.classList.remove('hidden');
+ progressBar.style.width = '2%';
+
+ var maxQueries = parseInt(document.getElementById('bench-query-count').value, 10);
+ var dataset = getBenchDataset();
+ var BATCH_SIZE = 15;
+ var startTime = Date.now();
+
+ try {
+ // Step 1: Get evaluable query IDs
+ progressText.textContent = 'Fetching query list...';
+ var idsRes = await fetch('/admin/plugins/ai-search/api/benchmark/query-ids?max_queries=' + maxQueries + '&dataset=' + dataset);
+ var idsData = await idsRes.json();
+ if (!idsData.success) {
+ alert('Failed to get query IDs: ' + (idsData.error || 'Unknown error'));
+ progressDiv.classList.add('hidden');
+ btn.textContent = origText;
+ btn.disabled = false;
+ return;
+ }
+
+ var allQueryIds = idsData.query_ids;
+ var totalQueries = allQueryIds.length;
+ progressText.textContent = 'Evaluating ' + mode + ' mode: 0/' + totalQueries + ' queries...';
+
+ // Step 2: Process in batches
+ var allPerQuery = [];
+ for (var i = 0; i < totalQueries; i += BATCH_SIZE) {
+ var batchIds = allQueryIds.slice(i, i + BATCH_SIZE);
+ var batchRes = await fetch('/admin/plugins/ai-search/api/benchmark/evaluate-batch', {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify({ mode: mode, limit: 10, query_ids: batchIds, dataset: dataset })
+ });
+ var batchData = await batchRes.json();
+
+ if (!batchData.success) {
+ alert('Batch evaluation failed: ' + (batchData.error || 'Unknown error'));
+ break;
+ }
+
+ allPerQuery = allPerQuery.concat(batchData.per_query);
+ var done = Math.min(i + BATCH_SIZE, totalQueries);
+ var pct = Math.round((done / totalQueries) * 100);
+ progressBar.style.width = pct + '%';
+ progressText.textContent = 'Evaluating ' + mode + ' mode: ' + done + '/' + totalQueries + ' queries...';
+ }
+
+ // Step 3: Compute aggregate metrics client-side
+ var totalTime = Date.now() - startTime;
+ var n = allPerQuery.length;
+ if (n > 0) {
+ var sumNDCG = 0, sumPrec = 0, sumRecall = 0, sumMRR = 0;
+ for (var j = 0; j < n; j++) {
+ sumNDCG += allPerQuery[j].ndcg;
+ sumPrec += allPerQuery[j].precision;
+ sumRecall += allPerQuery[j].recall;
+ sumMRR += allPerQuery[j].mrr;
+ }
+ var data = {
+ success: true,
+ mode: mode,
+ limit: 10,
+ queries_evaluated: n,
+ total_time_ms: totalTime,
+ avg_query_time_ms: Math.round(totalTime / n),
+ metrics: {
+ ndcg_at_k: sumNDCG / n,
+ precision_at_k: sumPrec / n,
+ recall_at_k: sumRecall / n,
+ mrr: sumMRR / n
+ },
+ per_query: allPerQuery
+ };
+ progressBar.style.width = '100%';
+ showBenchmarkResults(data, mode);
+ } else {
+ alert('No queries were evaluated.');
+ }
+ } catch (e) {
+ alert('Error: ' + e.message);
+ }
+
+ progressDiv.classList.add('hidden');
+ btn.textContent = origText;
+ btn.disabled = false;
+ }
+
+ // Persist benchmark results in localStorage across page refreshes
+ var BENCH_STORAGE_KEY = 'sonicjs_benchmark_runs';
+
+ function loadBenchmarkRuns() {
+ try {
+ var stored = localStorage.getItem(BENCH_STORAGE_KEY);
+ return stored ? JSON.parse(stored) : [];
+ } catch (e) { return []; }
+ }
+
+ function saveBenchmarkRuns(runs) {
+ try { localStorage.setItem(BENCH_STORAGE_KEY, JSON.stringify(runs)); } catch (e) { /* ignore */ }
+ }
+
+ var benchmarkRuns = loadBenchmarkRuns();
+ var benchmarkHistory = [];
+
+ // Restore and render saved results on page load
+ if (benchmarkRuns.length > 0) {
+ renderAllBenchmarkRuns();
+ }
+
+ function showBenchmarkResults(data, mode) {
+ var resultsDiv = document.getElementById('benchmark-results');
+ var dataset = getBenchDataset();
+
+ // Store in current session history
+ benchmarkHistory = benchmarkHistory.filter(function(h) { return h.mode !== mode || h.dataset !== dataset; });
+ benchmarkHistory.push({ mode: mode, dataset: dataset, data: data });
+
+ // Also persist to localStorage with dataset + corpus label
+ var corpusLabel = document.getElementById('bench-corpus-size').value;
+ var runKey = dataset + '_' + corpusLabel + '_' + mode;
+ var runEntry = {
+ key: runKey,
+ mode: mode,
+ dataset: dataset,
+ corpus: corpusLabel,
+ corpus_size: data.corpus_size,
+ metrics: data.metrics,
+ limit: data.limit,
+ queries_evaluated: data.queries_evaluated,
+ total_time_ms: data.total_time_ms,
+ avg_query_time_ms: data.avg_query_time_ms,
+ timestamp: new Date().toISOString()
+ };
+ benchmarkRuns = benchmarkRuns.filter(function(r) { return r.key !== runKey; });
+ benchmarkRuns.push(runEntry);
+ saveBenchmarkRuns(benchmarkRuns);
+
+ renderAllBenchmarkRuns();
+ resultsDiv.classList.remove('hidden');
+ }
+
+ function renderAllBenchmarkRuns() {
+ var resultsDiv = document.getElementById('benchmark-results');
+ var titleEl = document.getElementById('benchmark-results-title');
+ var metricsDiv = document.getElementById('benchmark-metrics');
+ var detailsDiv = document.getElementById('benchmark-details');
+
+ if (benchmarkRuns.length === 0) {
+ resultsDiv.classList.add('hidden');
+ return;
+ }
+
+ var datasetNames = { scifact: 'SciFact', nfcorpus: 'NFCorpus', fiqa: 'FiQA-2018' };
+ var datasetDomains = { scifact: 'Scientific claims', nfcorpus: 'Biomedical', fiqa: 'Financial Q&A' };
+ var modeOrder = ['fts5', 'hybrid', 'ai', 'keyword'];
+ var modeLabels = { fts5: 'FTS5', keyword: 'Keyword', hybrid: 'Hybrid', ai: 'AI/Vectorize' };
+ var modeBgClasses = {
+ fts5: 'bg-indigo-50 dark:bg-indigo-500/10 text-indigo-700 dark:text-indigo-300 ring-1 ring-inset ring-indigo-600/20 dark:ring-indigo-500/20',
+ ai: 'bg-cyan-50 dark:bg-cyan-500/10 text-cyan-700 dark:text-cyan-300 ring-1 ring-inset ring-cyan-600/20 dark:ring-cyan-500/20',
+ hybrid: 'bg-purple-50 dark:bg-purple-500/10 text-purple-700 dark:text-purple-300 ring-1 ring-inset ring-purple-600/20 dark:ring-purple-500/20',
+ keyword: 'bg-zinc-100 dark:bg-zinc-700/50 text-zinc-700 dark:text-zinc-300 ring-1 ring-inset ring-zinc-600/20 dark:ring-zinc-500/20'
+ };
+
+ titleEl.textContent = 'Benchmark Results (k=10)';
+
+ // Group by dataset -> corpus -> mode
+ var byDataset = {};
+ var datasetOrder = ['scifact', 'nfcorpus', 'fiqa'];
+ for (var i = 0; i < benchmarkRuns.length; i++) {
+ var r = benchmarkRuns[i];
+ var ds = r.dataset || 'scifact';
+ if (!byDataset[ds]) byDataset[ds] = {};
+ var corpus = r.corpus || 'subset';
+ if (!byDataset[ds][corpus]) byDataset[ds][corpus] = [];
+ byDataset[ds][corpus].push(r);
+ }
+
+ // Find best value per metric per dataset+corpus group
+ function findBests(runs) {
+ var bests = { ndcg: -1, precision: -1, recall: -1, mrr: -1 };
+ for (var i = 0; i < runs.length; i++) {
+ var m = runs[i].metrics;
+ if (m.ndcg_at_k > bests.ndcg) bests.ndcg = m.ndcg_at_k;
+ if (m.precision_at_k > bests.precision) bests.precision = m.precision_at_k;
+ if (m.recall_at_k > bests.recall) bests.recall = m.recall_at_k;
+ if (m.mrr > bests.mrr) bests.mrr = m.mrr;
+ }
+ return bests;
+ }
+
+ var html = '';
+ for (var di = 0; di < datasetOrder.length; di++) {
+ var dsKey = datasetOrder[di];
+ if (!byDataset[dsKey]) continue;
+ var corpusGroups = byDataset[dsKey];
+ var corpusKeys = Object.keys(corpusGroups).sort();
+
+ for (var ci = 0; ci < corpusKeys.length; ci++) {
+ var corpusKey = corpusKeys[ci];
+ var runs = corpusGroups[corpusKey];
+ runs.sort(function(a, b) { return modeOrder.indexOf(a.mode) - modeOrder.indexOf(b.mode); });
+ var sizeLabel = runs[0].corpus_size ? runs[0].corpus_size.toLocaleString() + ' docs' : '';
+ var corpusDisplay = corpusKey === 'full' ? 'Full corpus' : 'Subset';
+ if (sizeLabel) corpusDisplay += ' \\u00b7 ' + sizeLabel;
+ var bests = findBests(runs);
+
+ // Card wrapper per dataset+corpus
+ html += '';
+
+ // Card header
+ html += '
' +
+ '
' +
+ '
' +
+ '
' + (datasetNames[dsKey] || dsKey) + ' ' +
+ '' + (datasetDomains[dsKey] || '') + ' ' +
+ '' +
+ '
' + corpusDisplay + ' ' +
+ '
' +
+ '
';
+
+ // Table
+ html += '
' +
+ '
' +
+ '' +
+ 'Mode ' +
+ 'nDCG@10 ' +
+ 'P@10 ' +
+ 'Recall@10 ' +
+ 'MRR ' +
+ 'Queries ' +
+ 'Latency ' +
+ ' ';
+
+ for (var ri = 0; ri < runs.length; ri++) {
+ var run = runs[ri];
+ var m = run.metrics;
+ var isLast = ri === runs.length - 1;
+ var rowBorder = isLast ? '' : ' border-b border-zinc-100 dark:border-zinc-800';
+
+ // Highlight best values
+ var ndcgBest = m.ndcg_at_k === bests.ndcg && runs.length > 1;
+ var precBest = m.precision_at_k === bests.precision && runs.length > 1;
+ var recBest = m.recall_at_k === bests.recall && runs.length > 1;
+ var mrrBest = m.mrr === bests.mrr && runs.length > 1;
+
+ function metricCell(val, isBest) {
+ var pct = (val * 100).toFixed(1) + '%';
+ if (isBest) {
+ return '' + pct + ' ';
+ }
+ return '' + pct + ' ';
+ }
+
+ html += '' +
+ '' + (modeLabels[run.mode] || run.mode) + ' ' +
+ '' + metricCell(m.ndcg_at_k, ndcgBest) + ' ' +
+ '' + metricCell(m.precision_at_k, precBest) + ' ' +
+ '' + metricCell(m.recall_at_k, recBest) + ' ' +
+ '' + metricCell(m.mrr, mrrBest) + ' ' +
+ '' + run.queries_evaluated + ' ' +
+ '' + run.avg_query_time_ms + 'ms ' +
+ ' ';
+ }
+
+ html += '
';
+ }
+ }
+
+ // Summary + clear button
+ html += '' +
+ '' + benchmarkRuns.length + ' runs across ' + Object.keys(byDataset).length + ' dataset' + (Object.keys(byDataset).length !== 1 ? 's' : '') + ' ' +
+ 'Clear all results ' +
+ '
';
+
+ metricsDiv.innerHTML = html;
+ detailsDiv.textContent = '';
+ resultsDiv.classList.remove('hidden');
+ }
+
+ function getRelativeTime(date) {
+ var now = new Date();
+ var diff = Math.floor((now - date) / 1000);
+ if (diff < 60) return 'just now';
+ if (diff < 3600) return Math.floor(diff / 60) + 'm ago';
+ if (diff < 86400) return Math.floor(diff / 3600) + 'h ago';
+ return Math.floor(diff / 86400) + 'd ago';
+ }
+
+ function clearBenchmarkHistory() {
+ if (!confirm('Clear all saved benchmark results?')) return;
+ benchmarkRuns = [];
+ benchmarkHistory = [];
+ saveBenchmarkRuns([]);
+ document.getElementById('benchmark-results').classList.add('hidden');
+ }
+
+ async function purgeBenchmark() {
+ var dataset = getBenchDataset();
+ if (!confirm('Remove all ' + dataset + ' benchmark data? This will delete benchmark documents and index entries.')) return;
+ var btn = document.getElementById('bench-purge-btn');
+ btn.textContent = 'Purging...';
+ btn.disabled = true;
+ try {
+ var res = await fetch('/admin/plugins/ai-search/api/benchmark/purge', {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify({ dataset: dataset })
+ });
+ var data = await res.json();
+ if (data.success) {
+ document.getElementById('benchmark-status').textContent = data.message + '. Benchmark data removed.';
+ document.getElementById('benchmark-results').classList.add('hidden');
+ benchmarkHistory = benchmarkHistory.filter(function(h) { return h.dataset !== dataset; });
+ document.getElementById('bench-seed-btn').textContent = 'Seed Data';
+ document.getElementById('bench-index-btn').disabled = true;
+ document.getElementById('bench-vectorize-btn').disabled = true;
+ document.getElementById('bench-fts5-btn').disabled = true;
+ document.getElementById('bench-keyword-btn').disabled = true;
+ document.getElementById('bench-hybrid-btn').disabled = true;
+ document.getElementById('bench-ai-btn').disabled = true;
+ document.getElementById('bench-purge-btn').disabled = true;
+ } else {
+ alert('Purge failed: ' + (data.error || 'Unknown error'));
+ }
+ } catch (e) {
+ alert('Error: ' + e.message);
+ }
+ btn.textContent = 'Purge Data';
+ btn.disabled = false;
+ }
+ `;
+}
+
+// src/templates/pages/admin-search-relevance.template.ts
+function renderRelevanceTab(props) {
+ const { settings } = props;
+ return `
+
+
+
+
+
+
Ranking Pipeline
+
+ Composable scoring stages that post-process search results from any mode. Each stage produces a [0, 1] score, combined via weighted sum.
+
+
+
+
+
Loading pipeline configuration...
+
+
+
+
+
+
+
+
+
+
How scoring works
+
+ pipeline_score = sum(weight x score) / sum(weight)
+ Only enabled stages with weight > 0 participate. If no stages are active, the original search order is preserved.
+
+
+
+
+
+
+
+
+
+
+
+ Reset to Defaults
+
+
+ Save Pipeline
+
+
+
+
+
+
+
+
Live Preview
+
+ Test search results with current pipeline and field weight settings. Results update automatically as you adjust controls.
+
+
+
+
+
+
+
+
+
+
No results found for this query with current weights.
+
+
+
+
+
+
+
+
+
Field Weights
+
+ Adjust BM25 field boosting for FTS5 and hybrid search modes. Higher weights increase the importance of matches in that field.
+
+
+
+
+
+
+
+
+
+
+
Custom Synonyms
+
+ Define custom synonym groups for domain-specific terms, brand names, or acronyms. For general synonym expansion, enable Query Rewriting (LLM) in Configuration.
+
+
+
+ Enabled
+
+
+
+
+
+
+ Loading synonym groups...
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Add Synonym Group
+
+
+
+
+
+
+
+
+
+
Deterministic & fast \u2014 complements LLM Query Rewriting
+
+ Custom synonyms use a lookup table (no AI cost, zero latency). Best for exact mappings like brand names, acronyms, and domain jargon. For broad synonym coverage, use Query Rewriting in the Configuration tab.
+
+
+
+
+
+
+
+
+
+
+
Query Substitution Rules
+
+ Deterministic query replacement: "if user searches X, replace with Y". Runs before all search modes. First matching rule wins (priority order).
+
+
+
+
+
+
+ Loading query rules...
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Add Substitution Rule
+
+
+
+
+
+
+
+
+
+
Pre-dispatch — affects all search modes
+
+ Rules run before FTS5, AI, keyword, and hybrid search. The API response includes original_query when a substitution occurs, so the frontend can show "Showing results for Y instead of X".
+
+
+
+
+
+
+
+
+
+
Related Searches
+
+ Manage related search suggestions shown to users. Pairs can be created manually, generated by the Quality Agent, or cached automatically from search sessions.
+
+
+
+
+
+ Loading related searches...
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Add Related Search
+
+
+ Clear Auto Cache
+
+
+
+
+
+
+
+
+
+
+
Three-source architecture: manual > agent > auto
+
+ Manual pairs (created here) have highest priority. Agent suggestions come from the Quality Agent analysis. Auto-cached pairs are generated during search sessions. Results are merged with manual first, deduped, and limited to the configured max.
+
+
+
+
+
+
+
+ `;
+}
+function renderRelevanceScript() {
+ return `
+ // =============================================
+ // Relevance: Field Weights
+ // =============================================
+ document.getElementById('relevanceForm')?.addEventListener('submit', async function(e) {
+ e.preventDefault();
+ var btn = document.getElementById('saveWeightsBtn');
+ var origText = btn.textContent;
+ btn.textContent = 'Saving...';
+ btn.disabled = true;
+
+ try {
+ var formData = new FormData(e.target);
+ var data = {
+ fts5_title_boost: parseFloat(formData.get('fts5_title_boost')),
+ fts5_slug_boost: parseFloat(formData.get('fts5_slug_boost')),
+ fts5_body_boost: parseFloat(formData.get('fts5_body_boost'))
+ };
+
+ var res = await fetch('/admin/plugins/ai-search', {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify(data)
+ });
+
+ if (res.ok) {
+ document.getElementById('msg').classList.remove('hidden');
+ setTimeout(function() {
+ document.getElementById('msg').classList.add('hidden');
+ }, 2000);
+ } else {
+ var error = await res.text();
+ alert('Failed to save field weights: ' + error);
+ }
+ } catch (err) {
+ alert('Error saving field weights: ' + err.message);
+ }
+
+ btn.textContent = origText;
+ btn.disabled = false;
+ });
+
+ function resetFieldWeights() {
+ if (!confirm('Reset all field weights to defaults (Title: 5.0, Slug: 2.0, Body: 1.0)?')) return;
+
+ document.getElementById('fts5_title_boost').value = 5.0;
+ document.getElementById('fts5_slug_boost').value = 2.0;
+ document.getElementById('fts5_body_boost').value = 1.0;
+
+ document.getElementById('title-weight-value').textContent = '5.0';
+ document.getElementById('slug-weight-value').textContent = '2.0';
+ document.getElementById('body-weight-value').textContent = '1.0';
+
+ schedulePreview();
+ }
+
+ // =============================================
+ // Ranking Pipeline
+ // =============================================
+ var pipelineStages = [];
+
+ var STAGE_META = {
+ exactMatch: { name: 'Exact Match', desc: 'Score 1.0 if query appears verbatim in title, 0.0 otherwise' },
+ bm25: { name: 'BM25 Score', desc: 'Normalized BM25 score from FTS5 full-text search' },
+ semantic: { name: 'Semantic Score', desc: 'Cosine similarity from Vectorize AI embeddings' },
+ recency: { name: 'Recency', desc: 'Exponential decay based on content age (configurable half-life)' },
+ popularity: { name: 'Popularity', desc: 'External popularity score (set via API or future analytics)' },
+ custom: { name: 'Custom Boost', desc: 'Manual pin/boost score for specific content items' }
+ };
+
+ (async function loadPipeline() {
+ try {
+ var res = await fetch('/admin/plugins/ai-search/api/relevance/pipeline');
+ var data = await res.json();
+ if (data.success && data.data) {
+ pipelineStages = data.data;
+ renderPipelineStages();
+ }
+ } catch (e) {
+ console.error('Failed to load pipeline config:', e);
+ document.getElementById('pipeline-stages').innerHTML =
+ 'Failed to load pipeline configuration.
';
+ }
+ })();
+
+ function renderPipelineStages() {
+ var container = document.getElementById('pipeline-stages');
+ var html = '';
+
+ for (var i = 0; i < pipelineStages.length; i++) {
+ var s = pipelineStages[i];
+ var meta = STAGE_META[s.type] || { name: s.type, desc: '' };
+ var checked = s.enabled ? 'checked' : '';
+ var weight = parseFloat(s.weight).toFixed(1);
+
+ html += '';
+ }
+
+ container.innerHTML = html;
+ }
+
+ function toggleStage(type, enabled) {
+ for (var i = 0; i < pipelineStages.length; i++) {
+ if (pipelineStages[i].type === type) {
+ pipelineStages[i].enabled = enabled;
+ break;
+ }
+ }
+ renderPipelineStages();
+ schedulePreview();
+ }
+
+ function updateStageWeight(type, value) {
+ var val = parseFloat(value).toFixed(1);
+ var label = document.getElementById('stage-' + type + '-weight-value');
+ if (label) label.textContent = val;
+ for (var i = 0; i < pipelineStages.length; i++) {
+ if (pipelineStages[i].type === type) {
+ pipelineStages[i].weight = parseFloat(val);
+ break;
+ }
+ }
+ schedulePreview();
+ }
+
+ function resetPipeline() {
+ pipelineStages = [
+ { type: 'exactMatch', weight: 10, enabled: true },
+ { type: 'bm25', weight: 5, enabled: true },
+ { type: 'semantic', weight: 3, enabled: true },
+ { type: 'recency', weight: 1, enabled: true, config: { half_life_days: 30 } },
+ { type: 'popularity', weight: 0, enabled: false },
+ { type: 'custom', weight: 0, enabled: false }
+ ];
+ renderPipelineStages();
+ schedulePreview();
+ }
+
+ async function savePipeline() {
+ var btn = document.getElementById('savePipelineBtn');
+ btn.textContent = 'Saving...';
+ btn.disabled = true;
+
+ // Read recency half-life from input
+ var halfLifeInput = document.getElementById('stage-recency-halflife');
+ if (halfLifeInput) {
+ for (var i = 0; i < pipelineStages.length; i++) {
+ if (pipelineStages[i].type === 'recency') {
+ if (!pipelineStages[i].config) pipelineStages[i].config = {};
+ pipelineStages[i].config.half_life_days = parseInt(halfLifeInput.value, 10) || 30;
+ break;
+ }
+ }
+ }
+
+ try {
+ var res = await fetch('/admin/plugins/ai-search/api/relevance/pipeline', {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify({ stages: pipelineStages })
+ });
+
+ if (res.ok) {
+ document.getElementById('msg').classList.remove('hidden');
+ setTimeout(function() { document.getElementById('msg').classList.add('hidden'); }, 2000);
+ } else {
+ var error = await res.json().catch(function() { return {}; });
+ alert('Failed to save pipeline: ' + (error.error || 'Unknown error'));
+ }
+ } catch (err) {
+ alert('Error saving pipeline: ' + err.message);
+ }
+
+ btn.textContent = 'Save Pipeline';
+ btn.disabled = false;
+ }
+
+ // =============================================
+ // Live Preview: search with current slider values
+ // =============================================
+ var previewTimer = null;
+
+ function schedulePreview() {
+ var query = document.getElementById('preview-query').value.trim();
+ if (!query) return;
+ clearTimeout(previewTimer);
+ previewTimer = setTimeout(previewSearch, 600);
+ }
+
+ function sanitizePreviewHtml(html) {
+ if (!html) return '';
+ var tmp = document.createElement('div');
+ tmp.innerHTML = html;
+ // Walk nodes: keep only text and tags
+ var result = '';
+ function walk(node) {
+ if (node.nodeType === 3) {
+ // Text node \u2014 escape HTML entities
+ result += node.textContent.replace(/&/g, '&').replace(//g, '>');
+ } else if (node.nodeType === 1) {
+ if (node.tagName === 'MARK') {
+ result += '';
+ for (var i = 0; i < node.childNodes.length; i++) walk(node.childNodes[i]);
+ result += ' ';
+ } else {
+ for (var i = 0; i < node.childNodes.length; i++) walk(node.childNodes[i]);
+ }
+ }
+ }
+ for (var i = 0; i < tmp.childNodes.length; i++) walk(tmp.childNodes[i]);
+ return result;
+ }
+
+ async function previewSearch() {
+ var queryInput = document.getElementById('preview-query');
+ var query = queryInput.value.trim();
+ if (!query) return;
+
+ var btn = document.getElementById('preview-search-btn');
+ var resultsDiv = document.getElementById('preview-results');
+ var emptyDiv = document.getElementById('preview-empty');
+ var errorDiv = document.getElementById('preview-error');
+
+ // Hide previous state
+ resultsDiv.classList.add('hidden');
+ emptyDiv.classList.add('hidden');
+ errorDiv.classList.add('hidden');
+
+ btn.disabled = true;
+ btn.querySelector('svg').classList.add('animate-spin');
+
+ try {
+ var titleWeight = parseFloat(document.getElementById('fts5_title_boost').value);
+ var slugWeight = parseFloat(document.getElementById('fts5_slug_boost').value);
+ var bodyWeight = parseFloat(document.getElementById('fts5_body_boost').value);
+
+ var res = await fetch('/admin/plugins/ai-search/api/relevance/preview', {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify({
+ query: query,
+ title_weight: titleWeight,
+ slug_weight: slugWeight,
+ body_weight: bodyWeight,
+ limit: 10
+ })
+ });
+
+ if (!res.ok) {
+ var errData = await res.json().catch(function() { return { error: 'Request failed' }; });
+ throw new Error(errData.error || 'Preview search failed');
+ }
+
+ var json = await res.json();
+ var data = json.data;
+
+ if (!data.results || data.results.length === 0) {
+ emptyDiv.classList.remove('hidden');
+ } else {
+ renderPreviewResults(data);
+ resultsDiv.classList.remove('hidden');
+ }
+ } catch (err) {
+ document.getElementById('preview-error-text').textContent = err.message;
+ errorDiv.classList.remove('hidden');
+ }
+
+ btn.disabled = false;
+ btn.querySelector('svg').classList.remove('animate-spin');
+ }
+
+ function renderPreviewResults(data) {
+ var metaDiv = document.getElementById('preview-meta');
+ var listDiv = document.getElementById('preview-list');
+
+ // Meta line
+ metaDiv.innerHTML =
+ '' + data.total + ' result' + (data.total !== 1 ? 's' : '') + ' in ' + (data.query_time_ms || 0) + 'ms' +
+ (data.pipeline_applied ? ' (pipeline active) ' : '') +
+ ' ' +
+ 'T:' + data.weights.title.toFixed(1) + ' S:' + data.weights.slug.toFixed(1) + ' B:' + data.weights.body.toFixed(1) + ' ';
+
+ // Result cards
+ var html = '';
+ for (var i = 0; i < data.results.length; i++) {
+ var r = data.results[i];
+ var rank = i + 1;
+ var title = sanitizePreviewHtml(r.highlighted_title || r.title || 'Untitled');
+ var snippet = sanitizePreviewHtml(r.highlighted_body || r.body || '');
+ // Truncate snippet to ~200 chars
+ if (snippet.length > 250) {
+ var cutoff = snippet.lastIndexOf(' ', 250);
+ if (cutoff < 100) cutoff = 250;
+ snippet = snippet.substring(0, cutoff) + '...';
+ }
+ var score = r.bm25_score != null ? parseFloat(r.bm25_score).toFixed(3) : (r.score != null ? parseFloat(r.score).toFixed(3) : '\u2014');
+ var pipelineScore = r.pipeline_score != null ? parseFloat(r.pipeline_score).toFixed(3) : null;
+ var pipelineBadge = pipelineScore !== null
+ ? '' + pipelineScore + ' '
+ : '';
+ var collection = r.collection_id || r.collectionId || '';
+
+ html +=
+ '' +
+ '
' + rank + ' ' +
+ '
' +
+ '
' +
+ '
' + title + ' ' +
+ '
' +
+ '' + score + ' ' +
+ pipelineBadge +
+ '
' +
+ '
' +
+ (collection ? '
' + collection + '
' : '') +
+ (snippet ? '
' + snippet + '
' : '') +
+ '
' +
+ '
';
+ }
+
+ listDiv.innerHTML = html;
+ }
+ // =============================================
+ // Query Synonyms
+ // =============================================
+ var synonymGroups = [];
+ var editingSynonymId = null;
+
+ (async function loadSynonyms() {
+ try {
+ var res = await fetch('/admin/plugins/ai-search/api/relevance/synonyms');
+ var data = await res.json();
+ if (data.success && data.data) {
+ synonymGroups = data.data;
+ renderSynonyms();
+ }
+ } catch (e) {
+ console.error('Failed to load synonym groups:', e);
+ document.getElementById('synonyms-summary').textContent = 'Failed to load synonym groups.';
+ }
+ })();
+
+ function renderSynonyms() {
+ var container = document.getElementById('synonyms-list');
+ var summary = document.getElementById('synonyms-summary');
+ var enabledCount = synonymGroups.filter(function(g) { return g.enabled; }).length;
+ summary.textContent = synonymGroups.length + ' synonym group' + (synonymGroups.length !== 1 ? 's' : '') +
+ ' (' + enabledCount + ' enabled)';
+
+ if (synonymGroups.length === 0) {
+ container.innerHTML = 'No synonym groups defined. Click "Add Synonym Group" to create one.
';
+ return;
+ }
+
+ var html = '';
+ for (var i = 0; i < synonymGroups.length; i++) {
+ var g = synonymGroups[i];
+ var isEditing = editingSynonymId === g.id;
+
+ html += '';
+
+ // Enable/disable toggle
+ html += '
';
+
+ if (isEditing) {
+ // Editing mode: show input
+ var termsEscaped = g.terms.join(', ').replace(/"/g, '"');
+ html += '
';
+ html += '
Save ';
+ html += '
Cancel ';
+ } else {
+ // Display mode: show term chips
+ html += '
';
+ for (var j = 0; j < g.terms.length; j++) {
+ html += '' +
+ g.terms[j].replace(//g, '>') + ' ';
+ }
+ html += '
';
+
+ // Edit & Delete buttons
+ html += '
Edit ';
+ html += '
Delete ';
+ }
+
+ html += '
';
+ }
+
+ container.innerHTML = html;
+ }
+
+ function showSynonymAddForm() {
+ document.getElementById('synonym-add-form').classList.remove('hidden');
+ document.getElementById('synonym-add-btn').classList.add('hidden');
+ document.getElementById('synonym-new-terms').focus();
+ }
+
+ function cancelSynonymAdd() {
+ document.getElementById('synonym-add-form').classList.add('hidden');
+ document.getElementById('synonym-add-btn').classList.remove('hidden');
+ document.getElementById('synonym-new-terms').value = '';
+ }
+
+ async function saveSynonymGroup() {
+ var input = document.getElementById('synonym-new-terms');
+ var terms = input.value.split(',').map(function(t) { return t.trim(); }).filter(function(t) { return t.length > 0; });
+ if (terms.length < 2) {
+ alert('Please enter at least 2 comma-separated terms.');
+ return;
+ }
+
+ try {
+ var res = await fetch('/admin/plugins/ai-search/api/relevance/synonyms', {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify({ terms: terms })
+ });
+ var data = await res.json();
+ if (data.success) {
+ synonymGroups.unshift(data.data);
+ renderSynonyms();
+ cancelSynonymAdd();
+ document.getElementById('msg').classList.remove('hidden');
+ setTimeout(function() { document.getElementById('msg').classList.add('hidden'); }, 2000);
+ } else {
+ alert('Error: ' + (data.error || 'Failed to create synonym group'));
+ }
+ } catch (e) {
+ alert('Error creating synonym group: ' + e.message);
+ }
+ }
+
+ async function toggleSynonymGroup(id, enabled) {
+ try {
+ var res = await fetch('/admin/plugins/ai-search/api/relevance/synonyms/' + id, {
+ method: 'PUT',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify({ enabled: enabled })
+ });
+ var data = await res.json();
+ if (data.success) {
+ for (var i = 0; i < synonymGroups.length; i++) {
+ if (synonymGroups[i].id === id) {
+ synonymGroups[i].enabled = enabled;
+ break;
+ }
+ }
+ renderSynonyms();
+ }
+ } catch (e) {
+ console.error('Error toggling synonym group:', e);
+ }
+ }
+
+ function startEditSynonym(id) {
+ editingSynonymId = id;
+ renderSynonyms();
+ var input = document.getElementById('synonym-edit-input');
+ if (input) input.focus();
+ }
+
+ function cancelEditSynonym() {
+ editingSynonymId = null;
+ renderSynonyms();
+ }
+
+ async function saveEditSynonym(id) {
+ var input = document.getElementById('synonym-edit-input');
+ if (!input) return;
+ var terms = input.value.split(',').map(function(t) { return t.trim(); }).filter(function(t) { return t.length > 0; });
+ if (terms.length < 2) {
+ alert('Please enter at least 2 comma-separated terms.');
+ return;
+ }
+
+ try {
+ var res = await fetch('/admin/plugins/ai-search/api/relevance/synonyms/' + id, {
+ method: 'PUT',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify({ terms: terms })
+ });
+ var data = await res.json();
+ if (data.success) {
+ for (var i = 0; i < synonymGroups.length; i++) {
+ if (synonymGroups[i].id === id) {
+ synonymGroups[i] = data.data;
+ break;
+ }
+ }
+ editingSynonymId = null;
+ renderSynonyms();
+ } else {
+ alert('Error: ' + (data.error || 'Failed to update'));
+ }
+ } catch (e) {
+ alert('Error updating synonym group: ' + e.message);
+ }
+ }
+
+ async function deleteSynonymGroup(id) {
+ if (!confirm('Delete this synonym group?')) return;
+ try {
+ var res = await fetch('/admin/plugins/ai-search/api/relevance/synonyms/' + id, {
+ method: 'DELETE',
+ headers: { 'Content-Type': 'application/json' }
+ });
+ var data = await res.json();
+ if (data.success) {
+ synonymGroups = synonymGroups.filter(function(g) { return g.id !== id; });
+ renderSynonyms();
+ }
+ } catch (e) {
+ alert('Error deleting synonym group: ' + e.message);
+ }
+ }
+
+ async function toggleSynonymsGlobal(enabled) {
+ try {
+ var res = await fetch('/admin/plugins/ai-search', {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify({ query_synonyms_enabled: enabled })
+ });
+ if (res.ok) {
+ document.getElementById('msg').classList.remove('hidden');
+ setTimeout(function() { document.getElementById('msg').classList.add('hidden'); }, 2000);
+ } else {
+ alert('Failed to update synonym setting');
+ }
+ } catch (e) {
+ alert('Error: ' + e.message);
+ }
+ }
+
+ // =============================================
+ // Query Substitution Rules
+ // =============================================
+ var queryRules = [];
+ var editingRuleId = null;
+
+ (async function loadQueryRules() {
+ try {
+ var res = await fetch('/admin/plugins/ai-search/api/relevance/rules');
+ var data = await res.json();
+ if (data.success && data.data) {
+ queryRules = data.data;
+ renderQueryRules();
+ }
+ } catch (e) {
+ console.error('Failed to load query rules:', e);
+ document.getElementById('rules-summary').textContent = 'Failed to load query rules.';
+ }
+ })();
+
+ function renderQueryRules() {
+ var container = document.getElementById('rules-list');
+ var summary = document.getElementById('rules-summary');
+ var enabledCount = queryRules.filter(function(r) { return r.enabled; }).length;
+ summary.textContent = queryRules.length + ' rule' + (queryRules.length !== 1 ? 's' : '') +
+ ' (' + enabledCount + ' enabled)';
+
+ if (queryRules.length === 0) {
+ container.innerHTML = 'No substitution rules defined. Click "Add Substitution Rule" to create one.
';
+ return;
+ }
+
+ var html = '';
+ for (var i = 0; i < queryRules.length; i++) {
+ var r = queryRules[i];
+ var isEditing = editingRuleId === r.id;
+ var matchTypeBadge = r.match_type === 'prefix'
+ ? 'prefix '
+ : 'exact ';
+
+ html += '';
+
+ // Enable/disable toggle
+ html += '
';
+
+ if (isEditing) {
+ // Editing mode
+ var patternEscaped = r.match_pattern.replace(/"/g, '"');
+ var substituteEscaped = r.substitute_query.replace(/"/g, '"');
+ html += '
' +
+ ' ' +
+ ' ' +
+ '' +
+ 'Exact ' +
+ 'Prefix ' +
+ ' ' +
+ ' ' +
+ '
';
+ html += '
Save ';
+ html += '
Cancel ';
+ } else {
+ // Display mode
+ html += '
' +
+ matchTypeBadge +
+ '
' +
+ r.match_pattern.replace(//g, '>') +
+ ' ' +
+ '
' +
+ '
' +
+ r.substitute_query.replace(//g, '>') +
+ ' ' +
+ (r.priority > 0 ? '
p' + r.priority + ' ' : '') +
+ '
';
+
+ // Edit & Delete buttons
+ html += '
Edit ';
+ html += '
Delete ';
+ }
+
+ html += '
';
+ }
+
+ container.innerHTML = html;
+ }
+
+ function showRuleAddForm() {
+ document.getElementById('rule-add-form').classList.remove('hidden');
+ document.getElementById('rule-add-btn').classList.add('hidden');
+ document.getElementById('rule-new-pattern').focus();
+ }
+
+ function cancelRuleAdd() {
+ document.getElementById('rule-add-form').classList.add('hidden');
+ document.getElementById('rule-add-btn').classList.remove('hidden');
+ document.getElementById('rule-new-pattern').value = '';
+ document.getElementById('rule-new-substitute').value = '';
+ document.getElementById('rule-new-match-type').value = 'exact';
+ document.getElementById('rule-new-priority').value = '0';
+ }
+
+ async function saveQueryRule() {
+ var pattern = document.getElementById('rule-new-pattern').value.trim();
+ var substitute = document.getElementById('rule-new-substitute').value.trim();
+ var matchType = document.getElementById('rule-new-match-type').value;
+ var priority = parseInt(document.getElementById('rule-new-priority').value, 10) || 0;
+
+ if (!pattern || !substitute) {
+ alert('Both pattern and replacement are required.');
+ return;
+ }
+
+ try {
+ var res = await fetch('/admin/plugins/ai-search/api/relevance/rules', {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify({
+ match_pattern: pattern,
+ match_type: matchType,
+ substitute_query: substitute,
+ priority: priority
+ })
+ });
+ var data = await res.json();
+ if (data.success) {
+ queryRules.unshift(data.data);
+ // Re-sort by priority DESC
+ queryRules.sort(function(a, b) { return b.priority - a.priority; });
+ renderQueryRules();
+ cancelRuleAdd();
+ document.getElementById('msg').classList.remove('hidden');
+ setTimeout(function() { document.getElementById('msg').classList.add('hidden'); }, 2000);
+ } else {
+ alert('Error: ' + (data.error || 'Failed to create rule'));
+ }
+ } catch (e) {
+ alert('Error creating rule: ' + e.message);
+ }
+ }
+
+ async function toggleQueryRule(id, enabled) {
+ try {
+ var res = await fetch('/admin/plugins/ai-search/api/relevance/rules/' + id, {
+ method: 'PUT',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify({ enabled: enabled })
+ });
+ var data = await res.json();
+ if (data.success) {
+ for (var i = 0; i < queryRules.length; i++) {
+ if (queryRules[i].id === id) {
+ queryRules[i].enabled = enabled;
+ break;
+ }
+ }
+ renderQueryRules();
+ }
+ } catch (e) {
+ console.error('Error toggling query rule:', e);
+ }
+ }
+
+ function startEditRule(id) {
+ editingRuleId = id;
+ renderQueryRules();
+ var input = document.getElementById('rule-edit-pattern');
+ if (input) input.focus();
+ }
+
+ function cancelEditRule() {
+ editingRuleId = null;
+ renderQueryRules();
+ }
+
+ async function saveEditRule(id) {
+ var pattern = document.getElementById('rule-edit-pattern');
+ var substitute = document.getElementById('rule-edit-substitute');
+ var matchType = document.getElementById('rule-edit-match-type');
+ var priority = document.getElementById('rule-edit-priority');
+ if (!pattern || !substitute) return;
+
+ var patternVal = pattern.value.trim();
+ var substituteVal = substitute.value.trim();
+ if (!patternVal || !substituteVal) {
+ alert('Both pattern and replacement are required.');
+ return;
+ }
+
+ try {
+ var res = await fetch('/admin/plugins/ai-search/api/relevance/rules/' + id, {
+ method: 'PUT',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify({
+ match_pattern: patternVal,
+ match_type: matchType.value,
+ substitute_query: substituteVal,
+ priority: parseInt(priority.value, 10) || 0
+ })
+ });
+ var data = await res.json();
+ if (data.success) {
+ for (var i = 0; i < queryRules.length; i++) {
+ if (queryRules[i].id === id) {
+ queryRules[i] = data.data;
+ break;
+ }
+ }
+ editingRuleId = null;
+ queryRules.sort(function(a, b) { return b.priority - a.priority; });
+ renderQueryRules();
+ } else {
+ alert('Error: ' + (data.error || 'Failed to update'));
+ }
+ } catch (e) {
+ alert('Error updating rule: ' + e.message);
+ }
+ }
+
+ async function deleteQueryRule(id) {
+ if (!confirm('Delete this substitution rule?')) return;
+ try {
+ var res = await fetch('/admin/plugins/ai-search/api/relevance/rules/' + id, {
+ method: 'DELETE',
+ headers: { 'Content-Type': 'application/json' }
+ });
+ var data = await res.json();
+ if (data.success) {
+ queryRules = queryRules.filter(function(r) { return r.id !== id; });
+ renderQueryRules();
+ }
+ } catch (e) {
+ alert('Error deleting rule: ' + e.message);
+ }
+ }
+
+ // =============================================
+ // Related Searches
+ // =============================================
+ var relatedSearches = [];
+ var editingRelatedId = null;
+
+ (async function loadRelatedSearches() {
+ try {
+ var res = await fetch('/admin/plugins/ai-search/api/related-searches');
+ var data = await res.json();
+ if (data.success && data.data) {
+ relatedSearches = data.data;
+ renderRelatedSearches();
+ }
+ } catch (e) {
+ console.error('Failed to load related searches:', e);
+ document.getElementById('related-summary').textContent = 'Failed to load related searches.';
+ }
+ })();
+
+ function renderRelatedSearches() {
+ var container = document.getElementById('related-list');
+ var summary = document.getElementById('related-summary');
+ var enabledCount = relatedSearches.filter(function(r) { return r.enabled; }).length;
+ summary.textContent = relatedSearches.length + ' pair' + (relatedSearches.length !== 1 ? 's' : '') +
+ ' (' + enabledCount + ' enabled)';
+
+ if (relatedSearches.length === 0) {
+ container.innerHTML = 'No related search pairs configured. Click \\'Add Related Search\\' to create one, or run the Quality Agent to generate suggestions.
';
+ return;
+ }
+
+ var sourceColors = {
+ manual: 'bg-emerald-50 dark:bg-emerald-900/30 text-emerald-700 dark:text-emerald-300 ring-emerald-600/20 dark:ring-emerald-500/20',
+ agent: 'bg-purple-50 dark:bg-purple-900/30 text-purple-700 dark:text-purple-300 ring-purple-600/20 dark:ring-purple-500/20',
+ auto: 'bg-zinc-100 dark:bg-zinc-800 text-zinc-600 dark:text-zinc-400 ring-zinc-600/20 dark:ring-zinc-500/20'
+ };
+
+ var html = '';
+ for (var i = 0; i < relatedSearches.length; i++) {
+ var r = relatedSearches[i];
+ var isEditing = editingRelatedId === r.id;
+ var srcColor = sourceColors[r.source] || sourceColors.auto;
+
+ html += '';
+
+ // Enable/disable toggle
+ html += '
';
+
+ // Source badge
+ html += '
' + (r.source || 'manual') + ' ';
+
+ if (isEditing) {
+ // Edit mode: only related_query is editable
+ var targetEscaped = (r.related_query || '').replace(/"/g, '"');
+ html += '
' +
+ (r.source_query || '').replace(//g, '>') + ' ';
+ html += '
';
+ html += '
';
+ html += '
Save ';
+ html += '
Cancel ';
+ } else {
+ // Display mode
+ html += '
' +
+ '
' +
+ (r.source_query || '').replace(//g, '>') +
+ ' ' +
+ '
' +
+ '
' +
+ (r.related_query || '').replace(//g, '>') +
+ ' ';
+
+ // Bidirectional badge
+ if (r.bidirectional) {
+ html += '
bidi ';
+ }
+
+ html += '
';
+
+ // Edit & Delete buttons
+ html += '
Edit ';
+ html += '
Delete ';
+ }
+
+ html += '
';
+ }
+
+ container.innerHTML = html;
+ }
+
+ function showRelatedAddForm() {
+ document.getElementById('related-add-form').classList.remove('hidden');
+ document.getElementById('related-add-btn').classList.add('hidden');
+ document.getElementById('related-new-source').focus();
+ }
+
+ function cancelRelatedAdd() {
+ document.getElementById('related-add-form').classList.add('hidden');
+ document.getElementById('related-add-btn').classList.remove('hidden');
+ document.getElementById('related-new-source').value = '';
+ document.getElementById('related-new-target').value = '';
+ document.getElementById('related-new-bidirectional').checked = false;
+ }
+
+ async function saveRelatedSearch() {
+ var source = document.getElementById('related-new-source').value.trim();
+ var target = document.getElementById('related-new-target').value.trim();
+ var bidirectional = document.getElementById('related-new-bidirectional').checked;
+
+ if (!source || !target) {
+ alert('Both source query and related query are required.');
+ return;
+ }
+
+ try {
+ var body = { source_query: source, related_query: target };
+ if (bidirectional) body.bidirectional = true;
+
+ var res = await fetch('/admin/plugins/ai-search/api/related-searches', {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify(body)
+ });
+ var data = await res.json();
+ if (data.success) {
+ // Reload full list to pick up bidirectional reverse pair if created
+ var listRes = await fetch('/admin/plugins/ai-search/api/related-searches');
+ var listData = await listRes.json();
+ if (listData.success && listData.data) {
+ relatedSearches = listData.data;
+ }
+ renderRelatedSearches();
+ cancelRelatedAdd();
+ document.getElementById('msg').classList.remove('hidden');
+ setTimeout(function() { document.getElementById('msg').classList.add('hidden'); }, 2000);
+ } else {
+ alert('Error: ' + (data.error || 'Failed to create related search'));
+ }
+ } catch (e) {
+ alert('Error creating related search: ' + e.message);
+ }
+ }
+
+ async function toggleRelatedSearch(id, enabled) {
+ try {
+ var res = await fetch('/admin/plugins/ai-search/api/related-searches/' + id, {
+ method: 'PUT',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify({ enabled: enabled })
+ });
+ var data = await res.json();
+ if (data.success) {
+ for (var i = 0; i < relatedSearches.length; i++) {
+ if (relatedSearches[i].id === id) {
+ relatedSearches[i].enabled = enabled;
+ break;
+ }
+ }
+ renderRelatedSearches();
+ }
+ } catch (e) {
+ console.error('Error toggling related search:', e);
+ }
+ }
+
+ function startEditRelated(id) {
+ editingRelatedId = id;
+ renderRelatedSearches();
+ var input = document.getElementById('related-edit-input');
+ if (input) input.focus();
+ }
+
+ function cancelEditRelated() {
+ editingRelatedId = null;
+ renderRelatedSearches();
+ }
+
+ async function saveEditRelated(id) {
+ var input = document.getElementById('related-edit-input');
+ if (!input) return;
+ var relatedQuery = input.value.trim();
+ if (!relatedQuery) {
+ alert('Related query cannot be empty.');
+ return;
+ }
+
+ try {
+ var res = await fetch('/admin/plugins/ai-search/api/related-searches/' + id, {
+ method: 'PUT',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify({ related_query: relatedQuery })
+ });
+ var data = await res.json();
+ if (data.success) {
+ for (var i = 0; i < relatedSearches.length; i++) {
+ if (relatedSearches[i].id === id) {
+ relatedSearches[i] = data.data;
+ break;
+ }
+ }
+ editingRelatedId = null;
+ renderRelatedSearches();
+ } else {
+ alert('Error: ' + (data.error || 'Failed to update'));
+ }
+ } catch (e) {
+ alert('Error updating related search: ' + e.message);
+ }
+ }
+
+ async function deleteRelatedSearch(id) {
+ if (!confirm('Delete this related search pair?')) return;
+ try {
+ var res = await fetch('/admin/plugins/ai-search/api/related-searches/' + id, {
+ method: 'DELETE',
+ headers: { 'Content-Type': 'application/json' }
+ });
+ var data = await res.json();
+ if (data.success) {
+ relatedSearches = relatedSearches.filter(function(r) { return r.id !== id; });
+ renderRelatedSearches();
+ }
+ } catch (e) {
+ alert('Error deleting related search: ' + e.message);
+ }
+ }
+
+ async function clearRelatedCache() {
+ if (!confirm('This clears automatically generated suggestions. They will regenerate on the next search. Continue?')) return;
+ try {
+ var res = await fetch('/admin/plugins/ai-search/api/related-searches/cache', {
+ method: 'DELETE',
+ headers: { 'Content-Type': 'application/json' }
+ });
+ var data = await res.json();
+ if (data.success) {
+ document.getElementById('msg').classList.remove('hidden');
+ setTimeout(function() { document.getElementById('msg').classList.add('hidden'); }, 2000);
+ // Reload list in case auto entries were removed
+ var listRes = await fetch('/admin/plugins/ai-search/api/related-searches');
+ var listData = await listRes.json();
+ if (listData.success && listData.data) {
+ relatedSearches = listData.data;
+ renderRelatedSearches();
+ }
+ } else {
+ alert('Error: ' + (data.error || 'Failed to clear cache'));
+ }
+ } catch (e) {
+ alert('Error clearing cache: ' + e.message);
+ }
+ }
+ `;
+}
+
+// src/templates/pages/admin-search-analytics.template.ts
+function renderAnalyticsTab() {
+ return `
+
+
+
+
+
+
+
+
Total Queries (30d)
+
—
+
+
+
+
+
Avg Response Time
+
—
+
+
+
+
+
+
+
Click-Through Rate (30d)
+
—
+
+
+
+
+
Avg Click Position
+
—
+
+
+
+
+
+
+
+
+
Queries Over Time
+
+
+
+
+
+
+
+
Mode Distribution
+
+
+
+
+
+
+
+
+
Click-Through Rate Over Time
+
+
+
+
+
+
+
+
Facet Analytics
+
+
+
+
+
+
Facet Clicks (30d)
+
—
+
+
+
+
+
+
+
Facet Clicks Over Time
+
+
+
+
+
+
+
+
+
+
+
Most Used Facets
+
Which facet filters users click most (30 days)
+
+
+
+
+
+ Facet Field
+ Clicks
+
+
+
+ Loading...
+
+
+
+
+
+
+
+
+
Top Facet Values
+
Most clicked filter values (30 days)
+
+
+
+
+
+ Facet
+ Value
+ Clicks
+
+
+
+ Loading...
+
+
+
+
+
+
+
+
+
+
+
+
+
Popular Queries
+
+
+
+
+
+ Query
+ Count
+
+
+
+ Loading...
+
+
+
+
+
+
+
+
+
Zero-Result Queries
+
Content gaps \u2014 what users search for but can't find
+
+
+
+
+
+ Query
+ Count
+
+
+
+ Loading...
+
+
+
+
+
+
+
+
+
+
+
+
Most Clicked Content
+
Top content by click count (30 days)
+
+
+
+
+
+ Content
+ Clicks
+
+
+
+ Loading...
+
+
+
+
+
+
+
+
+
Searches With No Clicks
+
Queries that returned results but users didn't click
+
+
+
+
+
+ Query
+ Searches
+ Avg Results
+
+
+
+ Loading...
+
+
+
+
+
+
+
+
+
+
Recent Queries
+
+
+
+
+
+ Query
+ Mode
+ Results
+ Time
+ When
+
+
+
+ Loading...
+
+
+
+
+
+
+
+ `;
+}
+function renderAnalyticsScript() {
+ return `
+ // =============================================
+ // Analytics Tab
+ // =============================================
+ var analyticsLoaded = false;
+ var dailyChart = null;
+ var modeChart = null;
+ var ctrChart = null;
+
+ // Extend switchTab to trigger lazy loading
+ var _origSwitchTab = switchTab;
+ switchTab = function(tabId) {
+ _origSwitchTab(tabId);
+ if (tabId === 'analytics' && !analyticsLoaded) {
+ loadAnalytics();
+ }
+ if (tabId === 'configuration') {
+ loadFacetConfig();
+ }
+ };
+
+ async function loadAnalytics() {
+ try {
+ var res = await fetch('/admin/plugins/ai-search/api/analytics/extended');
+ if (!res.ok) throw new Error('Failed to fetch analytics');
+ var json = await res.json();
+ if (!json.success) throw new Error(json.error || 'Unknown error');
+ var d = json.data;
+ analyticsLoaded = true;
+
+ // Stat cards
+ document.getElementById('ana-total-queries').textContent = d.total_queries.toLocaleString();
+ document.getElementById('ana-avg-time').textContent = d.avg_response_time_ms > 0 ? d.avg_response_time_ms + 'ms' : 'N/A';
+ document.getElementById('ana-zero-rate').textContent = d.zero_result_rate + '%';
+ document.getElementById('ana-today').textContent = d.queries_today.toLocaleString();
+
+ // Daily chart
+ renderDailyChart(d.daily_counts);
+
+ // Mode chart
+ renderModeChart(d);
+
+ // Popular queries table
+ renderQueryTable('ana-popular-tbody', d.popular_queries, false);
+
+ // Zero-result queries table
+ renderQueryTable('ana-zero-tbody', d.zero_result_queries, true);
+
+ // Recent queries table
+ renderRecentTable(d.recent_queries);
+
+ // Click analytics
+ document.getElementById('ana-ctr').textContent = d.total_clicks_30d > 0 ? d.ctr_30d + '%' : 'No data';
+ document.getElementById('ana-avg-pos').textContent = d.avg_click_position_30d > 0 ? d.avg_click_position_30d.toFixed(1) : 'No data';
+
+ // CTR over time chart
+ renderCtrChart(d.ctr_over_time);
+
+ // Most clicked content table
+ renderClickedTable(d.most_clicked_content);
+
+ // No-click searches table
+ renderNoClickTable(d.no_click_searches);
+
+ // Facet analytics
+ document.getElementById('ana-facet-clicks').textContent =
+ d.total_facet_clicks_30d > 0 ? d.total_facet_clicks_30d.toLocaleString() : 'No data';
+ renderFacetClicksChart(d.facet_clicks_over_time || []);
+ renderFacetFieldsTable(d.top_facet_fields || []);
+ renderFacetValuesTable(d.top_facet_values || []);
+
+ } catch (e) {
+ console.error('Analytics load error:', e);
+ document.getElementById('ana-total-queries').textContent = 'Error';
+ }
+ }
+
+ function renderDailyChart(dailyCounts) {
+ var canvas = document.getElementById('ana-daily-chart');
+ if (!canvas || typeof Chart === 'undefined') return;
+
+ // Fill in missing days with 0
+ var labels = [];
+ var data = [];
+ var countMap = {};
+ for (var i = 0; i < dailyCounts.length; i++) {
+ countMap[dailyCounts[i].date] = dailyCounts[i].count;
+ }
+ var now = new Date();
+ for (var d = 29; d >= 0; d--) {
+ var dt = new Date(now);
+ dt.setDate(dt.getDate() - d);
+ var key = dt.toISOString().split('T')[0];
+ labels.push(dt.toLocaleDateString('en-US', { month: 'short', day: 'numeric' }));
+ data.push(countMap[key] || 0);
+ }
+
+ var isDark = document.documentElement.classList.contains('dark');
+ var gridColor = isDark ? 'rgba(255,255,255,0.06)' : 'rgba(0,0,0,0.06)';
+ var textColor = isDark ? '#a1a1aa' : '#71717a';
+
+ if (dailyChart) dailyChart.destroy();
+ dailyChart = new Chart(canvas, {
+ type: 'line',
+ data: {
+ labels: labels,
+ datasets: [{
+ label: 'Queries',
+ data: data,
+ borderColor: '#6366f1',
+ backgroundColor: isDark ? 'rgba(99,102,241,0.15)' : 'rgba(99,102,241,0.1)',
+ borderWidth: 2,
+ fill: true,
+ tension: 0.3,
+ pointRadius: 0,
+ pointHoverRadius: 5,
+ pointHoverBackgroundColor: '#6366f1'
+ }]
+ },
+ options: {
+ responsive: true,
+ maintainAspectRatio: false,
+ plugins: {
+ legend: { display: false },
+ tooltip: {
+ backgroundColor: isDark ? '#27272a' : '#fff',
+ titleColor: isDark ? '#e4e4e7' : '#18181b',
+ bodyColor: isDark ? '#a1a1aa' : '#52525b',
+ borderColor: isDark ? '#3f3f46' : '#e4e4e7',
+ borderWidth: 1
+ }
+ },
+ scales: {
+ x: {
+ grid: { color: gridColor },
+ ticks: { color: textColor, maxTicksLimit: 8, font: { size: 11 } }
+ },
+ y: {
+ beginAtZero: true,
+ grid: { color: gridColor },
+ ticks: { color: textColor, font: { size: 11 }, precision: 0 }
+ }
+ }
+ }
+ });
+ }
+
+ function renderModeChart(d) {
+ var canvas = document.getElementById('ana-mode-chart');
+ if (!canvas || typeof Chart === 'undefined') return;
+
+ var total = d.fts5_queries + d.keyword_queries + d.ai_queries + d.hybrid_queries;
+ if (total === 0) {
+ canvas.parentElement.innerHTML = 'No search data yet
';
+ return;
+ }
+
+ var isDark = document.documentElement.classList.contains('dark');
+
+ if (modeChart) modeChart.destroy();
+ modeChart = new Chart(canvas, {
+ type: 'doughnut',
+ data: {
+ labels: ['FTS5', 'Keyword', 'AI', 'Hybrid'],
+ datasets: [{
+ data: [d.fts5_queries, d.keyword_queries, d.ai_queries, d.hybrid_queries],
+ backgroundColor: ['#6366f1', '#71717a', '#06b6d4', '#a855f7'],
+ borderColor: isDark ? '#18181b' : '#ffffff',
+ borderWidth: 2
+ }]
+ },
+ options: {
+ responsive: true,
+ maintainAspectRatio: false,
+ plugins: {
+ legend: {
+ position: 'bottom',
+ labels: {
+ color: isDark ? '#a1a1aa' : '#52525b',
+ padding: 16,
+ usePointStyle: true,
+ pointStyleWidth: 10,
+ font: { size: 12 }
+ }
+ },
+ tooltip: {
+ backgroundColor: isDark ? '#27272a' : '#fff',
+ titleColor: isDark ? '#e4e4e7' : '#18181b',
+ bodyColor: isDark ? '#a1a1aa' : '#52525b',
+ borderColor: isDark ? '#3f3f46' : '#e4e4e7',
+ borderWidth: 1,
+ callbacks: {
+ label: function(ctx) {
+ var val = ctx.parsed;
+ var pct = total > 0 ? Math.round((val / total) * 100) : 0;
+ return ctx.label + ': ' + val + ' (' + pct + '%)';
+ }
+ }
+ }
+ },
+ cutout: '60%'
+ }
+ });
+ }
+
+ function escapeAnalyticsHtml(str) {
+ if (!str) return '';
+ return str.replace(/&/g, '&').replace(//g, '>').replace(/"/g, '"');
+ }
+
+ function renderQueryTable(tbodyId, queries, isZeroResult) {
+ var tbody = document.getElementById(tbodyId);
+ if (!tbody) return;
+
+ if (!queries || queries.length === 0) {
+ tbody.innerHTML = '' +
+ (isZeroResult ? 'No zero-result queries found' : 'No search data yet') + ' ';
+ return;
+ }
+
+ var html = '';
+ for (var i = 0; i < queries.length; i++) {
+ var q = queries[i];
+ html += '' +
+ '' + escapeAnalyticsHtml(q.query) + ' ' +
+ '' + q.count + ' ' +
+ ' ';
+ }
+ tbody.innerHTML = html;
+ }
+
+ function renderRecentTable(queries) {
+ var tbody = document.getElementById('ana-recent-tbody');
+ if (!tbody) return;
+
+ if (!queries || queries.length === 0) {
+ tbody.innerHTML = 'No recent queries ';
+ return;
+ }
+
+ var modeColors = {
+ fts5: 'bg-indigo-100 dark:bg-indigo-900/30 text-indigo-700 dark:text-indigo-300',
+ keyword: 'bg-zinc-100 dark:bg-zinc-700/50 text-zinc-700 dark:text-zinc-300',
+ ai: 'bg-cyan-100 dark:bg-cyan-900/30 text-cyan-700 dark:text-cyan-300',
+ hybrid: 'bg-purple-100 dark:bg-purple-900/30 text-purple-700 dark:text-purple-300'
+ };
+
+ var html = '';
+ var now = Date.now();
+ for (var i = 0; i < queries.length; i++) {
+ var q = queries[i];
+ var modeClass = modeColors[q.mode] || modeColors.keyword;
+ var timeStr = q.response_time_ms != null ? q.response_time_ms + 'ms' : '\u2014';
+ var ago = formatTimeAgo(now - q.created_at);
+
+ html += '' +
+ '' + escapeAnalyticsHtml(q.query) + ' ' +
+ '' + q.mode + ' ' +
+ '' + q.results_count + ' ' +
+ '' + timeStr + ' ' +
+ '' + ago + ' ' +
+ ' ';
+ }
+ tbody.innerHTML = html;
+ }
+
+ function renderCtrChart(ctrData) {
+ var canvas = document.getElementById('ana-ctr-chart');
+ if (!canvas || typeof Chart === 'undefined') return;
+
+ if (!ctrData || ctrData.length === 0) {
+ canvas.parentElement.innerHTML = 'No click data yet
';
+ return;
+ }
+
+ // Fill in missing days with 0
+ var labels = [];
+ var data = [];
+ var ctrMap = {};
+ for (var i = 0; i < ctrData.length; i++) {
+ ctrMap[ctrData[i].date] = ctrData[i].ctr;
+ }
+ var now = new Date();
+ for (var d = 29; d >= 0; d--) {
+ var dt = new Date(now);
+ dt.setDate(dt.getDate() - d);
+ var key = dt.toISOString().split('T')[0];
+ labels.push(dt.toLocaleDateString('en-US', { month: 'short', day: 'numeric' }));
+ data.push(ctrMap[key] || 0);
+ }
+
+ var isDark = document.documentElement.classList.contains('dark');
+ var gridColor = isDark ? 'rgba(255,255,255,0.06)' : 'rgba(0,0,0,0.06)';
+ var textColor = isDark ? '#a1a1aa' : '#71717a';
+
+ if (ctrChart) ctrChart.destroy();
+ ctrChart = new Chart(canvas, {
+ type: 'line',
+ data: {
+ labels: labels,
+ datasets: [{
+ label: 'CTR %',
+ data: data,
+ borderColor: '#10b981',
+ backgroundColor: isDark ? 'rgba(16,185,129,0.15)' : 'rgba(16,185,129,0.1)',
+ borderWidth: 2,
+ fill: true,
+ tension: 0.3,
+ pointRadius: 0,
+ pointHoverRadius: 5,
+ pointHoverBackgroundColor: '#10b981'
+ }]
+ },
+ options: {
+ responsive: true,
+ maintainAspectRatio: false,
+ plugins: {
+ legend: { display: false },
+ tooltip: {
+ backgroundColor: isDark ? '#27272a' : '#fff',
+ titleColor: isDark ? '#e4e4e7' : '#18181b',
+ bodyColor: isDark ? '#a1a1aa' : '#52525b',
+ borderColor: isDark ? '#3f3f46' : '#e4e4e7',
+ borderWidth: 1,
+ callbacks: {
+ label: function(ctx) { return 'CTR: ' + ctx.parsed.y.toFixed(1) + '%'; }
+ }
+ }
+ },
+ scales: {
+ x: {
+ grid: { color: gridColor },
+ ticks: { color: textColor, maxTicksLimit: 8, font: { size: 11 } }
+ },
+ y: {
+ beginAtZero: true,
+ grid: { color: gridColor },
+ ticks: { color: textColor, font: { size: 11 }, callback: function(v) { return v + '%'; } }
+ }
+ }
+ }
+ });
+ }
+
+ function renderClickedTable(items) {
+ var tbody = document.getElementById('ana-clicked-tbody');
+ if (!tbody) return;
+
+ if (!items || items.length === 0) {
+ tbody.innerHTML = 'No click data yet ';
+ return;
+ }
+
+ var html = '';
+ for (var i = 0; i < items.length; i++) {
+ var item = items[i];
+ html += '' +
+ '' + escapeAnalyticsHtml(item.content_title) + ' ' +
+ '' + item.click_count + ' ' +
+ ' ';
+ }
+ tbody.innerHTML = html;
+ }
+
+ function renderNoClickTable(items) {
+ var tbody = document.getElementById('ana-noclick-tbody');
+ if (!tbody) return;
+
+ if (!items || items.length === 0) {
+ tbody.innerHTML = 'No data yet \u2014 all searches got clicks! ';
+ return;
+ }
+
+ var html = '';
+ for (var i = 0; i < items.length; i++) {
+ var item = items[i];
+ html += '' +
+ '' + escapeAnalyticsHtml(item.query) + ' ' +
+ '' + item.search_count + ' ' +
+ '' + item.results_count_avg + ' ' +
+ ' ';
+ }
+ tbody.innerHTML = html;
+ }
+
+ var facetClicksChart = null;
+
+ function renderFacetClicksChart(dailyCounts) {
+ var canvas = document.getElementById('ana-facet-chart');
+ if (!canvas || typeof Chart === 'undefined') return;
+
+ if (!dailyCounts || dailyCounts.length === 0) {
+ canvas.parentElement.innerHTML = 'No facet click data yet
';
+ return;
+ }
+
+ var labels = [];
+ var data = [];
+ var countMap = {};
+ for (var i = 0; i < dailyCounts.length; i++) {
+ countMap[dailyCounts[i].date] = dailyCounts[i].count;
+ }
+ var now = new Date();
+ for (var dd = 29; dd >= 0; dd--) {
+ var dt = new Date(now);
+ dt.setDate(dt.getDate() - dd);
+ var key = dt.toISOString().split('T')[0];
+ labels.push(dt.toLocaleDateString('en-US', { month: 'short', day: 'numeric' }));
+ data.push(countMap[key] || 0);
+ }
+
+ var isDark = document.documentElement.classList.contains('dark');
+ var gridColor = isDark ? 'rgba(255,255,255,0.06)' : 'rgba(0,0,0,0.06)';
+ var textColor = isDark ? '#a1a1aa' : '#71717a';
+
+ if (facetClicksChart) facetClicksChart.destroy();
+ facetClicksChart = new Chart(canvas, {
+ type: 'bar',
+ data: {
+ labels: labels,
+ datasets: [{
+ label: 'Facet Clicks',
+ data: data,
+ backgroundColor: isDark ? 'rgba(168,85,247,0.4)' : 'rgba(168,85,247,0.6)',
+ borderColor: '#a855f7',
+ borderWidth: 1,
+ borderRadius: 3
+ }]
+ },
+ options: {
+ responsive: true,
+ maintainAspectRatio: false,
+ plugins: {
+ legend: { display: false },
+ tooltip: {
+ backgroundColor: isDark ? '#27272a' : '#fff',
+ titleColor: isDark ? '#e4e4e7' : '#18181b',
+ bodyColor: isDark ? '#a1a1aa' : '#52525b',
+ borderColor: isDark ? '#3f3f46' : '#e4e4e7',
+ borderWidth: 1
+ }
+ },
+ scales: {
+ x: { grid: { color: gridColor }, ticks: { color: textColor, maxTicksLimit: 8, font: { size: 11 } } },
+ y: { beginAtZero: true, grid: { color: gridColor }, ticks: { color: textColor, font: { size: 11 }, precision: 0 } }
+ }
+ }
+ });
+ }
+
+ function renderFacetFieldsTable(items) {
+ var tbody = document.getElementById('ana-facet-fields-tbody');
+ if (!tbody) return;
+
+ if (!items || items.length === 0) {
+ tbody.innerHTML = 'No facet click data yet ';
+ return;
+ }
+
+ var html = '';
+ for (var i = 0; i < items.length; i++) {
+ var item = items[i];
+ var displayName = item.facet_field;
+ if (displayName.startsWith('$.')) displayName = displayName.slice(2);
+ displayName = displayName.charAt(0).toUpperCase() + displayName.slice(1);
+ html += '' +
+ '' + escapeAnalyticsHtml(displayName) + ' ' +
+ '' + item.click_count + ' ' +
+ ' ';
+ }
+ tbody.innerHTML = html;
+ }
+
+ function renderFacetValuesTable(items) {
+ var tbody = document.getElementById('ana-facet-values-tbody');
+ if (!tbody) return;
+
+ if (!items || items.length === 0) {
+ tbody.innerHTML = 'No facet click data yet ';
+ return;
+ }
+
+ var html = '';
+ for (var i = 0; i < items.length; i++) {
+ var item = items[i];
+ var fieldDisplay = item.facet_field;
+ if (fieldDisplay.startsWith('$.')) fieldDisplay = fieldDisplay.slice(2);
+ fieldDisplay = fieldDisplay.charAt(0).toUpperCase() + fieldDisplay.slice(1);
+ html += '' +
+ '' + escapeAnalyticsHtml(fieldDisplay) + ' ' +
+ '' + escapeAnalyticsHtml(item.facet_value) + ' ' +
+ '' + item.click_count + ' ' +
+ ' ';
+ }
+ tbody.innerHTML = html;
+ }
+
+ function formatTimeAgo(ms) {
+ var sec = Math.floor(ms / 1000);
+ if (sec < 60) return 'just now';
+ var min = Math.floor(sec / 60);
+ if (min < 60) return min + 'm ago';
+ var hr = Math.floor(min / 60);
+ if (hr < 24) return hr + 'h ago';
+ var days = Math.floor(hr / 24);
+ return days + 'd ago';
+ }
+
+ // Auto-load if we navigated directly to #analytics
+ if (initTab === 'analytics') {
+ loadAnalytics();
+ }
+ `;
+}
+
+// src/templates/pages/admin-search-agent.template.ts
+function renderAgentTab() {
+ return `
+
+
+
+
+
+
+
Search Quality Agent
+
Automated analysis of search analytics to surface actionable improvements
+
+
+
+
+
+
+
+ Run Analysis
+
+
+
+
+
+
+
+
+
+
+ All Categories
+ Synonym
+ Query Rule
+ Low CTR
+ Unused Facet
+ Content Gap
+ Related Search
+
+
+ Pending
+ All Statuses
+ Applied
+ Dismissed
+
+
+ Dismiss All
+
+
+
+
+
+
Run analysis to generate recommendations
+
+
+
+
+
+ Run History
+
+
+
+
+
+
+ Status
+ Recommendations
+ Duration
+ When
+
+
+
+ No runs yet
+
+
+
+
+
+
+
+
+ `;
+}
+function renderAgentScript() {
+ return `
+ // =============================================
+ // Agent Tab
+ // =============================================
+ var agentLoaded = false;
+ var agentPollTimer = null;
+
+ // Hook into switchTab for lazy loading
+ var _agentOrigSwitchTab = switchTab;
+ switchTab = function(tabId) {
+ _agentOrigSwitchTab(tabId);
+ if (tabId === 'agent' && !agentLoaded) {
+ agentLoaded = true;
+ loadAgentStatus();
+ loadRecommendations();
+ loadRunHistory();
+ }
+ };
+
+ function agentBasePath() {
+ return '/admin/plugins/ai-search/api/agent';
+ }
+
+ async function loadAgentStatus() {
+ try {
+ var res = await fetch(agentBasePath() + '/status');
+ if (!res.ok) throw new Error('Failed');
+ var json = await res.json();
+ if (!json.success) throw new Error(json.error || 'Unknown');
+ var d = json.data;
+
+ document.getElementById('agent-stat-pending').textContent = d.stats.pending;
+ document.getElementById('agent-stat-applied').textContent = d.stats.applied;
+ document.getElementById('agent-stat-dismissed').textContent = d.stats.dismissed;
+
+ if (d.latest_run) {
+ var badge = document.getElementById('agent-run-badge');
+ var statusColors = {
+ running: 'bg-blue-100 dark:bg-blue-900/30 text-blue-700 dark:text-blue-300',
+ completed: 'bg-lime-100 dark:bg-lime-900/30 text-lime-700 dark:text-lime-300',
+ failed: 'bg-red-100 dark:bg-red-900/30 text-red-700 dark:text-red-300'
+ };
+ badge.className = 'inline-flex items-center rounded-full px-2.5 py-0.5 text-xs font-medium ' + (statusColors[d.latest_run.status] || '');
+ badge.textContent = d.latest_run.status;
+ badge.classList.remove('hidden');
+
+ var lastRunEl = document.getElementById('agent-stat-lastrun');
+ if (d.latest_run.duration_ms) {
+ lastRunEl.textContent = (d.latest_run.duration_ms / 1000).toFixed(1) + 's';
+ } else if (d.latest_run.status === 'running') {
+ lastRunEl.textContent = 'Running...';
+ } else {
+ lastRunEl.textContent = 'N/A';
+ }
+
+ // Enable/disable run button
+ var btn = document.getElementById('agent-run-btn');
+ btn.disabled = d.latest_run.status === 'running';
+ }
+ } catch (e) {
+ console.error('Agent status error:', e);
+ }
+ }
+
+ async function loadRecommendations() {
+ var category = document.getElementById('agent-filter-category').value;
+ var status = document.getElementById('agent-filter-status').value;
+ var params = new URLSearchParams();
+ if (category) params.set('category', category);
+ if (status) params.set('status', status);
+
+ var container = document.getElementById('agent-recommendations-list');
+ try {
+ var res = await fetch(agentBasePath() + '/recommendations?' + params.toString());
+ if (!res.ok) throw new Error('Failed');
+ var json = await res.json();
+ if (!json.success) throw new Error(json.error || 'Unknown');
+
+ var recs = json.data;
+ if (!recs || recs.length === 0) {
+ container.innerHTML = 'No recommendations found
';
+ return;
+ }
+
+ var categoryColors = {
+ synonym: 'bg-purple-100 dark:bg-purple-900/30 text-purple-700 dark:text-purple-300',
+ query_rule: 'bg-blue-100 dark:bg-blue-900/30 text-blue-700 dark:text-blue-300',
+ low_ctr: 'bg-amber-100 dark:bg-amber-900/30 text-amber-700 dark:text-amber-300',
+ unused_facet: 'bg-red-100 dark:bg-red-900/30 text-red-700 dark:text-red-300',
+ content_gap: 'bg-sky-100 dark:bg-sky-900/30 text-sky-700 dark:text-sky-300',
+ related_search: 'bg-teal-100 dark:bg-teal-900/30 text-teal-700 dark:text-teal-300'
+ };
+ var categoryLabels = {
+ synonym: 'Synonym',
+ query_rule: 'Query Rule',
+ low_ctr: 'Low CTR',
+ unused_facet: 'Unused Facet',
+ content_gap: 'Content Gap',
+ related_search: 'Related Search'
+ };
+
+ var html = '';
+ for (var i = 0; i < recs.length; i++) {
+ var r = recs[i];
+ var catColor = categoryColors[r.category] || '';
+ var catLabel = categoryLabels[r.category] || r.category;
+ var canApply = (r.status === 'pending');
+ var isActionable = (r.category === 'synonym' || r.category === 'query_rule');
+
+ html += '';
+ html += '
';
+ html += '
';
+
+ // Category badge + status
+ html += '
';
+ html += '' + escapeAgentHtml(catLabel) + ' ';
+ if (r.status !== 'pending') {
+ var statusColor = r.status === 'applied' ? 'text-lime-600 dark:text-lime-400' : 'text-zinc-400 dark:text-zinc-500';
+ html += '' + r.status + ' ';
+ }
+ html += '
';
+
+ // Title + description
+ html += '
' + escapeAgentHtml(r.title) + ' ';
+ html += '
' + escapeAgentHtml(r.description) + '
';
+
+ // Supporting data badges
+ var sd = r.supporting_data || {};
+ var sdKeys = Object.keys(sd);
+ if (sdKeys.length > 0) {
+ html += '
';
+ for (var k = 0; k < sdKeys.length; k++) {
+ var key = sdKeys[k];
+ var val = sd[key];
+ html += '' + escapeAgentHtml(key.replace(/_/g, ' ')) + ': ' + escapeAgentHtml(String(val)) + ' ';
+ }
+ html += '
';
+ }
+
+ html += '
'; // end flex-1
+
+ // Action buttons
+ if (canApply) {
+ html += '
';
+ if (isActionable) {
+ html += 'Apply ';
+ } else {
+ html += 'Acknowledge ';
+ }
+ html += 'Dismiss ';
+ html += '
';
+ }
+
+ html += '
'; // end flex
+ html += '
'; // end card
+ }
+ container.innerHTML = html;
+ } catch (e) {
+ console.error('Load recommendations error:', e);
+ container.innerHTML = 'Failed to load recommendations
';
+ }
+ }
+
+ async function runAgentAnalysis() {
+ var btn = document.getElementById('agent-run-btn');
+ btn.disabled = true;
+ btn.textContent = 'Running...';
+
+ try {
+ var res = await fetch(agentBasePath() + '/run', { method: 'POST' });
+ if (!res.ok) throw new Error('Failed to start analysis');
+ var json = await res.json();
+ if (!json.success) throw new Error(json.error || 'Unknown');
+
+ // Poll until complete
+ agentPollTimer = setInterval(async function() {
+ try {
+ var statusRes = await fetch(agentBasePath() + '/status');
+ var statusJson = await statusRes.json();
+ if (statusJson.success && statusJson.data.latest_run) {
+ var run = statusJson.data.latest_run;
+ if (run.status !== 'running') {
+ clearInterval(agentPollTimer);
+ agentPollTimer = null;
+ btn.disabled = false;
+ btn.innerHTML = ' Run Analysis';
+
+ if (run.status === 'completed') {
+ showAgentToast('Analysis complete: ' + run.recommendations_count + ' recommendations');
+ } else {
+ showAgentToast('Analysis failed: ' + (run.error_message || 'Unknown error'), true);
+ }
+
+ loadAgentStatus();
+ loadRecommendations();
+ loadRunHistory();
+ }
+ }
+ } catch (e) {
+ console.error('Poll error:', e);
+ }
+ }, 2000);
+ } catch (e) {
+ btn.disabled = false;
+ btn.innerHTML = ' Run Analysis';
+ showAgentToast('Failed to start analysis', true);
+ }
+ }
+
+ async function applyRecommendation(id) {
+ try {
+ var res = await fetch(agentBasePath() + '/recommendations/' + id + '/apply', { method: 'POST' });
+ var json = await res.json();
+ if (json.success) {
+ showAgentToast(json.message || 'Applied');
+ } else {
+ showAgentToast(json.error || 'Failed', true);
+ }
+ loadAgentStatus();
+ loadRecommendations();
+ } catch (e) {
+ showAgentToast('Failed to apply', true);
+ }
+ }
+
+ async function dismissRecommendation(id) {
+ try {
+ await fetch(agentBasePath() + '/recommendations/' + id + '/dismiss', { method: 'POST' });
+ loadAgentStatus();
+ loadRecommendations();
+ } catch (e) {
+ showAgentToast('Failed to dismiss', true);
+ }
+ }
+
+ async function dismissAllPending() {
+ try {
+ var res = await fetch(agentBasePath() + '/recommendations/dismiss-all', { method: 'POST' });
+ var json = await res.json();
+ if (json.success) {
+ showAgentToast('Dismissed ' + (json.data?.dismissed || 'all') + ' recommendations');
+ }
+ loadAgentStatus();
+ loadRecommendations();
+ } catch (e) {
+ showAgentToast('Failed to dismiss all', true);
+ }
+ }
+
+ async function loadRunHistory() {
+ try {
+ var res = await fetch(agentBasePath() + '/runs');
+ if (!res.ok) return;
+ var json = await res.json();
+ if (!json.success || !json.data || json.data.length === 0) return;
+
+ var tbody = document.getElementById('agent-run-history-tbody');
+ var html = '';
+ var now = Date.now();
+ for (var i = 0; i < json.data.length; i++) {
+ var run = json.data[i];
+ var statusClass = run.status === 'completed' ? 'text-lime-600 dark:text-lime-400'
+ : run.status === 'failed' ? 'text-red-600 dark:text-red-400'
+ : 'text-blue-600 dark:text-blue-400';
+ var duration = run.duration_ms ? (run.duration_ms / 1000).toFixed(1) + 's' : '\u2014';
+ var ago = formatAgentTimeAgo(now - (run.created_at * 1000));
+
+ html += '';
+ html += '' + run.status + ' ';
+ html += '' + run.recommendations_count + ' ';
+ html += '' + duration + ' ';
+ html += '' + ago + ' ';
+ html += ' ';
+ }
+ tbody.innerHTML = html;
+ } catch (e) {
+ console.error('Load run history error:', e);
+ }
+ }
+
+ function showAgentToast(message, isError) {
+ var el = document.getElementById('msg');
+ if (!el) return;
+ el.querySelector('.font-semibold').textContent = message;
+ if (isError) {
+ el.className = 'fixed bottom-4 right-4 p-4 rounded-lg bg-red-50 text-red-900 border border-red-200 dark:bg-red-900/20 dark:text-red-100 dark:border-red-800 shadow-lg z-50';
+ } else {
+ el.className = 'fixed bottom-4 right-4 p-4 rounded-lg bg-green-50 text-green-900 border border-green-200 dark:bg-green-900/20 dark:text-green-100 dark:border-green-800 shadow-lg z-50';
+ }
+ el.classList.remove('hidden');
+ setTimeout(function() { el.classList.add('hidden'); }, 3000);
+ }
+
+ function escapeAgentHtml(str) {
+ if (!str) return '';
+ return str.replace(/&/g, '&').replace(//g, '>').replace(/"/g, '"');
+ }
+
+ function formatAgentTimeAgo(ms) {
+ var sec = Math.floor(ms / 1000);
+ if (sec < 60) return 'just now';
+ var min = Math.floor(sec / 60);
+ if (min < 60) return min + 'm ago';
+ var hr = Math.floor(min / 60);
+ if (hr < 24) return hr + 'h ago';
+ var days = Math.floor(hr / 24);
+ return days + 'd ago';
+ }
+
+ // Auto-load if we navigated directly to #agent
+ if (initTab === 'agent') {
+ agentLoaded = true;
+ loadAgentStatus();
+ loadRecommendations();
+ loadRunHistory();
+ }
+ `;
+}
+
+// src/plugins/core-plugins/ai-search-plugin/constants/experiment-templates.ts
+var DEFAULT_SETTINGS = {
+ fts5_title_boost: 5,
+ fts5_slug_boost: 2,
+ fts5_body_boost: 1,
+ query_rewriting_enabled: false,
+ reranking_enabled: true,
+ query_synonyms_enabled: true,
+ results_limit: 20,
+ cache_duration: 1,
+ facets_enabled: false
+};
+var TESTABLE_SETTINGS = [
+ { key: "fts5_title_boost", label: "Title Weight", type: "number", default_value: 5, min: 0, max: 20, step: 0.5 },
+ { key: "fts5_slug_boost", label: "Slug Weight", type: "number", default_value: 2, min: 0, max: 10, step: 0.5 },
+ { key: "fts5_body_boost", label: "Body Weight", type: "number", default_value: 1, min: 0, max: 10, step: 0.5 },
+ { key: "query_rewriting_enabled", label: "Query Rewriting", type: "boolean", default_value: false },
+ { key: "reranking_enabled", label: "Reranking", type: "boolean", default_value: true },
+ { key: "query_synonyms_enabled", label: "Synonyms", type: "boolean", default_value: true },
+ { key: "results_limit", label: "Results per Page", type: "number", default_value: 20, min: 5, max: 100, step: 5 },
+ { key: "cache_duration", label: "Cache Duration (hours)", type: "number", default_value: 1, min: 0, max: 24, step: 1 },
+ { key: "facets_enabled", label: "Faceted Search", type: "boolean", default_value: false }
+];
+var EXPERIMENT_TEMPLATES = [
+ {
+ id: "title-boost",
+ name: "Title Relevance Boost",
+ description: "Double the title weight to prioritize title matches over body content",
+ category: "relevance",
+ mode: "interleave",
+ mode_rationale: "Interleaving converges faster for relevance changes \u2014 users see both rankings side-by-side",
+ traffic_pct: 100,
+ split_ratio: 0.5,
+ min_searches: 200,
+ overrides: { fts5_title_boost: 10 },
+ why: "Title matches are often the strongest relevance signal. Doubling the weight can significantly improve result quality for sites with descriptive titles.",
+ good_for: "Sites with descriptive, keyword-rich titles"
+ },
+ {
+ id: "body-focus",
+ name: "Body Content Focus",
+ description: "Increase body weight to surface results from long-form content",
+ category: "relevance",
+ mode: "interleave",
+ mode_rationale: "Interleaving converges faster for relevance changes \u2014 users see both rankings side-by-side",
+ traffic_pct: 100,
+ split_ratio: 0.5,
+ min_searches: 200,
+ overrides: { fts5_body_boost: 3 },
+ why: "Blogs and documentation often have the best matches buried in body text. Boosting body weight helps surface these.",
+ good_for: "Blogs, documentation sites, long-form content"
+ },
+ {
+ id: "query-rewriting",
+ name: "Enable Query Rewriting",
+ description: "Use AI to rewrite ambiguous queries for better recall",
+ category: "features",
+ mode: "ab",
+ mode_rationale: "A/B split is better for feature toggles \u2014 measures overall impact on user satisfaction",
+ traffic_pct: 100,
+ split_ratio: 0.5,
+ min_searches: 300,
+ overrides: { query_rewriting_enabled: true },
+ why: "Query rewriting can dramatically reduce zero-result searches by expanding or reformulating user queries.",
+ good_for: "Sites with high zero-result rates or ambiguous queries"
+ },
+ {
+ id: "disable-reranking",
+ name: "Disable Reranking",
+ description: "Skip the reranking step to test if it improves speed without hurting quality",
+ category: "performance",
+ mode: "ab",
+ mode_rationale: "A/B split measures the impact on click-through rate when reranking is removed",
+ traffic_pct: 100,
+ split_ratio: 0.5,
+ min_searches: 200,
+ overrides: { reranking_enabled: false },
+ why: "Reranking adds latency. If your initial ranking is good enough, disabling it can improve response times.",
+ good_for: "Speed-critical sites with acceptable baseline relevance"
+ },
+ {
+ id: "compact-results",
+ name: "Compact Results",
+ description: "Reduce results per page from 20 to 10 to increase visibility of top results",
+ category: "performance",
+ mode: "ab",
+ mode_rationale: "A/B split measures whether fewer results leads to higher engagement with top results",
+ traffic_pct: 100,
+ split_ratio: 0.5,
+ min_searches: 300,
+ overrides: { results_limit: 10 },
+ why: "Showing fewer results focuses user attention on the best matches. Can improve CTR if your ranking is good.",
+ good_for: "Sites with low CTR or when users rarely scroll past first few results"
+ },
+ {
+ id: "enable-facets",
+ name: "Enable Faceted Search",
+ description: "Turn on faceted search to let users filter results by collection and fields",
+ category: "features",
+ mode: "ab",
+ mode_rationale: "A/B split measures whether facets improve user engagement and reduce zero-result frustration",
+ traffic_pct: 100,
+ split_ratio: 0.5,
+ min_searches: 300,
+ overrides: { facets_enabled: true },
+ why: "Facets help users narrow down results, especially useful for sites with diverse content across multiple collections.",
+ good_for: "Multi-collection sites with diverse content types"
+ },
+ {
+ id: "aggressive-title-slug",
+ name: "Aggressive Title + Slug",
+ description: "Maximize title and slug weights together for URL-keyword-heavy sites",
+ category: "relevance",
+ mode: "interleave",
+ mode_rationale: "Interleaving converges faster for relevance changes \u2014 users see both rankings side-by-side",
+ traffic_pct: 100,
+ split_ratio: 0.5,
+ min_searches: 200,
+ overrides: { fts5_title_boost: 10, fts5_slug_boost: 5 },
+ why: "When URLs contain meaningful keywords, boosting slug weight alongside title weight reinforces exact-match relevance.",
+ good_for: "Sites with descriptive URLs and keyword-rich slugs"
+ },
+ {
+ id: "full-ai-enhancement",
+ name: "Full AI Enhancement",
+ description: "Enable both query rewriting and synonyms for maximum recall",
+ category: "comprehensive",
+ mode: "interleave",
+ mode_rationale: "Interleaving lets you compare enhanced vs baseline results on the same queries",
+ traffic_pct: 100,
+ split_ratio: 0.5,
+ min_searches: 300,
+ overrides: { query_rewriting_enabled: true, query_synonyms_enabled: true },
+ why: "Combining query rewriting with synonym expansion provides the widest recall improvement, ideal for reducing zero-result rates.",
+ good_for: "Sites with high zero-result rates or diverse query vocabulary"
+ }
+];
+
+// src/templates/pages/admin-search-experiments.template.ts
+function renderExperimentsTab() {
+ return `
+
+
+
+
+
+
+
Search A/B Tests
+
A/B test and interleave search configurations to measure what works best
+
+
+
+
+
+
+ New A/B Test
+
+
+
+
+
+
+
+
+
+
+
+
+
+ —
+ A/B
+
+
—
+
+
+
+
+
+ Searches
+ 0
+
+
+ Confidence
+ 0%
+
+
+
+
+
+
+ Pause
+
+
+ Stop
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
All Tests
+
+ All statuses
+ Draft
+ Running
+ Paused
+ Completed
+ Archived
+
+
+
+
+
+
+
+
+
Test Recommendations
+
Based on your search analytics
+
+
+
+
+
+
+
+ Loading analytics data...
+
+
+
+
+
+
+
+
+
+
New A/B Test
+
+
+
+
Choose a Template
+
+
+
+
+
+
+
+
+
+
+
+ Name
+
+
+
+
+ Description
+
+
+
+
+
+ Mode
+
+ A/B Split
+ Interleaving
+
+
+
+ Traffic %
+
+
+
+ Min Searches
+
+
+
+
+
+
+
+ Treatment Overrides
+
+ Advanced: Raw JSON
+
+
+
+
+
+
+
+
+
+
+
+ + Add Setting Override
+
+
+ Add
+
+
+
+
+
+
+
+
+
+ Testable: fts5_title_boost, fts5_slug_boost, fts5_body_boost, query_rewriting_enabled,
+ reranking_enabled, query_synonyms_enabled, results_limit, cache_duration, facets_enabled
+
+
+
+
+
+
+
+
+
+
+ Cancel
+
+
+ Create Draft
+
+
+
+
+
+
+
+ `;
+}
+function renderExperimentsScript() {
+ const templatesJson = JSON.stringify(EXPERIMENT_TEMPLATES);
+ const settingsJson = JSON.stringify(TESTABLE_SETTINGS);
+ const defaultsJson = JSON.stringify(DEFAULT_SETTINGS);
+ return `
+ // \u2500\u2500 Experiments Tab State \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
+ let experimentsLoaded = false
+ let activeExperimentId = null
+ let expCurrentOverrides = {}
+ let expControlSettings = ${defaultsJson}
+ let expUsingRawJson = false
+ let expSelectedTemplateId = null
+ let expDailySearchVolume = 0
+ let expAllExperiments = []
+
+ // Embedded data
+ var EXP_TEMPLATES = ${templatesJson}
+ var EXP_TESTABLE_SETTINGS = ${settingsJson}
+ var EXP_DEFAULT_SETTINGS = ${defaultsJson}
+
+ function loadExperimentsOnTabSwitch() {
+ if (!experimentsLoaded) {
+ experimentsLoaded = true
+ loadExperiments()
+ fetchControlSettings()
+ loadRecommendations()
+ }
+ }
+
+ // \u2500\u2500 Fetch live control settings \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
+ async function fetchControlSettings() {
+ try {
+ const resp = await fetch('/admin/plugins/ai-search/api/settings')
+ const json = await resp.json()
+ if (json.success && json.data) {
+ // Merge live settings over defaults for keys we care about
+ for (var s of EXP_TESTABLE_SETTINGS) {
+ if (json.data[s.key] !== undefined) {
+ expControlSettings[s.key] = json.data[s.key]
+ }
+ }
+ }
+ } catch (e) {
+ console.warn('Could not fetch live settings, using defaults')
+ }
+ }
+
+ // \u2500\u2500 Template Picker \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
+ function renderTemplateGrid() {
+ var grid = document.getElementById('exp-template-grid')
+ if (!grid) return
+
+ var categoryColors = {
+ relevance: 'bg-blue-100 text-blue-700 dark:bg-blue-900 dark:text-blue-300',
+ performance: 'bg-amber-100 text-amber-700 dark:bg-amber-900 dark:text-amber-300',
+ features: 'bg-emerald-100 text-emerald-700 dark:bg-emerald-900 dark:text-emerald-300',
+ comprehensive: 'bg-purple-100 text-purple-700 dark:bg-purple-900 dark:text-purple-300',
+ }
+
+ var html = EXP_TEMPLATES.map(function(t) {
+ return ''
+ + ''
+ + '' + t.category + ' '
+ + '
'
+ + '' + t.name + '
'
+ + '' + t.description + '
'
+ + ' '
+ }).join('')
+
+ // Custom card
+ html += ''
+ + ''
+ + 'custom '
+ + '
'
+ + 'Custom Test
'
+ + 'Configure everything manually
'
+ + ' '
+
+ grid.innerHTML = html
+ }
+
+ function selectTemplate(templateId) {
+ expSelectedTemplateId = templateId
+
+ // Highlight selected card
+ document.querySelectorAll('.exp-tpl-card').forEach(function(card) {
+ card.classList.remove('ring-indigo-500', 'dark:ring-indigo-400', 'bg-indigo-50', 'dark:bg-indigo-950/20')
+ card.classList.add('ring-zinc-200', 'dark:ring-zinc-700')
+ })
+ var selected = document.getElementById('exp-tpl-' + templateId)
+ if (selected) {
+ selected.classList.remove('ring-zinc-200', 'dark:ring-zinc-700')
+ selected.classList.add('ring-indigo-500', 'dark:ring-indigo-400', 'bg-indigo-50', 'dark:bg-indigo-950/20')
+ }
+
+ var rationale = document.getElementById('exp-mode-rationale')
+
+ if (templateId === 'custom') {
+ // Clear all fields
+ document.getElementById('exp-name').value = ''
+ document.getElementById('exp-desc').value = ''
+ document.getElementById('exp-mode').value = 'ab'
+ document.getElementById('exp-traffic').value = '100'
+ document.getElementById('exp-min-searches').value = '100'
+ expCurrentOverrides = {}
+ renderOverrideRows()
+ rationale.classList.add('hidden')
+ updateTestSummary()
+ return
+ }
+
+ var tpl = EXP_TEMPLATES.find(function(t) { return t.id === templateId })
+ if (!tpl) return
+
+ document.getElementById('exp-name').value = tpl.name
+ document.getElementById('exp-desc').value = tpl.description
+ document.getElementById('exp-mode').value = tpl.mode
+ document.getElementById('exp-traffic').value = String(tpl.traffic_pct)
+ document.getElementById('exp-min-searches').value = String(tpl.min_searches)
+
+ // Set overrides
+ expCurrentOverrides = Object.assign({}, tpl.overrides)
+ renderOverrideRows()
+
+ // Show mode rationale
+ rationale.textContent = tpl.mode_rationale
+ rationale.classList.remove('hidden')
+
+ updateAddSettingDropdown()
+ updateTestSummary()
+ }
+
+ // \u2500\u2500 Visual Settings Editor \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
+ function renderOverrideRows() {
+ var container = document.getElementById('exp-overrides-list')
+ if (!container) return
+
+ var keys = Object.keys(expCurrentOverrides)
+ if (keys.length === 0) {
+ container.innerHTML = 'No overrides yet \u2014 select a template or add settings below
'
+ updateAddSettingDropdown()
+ updateTestSummary()
+ return
+ }
+
+ container.innerHTML = keys.map(function(key) {
+ var meta = EXP_TESTABLE_SETTINGS.find(function(s) { return s.key === key })
+ if (!meta) return ''
+
+ var value = expCurrentOverrides[key]
+ var controlVal = expControlSettings[key] !== undefined ? expControlSettings[key] : meta.default_value
+
+ var controlDisplay = meta.type === 'boolean' ? (controlVal ? 'ON' : 'OFF') : String(controlVal)
+
+ var controlHtml = 'Control: ' + controlDisplay + ' '
+
+ var inputHtml = ''
+ if (meta.type === 'number') {
+ inputHtml = ''
+ + ' '
+ + ' '
+ + '
'
+ } else {
+ // Boolean toggle
+ var checked = value ? 'checked' : ''
+ inputHtml = ''
+ + ' '
+ + '
'
+ + '' + (value ? 'ON' : 'OFF') + ' '
+ + ' '
+ }
+
+ return ''
+ + '
'
+ + '
' + meta.label + '
'
+ + controlHtml
+ + '
'
+ + '
'
+ + inputHtml
+ + '
'
+ + '
'
+ + ' '
+ + ' '
+ + '
'
+ }).join('')
+
+ updateAddSettingDropdown()
+ updateTestSummary()
+ }
+
+ function updateOverrideValue(key, value) {
+ expCurrentOverrides[key] = value
+
+ // Sync the range and number inputs for number types
+ var meta = EXP_TESTABLE_SETTINGS.find(function(s) { return s.key === key })
+ if (meta && meta.type === 'number') {
+ var row = document.querySelector('[data-override-key="' + key + '"]')
+ if (row) {
+ var rangeInput = row.querySelector('input[type="range"]')
+ var numInput = row.querySelector('input[type="number"]')
+ if (rangeInput) rangeInput.value = value
+ if (numInput) numInput.value = value
+ }
+ }
+
+ // Update toggle label for booleans
+ if (meta && meta.type === 'boolean') {
+ var row = document.querySelector('[data-override-key="' + key + '"]')
+ if (row) {
+ var label = row.querySelector('.peer ~ span')
+ if (label) label.textContent = value ? 'ON' : 'OFF'
+ }
+ }
+
+ updateTestSummary()
+ }
+
+ function removeOverride(key) {
+ delete expCurrentOverrides[key]
+ renderOverrideRows()
+ }
+
+ function updateAddSettingDropdown() {
+ var select = document.getElementById('exp-add-setting')
+ if (!select) return
+
+ var usedKeys = Object.keys(expCurrentOverrides)
+ var available = EXP_TESTABLE_SETTINGS.filter(function(s) {
+ return usedKeys.indexOf(s.key) === -1
+ })
+
+ select.innerHTML = '+ Add Setting Override '
+ + available.map(function(s) {
+ return '' + s.label + ' (' + s.key + ') '
+ }).join('')
+ }
+
+ function addSelectedOverride() {
+ var select = document.getElementById('exp-add-setting')
+ var key = select.value
+ if (!key) return
+
+ var meta = EXP_TESTABLE_SETTINGS.find(function(s) { return s.key === key })
+ if (!meta) return
+
+ expCurrentOverrides[key] = meta.default_value
+ renderOverrideRows()
+ select.value = ''
+ }
+
+ // \u2500\u2500 Raw JSON Toggle \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
+ function toggleRawJson() {
+ expUsingRawJson = !expUsingRawJson
+ var visual = document.getElementById('exp-visual-editor')
+ var raw = document.getElementById('exp-raw-editor')
+ var toggle = document.getElementById('exp-raw-toggle')
+
+ if (expUsingRawJson) {
+ visual.classList.add('hidden')
+ raw.classList.remove('hidden')
+ toggle.textContent = 'Visual Editor'
+ // Sync overrides to raw JSON
+ document.getElementById('exp-overrides').value = JSON.stringify(expCurrentOverrides, null, 2)
+ } else {
+ visual.classList.remove('hidden')
+ raw.classList.add('hidden')
+ toggle.textContent = 'Advanced: Raw JSON'
+ // Sync raw JSON back to visual
+ try {
+ var parsed = JSON.parse(document.getElementById('exp-overrides').value.trim() || '{}')
+ expCurrentOverrides = parsed
+ renderOverrideRows()
+ } catch (e) {
+ // Keep existing overrides if JSON is invalid
+ }
+ }
+ }
+
+ function onModeChange() {
+ // Clear the template-specific rationale when mode is manually changed
+ var rationale = document.getElementById('exp-mode-rationale')
+ rationale.classList.add('hidden')
+ updateTestSummary()
+ }
+
+ // \u2500\u2500 Summary Panel \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
+ function updateTestSummary() {
+ var panel = document.getElementById('exp-summary-panel')
+ var textEl = document.getElementById('exp-summary-text')
+ var durationEl = document.getElementById('exp-duration-estimate')
+
+ var keys = Object.keys(expCurrentOverrides)
+ if (keys.length === 0) {
+ panel.classList.add('hidden')
+ return
+ }
+ panel.classList.remove('hidden')
+
+ var lines = []
+ keys.forEach(function(key) {
+ var meta = EXP_TESTABLE_SETTINGS.find(function(s) { return s.key === key })
+ var label = meta ? meta.label : key
+ var controlVal = expControlSettings[key]
+ var treatmentVal = expCurrentOverrides[key]
+
+ if (typeof treatmentVal === 'boolean') {
+ lines.push('Testing ' + label + ' = ' + (treatmentVal ? 'ON' : 'OFF') + ' vs control (' + (controlVal ? 'ON' : 'OFF') + ')')
+ } else {
+ lines.push('Testing ' + label + ' = ' + treatmentVal + ' vs control (' + controlVal + ')')
+ }
+ })
+
+ var minSearches = Number(document.getElementById('exp-min-searches').value) || 100
+ lines.push('Minimum searches needed: ' + minSearches.toLocaleString() + ' ')
+
+ textEl.innerHTML = lines.map(function(l) { return '' + l + '
' }).join('')
+
+ // Duration estimate
+ if (expDailySearchVolume > 0) {
+ var days = Math.ceil(minSearches / expDailySearchVolume)
+ durationEl.textContent = 'At ~' + expDailySearchVolume + ' searches/day, roughly ' + days + ' day' + (days !== 1 ? 's' : '')
+ durationEl.classList.remove('hidden')
+ } else {
+ durationEl.classList.add('hidden')
+ }
+ }
+
+ // \u2500\u2500 Load Experiments \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
+ async function loadExperiments() {
+ try {
+ const status = document.getElementById('exp-filter-status')?.value || ''
+ const params = status ? '?status=' + status : ''
+ const resp = await fetch('/admin/plugins/ai-search/api/experiments' + params)
+ const json = await resp.json()
+ if (!json.success) throw new Error(json.error)
+
+ const experiments = json.data || []
+ expAllExperiments = experiments
+
+ // Update stat cards
+ const total = experiments.length
+ const running = experiments.filter(e => e.status === 'running').length
+ const completed = experiments.filter(e => e.status === 'completed').length
+ const draft = experiments.filter(e => e.status === 'draft').length
+
+ document.getElementById('exp-stat-total').textContent = total
+ document.getElementById('exp-stat-running').textContent = running
+ document.getElementById('exp-stat-completed').textContent = completed
+ document.getElementById('exp-stat-draft').textContent = draft
+
+ // Active experiment banner
+ const activeExp = experiments.find(e => e.status === 'running')
+ const banner = document.getElementById('exp-active-banner')
+ if (activeExp) {
+ activeExperimentId = activeExp.id
+ banner.classList.remove('hidden')
+ document.getElementById('exp-active-name').textContent = activeExp.name
+ document.getElementById('exp-active-desc').textContent = activeExp.description || 'No description'
+ document.getElementById('exp-active-mode-badge').textContent = activeExp.mode === 'interleave' ? 'Interleaving' : 'A/B Split'
+
+ if (activeExp.metrics) {
+ const m = activeExp.metrics
+ document.getElementById('exp-active-metrics').classList.remove('hidden')
+ document.getElementById('exp-active-searches').textContent = (m.control.searches + m.treatment.searches).toLocaleString()
+ document.getElementById('exp-active-confidence').textContent = (m.confidence * 100).toFixed(1) + '%'
+ document.getElementById('exp-active-confidence-bar').style.width = (m.confidence * 100) + '%'
+
+ document.getElementById('exp-ctrl-ctr').textContent = (m.control.ctr * 100).toFixed(1) + '%'
+ document.getElementById('exp-ctrl-zero').textContent = (m.control.zero_result_rate * 100).toFixed(1) + '%'
+ document.getElementById('exp-ctrl-pos').textContent = m.control.avg_click_position ? m.control.avg_click_position.toFixed(1) : '\u2014'
+
+ document.getElementById('exp-treat-ctr').textContent = (m.treatment.ctr * 100).toFixed(1) + '%'
+ document.getElementById('exp-treat-zero').textContent = (m.treatment.zero_result_rate * 100).toFixed(1) + '%'
+ document.getElementById('exp-treat-pos').textContent = m.treatment.avg_click_position ? m.treatment.avg_click_position.toFixed(1) : '\u2014'
+ } else {
+ document.getElementById('exp-active-metrics').classList.add('hidden')
+ document.getElementById('exp-active-searches').textContent = '0'
+ document.getElementById('exp-active-confidence').textContent = '0%'
+ document.getElementById('exp-active-confidence-bar').style.width = '0%'
+ }
+ } else {
+ activeExperimentId = null
+ banner.classList.add('hidden')
+ }
+
+ // Render experiment list
+ const listEl = document.getElementById('exp-list')
+ if (experiments.length === 0) {
+ listEl.innerHTML = 'No tests yet. Click "New A/B Test" to get started.
'
+ return
+ }
+
+ listEl.innerHTML = experiments.map(exp => {
+ const statusColors = {
+ draft: 'bg-zinc-100 text-zinc-700 dark:bg-zinc-800 dark:text-zinc-300',
+ running: 'bg-indigo-100 text-indigo-700 dark:bg-indigo-900 dark:text-indigo-300',
+ paused: 'bg-amber-100 text-amber-700 dark:bg-amber-900 dark:text-amber-300',
+ completed: 'bg-lime-100 text-lime-700 dark:bg-lime-900 dark:text-lime-300',
+ archived: 'bg-zinc-100 text-zinc-500 dark:bg-zinc-800 dark:text-zinc-500',
+ }
+ const modeLabel = exp.mode === 'interleave' ? 'Interleave' : 'A/B'
+ const date = new Date(exp.created_at).toLocaleDateString()
+ const winnerBadge = exp.winner
+ ? 'Winner: ' + exp.winner + ' '
+ : ''
+
+ let actions = ''
+ if (exp.status === 'draft') {
+ actions = 'Start '
+ + ' Delete '
+ } else if (exp.status === 'completed') {
+ actions = 'Archive '
+ }
+
+ return ''
+ + '
'
+ + '' + exp.status + ' '
+ + '' + modeLabel + ' '
+ + '' + exp.name + ' '
+ + winnerBadge
+ + '
'
+ + '
'
+ + '' + date + ' '
+ + actions
+ + '
'
+ + '
'
+ }).join('')
+
+ } catch (error) {
+ console.error('Failed to load experiments:', error)
+ document.getElementById('exp-list').innerHTML = 'Failed to load tests
'
+ }
+ }
+
+ // \u2500\u2500 CRUD Operations \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
+ function openCreateExperiment(templateId) {
+ renderTemplateGrid()
+ expCurrentOverrides = {}
+ expSelectedTemplateId = null
+ expUsingRawJson = false
+ document.getElementById('exp-visual-editor').classList.remove('hidden')
+ document.getElementById('exp-raw-editor').classList.add('hidden')
+ document.getElementById('exp-raw-toggle').textContent = 'Advanced: Raw JSON'
+ document.getElementById('exp-mode-rationale').classList.add('hidden')
+ document.getElementById('exp-summary-panel').classList.add('hidden')
+
+ // Reset form
+ document.getElementById('exp-name').value = ''
+ document.getElementById('exp-desc').value = ''
+ document.getElementById('exp-mode').value = 'ab'
+ document.getElementById('exp-traffic').value = '100'
+ document.getElementById('exp-min-searches').value = '100'
+ document.getElementById('exp-overrides').value = ''
+
+ renderOverrideRows()
+ document.getElementById('exp-create-modal').classList.remove('hidden')
+
+ // If a template was requested (e.g. from recommendations), select it
+ if (templateId) {
+ setTimeout(function() { selectTemplate(templateId) }, 50)
+ }
+ }
+
+ function closeCreateExperiment() {
+ document.getElementById('exp-create-modal').classList.add('hidden')
+ }
+
+ async function createExperiment() {
+ try {
+ const name = document.getElementById('exp-name').value.trim()
+ if (!name) { alert('Name is required'); return }
+
+ let overrides = {}
+
+ if (expUsingRawJson) {
+ const overridesText = document.getElementById('exp-overrides').value.trim()
+ if (overridesText) {
+ try { overrides = JSON.parse(overridesText) }
+ catch { alert('Invalid JSON in treatment overrides'); return }
+ }
+ } else {
+ overrides = Object.assign({}, expCurrentOverrides)
+ }
+
+ const resp = await fetch('/admin/plugins/ai-search/api/experiments', {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify({
+ name,
+ description: document.getElementById('exp-desc').value.trim() || null,
+ mode: document.getElementById('exp-mode').value,
+ traffic_pct: Number(document.getElementById('exp-traffic').value),
+ split_ratio: 0.5,
+ min_searches: Number(document.getElementById('exp-min-searches').value),
+ variants: { control: {}, treatment: overrides },
+ }),
+ })
+ const json = await resp.json()
+ if (!json.success) throw new Error(json.error)
+
+ closeCreateExperiment()
+ showMsg('Test created: ' + json.data.name)
+ loadExperiments()
+
+ } catch (error) {
+ alert('Error: ' + error.message)
+ }
+ }
+
+ async function startExperimentById(id) {
+ if (!confirm('Start this test? It will affect live search traffic.')) return
+ try {
+ const resp = await fetch('/admin/plugins/ai-search/api/experiments/' + id + '/start', { method: 'POST' })
+ const json = await resp.json()
+ if (!json.success) throw new Error(json.error)
+ showMsg('Test started')
+ loadExperiments()
+ } catch (error) {
+ alert('Error: ' + error.message)
+ }
+ }
+
+ async function pauseExperiment() {
+ if (!activeExperimentId) return
+ try {
+ const resp = await fetch('/admin/plugins/ai-search/api/experiments/' + activeExperimentId + '/pause', { method: 'POST' })
+ const json = await resp.json()
+ if (!json.success) throw new Error(json.error)
+ showMsg('Test paused')
+ loadExperiments()
+ } catch (error) {
+ alert('Error: ' + error.message)
+ }
+ }
+
+ async function completeExperiment() {
+ if (!activeExperimentId) return
+ if (!confirm('Stop this test? This will complete it and stop collecting data.')) return
+ try {
+ const resp = await fetch('/admin/plugins/ai-search/api/experiments/' + activeExperimentId + '/complete', {
+ method: 'POST',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify({}),
+ })
+ const json = await resp.json()
+ if (!json.success) throw new Error(json.error)
+ showMsg('Test completed' + (json.data.winner ? ' \u2014 Winner: ' + json.data.winner : ''))
+ loadExperiments()
+ } catch (error) {
+ alert('Error: ' + error.message)
+ }
+ }
+
+ async function deleteExperimentById(id) {
+ if (!confirm('Delete this test? This cannot be undone.')) return
+ try {
+ const resp = await fetch('/admin/plugins/ai-search/api/experiments/' + id, { method: 'DELETE' })
+ const json = await resp.json()
+ if (!json.success) throw new Error(json.error)
+ showMsg('Test deleted')
+ loadExperiments()
+ } catch (error) {
+ alert('Error: ' + error.message)
+ }
+ }
+
+ async function archiveExperimentById(id) {
+ try {
+ const resp = await fetch('/admin/plugins/ai-search/api/experiments/' + id, {
+ method: 'PUT',
+ headers: { 'Content-Type': 'application/json' },
+ body: JSON.stringify({ status: 'archived' }),
+ })
+ } catch (error) {
+ alert('Error: ' + error.message)
+ }
+ }
+
+ // \u2500\u2500 Recommendations \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500
+ async function loadRecommendations() {
+ var container = document.getElementById('exp-recommendations')
+ if (!container) return
+
+ try {
+ var resp = await fetch('/admin/plugins/ai-search/api/analytics/extended')
+ var json = await resp.json()
+
+ if (!json.success) {
+ container.innerHTML = 'Could not load analytics data
'
+ return
+ }
+
+ var analytics = json.data || {}
+ var totalQueries = analytics.total_queries || 0
+ var zeroResults = analytics.zero_result_queries || 0
+ var totalClicks = analytics.total_clicks || 0
+ var avgPosition = analytics.avg_click_position || 0
+ var avgResponseTime = analytics.avg_response_time_ms || 0
+ var facetClicks = analytics.facet_clicks || 0
+ var facetsEnabled = analytics.facets_enabled || false
+ var distinctZeroQueries = analytics.distinct_zero_result_queries || 0
+
+ // Calculate daily volume for duration estimates
+ var daysOfData = analytics.days_of_data || 30
+ expDailySearchVolume = daysOfData > 0 ? Math.round(totalQueries / daysOfData) : 0
+
+ // Not enough data
+ if (totalQueries < 10) {
+ container.innerHTML = ''
+ + '
'
+ + ' '
+ + ' '
+ + '
Not enough data yet
'
+ + '
Run at least 10 searches to get recommendations
'
+ + '
'
+ return
+ }
+
+ // Rule engine
+ var recommendations = []
+ var zeroRate = totalQueries > 0 ? (zeroResults / totalQueries) : 0
+ var ctr = totalQueries > 0 ? (totalClicks / totalQueries) : 0
+
+ // High zero-result rate
+ if (zeroRate > 0.10) {
+ recommendations.push({
+ templateId: 'query-rewriting',
+ reason: 'Zero-result rate is ' + (zeroRate * 100).toFixed(1) + '% (above 10% threshold)',
+ impact: 'HIGH',
+ })
+ recommendations.push({
+ templateId: 'full-ai-enhancement',
+ reason: 'High zero-result rate (' + (zeroRate * 100).toFixed(1) + '%) suggests queries need expansion',
+ impact: 'HIGH',
+ })
+ }
+
+ // Low CTR
+ if (ctr < 0.05 && totalQueries > 50) {
+ recommendations.push({
+ templateId: 'title-boost',
+ reason: 'CTR is ' + (ctr * 100).toFixed(1) + '% (below 5% threshold with ' + totalQueries + ' queries)',
+ impact: 'HIGH',
+ })
+ recommendations.push({
+ templateId: 'compact-results',
+ reason: 'Low CTR (' + (ctr * 100).toFixed(1) + '%) \u2014 fewer results may increase engagement',
+ impact: 'HIGH',
+ })
+ }
+
+ // High average click position
+ if (avgPosition > 3.0) {
+ recommendations.push({
+ templateId: 'title-boost',
+ reason: 'Average click position is ' + avgPosition.toFixed(1) + ' (above 3.0 \u2014 users scrolling past top results)',
+ impact: 'HIGH',
+ })
+ recommendations.push({
+ templateId: 'aggressive-title-slug',
+ reason: 'Users clicking results at position ' + avgPosition.toFixed(1) + ' suggests ranking needs improvement',
+ impact: 'MEDIUM',
+ })
+ }
+
+ // Slow response times
+ if (avgResponseTime > 500) {
+ recommendations.push({
+ templateId: 'disable-reranking',
+ reason: 'Average response time is ' + Math.round(avgResponseTime) + 'ms (above 500ms threshold)',
+ impact: 'MEDIUM',
+ })
+ recommendations.push({
+ templateId: 'compact-results',
+ reason: 'Slow responses (' + Math.round(avgResponseTime) + 'ms) \u2014 fewer results may speed things up',
+ impact: 'MEDIUM',
+ })
+ }
+
+ // No facet usage
+ if (!facetsEnabled && facetClicks === 0) {
+ recommendations.push({
+ templateId: 'enable-facets',
+ reason: 'Faceted search is disabled \u2014 could help users narrow down results',
+ impact: 'MEDIUM',
+ })
+ }
+
+ // Many zero-result queries
+ if (distinctZeroQueries > 5) {
+ recommendations.push({
+ templateId: 'body-focus',
+ reason: distinctZeroQueries + ' distinct queries returned zero results \u2014 body content may contain matches',
+ impact: 'LOW',
+ })
+ }
+
+ // Deduplicate by templateId, keeping highest impact
+ var impactOrder = { HIGH: 3, MEDIUM: 2, LOW: 1 }
+ var seen = {}
+ var deduped = []
+ recommendations.sort(function(a, b) { return (impactOrder[b.impact] || 0) - (impactOrder[a.impact] || 0) })
+ recommendations.forEach(function(r) {
+ if (!seen[r.templateId]) {
+ seen[r.templateId] = true
+ deduped.push(r)
+ }
+ })
+
+ // Exclude templates matching already-run experiments
+ var pastOverrides = expAllExperiments
+ .filter(function(e) { return e.status === 'completed' || e.status === 'running' })
+ .map(function(e) {
+ return e.variants && e.variants.treatment ? JSON.stringify(e.variants.treatment) : '{}'
+ })
+
+ var filtered = deduped.filter(function(r) {
+ var tpl = EXP_TEMPLATES.find(function(t) { return t.id === r.templateId })
+ if (!tpl) return false
+ var overridesStr = JSON.stringify(tpl.overrides)
+ return pastOverrides.indexOf(overridesStr) === -1
+ })
+
+ // Render
+ if (filtered.length === 0) {
+ container.innerHTML = ''
+ + '
'
+ + ' '
+ + ' '
+ + '
All healthy
'
+ + '
Your search metrics look good \u2014 no tests recommended right now
'
+ + '
'
+ return
+ }
+
+ var impactColors = {
+ HIGH: 'bg-red-100 text-red-700 dark:bg-red-900 dark:text-red-300',
+ MEDIUM: 'bg-amber-100 text-amber-700 dark:bg-amber-900 dark:text-amber-300',
+ LOW: 'bg-blue-100 text-blue-700 dark:bg-blue-900 dark:text-blue-300',
+ }
+
+ container.innerHTML = ''
+ + filtered.map(function(r) {
+ var tpl = EXP_TEMPLATES.find(function(t) { return t.id === r.templateId })
+ if (!tpl) return ''
+ return '
'
+ + '
'
+ + '
'
+ + '' + r.impact + ' '
+ + '' + tpl.name + ' '
+ + '
'
+ + '
' + r.reason + '
'
+ + '
'
+ + '
'
+ + 'Create This Test'
+ + ' '
+ + '
'
+ }).join('')
+ + '
'
+
+ } catch (error) {
+ console.error('Failed to load recommendations:', error)
+ container.innerHTML = 'Could not load analytics data
'
+ }
+ }
+
+ function showMsg(text) {
+ const el = document.getElementById('msg')
+ if (el) {
+ el.textContent = text
+ el.classList.remove('hidden')
+ setTimeout(() => el.classList.add('hidden'), 3000)
+ }
+ }
+ `;
+}
+
+// src/templates/pages/admin-search.template.ts
+function renderSearchDashboard(data) {
+ const settings = data.settings || {
+ enabled: false,
+ ai_mode_enabled: true,
+ selected_collections: [],
+ dismissed_collections: [],
+ autocomplete_enabled: true,
+ cache_duration: 1,
+ results_limit: 20,
+ index_media: false
+ };
+ const selectedCollections = Array.isArray(settings.selected_collections) ? settings.selected_collections : [];
+ const dismissedCollections = Array.isArray(settings.dismissed_collections) ? settings.dismissed_collections : [];
+ const enabled = settings.enabled === true;
+ const aiModeEnabled = settings.ai_mode_enabled !== false;
+ const autocompleteEnabled = settings.autocomplete_enabled !== false;
+ const indexMedia = settings.index_media === true;
+ const selectedCollectionIds = new Set(selectedCollections.map((id) => String(id)));
+ const dismissedCollectionIds = new Set(dismissedCollections.map((id) => String(id)));
+ const collections = Array.isArray(data.collections) ? data.collections : [];
+ const fts5Status = data.fts5Status;
+ const fts5Available = fts5Status ? fts5Status.available : false;
+ const fts5TotalIndexed = fts5Status ? fts5Status.total_indexed : 0;
+ const indexStatus = data.indexStatus || {};
+ let vectorizeIndexedItems = 0;
+ let vectorizeHasData = false;
+ for (const colId of Object.keys(indexStatus)) {
+ const s = indexStatus[colId];
+ if (s) {
+ vectorizeIndexedItems += s.indexed_items || 0;
+ vectorizeHasData = true;
+ }
+ }
+ const vectorizeStatusText = vectorizeHasData ? `Vectorize index: ${vectorizeIndexedItems} items indexed` : "Click reindex to rebuild the vector index for all selected collections";
+ const totalQueries = data.analytics ? data.analytics.total_queries : 0;
+ const queriesToday = data.queriesToday ?? 0;
+ const totalClicks30d = data.totalClicks30d ?? 0;
+ const zeroResults30d = data.zeroResults30d ?? 0;
+ const avgQueryTime = data.analytics ? data.analytics.average_query_time : 0;
+ const ctr = totalQueries > 0 ? (totalClicks30d / totalQueries * 100).toFixed(1) : null;
+ const popularQueries = data.analytics ? data.analytics.popular_queries || [] : [];
+ const facetsEnabled = settings.facets_enabled === true;
+ const props = {
+ settings,
+ collections,
+ selectedCollections,
+ selectedCollectionIds,
+ dismissedCollectionIds,
+ enabled,
+ aiModeEnabled,
+ autocompleteEnabled,
+ indexMedia,
+ fts5Available,
+ fts5TotalIndexed,
+ vectorizeIndexedItems,
+ vectorizeStatusText,
+ totalQueries,
+ queriesToday,
+ totalClicks30d,
+ zeroResults30d,
+ avgQueryTime,
+ ctr,
+ popularQueries,
+ facetsEnabled,
+ data
+ };
+ const pageContent = `
+
+
+
+
+
Search
+
+ Monitor and configure search across your content
+
+
+
+
+
+
+
+
+
+ Overview
+
+
+ Configuration
+
+
+ Benchmark
+
+
+ Relevance & Ranking
+
+
+ Analytics
+
+
+ Agent
+
+
+ A/B Tests
+
+
+
+
+ ${renderOverviewTab(props)}
+ ${renderConfigTab(props)}
+ ${renderBenchmarkTab()}
+ ${renderRelevanceTab(props)}
+ ${renderAnalyticsTab()}
+ ${renderAgentTab()}
+ ${renderExperimentsTab()}
+
+
+
+
+ Settings Saved Successfully!
+
+
+
+
+
+ `;
+ const layoutData = {
+ title: "Search",
+ pageTitle: "Search",
+ currentPath: "/admin/search",
+ user: data.user,
+ version: data.version,
+ content: pageContent
+ };
+ return renderAdminLayoutCatalyst(layoutData);
+}
+function renderStatCard(label, value, color, icon, colorOverride) {
+ const finalColor = color;
+ const colorClasses = {
+ lime: "bg-lime-50 dark:bg-lime-500/10 text-lime-600 dark:text-lime-400 ring-lime-600/20 dark:ring-lime-500/20",
+ blue: "bg-blue-50 dark:bg-blue-500/10 text-blue-600 dark:text-blue-400 ring-blue-600/20 dark:ring-blue-500/20",
+ purple: "bg-purple-50 dark:bg-purple-500/10 text-purple-600 dark:text-purple-400 ring-purple-600/20 dark:ring-purple-500/20",
+ sky: "bg-sky-50 dark:bg-sky-500/10 text-sky-600 dark:text-sky-400 ring-sky-600/20 dark:ring-sky-500/20",
+ amber: "bg-amber-50 dark:bg-amber-500/10 text-amber-600 dark:text-amber-400 ring-amber-600/20 dark:ring-amber-500/20",
+ red: "bg-red-50 dark:bg-red-500/10 text-red-600 dark:text-red-400 ring-red-600/20 dark:ring-red-500/20"
+ };
+ return `
+
+ `;
+}
+function renderFeatureToggle(name, isOn) {
+ const dotClass = isOn ? "bg-lime-500" : "bg-zinc-300 dark:bg-zinc-600";
+ const labelClass = isOn ? "text-lime-700 dark:text-lime-400" : "text-zinc-500 dark:text-zinc-400";
+ return `
+
+ ${name}
+
+
+ ${isOn ? "On" : "Off"}
+
+
+ `;
+}
+function escapeHtml6(str) {
+ return str.replace(/&/g, "&").replace(//g, ">").replace(/"/g, """);
+}
+
+// src/routes/admin-search.ts
+var adminSearchRoutes = new Hono();
+adminSearchRoutes.use("*", requireAuth());
+adminSearchRoutes.get("/", async (c) => {
+ try {
+ const user = c.get("user");
+ const db = c.env.DB;
+ const ai = c.env.AI;
+ const vectorize = c.env.VECTORIZE_INDEX;
+ const kv = c.env.CACHE_KV;
+ const service = new AISearchService(db, ai, vectorize, kv);
+ const indexer = new IndexManager(db, ai, vectorize);
+ const fts5Service = new FTS5Service(db);
+ const benchmarkService = new BenchmarkService(db, kv);
+ const now = Date.now();
+ const midnightToday = /* @__PURE__ */ new Date();
+ midnightToday.setHours(0, 0, 0, 0);
+ const thirtyDaysAgo = now - 30 * 24 * 60 * 60 * 1e3;
+ const [settings, collections, newCollections, indexStatus, analytics, queriesTodayRow, totalClicks30dRow, zeroResults30dRow] = await Promise.all([
+ service.getSettings(),
+ service.getAllCollections(),
+ service.detectNewCollections(),
+ indexer.getAllIndexStatus(),
+ service.getSearchAnalytics(),
+ db.prepare("SELECT COUNT(*) as count FROM ai_search_history WHERE created_at >= ?").bind(midnightToday.getTime()).first().catch(() => null),
+ db.prepare("SELECT COUNT(*) as count FROM ai_search_clicks WHERE created_at > datetime('now', '-30 days')").first().catch(() => null),
+ db.prepare("SELECT COUNT(*) as count FROM ai_search_history WHERE results_count = 0 AND created_at >= ?").bind(thirtyDaysAgo).first().catch(() => null)
+ ]);
+ let fts5Status = null;
+ try {
+ const isAvailable = await fts5Service.isAvailable();
+ if (isAvailable) {
+ const stats = await fts5Service.getStats();
+ fts5Status = { available: true, total_indexed: stats.total_indexed, by_collection: stats.by_collection };
+ } else {
+ fts5Status = { available: false, total_indexed: 0, by_collection: {} };
+ }
+ } catch {
+ fts5Status = { available: false, total_indexed: 0, by_collection: {} };
+ }
+ let benchmarkStatus = null;
+ try {
+ const { seeded, count } = await benchmarkService.isSeeded();
+ const meta = benchmarkService.getMeta();
+ benchmarkStatus = {
+ seeded,
+ seeded_count: count,
+ corpus_size: meta.corpus_size,
+ query_count: meta.query_count
+ };
+ } catch {
+ benchmarkStatus = null;
+ }
+ return c.html(
+ renderSearchDashboard({
+ settings,
+ collections: collections || [],
+ newCollections: (newCollections || []).map((n) => ({ id: String(n.collection.id), name: n.collection.name })),
+ indexStatus: indexStatus || {},
+ analytics,
+ fts5Status,
+ benchmarkStatus,
+ queriesToday: queriesTodayRow?.count ?? 0,
+ totalClicks30d: totalClicks30dRow?.count ?? 0,
+ zeroResults30d: zeroResults30dRow?.count ?? 0,
+ user: user ? { name: user.email, email: user.email, role: user.role } : void 0,
+ version: getCoreVersion()
+ })
+ );
+ } catch (error) {
+ console.error("Error rendering Search admin page:", error);
+ return c.html(`Error loading search dashboard: ${error instanceof Error ? error.message : String(error)}
`, 500);
+ }
+});
+var adminApiKeyRoutes = new Hono();
+adminApiKeyRoutes.use("*", requireAuth());
+adminApiKeyRoutes.post("/", async (c) => {
+ try {
+ const body = await c.req.json();
+ const { name, scopes, expires_at: expiresAt } = body;
+ if (!name || typeof name !== "string") {
+ return c.json({ error: "name is required" }, 400);
+ }
+ if (!Array.isArray(scopes) || scopes.length === 0) {
+ return c.json({ error: "scopes array is required" }, 400);
+ }
+ const invalidScopes = scopes.filter((s) => !VALID_SCOPES.includes(s));
+ if (invalidScopes.length > 0) {
+ return c.json({ error: `Invalid scopes: ${invalidScopes.join(", ")}` }, 400);
+ }
+ const randomBytes = new Uint8Array(32);
+ crypto.getRandomValues(randomBytes);
+ const hex = Array.from(randomBytes).map((b) => b.toString(16).padStart(2, "0")).join("");
+ const plainToken = `sk_live_${hex}`;
+ const tokenHash = await hashApiKey(plainToken);
+ const id = crypto.randomUUID();
+ const user = c.get("user");
+ const userId = user?.userId || "system";
+ const db = c.env.DB;
+ let expiresAtValue = null;
+ if (expiresAt) {
+ if (typeof expiresAt === "number") {
+ expiresAtValue = new Date(expiresAt).toISOString();
+ } else {
+ expiresAtValue = String(expiresAt);
+ }
+ }
+ await db.prepare(
+ `INSERT INTO api_tokens (id, name, token, user_id, permissions, expires_at, created_at)
+ VALUES (?, ?, ?, ?, ?, ?, datetime('now'))`
+ ).bind(id, name, tokenHash, userId, JSON.stringify(scopes), expiresAtValue).run();
+ return c.json(
+ {
+ success: true,
+ data: {
+ id,
+ name,
+ token: plainToken,
+ // shown once
+ scopes,
+ expires_at: expiresAtValue,
+ created_at: (/* @__PURE__ */ new Date()).toISOString()
+ }
+ },
+ 201
+ );
+ } catch (error) {
+ console.error("Create API key error:", error);
+ return c.json({ error: "Failed to create API key" }, 500);
+ }
+});
+adminApiKeyRoutes.get("/", async (c) => {
+ try {
+ const db = c.env.DB;
+ const rows = await db.prepare(
+ "SELECT id, name, token, user_id, permissions, expires_at, last_used_at, created_at FROM api_tokens ORDER BY created_at DESC"
+ ).all();
+ const keys = (rows.results || []).map((row) => {
+ const hash = row.token || "";
+ const tokenHint = `sk_live_...${hash.slice(-8)}`;
+ let scopes = [];
+ try {
+ scopes = JSON.parse(row.permissions);
+ } catch {
+ scopes = [];
+ }
+ return {
+ id: row.id,
+ name: row.name,
+ token_hint: tokenHint,
+ scopes,
+ user_id: row.user_id,
+ expires_at: row.expires_at,
+ last_used_at: row.last_used_at,
+ created_at: row.created_at
+ };
+ });
+ return c.json({ success: true, data: keys });
+ } catch (error) {
+ console.error("List API keys error:", error);
+ return c.json({ error: "Failed to list API keys" }, 500);
+ }
+});
+adminApiKeyRoutes.patch("/:id", async (c) => {
+ try {
+ const id = c.req.param("id");
+ const body = await c.req.json();
+ const db = c.env.DB;
+ const existing = await db.prepare("SELECT id FROM api_tokens WHERE id = ?").bind(id).first();
+ if (!existing) {
+ return c.json({ error: "API key not found" }, 404);
+ }
+ const updates = [];
+ const values = [];
+ if (body.name !== void 0) {
+ updates.push("name = ?");
+ values.push(body.name);
+ }
+ if (body.scopes !== void 0) {
+ if (!Array.isArray(body.scopes)) {
+ return c.json({ error: "scopes must be an array" }, 400);
+ }
+ const invalid = body.scopes.filter((s) => !VALID_SCOPES.includes(s));
+ if (invalid.length > 0) {
+ return c.json({ error: `Invalid scopes: ${invalid.join(", ")}` }, 400);
+ }
+ updates.push("permissions = ?");
+ values.push(JSON.stringify(body.scopes));
+ }
+ if (updates.length === 0) {
+ return c.json({ error: "No fields to update" }, 400);
+ }
+ values.push(id);
+ await db.prepare(`UPDATE api_tokens SET ${updates.join(", ")} WHERE id = ?`).bind(...values).run();
+ return c.json({ success: true });
+ } catch (error) {
+ console.error("Update API key error:", error);
+ return c.json({ error: "Failed to update API key" }, 500);
+ }
+});
+adminApiKeyRoutes.delete("/:id", async (c) => {
+ try {
+ const id = c.req.param("id");
+ const db = c.env.DB;
+ const existing = await db.prepare("SELECT id, token FROM api_tokens WHERE id = ?").bind(id).first();
+ if (!existing) {
+ return c.json({ error: "API key not found" }, 404);
+ }
+ await db.prepare("DELETE FROM api_tokens WHERE id = ?").bind(id).run();
+ const kv = c.env.CACHE_KV;
+ if (kv && existing.token) {
+ try {
+ await kv.delete(`apikey:${existing.token}`);
+ } catch {
+ }
+ }
+ return c.json({ success: true, message: "API key revoked" });
+ } catch (error) {
+ console.error("Revoke API key error:", error);
+ return c.json({ error: "Failed to revoke API key" }, 500);
+ }
+});
+
// src/routes/index.ts
var ROUTES_INFO = {
message: "Core routes available",
@@ -27751,12 +38689,14 @@ var ROUTES_INFO = {
"adminSettingsRoutes",
"adminFormsRoutes",
"publicFormsRoutes",
- "adminApiReferenceRoutes"
+ "adminApiReferenceRoutes",
+ "adminSearchRoutes",
+ "adminApiKeyRoutes"
],
status: "Core package routes ready",
reference: "https://github.com/sonicjs/sonicjs"
};
-export { ROUTES_INFO, adminCheckboxRoutes, adminCollectionsRoutes, adminDesignRoutes, adminFormsRoutes, adminLogsRoutes, adminMediaRoutes, adminPluginRoutes, adminSettingsRoutes, admin_api_default, admin_code_examples_default, admin_content_default, admin_testimonials_default, api_content_crud_default, api_default, api_media_default, api_system_default, auth_default, getConfirmationDialogScript2 as getConfirmationDialogScript, public_forms_default, renderConfirmationDialog2 as renderConfirmationDialog, router, router2, test_cleanup_default, userRoutes };
-//# sourceMappingURL=chunk-7DU5PUKL.js.map
-//# sourceMappingURL=chunk-7DU5PUKL.js.map
\ No newline at end of file
+export { AISearchService, BENCHMARK_DATASETS, BenchmarkService, ChunkingService, EmbeddingService, FTS5Service, FacetService, IndexManager, QueryRulesService, ROUTES_INFO, RankingPipelineService, RelatedSearchService, SynonymService, TrendingSearchService, adminApiKeyRoutes, adminCheckboxRoutes, adminCollectionsRoutes, adminDesignRoutes, adminFormsRoutes, adminLogsRoutes, adminMediaRoutes, adminPluginRoutes, adminSearchRoutes, adminSettingsRoutes, admin_api_default, admin_code_examples_default, admin_content_default, admin_testimonials_default, api_content_crud_default, api_default, api_media_default, api_system_default, auth_default, getConfirmationDialogScript2 as getConfirmationDialogScript, public_forms_default, renderConfirmationDialog2 as renderConfirmationDialog, renderSearchDashboard, router, router2, test_cleanup_default, userRoutes };
+//# sourceMappingURL=chunk-3TMCOE5J.js.map
+//# sourceMappingURL=chunk-3TMCOE5J.js.map
\ No newline at end of file
diff --git a/packages/core/dist/chunk-3TMCOE5J.js.map b/packages/core/dist/chunk-3TMCOE5J.js.map
new file mode 100644
index 000000000..552a0d243
--- /dev/null
+++ b/packages/core/dist/chunk-3TMCOE5J.js.map
@@ -0,0 +1 @@
+{"version":3,"sources":["../src/schemas/index.ts","../src/plugins/core-plugins/ai-search-plugin/services/facet.service.ts","../src/plugins/core-plugins/ai-search-plugin/services/fts5.service.ts","../src/plugins/core-plugins/ai-search-plugin/services/search-cache.service.ts","../src/routes/api-content-crud.ts","../src/routes/api.ts","../src/routes/api-media.ts","../src/routes/api-system.ts","../src/routes/admin-api.ts","../src/templates/pages/auth-login.template.ts","../src/templates/pages/auth-register.template.ts","../src/services/auth-validation.ts","../src/routes/auth.ts","../src/routes/test-cleanup.ts","../src/templates/pages/admin-content-form.template.ts","../src/templates/components/drag-sortable.template.ts","../src/templates/components/dynamic-field.template.ts","../src/plugins/available/tinymce-plugin/index.ts","../src/plugins/core-plugins/quill-editor/index.ts","../src/plugins/available/easy-mdx/index.ts","../src/templates/pages/admin-content-list.template.ts","../src/templates/components/version-history.template.ts","../src/middleware/plugin-middleware.ts","../src/routes/admin-content.ts","../src/templates/pages/admin-profile.template.ts","../src/templates/components/alert.template.ts","../src/templates/pages/admin-activity-logs.template.ts","../src/templates/pages/admin-user-edit.template.ts","../src/templates/components/confirmation-dialog.template.ts","../src/templates/pages/admin-user-new.template.ts","../src/templates/pages/admin-users-list.template.ts","../src/routes/admin-users.ts","../src/templates/components/media-grid.template.ts","../src/templates/pages/admin-media-library.template.ts","../src/templates/components/media-file-details.template.ts","../src/routes/admin-media.ts","../src/templates/pages/admin-plugins-list.template.ts","../src/templates/components/auth-settings-form.template.ts","../src/templates/pages/admin-plugin-settings.template.ts","../src/routes/admin-plugins.ts","../src/templates/pages/admin-logs-list.template.ts","../src/templates/pages/admin-log-details.template.ts","../src/templates/pages/admin-log-config.template.ts","../src/routes/admin-logs.ts","../src/routes/admin-design.ts","../src/routes/admin-checkboxes.ts","../src/templates/pages/admin-testimonials-form.template.ts","../src/routes/admin-testimonials.ts","../src/templates/pages/admin-code-examples-form.template.ts","../src/routes/admin-code-examples.ts","../src/templates/pages/admin-dashboard.template.ts","../src/routes/admin-dashboard.ts","../src/templates/pages/admin-collections-list.template.ts","../src/templates/components/table.template.ts","../src/templates/pages/admin-collections-form.template.ts","../src/routes/admin-collections.ts","../src/templates/pages/admin-settings.template.ts","../src/routes/admin-settings.ts","../src/templates/pages/admin-forms-list.template.ts","../src/templates/pages/admin-forms-builder.template.ts","../src/templates/pages/admin-forms-create.template.ts","../src/routes/admin-forms.ts","../src/routes/public-forms.ts","../src/templates/pages/admin-api-reference.template.ts","../src/routes/admin-api-reference.ts","../src/plugins/core-plugins/ai-search-plugin/services/embedding.service.ts","../src/plugins/core-plugins/ai-search-plugin/services/chunking.service.ts","../src/plugins/core-plugins/ai-search-plugin/services/custom-rag.service.ts","../src/plugins/core-plugins/ai-search-plugin/services/hybrid-search.service.ts","../src/plugins/core-plugins/ai-search-plugin/services/query-rewriter.service.ts","../src/plugins/core-plugins/ai-search-plugin/services/query-rules.service.ts","../src/plugins/core-plugins/ai-search-plugin/types.ts","../src/plugins/core-plugins/ai-search-plugin/services/ranking-pipeline.service.ts","../src/plugins/core-plugins/ai-search-plugin/services/synonym.service.ts","../src/plugins/core-plugins/ai-search-plugin/services/reranker.service.ts","../src/plugins/core-plugins/ai-search-plugin/services/trending-search.service.ts","../src/plugins/core-plugins/ai-search-plugin/services/related-search.service.ts","../src/plugins/core-plugins/ai-search-plugin/services/ai-search.ts","../src/plugins/core-plugins/ai-search-plugin/services/indexer.ts","../src/plugins/core-plugins/ai-search-plugin/data/benchmark-datasets.ts","../src/plugins/core-plugins/ai-search-plugin/services/benchmark.service.ts","../src/templates/pages/admin-search.template.ts","../src/templates/pages/admin-search-overview.template.ts","../src/templates/pages/admin-search-config.template.ts","../src/templates/pages/admin-search-benchmark.template.ts","../src/templates/pages/admin-search-relevance.template.ts","../src/templates/pages/admin-search-analytics.template.ts","../src/templates/pages/admin-search-agent.template.ts","../src/plugins/core-plugins/ai-search-plugin/constants/experiment-templates.ts","../src/templates/pages/admin-search-experiments.template.ts","../src/routes/admin-search.ts","../src/routes/admin-api-keys.ts","../src/routes/index.ts"],"names":["Hono","builder","z","MigrationService","error","passwordHash","c","escapeHtml","isPluginActive","db","collection","formData","tinymcePlugin","html","renderAlert","renderConfirmationDialog","getConfirmationDialogScript","fileValidationSchema","getImageDimensions","getJPEGDimensions","getPNGDimensions","easyMdxPlugin","renderTable","tinymceActive","quillActive","mdxeditorActive","result","VERSION","router","raw","existingQueries","relatedSearches","fallbackStatus"],"mappings":"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;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA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A;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;A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C;;;ACrSA,mCAAA,EAAA;AAuBA,SAAS,2BAAA,GAAsC;AAC7C,EAAA,OAAO;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAA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AAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AA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;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA,EAAA,CAAA;AAkbT;;;AC/pBO,SAAS,kBAAA,GAA6B;AAC3C,EAAA,OAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAAA,CAAA;AAyGT;AAEO,SAAS,qBAAA,GAAgC;AAC9C,EAAA,OAAO;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;A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AAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAAA,CAAA;AAkjCT;;;AClmDO,SAAS,kBAAA,GAA6B;AAC3C,EAAA,OAAO;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA,EAAA,CAAA;AAgQT;AAEO,SAAS,qBAAA,GAAgC;AAC9C,EAAA,OAAO;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA,EAAA,CAAA;AAigBT;;;ACrwBO,SAAS,cAAA,GAAyB;AACvC,EAAA,OAAO;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;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,GAA+B;AAC7C,EAAA,OAAO;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAAA,CAAA;AA6RT;AAEO,SAAS,uBAAA,GAAkC;AAEhD,EAAA,MAAM,aAAA,GAAgB,IAAA,CAAK,SAAA,CAAU,oBAAoB,CAAA;AACzD,EAAA,MAAM,YAAA,GAAe,IAAA,CAAK,SAAA,CAAU,iBAAiB,CAAA;AACrD,EAAA,MAAM,YAAA,GAAe,IAAA,CAAK,SAAA,CAAU,gBAAgB,CAAA;AAEpD,EAAA,OAAO;AAAA;AAAA;AAAA;AAAA;AAAA,+BAAA,EAKwB,YAAY;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA,0BAAA,EAOjB,aAAa;AAAA,kCAAA,EACL,YAAY;AAAA,iCAAA,EACb,YAAY;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;;A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","file":"chunk-3TMCOE5J.js","sourcesContent":["/**\n * Schema Definitions\n *\n * Placeholder for schema definitions - to be populated as needed\n */\n\nexport interface SchemaDefinition {\n name: string\n fields: any[]\n}\n\n// Empty array for now - schemas will be migrated incrementally\nexport const schemaDefinitions: SchemaDefinition[] = []\n","/**\n * FacetService ā Schema-aware facet discovery and computation\n *\n * Discovers facetable fields from collection JSON schemas,\n * computes facet counts via SQL GROUP BY (full result set),\n * and provides in-memory counting for AI/hybrid modes.\n *\n * Designed as the shared foundation for both manual admin config\n * and the Phase 6 AI Search Quality Agent's facet discovery job.\n */\n\nimport type {\n FacetDefinition,\n FacetResult,\n FacetValue,\n DiscoveredField,\n SearchResult,\n} from '../types'\n\n// Fields that are never useful as facets\nconst NON_FACETABLE_FORMATS = new Set(['richtext', 'media', 'date-time', 'slug'])\n\n// Schema field names that shadow built-in facets ā skip to avoid duplicates\nconst BUILTIN_FIELD_NAMES = new Set(['author', 'status'])\n\nexport class FacetService {\n constructor(private db: D1Database) {}\n\n // =============================================\n // Discovery ā introspect collection schemas\n // =============================================\n\n /**\n * Discover facetable fields from all active collection schemas.\n * Returns built-in facets + custom fields classified by type.\n */\n async discoverFields(): Promise {\n const discovered: DiscoveredField[] = []\n\n // Built-in facets (always available)\n discovered.push(\n { field: 'collection_name', title: 'Collection', type: 'builtin', recommended: true, collections: [] },\n { field: 'status', title: 'Status', type: 'builtin', recommended: true, collections: [], enumValues: ['draft', 'published', 'archived'] },\n { field: 'author', title: 'Author', type: 'builtin', recommended: true, collections: [] },\n )\n\n // Read all active collection schemas\n try {\n const { results } = await this.db\n .prepare(`SELECT id, name, display_name, schema FROM collections WHERE is_active = 1`)\n .all<{ id: string; name: string; display_name: string; schema: string }>()\n\n if (!results?.length) return discovered\n\n // Map: fieldPath ā { title, type, recommended, collections, enumValues }\n const fieldMap = new Map\n enumValues?: string[]\n }>()\n\n for (const col of results) {\n let schema: any\n try {\n schema = typeof col.schema === 'string' ? JSON.parse(col.schema) : col.schema\n } catch {\n continue\n }\n\n const properties = schema?.properties\n if (!properties || typeof properties !== 'object') continue\n\n for (const [fieldName, fieldDef] of Object.entries(properties)) {\n const def = fieldDef as any\n if (!def || typeof def !== 'object') continue\n\n // Skip fields that shadow built-in facets (e.g. schema \"author\" vs built-in author)\n if (BUILTIN_FIELD_NAMES.has(fieldName)) continue\n\n const classification = this.classifyField(fieldName, def)\n if (!classification) continue\n\n const path = `$.${fieldName}`\n const existing = fieldMap.get(path)\n if (existing) {\n existing.collections.push({ id: col.id, name: col.display_name })\n } else {\n fieldMap.set(path, {\n title: def.title || fieldName,\n type: classification.type,\n recommended: classification.recommended,\n collections: [{ id: col.id, name: col.display_name }],\n enumValues: classification.enumValues,\n })\n }\n }\n }\n\n // Convert map to DiscoveredField array\n for (const [field, info] of fieldMap) {\n discovered.push({\n field,\n title: info.title,\n type: info.type,\n recommended: info.recommended,\n collections: info.collections,\n enumValues: info.enumValues,\n })\n }\n } catch (error) {\n console.error('[FacetService] Discovery error:', error)\n }\n\n return discovered\n }\n\n /**\n * Classify a field definition from collection schema.\n * Returns null if the field is not facetable.\n */\n private classifyField(\n fieldName: string,\n def: any\n ): { type: 'json_scalar' | 'json_array'; recommended: boolean; enumValues?: string[] } | null {\n const fieldType = def.type\n const format = def.format\n\n // Not facetable: richtext, media, date-time, slug, object, number\n if (format && NON_FACETABLE_FORMATS.has(format)) return null\n if (fieldType === 'object') return null\n if (fieldType === 'number' || fieldType === 'integer') return null\n\n // Array of strings ā json_array, recommended\n if (fieldType === 'array' && def.items?.type === 'string') {\n return { type: 'json_array', recommended: true }\n }\n\n // String with enum ā json_scalar, recommended\n if (fieldType === 'string' && Array.isArray(def.enum) && def.enum.length > 0) {\n return { type: 'json_scalar', recommended: true, enumValues: def.enum }\n }\n\n // Boolean ā json_scalar, recommended\n if (fieldType === 'boolean') {\n return { type: 'json_scalar', recommended: true, enumValues: ['true', 'false'] }\n }\n\n // Plain string without format ā available but not recommended (high cardinality)\n if (fieldType === 'string' && !format) {\n return { type: 'json_scalar', recommended: false }\n }\n\n return null\n }\n\n // =============================================\n // Auto-generation ā create default config\n // =============================================\n\n /**\n * Generate default facet config from discovered fields.\n * Only enables recommended fields.\n */\n autoGenerateConfig(discovered: DiscoveredField[]): FacetDefinition[] {\n return discovered\n .filter(d => d.recommended)\n .map((d, i) => ({\n name: d.title,\n field: d.field,\n type: d.type,\n collections: d.collections.map(c => c.id),\n enabled: true,\n source: 'auto' as const,\n position: i,\n sortBy: 'count' as const,\n }))\n }\n\n // =============================================\n // Computation ā SQL GROUP BY (FTS5/keyword)\n // =============================================\n\n /**\n * Compute facets for FTS5 mode using parallel SQL GROUP BY queries.\n * Counts reflect the full matching result set (not just current page).\n */\n async computeFacetsFts(\n config: FacetDefinition[],\n matchQuery: string,\n collectionIds: string[],\n maxValues: number,\n activeFilters?: Record\n ): Promise {\n const enabled = config.filter(f => f.enabled)\n if (enabled.length === 0 || collectionIds.length === 0) return []\n\n const collPlaceholders = collectionIds.map(() => '?').join(', ')\n\n const promises = enabled.map(async (facet): Promise => {\n const limit = facet.maxValues || maxValues\n // Cross-filtering: apply all active filters EXCEPT this facet's own field\n let extraConditions: string[] = []\n let extraParams: any[] = []\n if (activeFilters && Object.keys(activeFilters).length > 0) {\n const cross = FacetService.buildFacetFilterSQL(activeFilters, config, facet.field)\n extraConditions = cross.conditions\n extraParams = cross.params\n }\n try {\n const values = await this.runFtsFacetQuery(facet, matchQuery, collectionIds, collPlaceholders, limit, extraConditions, extraParams)\n return this.sortFacetValues(facet, values)\n } catch (error) {\n console.error(`[FacetService] Facet query error for ${facet.field}:`, error)\n return { name: facet.name, field: facet.field, values: [] }\n }\n })\n\n return Promise.all(promises)\n }\n\n private async runFtsFacetQuery(\n facet: FacetDefinition,\n matchQuery: string,\n collectionIds: string[],\n collPlaceholders: string,\n limit: number,\n extraConditions: string[] = [],\n extraParams: any[] = []\n ): Promise {\n const extraWhere = extraConditions.length > 0\n ? '\\n ' + extraConditions.map(c => `AND ${c}`).join('\\n ')\n : ''\n\n let sql: string\n let params: any[]\n\n switch (facet.field) {\n case 'collection_name':\n sql = `\n SELECT col.display_name as value, COUNT(*) as count\n FROM content_fts fts\n JOIN content c ON fts.content_id = c.id\n JOIN collections col ON fts.collection_id = col.id\n WHERE content_fts MATCH ?\n AND fts.collection_id IN (${collPlaceholders})\n AND c.status != 'deleted'${extraWhere}\n GROUP BY value ORDER BY count DESC LIMIT ?\n `\n params = [matchQuery, ...collectionIds, ...extraParams, limit]\n break\n\n case 'status':\n sql = `\n SELECT c.status as value, COUNT(*) as count\n FROM content_fts fts\n JOIN content c ON fts.content_id = c.id\n WHERE content_fts MATCH ?\n AND fts.collection_id IN (${collPlaceholders})\n AND c.status != 'deleted'${extraWhere}\n GROUP BY c.status ORDER BY count DESC LIMIT ?\n `\n params = [matchQuery, ...collectionIds, ...extraParams, limit]\n break\n\n case 'author':\n sql = `\n SELECT COALESCE(u.email, 'Unknown') as value, COUNT(*) as count\n FROM content_fts fts\n JOIN content c ON fts.content_id = c.id\n LEFT JOIN users u ON c.author_id = u.id\n WHERE content_fts MATCH ?\n AND fts.collection_id IN (${collPlaceholders})\n AND c.status != 'deleted'${extraWhere}\n GROUP BY value ORDER BY count DESC LIMIT ?\n `\n params = [matchQuery, ...collectionIds, ...extraParams, limit]\n break\n\n default:\n // Custom JSON field\n if (facet.type === 'json_array') {\n const jsonPath = facet.field // e.g. \"$.tags\"\n sql = `\n SELECT j.value as value, COUNT(*) as count\n FROM content_fts fts\n JOIN content c ON fts.content_id = c.id,\n json_each(json_extract(c.data, '${jsonPath}')) j\n WHERE content_fts MATCH ?\n AND fts.collection_id IN (${collPlaceholders})\n AND c.status != 'deleted'${extraWhere}\n GROUP BY j.value ORDER BY count DESC LIMIT ?\n `\n } else {\n const jsonPath = facet.field\n sql = `\n SELECT json_extract(c.data, '${jsonPath}') as value, COUNT(*) as count\n FROM content_fts fts\n JOIN content c ON fts.content_id = c.id\n WHERE content_fts MATCH ?\n AND fts.collection_id IN (${collPlaceholders})\n AND c.status != 'deleted'\n AND json_extract(c.data, '${jsonPath}') IS NOT NULL${extraWhere}\n GROUP BY value ORDER BY count DESC LIMIT ?\n `\n }\n params = [matchQuery, ...collectionIds, ...extraParams, limit]\n }\n\n const { results } = await this.db.prepare(sql).bind(...params)\n .all<{ value: string; count: number }>()\n\n return (results || []).map(r => ({\n value: String(r.value),\n count: r.count,\n }))\n }\n\n /**\n * Compute facets for keyword mode using parallel SQL GROUP BY queries.\n */\n async computeFacetsKeyword(\n config: FacetDefinition[],\n queryTerm: string,\n collectionIds: string[],\n maxValues: number,\n activeFilters?: Record\n ): Promise {\n const enabled = config.filter(f => f.enabled)\n if (enabled.length === 0 || collectionIds.length === 0) return []\n\n const collPlaceholders = collectionIds.map(() => '?').join(', ')\n const likeTerm = `%${queryTerm}%`\n\n const promises = enabled.map(async (facet): Promise => {\n const limit = facet.maxValues || maxValues\n // Cross-filtering: apply all active filters EXCEPT this facet's own field\n let extraConditions: string[] = []\n let extraParams: any[] = []\n if (activeFilters && Object.keys(activeFilters).length > 0) {\n const cross = FacetService.buildFacetFilterSQL(activeFilters, config, facet.field)\n extraConditions = cross.conditions\n extraParams = cross.params\n }\n try {\n const values = await this.runKeywordFacetQuery(facet, likeTerm, collectionIds, collPlaceholders, limit, extraConditions, extraParams)\n return this.sortFacetValues(facet, values)\n } catch (error) {\n console.error(`[FacetService] Keyword facet error for ${facet.field}:`, error)\n return { name: facet.name, field: facet.field, values: [] }\n }\n })\n\n return Promise.all(promises)\n }\n\n private async runKeywordFacetQuery(\n facet: FacetDefinition,\n likeTerm: string,\n collectionIds: string[],\n collPlaceholders: string,\n limit: number,\n extraConditions: string[] = [],\n extraParams: any[] = []\n ): Promise {\n const extraWhere = extraConditions.length > 0\n ? '\\n ' + extraConditions.map(c => `AND ${c}`).join('\\n ')\n : ''\n\n // Base WHERE clause for keyword search\n const baseWhere = `\n c.collection_id IN (${collPlaceholders})\n AND c.status != 'deleted'\n AND (c.title LIKE ? OR c.slug LIKE ? OR c.data LIKE ?)${extraWhere}\n `\n const baseParams = [...collectionIds, likeTerm, likeTerm, likeTerm, ...extraParams]\n\n let sql: string\n let params: any[]\n\n switch (facet.field) {\n case 'collection_name':\n sql = `\n SELECT col.display_name as value, COUNT(*) as count\n FROM content c\n JOIN collections col ON c.collection_id = col.id\n WHERE ${baseWhere}\n GROUP BY value ORDER BY count DESC LIMIT ?\n `\n params = [...baseParams, limit]\n break\n\n case 'status':\n sql = `\n SELECT c.status as value, COUNT(*) as count\n FROM content c\n WHERE ${baseWhere}\n GROUP BY c.status ORDER BY count DESC LIMIT ?\n `\n params = [...baseParams, limit]\n break\n\n case 'author':\n sql = `\n SELECT COALESCE(u.email, 'Unknown') as value, COUNT(*) as count\n FROM content c\n LEFT JOIN users u ON c.author_id = u.id\n WHERE ${baseWhere}\n GROUP BY value ORDER BY count DESC LIMIT ?\n `\n params = [...baseParams, limit]\n break\n\n default:\n if (facet.type === 'json_array') {\n sql = `\n SELECT j.value as value, COUNT(*) as count\n FROM content c,\n json_each(json_extract(c.data, '${facet.field}')) j\n WHERE ${baseWhere}\n GROUP BY j.value ORDER BY count DESC LIMIT ?\n `\n } else {\n sql = `\n SELECT json_extract(c.data, '${facet.field}') as value, COUNT(*) as count\n FROM content c\n WHERE ${baseWhere}\n AND json_extract(c.data, '${facet.field}') IS NOT NULL\n GROUP BY value ORDER BY count DESC LIMIT ?\n `\n }\n params = [...baseParams, limit]\n }\n\n const { results } = await this.db.prepare(sql).bind(...params)\n .all<{ value: string; count: number }>()\n\n return (results || []).map(r => ({\n value: String(r.value),\n count: r.count,\n }))\n }\n\n // =============================================\n // Computation ā in-memory (AI/hybrid modes)\n // =============================================\n\n /**\n * Compute facets from a set of content IDs by fetching their data\n * and counting in-memory. Used for AI and hybrid modes where\n * Vectorize returns max 50 results.\n */\n async computeFacetsFromIds(\n config: FacetDefinition[],\n contentIds: string[],\n maxValues: number\n ): Promise {\n const enabled = config.filter(f => f.enabled)\n if (enabled.length === 0 || contentIds.length === 0) return []\n\n // Fetch content data for all result IDs\n const placeholders = contentIds.map(() => '?').join(', ')\n const { results: rows } = await this.db\n .prepare(`\n SELECT c.id, c.data, c.status, c.collection_id, c.author_id,\n col.display_name as collection_name,\n u.email as author_email\n FROM content c\n JOIN collections col ON c.collection_id = col.id\n LEFT JOIN users u ON c.author_id = u.id\n WHERE c.id IN (${placeholders})\n `)\n .bind(...contentIds)\n .all<{\n id: string; data: string; status: string; collection_id: string\n collection_name: string; author_email: string | null\n }>()\n\n if (!rows?.length) {\n return enabled.map(f => ({ name: f.name, field: f.field, values: [] }))\n }\n\n return enabled.map(facet => {\n const limit = facet.maxValues || maxValues\n const counts = new Map()\n\n for (const row of rows) {\n const values = this.extractFacetValues(facet, row)\n for (const v of values) {\n counts.set(v, (counts.get(v) || 0) + 1)\n }\n }\n\n let facetValues: FacetValue[] = Array.from(counts.entries())\n .map(([value, count]) => ({ value, count }))\n\n facetValues = this.sortValues(facet, facetValues).slice(0, limit)\n\n return { name: facet.name, field: facet.field, values: facetValues }\n })\n }\n\n /**\n * Also supports counting from already-loaded SearchResult array\n * (used by InstantSearch adapter when facets come from search response).\n */\n computeFacetsFromResults(\n config: FacetDefinition[],\n results: SearchResult[],\n maxValues: number\n ): FacetResult[] {\n const enabled = config.filter(f => f.enabled)\n if (enabled.length === 0 || results.length === 0) {\n return enabled.map(f => ({ name: f.name, field: f.field, values: [] }))\n }\n\n return enabled.map(facet => {\n const limit = facet.maxValues || maxValues\n const counts = new Map()\n\n for (const r of results) {\n let value: string | undefined\n switch (facet.field) {\n case 'collection_name': value = r.collection_name; break\n case 'status': value = r.status; break\n case 'author': value = r.author_name; break\n default: break // Custom JSON fields not available on SearchResult\n }\n if (value) counts.set(value, (counts.get(value) || 0) + 1)\n }\n\n let facetValues = Array.from(counts.entries())\n .map(([value, count]) => ({ value, count }))\n facetValues = this.sortValues(facet, facetValues).slice(0, limit)\n\n return { name: facet.name, field: facet.field, values: facetValues }\n })\n }\n\n // =============================================\n // Helpers\n // =============================================\n\n private extractFacetValues(\n facet: FacetDefinition,\n row: { data: string; status: string; collection_name: string; author_email: string | null }\n ): string[] {\n switch (facet.field) {\n case 'collection_name': return [row.collection_name]\n case 'status': return [row.status]\n case 'author': return [row.author_email || 'Unknown']\n default: {\n // Extract from JSON data\n try {\n const parsed = typeof row.data === 'string' ? JSON.parse(row.data) : row.data\n // Strip the \"$.\" prefix to get the field name\n const fieldName = facet.field.startsWith('$.') ? facet.field.slice(2) : facet.field\n const val = parsed[fieldName]\n\n if (val == null) return []\n if (facet.type === 'json_array' && Array.isArray(val)) {\n return val.filter((v: any) => typeof v === 'string')\n }\n return [String(val)]\n } catch {\n return []\n }\n }\n }\n }\n\n private sortFacetValues(facet: FacetDefinition, values: FacetValue[]): FacetResult {\n return {\n name: facet.name,\n field: facet.field,\n values: this.sortValues(facet, values),\n }\n }\n\n private sortValues(facet: FacetDefinition, values: FacetValue[]): FacetValue[] {\n if (facet.sortBy === 'alpha') {\n return values.sort((a, b) => a.value.localeCompare(b.value))\n }\n return values.sort((a, b) => b.count - a.count)\n }\n\n /**\n * Convert filters.custom to SQL WHERE clause fragments.\n * All conditions reference only the `c` (content) table alias,\n * making them safe to inject into any query that joins content.\n * Used by both search queries (narrowing results) and facet computation (cross-filtering).\n *\n * @param excludeField ā For cross-filtering: skip this field so facet X\n * shows counts unaffected by its own selection.\n */\n static buildFacetFilterSQL(\n customFilters: Record,\n facetConfig: FacetDefinition[],\n excludeField?: string\n ): { conditions: string[]; params: any[] } {\n const conditions: string[] = []\n const params: any[] = []\n\n if (!customFilters || typeof customFilters !== 'object') {\n return { conditions, params }\n }\n\n const configMap = new Map()\n for (const fc of facetConfig) {\n configMap.set(fc.field, fc)\n }\n\n for (const [field, values] of Object.entries(customFilters)) {\n if (!values || (Array.isArray(values) && values.length === 0)) continue\n if (excludeField && field === excludeField) continue\n\n const valueArr = Array.isArray(values) ? values : [values]\n if (valueArr.length === 0) continue\n const placeholders = valueArr.map(() => '?').join(', ')\n\n switch (field) {\n case 'collection_name':\n conditions.push(`c.collection_id IN (SELECT id FROM collections WHERE display_name IN (${placeholders}))`)\n params.push(...valueArr)\n break\n case 'status':\n conditions.push(`c.status IN (${placeholders})`)\n params.push(...valueArr)\n break\n case 'author':\n conditions.push(`c.author_id IN (SELECT id FROM users WHERE email IN (${placeholders}))`)\n params.push(...valueArr)\n break\n default: {\n const config = configMap.get(field)\n if (!config) break\n if (config.type === 'json_array') {\n conditions.push(\n `EXISTS(SELECT 1 FROM json_each(json_extract(c.data, '${field}')) t WHERE t.value IN (${placeholders}))`\n )\n } else {\n conditions.push(`json_extract(c.data, '${field}') IN (${placeholders})`)\n }\n params.push(...valueArr)\n break\n }\n }\n }\n\n return { conditions, params }\n }\n\n /**\n * Sanitize a query string for FTS5 MATCH syntax.\n * Mirrors the logic in FTS5Service.sanitizeFTS5Query so facet GROUP BY\n * queries use the same MATCH expression as the main search.\n */\n static sanitizeFTS5Query(query: string): string {\n if (!query || typeof query !== 'string') return '\"\"'\n\n let sanitized = query\n .replace(/-/g, ' ')\n .replace(/[^a-zA-Z0-9\\s]/g, '')\n .replace(/\\s+/g, ' ')\n .trim()\n .toLowerCase()\n\n const stopWords = new Set([\n 'a','an','the','is','are','was','were','be','to','of','in','on','at',\n 'by','or','and','not','for','it','as','do','if','no','so','up','but',\n 'its','has','had','near',\n ])\n const terms = sanitized.split(/\\s+/).filter(t => t.length > 1 && !stopWords.has(t))\n\n if (terms.length === 0) return '\"\"'\n if (terms.length === 1) return `${terms[0]}*`\n return terms.join(' OR ')\n }\n}\n","/**\n * FTS5 Full-Text Search Service\n *\n * Provides BM25-ranked full-text search with:\n * - Porter stemming (running/runs/ran -> run)\n * - Diacritics/accent folding (cafe matches cafe)\n * - Field boosting (title 5x, slug 2x, body 1x)\n * - Highlighting with tags\n * - Snippet extraction around matches\n */\n\nimport type { D1Database } from '@cloudflare/workers-types'\nimport type { SearchQuery, SearchResult, SearchResponse, AISearchSettings } from '../types'\nimport { FacetService } from './facet.service'\nimport type { SynonymService } from './synonym.service'\n\nexport interface FTS5SearchOptions {\n titleBoost?: number // Default: 5.0\n slugBoost?: number // Default: 2.0\n bodyBoost?: number // Default: 1.0\n snippetLength?: number // Default: 15 tokens (~150 chars)\n highlightTag?: string // Default: 'mark'\n}\n\nexport interface FTS5SearchResult extends SearchResult {\n highlights?: {\n title?: string\n body?: string\n }\n bm25_score?: number\n}\n\nexport interface FTS5IndexResult {\n total_items: number\n indexed_items: number\n errors: number\n}\n\nexport class FTS5Service {\n private defaultOptions: FTS5SearchOptions = {\n titleBoost: 5.0,\n slugBoost: 2.0,\n bodyBoost: 1.0,\n snippetLength: 15, // ~15 tokens per snippet fragment\n highlightTag: 'mark'\n }\n\n private options: FTS5SearchOptions\n private synonymService?: SynonymService\n\n constructor(\n private db: D1Database,\n options: FTS5SearchOptions = {}\n ) {\n this.options = { ...this.defaultOptions, ...options }\n }\n\n /** Set synonym service for query expansion */\n setSynonymService(service: SynonymService): void {\n this.synonymService = service\n }\n\n /**\n * Search using FTS5 with BM25 ranking and highlighting\n * Auto-indexes any missing content in selected collections before searching\n */\n async search(\n query: SearchQuery,\n settings: AISearchSettings,\n weightOverrides?: { titleBoost?: number; slugBoost?: number; bodyBoost?: number }\n ): Promise {\n const startTime = Date.now()\n\n try {\n // Sanitize and prepare query for FTS5 MATCH\n let escapedQuery = this.sanitizeFTS5Query(query.query)\n\n if (!escapedQuery || escapedQuery === '\"\"') {\n return {\n results: [],\n total: 0,\n query_time_ms: Date.now() - startTime,\n mode: 'fts5' as any\n }\n }\n\n // Synonym expansion: expand terms using admin-defined synonym groups\n if (this.synonymService && settings.query_synonyms_enabled !== false) {\n escapedQuery = await this.expandWithSynonyms(escapedQuery)\n }\n\n // Build collection filter\n const collections = query.filters?.collections?.length\n ? query.filters.collections\n : settings.selected_collections\n\n if (collections.length === 0) {\n return {\n results: [],\n total: 0,\n query_time_ms: Date.now() - startTime,\n mode: 'fts5' as any\n }\n }\n\n // Auto-index any content not yet in the FTS5 index\n await this.ensureCollectionsIndexed(collections)\n\n const collectionPlaceholders = collections.map(() => '?').join(', ')\n const tag = this.options.highlightTag || 'mark'\n\n // Effective weights: overrides (from settings) > constructor options > defaults\n const titleBoost = weightOverrides?.titleBoost ?? this.options.titleBoost\n const slugBoost = weightOverrides?.slugBoost ?? this.options.slugBoost\n const bodyBoost = weightOverrides?.bodyBoost ?? this.options.bodyBoost\n\n // Build facet filter conditions (narrows results by active facet selections)\n let filterWhere = ''\n let filterParams: any[] = []\n if (query.filters?.custom && settings.facet_config?.length) {\n const { conditions, params: fParams } = FacetService.buildFacetFilterSQL(\n query.filters.custom,\n settings.facet_config\n )\n if (conditions.length > 0) {\n filterWhere = '\\n ' + conditions.map(c => `AND ${c}`).join('\\n ')\n filterParams = fParams\n }\n }\n\n // FTS5 query with BM25 ranking and field boosting\n // bm25 weights: title, slug, body, content_id(0), collection_id(0)\n const sql = `\n SELECT\n fts.content_id,\n fts.collection_id,\n fts.title,\n bm25(content_fts, ${titleBoost}, ${slugBoost}, ${bodyBoost}, 0, 0) as score,\n snippet(content_fts, 2, '<${tag}>', '${tag}>', '...', ${this.options.snippetLength}) as body_snippet,\n highlight(content_fts, 0, '<${tag}>', '${tag}>') as title_highlight,\n c.slug,\n c.status,\n c.created_at,\n c.updated_at,\n col.display_name as collection_name\n FROM content_fts fts\n JOIN content c ON fts.content_id = c.id\n JOIN collections col ON fts.collection_id = col.id\n WHERE content_fts MATCH ?\n AND fts.collection_id IN (${collectionPlaceholders})\n AND c.status != 'deleted'${filterWhere}\n ORDER BY score\n LIMIT ? OFFSET ?\n `\n\n const limit = query.limit || settings.results_limit || 20\n const offset = query.offset || 0\n\n const { results } = await this.db\n .prepare(sql)\n .bind(escapedQuery, ...collections, ...filterParams, limit, offset)\n .all<{\n content_id: string\n collection_id: string\n title: string\n score: number\n body_snippet: string\n title_highlight: string\n slug: string\n status: string\n created_at: number\n updated_at: number\n collection_name: string\n }>()\n\n // Get total count (separate query for efficiency)\n const countSql = `\n SELECT COUNT(*) as total\n FROM content_fts fts\n JOIN content c ON fts.content_id = c.id\n WHERE content_fts MATCH ?\n AND fts.collection_id IN (${collectionPlaceholders})\n AND c.status != 'deleted'${filterWhere}\n `\n const countResult = await this.db\n .prepare(countSql)\n .bind(escapedQuery, ...collections, ...filterParams)\n .first<{ total: number }>()\n\n // Map results with highlighting\n const searchResults: FTS5SearchResult[] = (results || []).map(row => ({\n id: row.content_id,\n title: row.title,\n slug: row.slug,\n collection_id: row.collection_id,\n collection_name: row.collection_name,\n snippet: row.body_snippet,\n status: row.status,\n created_at: row.created_at,\n updated_at: row.updated_at,\n highlights: {\n title: row.title_highlight,\n body: row.body_snippet\n },\n // BM25 returns negative scores (more negative = better match)\n // Convert to positive for display\n bm25_score: Math.abs(row.score),\n relevance_score: Math.abs(row.score)\n }))\n\n const queryTime = Date.now() - startTime\n console.log(`[FTS5Service] Search completed in ${queryTime}ms, ${searchResults.length} results`)\n\n return {\n results: searchResults,\n total: countResult?.total || 0,\n query_time_ms: queryTime,\n mode: 'fts5' as any\n }\n } catch (error) {\n console.error('[FTS5Service] Search error:', error)\n throw error\n }\n }\n\n /**\n * Index a single content item\n * Indexes all non-deleted content; removes deleted content from index\n */\n async indexContent(contentId: string): Promise {\n try {\n // Get content with collection info\n const content = await this.db\n .prepare(`\n SELECT c.id, c.collection_id, c.title, c.slug, c.data, c.status\n FROM content c\n WHERE c.id = ?\n `)\n .bind(contentId)\n .first<{\n id: string\n collection_id: string\n title: string\n slug: string\n data: string\n status: string\n }>()\n\n if (!content) {\n console.warn(`[FTS5Service] Content ${contentId} not found`)\n return\n }\n\n // Skip deleted content\n if (content.status === 'deleted') {\n await this.removeFromIndex(contentId)\n return\n }\n\n // Extract searchable text from JSON data\n const bodyText = this.extractSearchableText(content.data)\n\n // Atomic update: delete then insert (handles race conditions)\n await this.db.batch([\n this.db.prepare('DELETE FROM content_fts WHERE content_id = ?').bind(contentId),\n this.db.prepare(`\n INSERT INTO content_fts(title, slug, body, content_id, collection_id)\n VALUES (?, ?, ?, ?, ?)\n `).bind(\n content.title || '',\n content.slug || '',\n bodyText,\n content.id,\n content.collection_id\n ),\n this.db.prepare(`\n INSERT OR REPLACE INTO content_fts_sync(content_id, collection_id, indexed_at, status)\n VALUES (?, ?, ?, 'indexed')\n `).bind(contentId, content.collection_id, Date.now())\n ])\n\n // Per-item logging omitted for bulk performance\n } catch (error) {\n console.error(`[FTS5Service] Error indexing ${contentId}:`, error)\n throw error\n }\n }\n\n /**\n * Index all published content in a collection (bulk approach).\n * Fetches all content in one query, processes text in memory,\n * then inserts in D1 batches for efficiency.\n */\n async indexCollection(\n collectionId: string,\n onProgress?: (indexed: number, total: number) => Promise\n ): Promise {\n console.log(`[FTS5Service] Starting bulk indexing for collection: ${collectionId}`)\n\n try {\n // Fetch all content with data in one query\n const { results } = await this.db\n .prepare(`\n SELECT id, title, slug, data, collection_id\n FROM content\n WHERE collection_id = ? AND status != 'deleted'\n `)\n .bind(collectionId)\n .all<{ id: string; title: string; slug: string; data: string; collection_id: string }>()\n\n const totalItems = results?.length || 0\n\n if (totalItems === 0) {\n console.log(`[FTS5Service] No content found in collection ${collectionId}`)\n if (onProgress) await onProgress(0, 0)\n return { total_items: 0, indexed_items: 0, errors: 0 }\n }\n\n // Clear existing FTS5 + sync entries for this collection (clean slate)\n await this.db.batch([\n this.db.prepare('DELETE FROM content_fts WHERE collection_id = ?').bind(collectionId),\n this.db.prepare('DELETE FROM content_fts_sync WHERE collection_id = ?').bind(collectionId),\n ])\n\n let indexedItems = 0\n let errors = 0\n const now = Date.now()\n\n // Process in batches of 25 items (50 statements per batch: INSERT fts + INSERT sync)\n const BATCH_SIZE = 25\n for (let i = 0; i < totalItems; i += BATCH_SIZE) {\n const batch = results!.slice(i, i + BATCH_SIZE)\n const statements: any[] = []\n\n for (const item of batch) {\n try {\n const bodyText = this.extractSearchableText(item.data)\n statements.push(\n this.db.prepare(`\n INSERT INTO content_fts(title, slug, body, content_id, collection_id)\n VALUES (?, ?, ?, ?, ?)\n `).bind(item.title || '', item.slug || '', bodyText, item.id, item.collection_id)\n )\n statements.push(\n this.db.prepare(`\n INSERT OR REPLACE INTO content_fts_sync(content_id, collection_id, indexed_at, status)\n VALUES (?, ?, ?, 'indexed')\n `).bind(item.id, item.collection_id, now)\n )\n } catch (error) {\n errors++\n }\n }\n\n if (statements.length > 0) {\n try {\n await this.db.batch(statements)\n indexedItems += statements.length / 2 // 2 statements per item\n } catch (error) {\n console.error(`[FTS5Service] Batch insert error at offset ${i}:`, error)\n errors += batch.length\n }\n }\n\n // Report progress every batch\n if (onProgress) {\n await onProgress(indexedItems, totalItems)\n }\n }\n\n console.log(`[FTS5Service] Bulk indexing complete: ${indexedItems}/${totalItems} items, ${errors} errors`)\n\n return {\n total_items: totalItems,\n indexed_items: indexedItems,\n errors\n }\n } catch (error) {\n console.error(`[FTS5Service] Error indexing collection ${collectionId}:`, error)\n throw error\n }\n }\n\n /**\n * Index a batch of content items from a collection using batch D1 inserts.\n * Returns the number remaining so the caller can loop.\n */\n async indexCollectionBatch(\n collectionId: string,\n batchSize: number = 200\n ): Promise<{ indexed: number; remaining: number; total: number }> {\n // Find un-indexed content with data for FTS5 extraction\n const { results } = await this.db\n .prepare(`\n SELECT c.id, c.title, c.slug, c.data, c.collection_id\n FROM content c\n LEFT JOIN content_fts_sync s ON c.id = s.content_id\n WHERE c.collection_id = ? AND c.status != 'deleted'\n AND s.content_id IS NULL\n LIMIT ?\n `)\n .bind(collectionId, batchSize)\n .all<{ id: string; title: string; slug: string; data: string; collection_id: string }>()\n\n const toIndex = results || []\n const now = Date.now()\n let indexed = 0\n\n // Process in sub-batches of 25 (50 D1 statements: FTS5 INSERT + sync INSERT)\n const SUB_BATCH = 25\n for (let i = 0; i < toIndex.length; i += SUB_BATCH) {\n const batch = toIndex.slice(i, i + SUB_BATCH)\n const statements: any[] = []\n\n for (const item of batch) {\n try {\n const bodyText = this.extractSearchableText(item.data)\n statements.push(\n this.db.prepare(\n 'INSERT INTO content_fts(title, slug, body, content_id, collection_id) VALUES (?, ?, ?, ?, ?)'\n ).bind(item.title || '', item.slug || '', bodyText, item.id, item.collection_id)\n )\n statements.push(\n this.db.prepare(\n \"INSERT OR REPLACE INTO content_fts_sync(content_id, collection_id, indexed_at, status) VALUES (?, ?, ?, 'indexed')\"\n ).bind(item.id, item.collection_id, now)\n )\n } catch (error) {\n // Skip items with extraction errors\n }\n }\n\n if (statements.length > 0) {\n try {\n await this.db.batch(statements)\n indexed += statements.length / 2\n } catch (error) {\n console.error(`[FTS5Service] Batch insert error at offset ${i}:`, error)\n }\n }\n }\n\n // Count remaining\n const remainResult = await this.db\n .prepare(`\n SELECT COUNT(*) as cnt FROM content c\n LEFT JOIN content_fts_sync s ON c.id = s.content_id\n WHERE c.collection_id = ? AND c.status != 'deleted'\n AND s.content_id IS NULL\n `)\n .bind(collectionId)\n .first<{ cnt: number }>()\n\n const totalResult = await this.db\n .prepare(\"SELECT COUNT(*) as cnt FROM content WHERE collection_id = ? AND status != 'deleted'\")\n .bind(collectionId)\n .first<{ cnt: number }>()\n\n return {\n indexed,\n remaining: remainResult?.cnt || 0,\n total: totalResult?.cnt || 0,\n }\n }\n\n /**\n * Remove content from FTS index\n */\n async removeFromIndex(contentId: string): Promise {\n try {\n await this.db.batch([\n this.db.prepare('DELETE FROM content_fts WHERE content_id = ?').bind(contentId),\n this.db.prepare('DELETE FROM content_fts_sync WHERE content_id = ?').bind(contentId)\n ])\n console.log(`[FTS5Service] Removed content ${contentId} from index`)\n } catch (error) {\n console.error(`[FTS5Service] Error removing ${contentId}:`, error)\n throw error\n }\n }\n\n /**\n * Process pending sync items (for deferred/batch indexing)\n */\n async processPendingSync(batchSize: number = 100): Promise {\n const { results } = await this.db\n .prepare(`\n SELECT content_id FROM content_fts_sync\n WHERE status = 'pending'\n LIMIT ?\n `)\n .bind(batchSize)\n .all<{ content_id: string }>()\n\n let processed = 0\n for (const item of results || []) {\n try {\n await this.indexContent(item.content_id)\n processed++\n } catch (error) {\n console.error(`[FTS5Service] Error processing pending item ${item.content_id}:`, error)\n }\n }\n\n return processed\n }\n\n /**\n * Get FTS5 index statistics\n */\n async getStats(): Promise<{\n total_indexed: number\n by_collection: Record\n }> {\n try {\n const totalResult = await this.db\n .prepare('SELECT COUNT(*) as count FROM content_fts')\n .first<{ count: number }>()\n\n const { results: collectionCounts } = await this.db\n .prepare(`\n SELECT collection_id, COUNT(*) as count\n FROM content_fts\n GROUP BY collection_id\n `)\n .all<{ collection_id: string; count: number }>()\n\n const byCollection: Record = {}\n for (const row of collectionCounts || []) {\n byCollection[row.collection_id] = row.count\n }\n\n return {\n total_indexed: totalResult?.count || 0,\n by_collection: byCollection\n }\n } catch (error) {\n console.error('[FTS5Service] Error getting stats:', error)\n return { total_indexed: 0, by_collection: {} }\n }\n }\n\n /**\n * Check if FTS5 table is available\n */\n async isAvailable(): Promise {\n try {\n await this.db.prepare('SELECT * FROM content_fts LIMIT 0').run()\n return true\n } catch {\n return false\n }\n }\n\n /**\n * Auto-index content in selected collections that isn't yet in the FTS5 index.\n * This makes FTS5 self-healing - existing content that predates the FTS5 feature\n * gets indexed on first search, so results match keyword search coverage.\n */\n private async ensureCollectionsIndexed(collections: string[]): Promise {\n try {\n const collectionPlaceholders = collections.map(() => '?').join(', ')\n\n // Find content in selected collections that's not yet indexed\n const { results } = await this.db\n .prepare(`\n SELECT c.id FROM content c\n LEFT JOIN content_fts_sync s ON c.id = s.content_id\n WHERE c.collection_id IN (${collectionPlaceholders})\n AND c.status != 'deleted'\n AND s.content_id IS NULL\n LIMIT 200\n `)\n .bind(...collections)\n .all<{ id: string }>()\n\n if (!results || results.length === 0) {\n return\n }\n\n console.log(`[FTS5Service] Auto-indexing ${results.length} unindexed items`)\n\n let indexed = 0\n for (const item of results) {\n try {\n await this.indexContent(item.id)\n indexed++\n } catch (error) {\n console.error(`[FTS5Service] Error auto-indexing ${item.id}:`, error)\n }\n }\n\n console.log(`[FTS5Service] Auto-indexed ${indexed}/${results.length} items`)\n } catch (error) {\n // Don't fail the search if auto-indexing fails\n console.error('[FTS5Service] Error during auto-indexing:', error)\n }\n }\n\n /**\n * Extract searchable text from JSON content data\n * Reuses logic pattern from ChunkingService\n */\n private extractSearchableText(data: string): string {\n try {\n const parsed = typeof data === 'string' ? JSON.parse(data) : data\n const parts: string[] = []\n\n // Common text fields (in priority order)\n if (parsed.description) parts.push(String(parsed.description))\n if (parsed.content) parts.push(String(parsed.content))\n if (parsed.body) parts.push(String(parsed.body))\n if (parsed.text) parts.push(String(parsed.text))\n if (parsed.summary) parts.push(String(parsed.summary))\n if (parsed.excerpt) parts.push(String(parsed.excerpt))\n\n // Recursively extract from nested objects\n const extractRecursive = (obj: any, depth: number = 0): void => {\n // Limit recursion depth to avoid deep nesting issues\n if (depth > 5) return\n\n if (typeof obj === 'string') {\n // Skip very short strings, URLs, and likely IDs\n if (obj.length > 20 && !obj.startsWith('http') && !obj.match(/^[a-f0-9-]{36}$/i)) {\n parts.push(obj)\n }\n } else if (Array.isArray(obj)) {\n obj.forEach(item => extractRecursive(item, depth + 1))\n } else if (obj && typeof obj === 'object') {\n // Skip certain keys that don't contain searchable content\n const skipKeys = new Set([\n 'id', '_id', 'slug', 'url', 'href', 'src',\n 'image', 'thumbnail', 'avatar', 'icon', 'logo',\n 'metadata', 'meta', 'created_at', 'updated_at',\n 'author_id', 'collection_id', 'parent_id'\n ])\n\n Object.entries(obj).forEach(([key, value]) => {\n if (!skipKeys.has(key.toLowerCase())) {\n extractRecursive(value, depth + 1)\n }\n })\n }\n }\n\n extractRecursive(parsed)\n\n // Join with spaces, deduplicate, and trim\n const combined = parts.join(' ').trim()\n\n // Remove excessive whitespace\n return combined.replace(/\\s+/g, ' ')\n } catch (error) {\n console.error('[FTS5Service] Error extracting text:', error)\n return ''\n }\n }\n\n /**\n * Expand a sanitized FTS5 query string with synonym terms.\n * Input: \"coffee*\" (single) or \"coffee OR beans\" (multiple)\n * Output: \"coffee* OR espresso OR caffeine\" or \"coffee OR espresso OR beans\"\n */\n private async expandWithSynonyms(sanitizedQuery: string): Promise {\n try {\n let terms: string[]\n let hasPrefixMatch = false\n\n if (sanitizedQuery.endsWith('*')) {\n terms = [sanitizedQuery.slice(0, -1)]\n hasPrefixMatch = true\n } else {\n terms = sanitizedQuery.split(' OR ').map(t => t.trim()).filter(Boolean)\n }\n\n if (terms.length === 0) return sanitizedQuery\n\n const expanded = await this.synonymService!.expandQuery(terms)\n\n // No new terms added\n if (expanded.length === terms.length) return sanitizedQuery\n\n // Cap at 20 terms for safety\n const capped = expanded.slice(0, 20)\n\n if (hasPrefixMatch && terms.length === 1) {\n // Keep prefix on original term, synonyms are exact\n const original = terms[0] + '*'\n const synonyms = capped.filter(t => t !== terms[0])\n return [original, ...synonyms].join(' OR ')\n }\n\n return capped.join(' OR ')\n } catch (error) {\n console.error('[FTS5Service] Synonym expansion error (using original query):', error)\n return sanitizedQuery\n }\n }\n\n /**\n * Sanitize user input for FTS5 MATCH clause\n * Removes operators and special characters that could cause errors\n */\n private sanitizeFTS5Query(query: string): string {\n if (!query || typeof query !== 'string') {\n return '\"\"'\n }\n\n // Step 1: Strip everything except letters, numbers, spaces, and hyphens\n let sanitized = query\n .replace(/-/g, ' ') // Convert hyphens to spaces first\n .replace(/[^a-zA-Z0-9\\s]/g, '') // Strip all punctuation/special chars\n .replace(/\\s+/g, ' ') // Collapse whitespace\n .trim()\n .toLowerCase()\n\n // Step 2: Split into terms, filter short/stop words\n const stopWords = new Set(['a', 'an', 'the', 'is', 'are', 'was', 'were', 'be',\n 'to', 'of', 'in', 'on', 'at', 'by', 'or', 'and', 'not', 'for', 'it',\n 'as', 'do', 'if', 'no', 'so', 'up', 'but', 'its', 'has', 'had', 'near'])\n const terms = sanitized\n .split(/\\s+/)\n .filter(t => t.length > 1 && !stopWords.has(t))\n\n if (terms.length === 0) {\n return '\"\"'\n }\n\n // Single term: use prefix matching for autocomplete-like behavior\n if (terms.length === 1) {\n return `${terms[0]}*`\n }\n\n // Multiple terms: unquoted with OR for proper BM25 ranking\n // Unquoted terms enable porter stemming (runningārun, propertiesāproperty)\n // OR means any matching term contributes to BM25 score ā more matches rank higher\n return terms.join(' OR ')\n }\n}\n","/**\n * Search Result Cache Service\n *\n * KV-backed caching for search results. Wraps Cloudflare KV get/put with\n * SHA-256 key hashing. Returns cached results on hit, stores on miss.\n * Content CRUD hooks call invalidateAll() to clear stale entries.\n */\n\nimport type { SearchQuery, SearchResponse } from '../types'\n\nexport class SearchCacheService {\n private static readonly PREFIX = 'search-cache:v1:'\n\n constructor(private kv: any) {} // KVNamespace\n\n /**\n * Build a deterministic cache key from post-rule query params.\n * Returns null if caching should be skipped.\n */\n async buildKey(query: SearchQuery): Promise {\n if (query.cache === false || !query.query?.trim()) {\n return null\n }\n\n const canonical = JSON.stringify({\n q: query.query.toLowerCase().trim(),\n m: query.mode,\n l: query.limit ?? null,\n o: query.offset ?? null,\n f: this.normalizeFilters(query.filters),\n fct: query.facets ?? false,\n })\n\n const hash = await crypto.subtle.digest(\n 'SHA-256',\n new TextEncoder().encode(canonical)\n )\n const hex = Array.from(new Uint8Array(hash))\n .map((b) => b.toString(16).padStart(2, '0'))\n .join('')\n\n return `${SearchCacheService.PREFIX}${hex.slice(0, 16)}`\n }\n\n /**\n * Get cached search response. Returns null on miss or error.\n */\n async get(key: string): Promise {\n try {\n return await this.kv.get(key, 'json')\n } catch (error) {\n console.warn('[SearchCache] Get error:', error)\n return null\n }\n }\n\n /**\n * Store search response in cache. Fire-and-forget ā never blocks the response.\n * Strips search_id before caching (must be fresh per search for click tracking).\n */\n async put(key: string, response: SearchResponse, ttlSeconds: number): Promise {\n try {\n const toCache = { ...response }\n delete toCache.search_id // Must be unique per search for click tracking\n delete toCache.cached // Don't store the cached flag itself\n\n // KV minimum TTL is 60 seconds\n const ttl = Math.max(60, ttlSeconds)\n await this.kv.put(key, JSON.stringify(toCache), { expirationTtl: ttl })\n } catch (error) {\n console.warn('[SearchCache] Put error:', error)\n }\n }\n\n /**\n * Invalidate all cached search results by listing and deleting keys with our prefix.\n * Returns the number of keys deleted.\n */\n async invalidateAll(): Promise {\n let deleted = 0\n let cursor: string | undefined\n\n try {\n do {\n const listOptions: any = { prefix: SearchCacheService.PREFIX, limit: 1000 }\n if (cursor) listOptions.cursor = cursor\n\n const list = await this.kv.list(listOptions)\n const keys = list.keys || []\n\n for (const key of keys) {\n await this.kv.delete(key.name)\n deleted++\n }\n\n cursor = list.list_complete ? undefined : list.cursor\n } while (cursor)\n } catch (error) {\n console.warn('[SearchCache] Invalidation error:', error)\n }\n\n if (deleted > 0) {\n console.log(`[SearchCache] Invalidated ${deleted} cached entries`)\n }\n return deleted\n }\n\n /**\n * Normalize filters for deterministic hashing.\n * Sorts collections, status, and custom keys/values.\n */\n private normalizeFilters(filters?: SearchQuery['filters']): any {\n if (!filters) return null\n\n const normalized: any = {}\n\n if (filters.collections?.length) {\n normalized.collections = [...filters.collections].sort()\n }\n if (filters.status?.length) {\n normalized.status = [...filters.status].sort()\n }\n if (filters.tags?.length) {\n normalized.tags = [...filters.tags].sort()\n }\n if (filters.author) {\n normalized.author = filters.author\n }\n if (filters.dateRange) {\n normalized.dateRange = filters.dateRange\n }\n if (filters.custom && Object.keys(filters.custom).length > 0) {\n const sortedCustom: Record = {}\n for (const key of Object.keys(filters.custom).sort()) {\n const val = filters.custom[key]\n sortedCustom[key] = Array.isArray(val) ? [...val].sort() : val\n }\n normalized.custom = sortedCustom\n }\n\n return Object.keys(normalized).length > 0 ? normalized : null\n }\n}\n","import { Hono } from 'hono'\nimport { requireAuth } from '../middleware'\nimport { getCacheService, CACHE_CONFIGS } from '../services'\nimport type { Bindings, Variables } from '../app'\nimport { FTS5Service } from '../plugins/core-plugins/ai-search-plugin/services/fts5.service'\nimport { SearchCacheService } from '../plugins/core-plugins/ai-search-plugin/services/search-cache.service'\n\nconst apiContentCrudRoutes = new Hono<{ Bindings: Bindings; Variables: Variables }>()\n\n// GET /api/content/check-slug - Check if slug is available in collection\n// Query params: collectionId, slug, excludeId (optional - when editing)\n// NOTE: This MUST come before /:id route to avoid route conflict\napiContentCrudRoutes.get('/check-slug', async (c) => {\n try {\n const db = c.env.DB\n const collectionId = c.req.query('collectionId')\n const slug = c.req.query('slug')\n const excludeId = c.req.query('excludeId') // When editing, exclude current item\n \n if (!collectionId || !slug) {\n return c.json({ error: 'collectionId and slug are required' }, 400)\n }\n \n // Check for existing content with this slug in the collection\n let query = 'SELECT id FROM content WHERE collection_id = ? AND slug = ?'\n const params: string[] = [collectionId, slug]\n \n if (excludeId) {\n query += ' AND id != ?'\n params.push(excludeId)\n }\n \n const existing = await db.prepare(query).bind(...params).first()\n \n if (existing) {\n return c.json({ \n available: false, \n message: 'This URL slug is already in use in this collection' \n })\n }\n \n return c.json({ available: true })\n } catch (error: unknown) {\n console.error('Error checking slug:', error)\n return c.json({ \n error: 'Failed to check slug availability',\n details: error instanceof Error ? error.message : String(error)\n }, 500)\n }\n})\n\n// GET /api/content/:id - Get single content item by ID\napiContentCrudRoutes.get('/:id', async (c) => {\n try {\n const id = c.req.param('id')\n const db = c.env.DB\n\n const stmt = db.prepare('SELECT * FROM content WHERE id = ?')\n const content = await stmt.bind(id).first()\n\n if (!content) {\n return c.json({ error: 'Content not found' }, 404)\n }\n\n const transformedContent = {\n id: (content as any).id,\n title: (content as any).title,\n slug: (content as any).slug,\n status: (content as any).status,\n collectionId: (content as any).collection_id,\n data: (content as any).data ? JSON.parse((content as any).data) : {},\n created_at: (content as any).created_at,\n updated_at: (content as any).updated_at\n }\n\n return c.json({ data: transformedContent })\n } catch (error) {\n console.error('Error fetching content:', error)\n return c.json({\n error: 'Failed to fetch content',\n details: error instanceof Error ? error.message : String(error)\n }, 500)\n }\n})\n\n// POST /api/content - Create new content (requires authentication)\napiContentCrudRoutes.post('/', requireAuth(), async (c) => {\n try {\n const db = c.env.DB\n const user = c.get('user')\n const body = await c.req.json()\n\n const { collectionId, title, slug, status, data } = body\n\n // Validate required fields\n if (!collectionId) {\n return c.json({ error: 'collectionId is required' }, 400)\n }\n\n if (!title) {\n return c.json({ error: 'title is required' }, 400)\n }\n\n // Generate slug from title if not provided\n let finalSlug = slug || title\n finalSlug = finalSlug.toLowerCase()\n .replace(/[^a-z0-9\\s-]/g, '')\n .replace(/\\s+/g, '-')\n .replace(/-+/g, '-')\n .trim()\n\n // Check for duplicate slug within the same collection\n const duplicateCheck = db.prepare(\n 'SELECT id FROM content WHERE collection_id = ? AND slug = ?'\n )\n const existing = await duplicateCheck.bind(collectionId, finalSlug).first()\n\n if (existing) {\n return c.json({ error: 'A content item with this slug already exists in this collection' }, 409)\n }\n\n // Create new content\n const contentId = crypto.randomUUID()\n const now = Date.now()\n\n const insertStmt = db.prepare(`\n INSERT INTO content (\n id, collection_id, slug, title, data, status,\n author_id, created_at, updated_at\n )\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)\n `)\n\n await insertStmt.bind(\n contentId,\n collectionId,\n finalSlug,\n title,\n JSON.stringify(data || {}),\n status || 'draft',\n user?.userId || 'system',\n now,\n now\n ).run()\n\n // Invalidate cache\n const cache = getCacheService(CACHE_CONFIGS.api!)\n await cache.invalidate(`content:list:${collectionId}:*`)\n await cache.invalidate('content-filtered:*')\n\n // Sync to FTS5 index (non-blocking)\n const fts5Service = new FTS5Service(db)\n c.executionCtx.waitUntil(\n fts5Service.indexContent(contentId).catch(err =>\n console.error('[API Content] FTS5 indexing failed:', err)\n )\n )\n\n // Invalidate search result cache (non-blocking)\n if (c.env.CACHE_KV) {\n const searchCache = new SearchCacheService(c.env.CACHE_KV)\n c.executionCtx.waitUntil(searchCache.invalidateAll())\n }\n\n // Get the created content\n const getStmt = db.prepare('SELECT * FROM content WHERE id = ?')\n const createdContent = await getStmt.bind(contentId).first() as any\n\n return c.json({\n data: {\n id: createdContent.id,\n title: createdContent.title,\n slug: createdContent.slug,\n status: createdContent.status,\n collectionId: createdContent.collection_id,\n data: createdContent.data ? JSON.parse(createdContent.data) : {},\n created_at: createdContent.created_at,\n updated_at: createdContent.updated_at\n }\n }, 201)\n } catch (error) {\n console.error('Error creating content:', error)\n return c.json({\n error: 'Failed to create content',\n details: error instanceof Error ? error.message : String(error)\n }, 500)\n }\n})\n\n// PUT /api/content/:id - Update content (requires authentication)\napiContentCrudRoutes.put('/:id', requireAuth(), async (c) => {\n try {\n const id = c.req.param('id')\n const db = c.env.DB\n const body = await c.req.json()\n\n // Check if content exists\n const existingStmt = db.prepare('SELECT * FROM content WHERE id = ?')\n const existing = await existingStmt.bind(id).first() as any\n\n if (!existing) {\n return c.json({ error: 'Content not found' }, 404)\n }\n\n // Build update fields dynamically\n const updates: string[] = []\n const params: any[] = []\n\n if (body.title !== undefined) {\n updates.push('title = ?')\n params.push(body.title)\n }\n\n if (body.slug !== undefined) {\n let finalSlug = body.slug.toLowerCase()\n .replace(/[^a-z0-9\\s-]/g, '')\n .replace(/\\s+/g, '-')\n .replace(/-+/g, '-')\n .trim()\n updates.push('slug = ?')\n params.push(finalSlug)\n }\n\n if (body.status !== undefined) {\n updates.push('status = ?')\n params.push(body.status)\n }\n\n if (body.data !== undefined) {\n updates.push('data = ?')\n params.push(JSON.stringify(body.data))\n }\n\n // Always update updated_at\n const now = Date.now()\n updates.push('updated_at = ?')\n params.push(now)\n\n // Add id to params for WHERE clause\n params.push(id)\n\n // Execute update\n const updateStmt = db.prepare(`\n UPDATE content SET ${updates.join(', ')}\n WHERE id = ?\n `)\n\n await updateStmt.bind(...params).run()\n\n // Invalidate cache\n const cache = getCacheService(CACHE_CONFIGS.api!)\n await cache.delete(cache.generateKey('content', id))\n await cache.invalidate(`content:list:${existing.collection_id}:*`)\n await cache.invalidate('content-filtered:*')\n\n // Sync to FTS5 index (non-blocking)\n const fts5Service = new FTS5Service(db)\n c.executionCtx.waitUntil(\n fts5Service.indexContent(id).catch(err =>\n console.error('[API Content] FTS5 reindexing failed:', err)\n )\n )\n\n // Invalidate search result cache (non-blocking)\n if (c.env.CACHE_KV) {\n const searchCache = new SearchCacheService(c.env.CACHE_KV)\n c.executionCtx.waitUntil(searchCache.invalidateAll())\n }\n\n // Get updated content\n const getStmt = db.prepare('SELECT * FROM content WHERE id = ?')\n const updatedContent = await getStmt.bind(id).first() as any\n\n return c.json({\n data: {\n id: updatedContent.id,\n title: updatedContent.title,\n slug: updatedContent.slug,\n status: updatedContent.status,\n collectionId: updatedContent.collection_id,\n data: updatedContent.data ? JSON.parse(updatedContent.data) : {},\n created_at: updatedContent.created_at,\n updated_at: updatedContent.updated_at\n }\n })\n } catch (error) {\n console.error('Error updating content:', error)\n return c.json({\n error: 'Failed to update content',\n details: error instanceof Error ? error.message : String(error)\n }, 500)\n }\n})\n\n// DELETE /api/content/:id - Delete content (requires authentication)\napiContentCrudRoutes.delete('/:id', requireAuth(), async (c) => {\n try {\n const id = c.req.param('id')\n const db = c.env.DB\n\n // Check if content exists\n const existingStmt = db.prepare('SELECT collection_id FROM content WHERE id = ?')\n const existing = await existingStmt.bind(id).first() as any\n\n if (!existing) {\n return c.json({ error: 'Content not found' }, 404)\n }\n\n // Delete the content (hard delete for API, soft delete happens in admin routes)\n const deleteStmt = db.prepare('DELETE FROM content WHERE id = ?')\n await deleteStmt.bind(id).run()\n\n // Invalidate cache\n const cache = getCacheService(CACHE_CONFIGS.api!)\n await cache.delete(cache.generateKey('content', id))\n await cache.invalidate(`content:list:${existing.collection_id}:*`)\n await cache.invalidate('content-filtered:*')\n\n // Remove from FTS5 index (non-blocking)\n const fts5Service = new FTS5Service(db)\n c.executionCtx.waitUntil(\n fts5Service.removeFromIndex(id).catch(err =>\n console.error('[API Content] FTS5 removal failed:', err)\n )\n )\n\n // Invalidate search result cache (non-blocking)\n if (c.env.CACHE_KV) {\n const searchCache = new SearchCacheService(c.env.CACHE_KV)\n c.executionCtx.waitUntil(searchCache.invalidateAll())\n }\n\n return c.json({ success: true })\n } catch (error) {\n console.error('Error deleting content:', error)\n return c.json({\n error: 'Failed to delete content',\n details: error instanceof Error ? error.message : String(error)\n }, 500)\n }\n})\n\nexport default apiContentCrudRoutes\n","import { Hono } from 'hono'\nimport { cors } from 'hono/cors'\nimport { schemaDefinitions } from '../schemas'\nimport { getCacheService, CACHE_CONFIGS } from '../services'\nimport { QueryFilterBuilder, QueryFilter } from '../utils'\nimport { isPluginActive } from '../middleware'\nimport apiContentCrudRoutes from './api-content-crud'\nimport type { Bindings, Variables as AppVariables } from '../app'\n\n// Extend Variables with API-specific fields\ninterface Variables extends AppVariables {\n startTime: number\n cacheEnabled?: boolean\n}\n\nconst apiRoutes = new Hono<{ Bindings: Bindings; Variables: Variables }>()\n\n// Add timing middleware\napiRoutes.use('*', async (c, next) => {\n const startTime = Date.now()\n c.set('startTime', startTime)\n await next()\n const totalTime = Date.now() - startTime\n c.header('X-Response-Time', `${totalTime}ms`)\n})\n\n// Check if cache plugin is active\napiRoutes.use('*', async (c, next) => {\n const cacheEnabled = await isPluginActive(c.env.DB, 'core-cache')\n c.set('cacheEnabled', cacheEnabled)\n await next()\n})\n\n// Add CORS middleware\napiRoutes.use('*', cors({\n origin: '*',\n allowMethods: ['GET', 'POST', 'PUT', 'DELETE', 'OPTIONS'],\n allowHeaders: ['Content-Type', 'Authorization']\n}))\n\n// Helper function to add timing metadata\nfunction addTimingMeta(c: any, meta: any = {}, executionStartTime?: number) {\n const totalTime = Date.now() - c.get('startTime')\n const executionTime = executionStartTime ? Date.now() - executionStartTime : undefined\n\n return {\n ...meta,\n timing: {\n total: totalTime,\n execution: executionTime,\n unit: 'ms'\n }\n }\n}\n\n// Root endpoint - OpenAPI 3.0.0 specification\napiRoutes.get('/', (c) => {\n const baseUrl = new URL(c.req.url)\n const serverUrl = `${baseUrl.protocol}//${baseUrl.host}`\n\n return c.json({\n openapi: '3.0.0',\n info: {\n title: 'SonicJS AI API',\n version: '0.1.0',\n description: 'RESTful API for SonicJS headless CMS - a modern, AI-powered content management system built on Cloudflare Workers',\n contact: {\n name: 'SonicJS Support',\n url: `${serverUrl}/docs`,\n email: 'support@sonicjs.com'\n },\n license: {\n name: 'MIT',\n url: 'https://opensource.org/licenses/MIT'\n }\n },\n servers: [\n {\n url: serverUrl,\n description: 'Current server'\n }\n ],\n paths: {\n '/api/': {\n get: {\n summary: 'API Information',\n description: 'Returns OpenAPI specification for the SonicJS API',\n operationId: 'getApiInfo',\n tags: ['System'],\n responses: {\n '200': {\n description: 'OpenAPI specification',\n content: {\n 'application/json': {\n schema: { type: 'object' }\n }\n }\n }\n }\n }\n },\n '/api/health': {\n get: {\n summary: 'Health Check',\n description: 'Returns API health status and available schemas',\n operationId: 'getHealth',\n tags: ['System'],\n responses: {\n '200': {\n description: 'Health status',\n content: {\n 'application/json': {\n schema: {\n type: 'object',\n properties: {\n status: { type: 'string', example: 'healthy' },\n timestamp: { type: 'string', format: 'date-time' },\n schemas: { type: 'array', items: { type: 'string' } }\n }\n }\n }\n }\n }\n }\n }\n },\n '/api/collections': {\n get: {\n summary: 'List Collections',\n description: 'Returns all active collections with their schemas',\n operationId: 'getCollections',\n tags: ['Content'],\n responses: {\n '200': {\n description: 'List of collections',\n content: {\n 'application/json': {\n schema: {\n type: 'object',\n properties: {\n data: {\n type: 'array',\n items: {\n type: 'object',\n properties: {\n id: { type: 'string' },\n name: { type: 'string' },\n display_name: { type: 'string' },\n schema: { type: 'object' },\n is_active: { type: 'integer' }\n }\n }\n },\n meta: { type: 'object' }\n }\n }\n }\n }\n }\n }\n }\n },\n '/api/collections/{collection}/content': {\n get: {\n summary: 'Get Collection Content',\n description: 'Returns content items from a specific collection with filtering support',\n operationId: 'getCollectionContent',\n tags: ['Content'],\n parameters: [\n {\n name: 'collection',\n in: 'path',\n required: true,\n schema: { type: 'string' },\n description: 'Collection name'\n },\n {\n name: 'limit',\n in: 'query',\n schema: { type: 'integer', default: 50, maximum: 1000 },\n description: 'Maximum number of items to return'\n },\n {\n name: 'offset',\n in: 'query',\n schema: { type: 'integer', default: 0 },\n description: 'Number of items to skip'\n },\n {\n name: 'status',\n in: 'query',\n schema: { type: 'string', enum: ['draft', 'published', 'archived'] },\n description: 'Filter by content status'\n }\n ],\n responses: {\n '200': {\n description: 'List of content items',\n content: {\n 'application/json': {\n schema: {\n type: 'object',\n properties: {\n data: { type: 'array', items: { type: 'object' } },\n meta: { type: 'object' }\n }\n }\n }\n }\n },\n '404': {\n description: 'Collection not found'\n }\n }\n }\n },\n '/api/content': {\n get: {\n summary: 'List Content',\n description: 'Returns content items with advanced filtering support',\n operationId: 'getContent',\n tags: ['Content'],\n parameters: [\n {\n name: 'collection',\n in: 'query',\n schema: { type: 'string' },\n description: 'Filter by collection name'\n },\n {\n name: 'limit',\n in: 'query',\n schema: { type: 'integer', default: 50, maximum: 1000 },\n description: 'Maximum number of items to return'\n },\n {\n name: 'offset',\n in: 'query',\n schema: { type: 'integer', default: 0 },\n description: 'Number of items to skip'\n }\n ],\n responses: {\n '200': {\n description: 'List of content items',\n content: {\n 'application/json': {\n schema: {\n type: 'object',\n properties: {\n data: { type: 'array', items: { type: 'object' } },\n meta: { type: 'object' }\n }\n }\n }\n }\n }\n }\n },\n post: {\n summary: 'Create Content',\n description: 'Creates a new content item',\n operationId: 'createContent',\n tags: ['Content'],\n security: [{ bearerAuth: [] }],\n requestBody: {\n required: true,\n content: {\n 'application/json': {\n schema: {\n type: 'object',\n required: ['collection_id', 'title'],\n properties: {\n collection_id: { type: 'string' },\n title: { type: 'string' },\n slug: { type: 'string' },\n status: { type: 'string', enum: ['draft', 'published', 'archived'] },\n data: { type: 'object' }\n }\n }\n }\n }\n },\n responses: {\n '201': { description: 'Content created successfully' },\n '400': { description: 'Invalid request body' },\n '401': { description: 'Unauthorized' }\n }\n }\n },\n '/api/content/{id}': {\n get: {\n summary: 'Get Content by ID',\n description: 'Returns a specific content item by ID',\n operationId: 'getContentById',\n tags: ['Content'],\n parameters: [\n {\n name: 'id',\n in: 'path',\n required: true,\n schema: { type: 'string' },\n description: 'Content item ID'\n }\n ],\n responses: {\n '200': { description: 'Content item' },\n '404': { description: 'Content not found' }\n }\n },\n put: {\n summary: 'Update Content',\n description: 'Updates an existing content item',\n operationId: 'updateContent',\n tags: ['Content'],\n security: [{ bearerAuth: [] }],\n parameters: [\n {\n name: 'id',\n in: 'path',\n required: true,\n schema: { type: 'string' },\n description: 'Content item ID'\n }\n ],\n responses: {\n '200': { description: 'Content updated successfully' },\n '401': { description: 'Unauthorized' },\n '404': { description: 'Content not found' }\n }\n },\n delete: {\n summary: 'Delete Content',\n description: 'Deletes a content item',\n operationId: 'deleteContent',\n tags: ['Content'],\n security: [{ bearerAuth: [] }],\n parameters: [\n {\n name: 'id',\n in: 'path',\n required: true,\n schema: { type: 'string' },\n description: 'Content item ID'\n }\n ],\n responses: {\n '200': { description: 'Content deleted successfully' },\n '401': { description: 'Unauthorized' },\n '404': { description: 'Content not found' }\n }\n }\n },\n '/api/media': {\n get: {\n summary: 'List Media',\n description: 'Returns all media files with pagination',\n operationId: 'getMedia',\n tags: ['Media'],\n responses: {\n '200': { description: 'List of media files' }\n }\n }\n },\n '/api/media/upload': {\n post: {\n summary: 'Upload Media',\n description: 'Uploads a new media file to R2 storage',\n operationId: 'uploadMedia',\n tags: ['Media'],\n security: [{ bearerAuth: [] }],\n requestBody: {\n required: true,\n content: {\n 'multipart/form-data': {\n schema: {\n type: 'object',\n properties: {\n file: { type: 'string', format: 'binary' }\n }\n }\n }\n }\n },\n responses: {\n '201': { description: 'Media uploaded successfully' },\n '401': { description: 'Unauthorized' }\n }\n }\n }\n },\n components: {\n securitySchemes: {\n bearerAuth: {\n type: 'http',\n scheme: 'bearer',\n bearerFormat: 'JWT'\n }\n },\n schemas: {\n Content: {\n type: 'object',\n properties: {\n id: { type: 'string', format: 'uuid' },\n title: { type: 'string' },\n slug: { type: 'string' },\n status: { type: 'string', enum: ['draft', 'published', 'archived'] },\n collectionId: { type: 'string', format: 'uuid' },\n data: { type: 'object' },\n created_at: { type: 'integer' },\n updated_at: { type: 'integer' }\n }\n },\n Collection: {\n type: 'object',\n properties: {\n id: { type: 'string', format: 'uuid' },\n name: { type: 'string' },\n display_name: { type: 'string' },\n description: { type: 'string' },\n schema: { type: 'object' },\n is_active: { type: 'integer' }\n }\n },\n Media: {\n type: 'object',\n properties: {\n id: { type: 'string', format: 'uuid' },\n filename: { type: 'string' },\n mimetype: { type: 'string' },\n size: { type: 'integer' },\n url: { type: 'string' }\n }\n },\n Error: {\n type: 'object',\n properties: {\n error: { type: 'string' },\n details: { type: 'string' }\n }\n }\n }\n },\n tags: [\n { name: 'System', description: 'System and health endpoints' },\n { name: 'Content', description: 'Content management operations' },\n { name: 'Media', description: 'Media file operations' }\n ]\n })\n})\n\n// Health check endpoint\napiRoutes.get('/health', (c) => {\n return c.json({\n status: 'healthy',\n timestamp: new Date().toISOString(),\n schemas: schemaDefinitions.map(s => s.name)\n })\n})\n\n// Basic collections endpoint\napiRoutes.get('/collections', async (c) => {\n const executionStart = Date.now()\n\n try {\n const db = c.env.DB\n const cacheEnabled = c.get('cacheEnabled')\n const cache = getCacheService(CACHE_CONFIGS.api!)\n const cacheKey = cache.generateKey('collections', 'all')\n\n // Use cache only if cache plugin is active\n if (cacheEnabled) {\n const cacheResult = await cache.getWithSource(cacheKey)\n if (cacheResult.hit && cacheResult.data) {\n // Add cache headers\n c.header('X-Cache-Status', 'HIT')\n c.header('X-Cache-Source', cacheResult.source)\n if (cacheResult.ttl) {\n c.header('X-Cache-TTL', Math.floor(cacheResult.ttl).toString())\n }\n\n // Add cache info and timing to meta\n const dataWithMeta = {\n ...cacheResult.data,\n meta: addTimingMeta(c, {\n ...cacheResult.data.meta,\n cache: {\n hit: true,\n source: cacheResult.source,\n ttl: cacheResult.ttl ? Math.floor(cacheResult.ttl) : undefined\n }\n }, executionStart)\n }\n\n return c.json(dataWithMeta)\n }\n }\n\n // Cache miss - fetch from database\n c.header('X-Cache-Status', 'MISS')\n c.header('X-Cache-Source', 'database')\n\n const stmt = db.prepare('SELECT * FROM collections WHERE is_active = 1')\n const { results } = await stmt.all()\n\n // Parse schema and format results\n const transformedResults = results.map((row: any) => ({\n ...row,\n schema: row.schema ? JSON.parse(row.schema) : {},\n is_active: row.is_active // Keep as number (1 or 0)\n }))\n\n const responseData = {\n data: transformedResults,\n meta: addTimingMeta(c, {\n count: results.length,\n timestamp: new Date().toISOString(),\n cache: {\n hit: false,\n source: 'database'\n }\n }, executionStart)\n }\n\n // Cache the response only if cache plugin is enabled\n if (cacheEnabled) {\n await cache.set(cacheKey, responseData)\n }\n\n return c.json(responseData)\n } catch (error) {\n console.error('Error fetching collections:', error)\n return c.json({ error: 'Failed to fetch collections' }, 500)\n }\n})\n\n// Basic content endpoint with advanced filtering\napiRoutes.get('/content', async (c) => {\n const executionStart = Date.now()\n\n try {\n const db = c.env.DB\n const queryParams = c.req.query()\n\n // Handle collection parameter - convert collection name to collection_id\n if (queryParams.collection) {\n const collectionName = queryParams.collection\n const collectionStmt = db.prepare('SELECT id FROM collections WHERE name = ? AND is_active = 1')\n const collectionResult = await collectionStmt.bind(collectionName).first()\n\n if (collectionResult) {\n // Replace 'collection' param with 'collection_id' for the filter builder\n queryParams.collection_id = (collectionResult as any).id\n delete queryParams.collection\n } else {\n // Collection not found - return empty result\n return c.json({\n data: [],\n meta: addTimingMeta(c, {\n count: 0,\n timestamp: new Date().toISOString(),\n message: `Collection '${collectionName}' not found`\n }, executionStart)\n })\n }\n }\n\n // Parse filter from query parameters\n const filter: QueryFilter = QueryFilterBuilder.parseFromQuery(queryParams)\n\n // Set default limit if not provided\n if (!filter.limit) {\n filter.limit = 50\n }\n filter.limit = Math.min(filter.limit, 1000) // Max 1000\n\n // Build SQL query from filter\n const builder = new QueryFilterBuilder()\n const queryResult = builder.build('content', filter)\n\n // Check for query building errors\n if (queryResult.errors.length > 0) {\n return c.json({\n error: 'Invalid filter parameters',\n details: queryResult.errors\n }, 400)\n }\n\n // Only use cache if cache plugin is active\n const cacheEnabled = c.get('cacheEnabled')\n const cache = getCacheService(CACHE_CONFIGS.api!)\n const cacheKey = cache.generateKey('content-filtered', JSON.stringify({ filter, query: queryResult.sql }))\n\n if (cacheEnabled) {\n const cacheResult = await cache.getWithSource(cacheKey)\n if (cacheResult.hit && cacheResult.data) {\n // Add cache headers\n c.header('X-Cache-Status', 'HIT')\n c.header('X-Cache-Source', cacheResult.source)\n if (cacheResult.ttl) {\n c.header('X-Cache-TTL', Math.floor(cacheResult.ttl).toString())\n }\n\n // Add cache info and timing to meta\n const dataWithMeta = {\n ...cacheResult.data,\n meta: addTimingMeta(c, {\n ...cacheResult.data.meta,\n cache: {\n hit: true,\n source: cacheResult.source,\n ttl: cacheResult.ttl ? Math.floor(cacheResult.ttl) : undefined\n }\n }, executionStart)\n }\n\n return c.json(dataWithMeta)\n }\n }\n\n // Cache miss - fetch from database\n c.header('X-Cache-Status', 'MISS')\n c.header('X-Cache-Source', 'database')\n\n // Execute query with parameters\n const stmt = db.prepare(queryResult.sql)\n const boundStmt = queryResult.params.length > 0\n ? stmt.bind(...queryResult.params)\n : stmt\n\n const { results } = await boundStmt.all()\n\n // Transform results to match API spec (camelCase)\n const transformedResults = results.map((row: any) => ({\n id: row.id,\n title: row.title,\n slug: row.slug,\n status: row.status,\n collectionId: row.collection_id,\n data: row.data ? JSON.parse(row.data) : {},\n created_at: row.created_at,\n updated_at: row.updated_at\n }))\n\n const responseData = {\n data: transformedResults,\n meta: addTimingMeta(c, {\n count: results.length,\n timestamp: new Date().toISOString(),\n filter: filter,\n query: {\n sql: queryResult.sql,\n params: queryResult.params\n },\n cache: {\n hit: false,\n source: 'database'\n }\n }, executionStart)\n }\n\n // Cache the response only if cache is enabled\n if (cacheEnabled) {\n await cache.set(cacheKey, responseData)\n }\n\n return c.json(responseData)\n } catch (error) {\n console.error('Error fetching content:', error)\n return c.json({\n error: 'Failed to fetch content',\n details: error instanceof Error ? error.message : String(error)\n }, 500)\n }\n})\n\n// Collection-specific routes with advanced filtering\napiRoutes.get('/collections/:collection/content', async (c) => {\n const executionStart = Date.now()\n\n try {\n const collection = c.req.param('collection')\n const db = c.env.DB\n const queryParams = c.req.query()\n\n // First check if collection exists\n const collectionStmt = db.prepare('SELECT * FROM collections WHERE name = ? AND is_active = 1')\n const collectionResult = await collectionStmt.bind(collection).first()\n\n if (!collectionResult) {\n return c.json({ error: 'Collection not found' }, 404)\n }\n\n // Parse filter from query parameters\n const filter: QueryFilter = QueryFilterBuilder.parseFromQuery(queryParams)\n\n // Add collection_id filter to where clause\n if (!filter.where) {\n filter.where = { and: [] }\n }\n\n if (!filter.where.and) {\n filter.where.and = []\n }\n\n // Add collection filter\n filter.where.and.push({\n field: 'collection_id',\n operator: 'equals',\n value: (collectionResult as any).id\n })\n\n // Set default limit if not provided\n if (!filter.limit) {\n filter.limit = 50\n }\n filter.limit = Math.min(filter.limit, 1000)\n\n // Build SQL query from filter\n const builder = new QueryFilterBuilder()\n const queryResult = builder.build('content', filter)\n\n // Check for query building errors\n if (queryResult.errors.length > 0) {\n return c.json({\n error: 'Invalid filter parameters',\n details: queryResult.errors\n }, 400)\n }\n\n // Generate cache key\n const cacheEnabled = c.get('cacheEnabled')\n const cache = getCacheService(CACHE_CONFIGS.api!)\n const cacheKey = cache.generateKey('collection-content-filtered', `${collection}:${JSON.stringify({ filter, query: queryResult.sql })}`)\n\n // Only check cache if plugin is enabled\n if (cacheEnabled) {\n const cacheResult = await cache.getWithSource(cacheKey)\n if (cacheResult.hit && cacheResult.data) {\n // Add cache headers\n c.header('X-Cache-Status', 'HIT')\n c.header('X-Cache-Source', cacheResult.source)\n if (cacheResult.ttl) {\n c.header('X-Cache-TTL', Math.floor(cacheResult.ttl).toString())\n }\n\n // Add cache info and timing to meta\n const dataWithMeta = {\n ...cacheResult.data,\n meta: addTimingMeta(c, {\n ...cacheResult.data.meta,\n cache: {\n hit: true,\n source: cacheResult.source,\n ttl: cacheResult.ttl ? Math.floor(cacheResult.ttl) : undefined\n }\n }, executionStart)\n }\n\n return c.json(dataWithMeta)\n }\n }\n\n // Cache miss - fetch from database\n c.header('X-Cache-Status', 'MISS')\n c.header('X-Cache-Source', 'database')\n\n // Execute query with parameters\n const stmt = db.prepare(queryResult.sql)\n const boundStmt = queryResult.params.length > 0\n ? stmt.bind(...queryResult.params)\n : stmt\n\n const { results } = await boundStmt.all()\n\n // Transform results to match API spec (camelCase)\n const transformedResults = results.map((row: any) => ({\n id: row.id,\n title: row.title,\n slug: row.slug,\n status: row.status,\n collectionId: row.collection_id,\n data: row.data ? JSON.parse(row.data) : {},\n created_at: row.created_at,\n updated_at: row.updated_at\n }))\n\n const responseData = {\n data: transformedResults,\n meta: addTimingMeta(c, {\n collection: {\n ...(collectionResult as any),\n schema: (collectionResult as any).schema ? JSON.parse((collectionResult as any).schema) : {}\n },\n count: results.length,\n timestamp: new Date().toISOString(),\n filter: filter,\n query: {\n sql: queryResult.sql,\n params: queryResult.params\n },\n cache: {\n hit: false,\n source: 'database'\n }\n }, executionStart)\n }\n\n // Cache the response only if cache plugin is enabled\n if (cacheEnabled) {\n await cache.set(cacheKey, responseData)\n }\n\n return c.json(responseData)\n } catch (error) {\n console.error('Error fetching content:', error)\n return c.json({\n error: 'Failed to fetch content',\n details: error instanceof Error ? error.message : String(error)\n }, 500)\n }\n})\n\n// Mount CRUD routes for content\napiRoutes.route('/content', apiContentCrudRoutes)\n\nexport default apiRoutes\n","import { Hono } from 'hono'\nimport { z } from 'zod'\nimport { requireAuth } from '../middleware'\nimport type { Bindings, Variables } from '../app'\n\n// Helper function to generate short IDs (replacement for nanoid)\nfunction generateId(): string {\n return crypto.randomUUID().replace(/-/g, '').substring(0, 21)\n}\n\n// Helper function for emitting events (simplified for core package)\nasync function emitEvent(eventName: string, data: any) {\n console.log(`[Event] ${eventName}:`, data)\n // TODO: Implement proper event system when plugin architecture is ready\n}\n\n// File validation schema\nconst fileValidationSchema = z.object({\n name: z.string().min(1).max(255),\n type: z.string().refine(\n (type) => {\n const allowedTypes = [\n // Images\n 'image/jpeg', 'image/jpg', 'image/png', 'image/gif', 'image/webp', 'image/svg+xml',\n // Documents\n 'application/pdf', 'text/plain', 'application/msword', \n 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',\n // Videos\n 'video/mp4', 'video/webm', 'video/ogg', 'video/avi', 'video/mov',\n // Audio\n 'audio/mp3', 'audio/wav', 'audio/ogg', 'audio/m4a'\n ]\n return allowedTypes.includes(type)\n },\n { message: 'Unsupported file type' }\n ),\n size: z.number().min(1).max(50 * 1024 * 1024) // 50MB max\n})\n\nexport const apiMediaRoutes = new Hono<{ Bindings: Bindings; Variables: Variables }>()\n\n// Apply auth middleware to all routes\napiMediaRoutes.use('*', requireAuth())\n\n// Upload single file\napiMediaRoutes.post('/upload', async (c) => {\n try {\n const user = c.get('user')!\n const formData = await c.req.formData()\n const fileData = formData.get('file')\n\n if (!fileData || typeof fileData === 'string') {\n return c.json({ error: 'No file provided' }, 400)\n }\n\n const file = fileData as File\n\n // Validate file\n const validation = fileValidationSchema.safeParse({\n name: file.name,\n type: file.type,\n size: file.size\n })\n\n if (!validation.success) {\n return c.json({ \n error: 'File validation failed', \n details: validation.error.issues \n }, 400)\n }\n\n // Generate unique filename and R2 key\n const fileId = generateId()\n const fileExtension = file.name.split('.').pop() || ''\n const filename = `${fileId}.${fileExtension}`\n const folder = formData.get('folder') as string || 'uploads'\n const r2Key = `${folder}/${filename}`\n\n // Upload to R2\n const arrayBuffer = await file.arrayBuffer()\n const uploadResult = await c.env.MEDIA_BUCKET.put(r2Key, arrayBuffer, {\n httpMetadata: {\n contentType: file.type,\n contentDisposition: `inline; filename=\"${file.name}\"`\n },\n customMetadata: {\n originalName: file.name,\n uploadedBy: user.userId,\n uploadedAt: new Date().toISOString()\n }\n })\n\n if (!uploadResult) {\n return c.json({ error: 'Failed to upload file to storage' }, 500)\n }\n\n // Generate public URL using environment variable for bucket name\n const bucketName = c.env.BUCKET_NAME || 'sonicjs-media-dev'\n const publicUrl = `https://pub-${bucketName}.r2.dev/${r2Key}`\n \n // Extract image dimensions if it's an image\n let width: number | undefined\n let height: number | undefined\n \n if (file.type.startsWith('image/') && !file.type.includes('svg')) {\n try {\n const dimensions = await getImageDimensions(arrayBuffer)\n width = dimensions.width\n height = dimensions.height\n } catch (error) {\n console.warn('Failed to extract image dimensions:', error)\n }\n }\n\n // Generate thumbnail URL for images\n let thumbnailUrl: string | undefined\n if (file.type.startsWith('image/') && c.env.IMAGES_ACCOUNT_ID) {\n thumbnailUrl = `https://imagedelivery.net/${c.env.IMAGES_ACCOUNT_ID}/${r2Key}/thumbnail`\n }\n\n // Save to database\n const mediaRecord = {\n id: fileId,\n filename: filename,\n original_name: file.name,\n mime_type: file.type,\n size: file.size,\n width,\n height,\n folder,\n r2_key: r2Key,\n public_url: publicUrl,\n thumbnail_url: thumbnailUrl,\n uploaded_by: user.userId,\n uploaded_at: Math.floor(Date.now() / 1000),\n created_at: Math.floor(Date.now() / 1000)\n }\n\n const stmt = c.env.DB.prepare(`\n INSERT INTO media (\n id, filename, original_name, mime_type, size, width, height, \n folder, r2_key, public_url, thumbnail_url, uploaded_by, uploaded_at\n ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\n `)\n \n await stmt.bind(\n mediaRecord.id,\n mediaRecord.filename,\n mediaRecord.original_name,\n mediaRecord.mime_type,\n mediaRecord.size,\n mediaRecord.width ?? null,\n mediaRecord.height ?? null,\n mediaRecord.folder,\n mediaRecord.r2_key,\n mediaRecord.public_url,\n mediaRecord.thumbnail_url ?? null,\n mediaRecord.uploaded_by,\n mediaRecord.uploaded_at\n ).run()\n\n // Emit media upload event\n await emitEvent('media.upload', { id: mediaRecord.id, filename: mediaRecord.filename })\n\n return c.json({\n success: true,\n file: {\n id: mediaRecord.id,\n filename: mediaRecord.filename,\n originalName: mediaRecord.original_name,\n mimeType: mediaRecord.mime_type,\n size: mediaRecord.size,\n width: mediaRecord.width,\n height: mediaRecord.height,\n r2_key: mediaRecord.r2_key,\n publicUrl: mediaRecord.public_url,\n thumbnailUrl: mediaRecord.thumbnail_url,\n uploadedAt: new Date(mediaRecord.uploaded_at * 1000).toISOString()\n }\n })\n } catch (error) {\n console.error('Upload error:', error)\n return c.json({ error: 'Upload failed' }, 500)\n }\n})\n\n// Upload multiple files\napiMediaRoutes.post('/upload-multiple', async (c) => {\n try {\n const user = c.get('user')!\n const formData = await c.req.formData()\n const filesData = formData.getAll('files')\n\n // Filter out strings and ensure we only have File objects\n const files: File[] = []\n for (const f of filesData) {\n if (typeof f !== 'string') {\n files.push(f as File)\n }\n }\n\n if (!files || files.length === 0) {\n return c.json({ error: 'No files provided' }, 400)\n }\n\n const uploadResults = []\n const errors = []\n\n for (const file of files) {\n try {\n // Validate file\n const validation = fileValidationSchema.safeParse({\n name: file.name,\n type: file.type,\n size: file.size\n })\n\n if (!validation.success) {\n errors.push({\n filename: file.name,\n error: 'Validation failed',\n details: validation.error.issues\n })\n continue\n }\n\n // Generate unique filename and R2 key\n const fileId = generateId()\n const fileExtension = file.name.split('.').pop() || ''\n const filename = `${fileId}.${fileExtension}`\n const folder = formData.get('folder') as string || 'uploads'\n const r2Key = `${folder}/${filename}`\n\n // Upload to R2\n const arrayBuffer = await file.arrayBuffer()\n const uploadResult = await c.env.MEDIA_BUCKET.put(r2Key, arrayBuffer, {\n httpMetadata: {\n contentType: file.type,\n contentDisposition: `inline; filename=\"${file.name}\"`\n },\n customMetadata: {\n originalName: file.name,\n uploadedBy: user.userId,\n uploadedAt: new Date().toISOString()\n }\n })\n\n if (!uploadResult) {\n errors.push({\n filename: file.name,\n error: 'Failed to upload to storage'\n })\n continue\n }\n\n // Generate public URL using environment variable for bucket name\n const bucketName = c.env.BUCKET_NAME || 'sonicjs-media-dev'\n const publicUrl = `https://pub-${bucketName}.r2.dev/${r2Key}`\n \n // Extract image dimensions if it's an image\n let width: number | undefined\n let height: number | undefined\n \n if (file.type.startsWith('image/') && !file.type.includes('svg')) {\n try {\n const dimensions = await getImageDimensions(arrayBuffer)\n width = dimensions.width\n height = dimensions.height\n } catch (error) {\n console.warn('Failed to extract image dimensions:', error)\n }\n }\n\n // Generate thumbnail URL for images\n let thumbnailUrl: string | undefined\n if (file.type.startsWith('image/') && c.env.IMAGES_ACCOUNT_ID) {\n thumbnailUrl = `https://imagedelivery.net/${c.env.IMAGES_ACCOUNT_ID}/${r2Key}/thumbnail`\n }\n\n // Save to database\n const mediaRecord = {\n id: fileId,\n filename: filename,\n original_name: file.name,\n mime_type: file.type,\n size: file.size,\n width,\n height,\n folder,\n r2_key: r2Key,\n public_url: publicUrl,\n thumbnail_url: thumbnailUrl,\n uploaded_by: user.userId,\n uploaded_at: Math.floor(Date.now() / 1000)\n }\n\n const stmt = c.env.DB.prepare(`\n INSERT INTO media (\n id, filename, original_name, mime_type, size, width, height, \n folder, r2_key, public_url, thumbnail_url, uploaded_by, uploaded_at\n ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\n `)\n \n await stmt.bind(\n mediaRecord.id,\n mediaRecord.filename,\n mediaRecord.original_name,\n mediaRecord.mime_type,\n mediaRecord.size,\n mediaRecord.width ?? null,\n mediaRecord.height ?? null,\n mediaRecord.folder,\n mediaRecord.r2_key,\n mediaRecord.public_url,\n mediaRecord.thumbnail_url ?? null,\n mediaRecord.uploaded_by,\n mediaRecord.uploaded_at\n ).run()\n\n uploadResults.push({\n id: mediaRecord.id,\n filename: mediaRecord.filename,\n originalName: mediaRecord.original_name,\n mimeType: mediaRecord.mime_type,\n size: mediaRecord.size,\n width: mediaRecord.width,\n height: mediaRecord.height,\n r2_key: mediaRecord.r2_key,\n publicUrl: mediaRecord.public_url,\n thumbnailUrl: mediaRecord.thumbnail_url,\n uploadedAt: new Date(mediaRecord.uploaded_at * 1000).toISOString()\n })\n } catch (error) {\n errors.push({\n filename: file.name,\n error: 'Upload failed',\n details: error instanceof Error ? error.message : 'Unknown error'\n })\n }\n }\n\n // Emit media upload event if any uploads succeeded\n if (uploadResults.length > 0) {\n await emitEvent('media.upload', { count: uploadResults.length })\n }\n\n return c.json({\n success: uploadResults.length > 0,\n uploaded: uploadResults,\n errors: errors,\n summary: {\n total: files.length,\n successful: uploadResults.length,\n failed: errors.length\n }\n })\n } catch (error) {\n console.error('Multiple upload error:', error)\n return c.json({ error: 'Upload failed' }, 500)\n }\n})\n\n// Bulk delete files\napiMediaRoutes.post('/bulk-delete', async (c) => {\n try {\n const user = c.get('user')!\n const body = await c.req.json()\n const fileIds = body.fileIds as string[]\n \n if (!fileIds || !Array.isArray(fileIds) || fileIds.length === 0) {\n return c.json({ error: 'No file IDs provided' }, 400)\n }\n\n // Limit bulk operations to prevent abuse\n if (fileIds.length > 50) {\n return c.json({ error: 'Too many files selected. Maximum 50 files per operation.' }, 400)\n }\n\n const results = []\n const errors = []\n\n for (const fileId of fileIds) {\n try {\n // Get file record (including already deleted files to check if they exist at all)\n const stmt = c.env.DB.prepare('SELECT * FROM media WHERE id = ?')\n const fileRecord = await stmt.bind(fileId).first() as any\n\n if (!fileRecord) {\n errors.push({ fileId, error: 'File not found' })\n continue\n }\n\n // Skip if already deleted (treat as success)\n if (fileRecord.deleted_at !== null) {\n console.log(`File ${fileId} already deleted, skipping`)\n results.push({\n fileId,\n filename: fileRecord.original_name,\n success: true,\n alreadyDeleted: true\n })\n continue\n }\n\n // Check permissions (only allow deletion by uploader or admin)\n if (fileRecord.uploaded_by !== user.userId && user.role !== 'admin') {\n errors.push({ fileId, error: 'Permission denied' })\n continue\n }\n\n // Delete from R2\n try {\n await c.env.MEDIA_BUCKET.delete(fileRecord.r2_key)\n } catch (error) {\n console.warn(`Failed to delete from R2 for file ${fileId}:`, error)\n // Continue with database deletion even if R2 deletion fails\n }\n\n // Soft delete in database\n const deleteStmt = c.env.DB.prepare('UPDATE media SET deleted_at = ? WHERE id = ?')\n await deleteStmt.bind(Math.floor(Date.now() / 1000), fileId).run()\n\n results.push({\n fileId,\n filename: fileRecord.original_name,\n success: true\n })\n } catch (error) {\n errors.push({\n fileId,\n error: 'Delete failed',\n details: error instanceof Error ? error.message : 'Unknown error'\n })\n }\n }\n\n // Emit media delete event if any deletes succeeded\n if (results.length > 0) {\n await emitEvent('media.delete', { count: results.length, ids: fileIds })\n }\n\n return c.json({\n success: results.length > 0,\n deleted: results,\n errors: errors,\n summary: {\n total: fileIds.length,\n successful: results.length,\n failed: errors.length\n }\n })\n } catch (error) {\n console.error('Bulk delete error:', error)\n return c.json({ error: 'Bulk delete failed' }, 500)\n }\n})\n\n// Create folder\napiMediaRoutes.post('/create-folder', async (c) => {\n try {\n const body = await c.req.json()\n const folderName = body.folderName as string\n\n if (!folderName || typeof folderName !== 'string') {\n return c.json({ success: false, error: 'No folder name provided' }, 400)\n }\n\n // Validate folder name format\n const folderPattern = /^[a-z0-9-_]+$/\n if (!folderPattern.test(folderName)) {\n return c.json({\n success: false,\n error: 'Folder name can only contain lowercase letters, numbers, hyphens, and underscores'\n }, 400)\n }\n\n // Check if folder already exists in the database\n const checkStmt = c.env.DB.prepare('SELECT COUNT(*) as count FROM media WHERE folder = ? AND deleted_at IS NULL')\n const existingFolder = await checkStmt.bind(folderName).first() as any\n\n if (existingFolder && existingFolder.count > 0) {\n return c.json({\n success: false,\n error: `Folder \"${folderName}\" already exists`\n }, 400)\n }\n\n // Note: R2 folders are virtual - they only exist when files are uploaded to them\n // Return success message explaining this behavior\n return c.json({\n success: true,\n message: `Folder \"${folderName}\" is ready. Upload files to this folder to make it appear in the media library.`,\n folder: folderName,\n note: 'Folders appear automatically when you upload files to them'\n })\n } catch (error) {\n console.error('Create folder error:', error)\n return c.json({ success: false, error: 'Failed to create folder' }, 500)\n }\n})\n\n// Bulk move files to folder\napiMediaRoutes.post('/bulk-move', async (c) => {\n try {\n const user = c.get('user')!\n const body = await c.req.json()\n const fileIds = body.fileIds as string[]\n const targetFolder = body.folder as string\n\n if (!fileIds || !Array.isArray(fileIds) || fileIds.length === 0) {\n return c.json({ error: 'No file IDs provided' }, 400)\n }\n\n if (!targetFolder || typeof targetFolder !== 'string') {\n return c.json({ error: 'No target folder provided' }, 400)\n }\n\n // Limit bulk operations to prevent abuse\n if (fileIds.length > 50) {\n return c.json({ error: 'Too many files selected. Maximum 50 files per operation.' }, 400)\n }\n\n const results = []\n const errors = []\n\n for (const fileId of fileIds) {\n try {\n // Get file record\n const stmt = c.env.DB.prepare('SELECT * FROM media WHERE id = ? AND deleted_at IS NULL')\n const fileRecord = await stmt.bind(fileId).first() as any\n\n if (!fileRecord) {\n errors.push({ fileId, error: 'File not found' })\n continue\n }\n\n // Check permissions (only allow move by uploader or admin)\n if (fileRecord.uploaded_by !== user.userId && user.role !== 'admin') {\n errors.push({ fileId, error: 'Permission denied' })\n continue\n }\n\n // Skip if already in target folder\n if (fileRecord.folder === targetFolder) {\n results.push({\n fileId,\n filename: fileRecord.original_name,\n success: true,\n skipped: true\n })\n continue\n }\n\n // Generate new R2 key with new folder\n const oldR2Key = fileRecord.r2_key\n const filename = oldR2Key.split('/').pop() || fileRecord.filename\n const newR2Key = `${targetFolder}/${filename}`\n\n // Copy file to new location in R2\n try {\n const object = await c.env.MEDIA_BUCKET.get(oldR2Key)\n if (!object) {\n errors.push({ fileId, error: 'File not found in storage' })\n continue\n }\n\n await c.env.MEDIA_BUCKET.put(newR2Key, object.body, {\n httpMetadata: object.httpMetadata,\n customMetadata: {\n ...object.customMetadata,\n movedBy: user.userId,\n movedAt: new Date().toISOString()\n }\n })\n\n // Delete old file from R2\n await c.env.MEDIA_BUCKET.delete(oldR2Key)\n } catch (error) {\n console.warn(`Failed to move file in R2 for file ${fileId}:`, error)\n errors.push({ fileId, error: 'Failed to move file in storage' })\n continue\n }\n\n // Update database with new folder and R2 key\n const bucketName = c.env.BUCKET_NAME || 'sonicjs-media-dev'\n const newPublicUrl = `https://pub-${bucketName}.r2.dev/${newR2Key}`\n\n const updateStmt = c.env.DB.prepare(`\n UPDATE media\n SET folder = ?, r2_key = ?, public_url = ?, updated_at = ?\n WHERE id = ?\n `)\n await updateStmt.bind(\n targetFolder,\n newR2Key,\n newPublicUrl,\n Math.floor(Date.now() / 1000),\n fileId\n ).run()\n\n results.push({\n fileId,\n filename: fileRecord.original_name,\n success: true,\n skipped: false\n })\n } catch (error) {\n errors.push({\n fileId,\n error: 'Move failed',\n details: error instanceof Error ? error.message : 'Unknown error'\n })\n }\n }\n\n // Emit media move event if any moves succeeded\n if (results.length > 0) {\n await emitEvent('media.move', { count: results.length, targetFolder, ids: fileIds })\n }\n\n return c.json({\n success: results.length > 0,\n moved: results,\n errors: errors,\n summary: {\n total: fileIds.length,\n successful: results.length,\n failed: errors.length\n }\n })\n } catch (error) {\n console.error('Bulk move error:', error)\n return c.json({ error: 'Bulk move failed' }, 500)\n }\n})\n\n// Delete file\napiMediaRoutes.delete('/:id', async (c) => {\n try {\n const user = c.get('user')!\n const fileId = c.req.param('id')\n \n // Get file record\n const stmt = c.env.DB.prepare('SELECT * FROM media WHERE id = ? AND deleted_at IS NULL')\n const fileRecord = await stmt.bind(fileId).first() as any\n \n if (!fileRecord) {\n return c.json({ error: 'File not found' }, 404)\n }\n\n // Check permissions (only allow deletion by uploader or admin)\n if (fileRecord.uploaded_by !== user.userId && user.role !== 'admin') {\n return c.json({ error: 'Permission denied' }, 403)\n }\n\n // Delete from R2\n try {\n await c.env.MEDIA_BUCKET.delete(fileRecord.r2_key)\n } catch (error) {\n console.warn('Failed to delete from R2:', error)\n // Continue with database deletion even if R2 deletion fails\n }\n\n // Soft delete in database\n const deleteStmt = c.env.DB.prepare('UPDATE media SET deleted_at = ? WHERE id = ?')\n await deleteStmt.bind(Math.floor(Date.now() / 1000), fileId).run()\n\n // Emit media delete event\n await emitEvent('media.delete', { id: fileId })\n\n return c.json({ success: true, message: 'File deleted successfully' })\n } catch (error) {\n console.error('Delete error:', error)\n return c.json({ error: 'Delete failed' }, 500)\n }\n})\n\n// Update file metadata\napiMediaRoutes.patch('/:id', async (c) => {\n try {\n const user = c.get('user')!\n const fileId = c.req.param('id')\n const body = await c.req.json()\n \n // Get file record\n const stmt = c.env.DB.prepare('SELECT * FROM media WHERE id = ? AND deleted_at IS NULL')\n const fileRecord = await stmt.bind(fileId).first() as any\n \n if (!fileRecord) {\n return c.json({ error: 'File not found' }, 404)\n }\n\n // Check permissions (only allow updates by uploader or admin)\n if (fileRecord.uploaded_by !== user.userId && user.role !== 'admin') {\n return c.json({ error: 'Permission denied' }, 403)\n }\n\n // Update allowed fields\n const allowedFields = ['alt', 'caption', 'tags', 'folder']\n const updates = []\n const values = []\n \n for (const [key, value] of Object.entries(body)) {\n if (allowedFields.includes(key)) {\n updates.push(`${key} = ?`)\n values.push(key === 'tags' ? JSON.stringify(value) : value)\n }\n }\n\n if (updates.length === 0) {\n return c.json({ error: 'No valid fields to update' }, 400)\n }\n\n updates.push('updated_at = ?')\n values.push(Math.floor(Date.now() / 1000))\n values.push(fileId)\n\n const updateStmt = c.env.DB.prepare(`\n UPDATE media SET ${updates.join(', ')} WHERE id = ?\n `)\n await updateStmt.bind(...values).run()\n\n // Emit media update event\n await emitEvent('media.update', { id: fileId })\n\n return c.json({ success: true, message: 'File updated successfully' })\n } catch (error) {\n console.error('Update error:', error)\n return c.json({ error: 'Update failed' }, 500)\n }\n})\n\n// Helper function to extract image dimensions\nasync function getImageDimensions(arrayBuffer: ArrayBuffer): Promise<{ width: number; height: number }> {\n // This is a simplified implementation\n // In a real-world scenario, you'd use a proper image processing library\n const uint8Array = new Uint8Array(arrayBuffer)\n \n // Check for JPEG\n if (uint8Array[0] === 0xFF && uint8Array[1] === 0xD8) {\n return getJPEGDimensions(uint8Array)\n }\n \n // Check for PNG\n if (uint8Array[0] === 0x89 && uint8Array[1] === 0x50 && uint8Array[2] === 0x4E && uint8Array[3] === 0x47) {\n return getPNGDimensions(uint8Array)\n }\n \n // Default fallback\n return { width: 0, height: 0 }\n}\n\nfunction getJPEGDimensions(uint8Array: Uint8Array): { width: number; height: number } {\n let i = 2\n while (i < uint8Array.length) {\n if (i + 8 >= uint8Array.length) break\n if (uint8Array[i] === 0xFF && uint8Array[i + 1] === 0xC0) {\n if (i + 8 < uint8Array.length) {\n return {\n height: (uint8Array[i + 5]! << 8) | uint8Array[i + 6]!,\n width: (uint8Array[i + 7]! << 8) | uint8Array[i + 8]!\n }\n }\n }\n if (i + 3 < uint8Array.length) {\n i += 2 + ((uint8Array[i + 2]! << 8) | uint8Array[i + 3]!)\n } else {\n break\n }\n }\n return { width: 0, height: 0 }\n}\n\nfunction getPNGDimensions(uint8Array: Uint8Array): { width: number; height: number } {\n if (uint8Array.length < 24) {\n return { width: 0, height: 0 }\n }\n return {\n width: (uint8Array[16]! << 24) | (uint8Array[17]! << 16) | (uint8Array[18]! << 8) | uint8Array[19]!,\n height: (uint8Array[20]! << 24) | (uint8Array[21]! << 16) | (uint8Array[22]! << 8) | uint8Array[23]!\n }\n}\n\nexport default apiMediaRoutes","/**\n * API System Routes\n *\n * Provides system health, status, and metadata endpoints\n * These are lightweight routes without heavy dependencies\n */\n\nimport { Hono } from 'hono'\nimport type { Bindings, Variables } from '../app'\n\nexport const apiSystemRoutes = new Hono<{ Bindings: Bindings; Variables: Variables }>()\n\n/**\n * System health check\n * GET /api/system/health\n */\napiSystemRoutes.get('/health', async (c) => {\n try {\n const startTime = Date.now()\n\n // Check database connectivity\n let dbStatus = 'unknown'\n let dbLatency = 0\n\n try {\n const dbStart = Date.now()\n await c.env.DB.prepare('SELECT 1').first()\n dbLatency = Date.now() - dbStart\n dbStatus = 'healthy'\n } catch (error) {\n console.error('Database health check failed:', error)\n dbStatus = 'unhealthy'\n }\n\n // Check KV connectivity (if available)\n let kvStatus = 'not_configured'\n let kvLatency = 0\n\n if (c.env.CACHE_KV) {\n try {\n const kvStart = Date.now()\n await c.env.CACHE_KV.get('__health_check__')\n kvLatency = Date.now() - kvStart\n kvStatus = 'healthy'\n } catch (error) {\n console.error('KV health check failed:', error)\n kvStatus = 'unhealthy'\n }\n }\n\n // Check R2 connectivity (if available)\n let r2Status = 'not_configured'\n\n if (c.env.MEDIA_BUCKET) {\n try {\n await c.env.MEDIA_BUCKET.head('__health_check__')\n r2Status = 'healthy'\n } catch (error) {\n // R2 head on non-existent key returns null, not an error\n // This is expected, so we consider it healthy\n r2Status = 'healthy'\n }\n }\n\n const totalLatency = Date.now() - startTime\n const overall = dbStatus === 'healthy' ? 'healthy' : 'degraded'\n\n return c.json({\n status: overall,\n timestamp: new Date().toISOString(),\n uptime: totalLatency,\n checks: {\n database: {\n status: dbStatus,\n latency: dbLatency\n },\n cache: {\n status: kvStatus,\n latency: kvLatency\n },\n storage: {\n status: r2Status\n }\n },\n environment: c.env.ENVIRONMENT || 'production'\n })\n } catch (error) {\n console.error('Health check failed:', error)\n return c.json({\n status: 'unhealthy',\n timestamp: new Date().toISOString(),\n error: 'Health check failed'\n }, 503)\n }\n})\n\n/**\n * System information\n * GET /api/system/info\n */\napiSystemRoutes.get('/info', (c) => {\n const appVersion = c.get('appVersion') || '1.0.0'\n\n return c.json({\n name: 'SonicJS',\n version: appVersion,\n description: 'Modern headless CMS built on Cloudflare Workers',\n endpoints: {\n api: '/api',\n auth: '/auth',\n health: '/api/system/health',\n docs: '/docs'\n },\n features: {\n content: true,\n media: true,\n auth: true,\n collections: true,\n caching: !!c.env.CACHE_KV,\n storage: !!c.env.MEDIA_BUCKET\n },\n timestamp: new Date().toISOString()\n })\n})\n\n/**\n * System stats\n * GET /api/system/stats\n */\napiSystemRoutes.get('/stats', async (c) => {\n try {\n const db = c.env.DB\n\n // Get content statistics\n const contentStats = await db.prepare(`\n SELECT COUNT(*) as total_content\n FROM content\n WHERE deleted_at IS NULL\n `).first() as any\n\n // Get media statistics\n const mediaStats = await db.prepare(`\n SELECT\n COUNT(*) as total_files,\n SUM(size) as total_size\n FROM media\n WHERE deleted_at IS NULL\n `).first() as any\n\n // Get user statistics\n const userStats = await db.prepare(`\n SELECT COUNT(*) as total_users\n FROM users\n `).first() as any\n\n return c.json({\n content: {\n total: contentStats?.total_content || 0\n },\n media: {\n total_files: mediaStats?.total_files || 0,\n total_size_bytes: mediaStats?.total_size || 0,\n total_size_mb: Math.round((mediaStats?.total_size || 0) / 1024 / 1024 * 100) / 100\n },\n users: {\n total: userStats?.total_users || 0\n },\n timestamp: new Date().toISOString()\n })\n } catch (error) {\n console.error('Stats query failed:', error)\n return c.json({ error: 'Failed to fetch system statistics' }, 500)\n }\n})\n\n/**\n * Database ping\n * GET /api/system/ping\n */\napiSystemRoutes.get('/ping', async (c) => {\n try {\n const start = Date.now()\n await c.env.DB.prepare('SELECT 1').first()\n const latency = Date.now() - start\n\n return c.json({\n pong: true,\n latency,\n timestamp: new Date().toISOString()\n })\n } catch (error) {\n console.error('Ping failed:', error)\n return c.json({\n pong: false,\n error: 'Database connection failed'\n }, 503)\n }\n})\n\n/**\n * Environment check\n * GET /api/system/env\n */\napiSystemRoutes.get('/env', (c) => {\n return c.json({\n environment: c.env.ENVIRONMENT || 'production',\n features: {\n database: !!c.env.DB,\n cache: !!c.env.CACHE_KV,\n media_bucket: !!c.env.MEDIA_BUCKET,\n email_queue: !!c.env.EMAIL_QUEUE,\n sendgrid: !!c.env.SENDGRID_API_KEY,\n cloudflare_images: !!(c.env.IMAGES_ACCOUNT_ID && c.env.IMAGES_API_TOKEN)\n },\n timestamp: new Date().toISOString()\n })\n})\n\nexport default apiSystemRoutes\n","/**\n * Admin API Routes\n *\n * Provides JSON API endpoints for admin operations\n * These routes complement the admin UI and can be used programmatically\n */\n\nimport { Hono } from 'hono'\nimport { z } from 'zod'\n// import { zValidator } from '@hono/zod-validator'\nimport { requireAuth, requireRole } from '../middleware'\nimport type { Bindings, Variables } from '../app'\n\nexport const adminApiRoutes = new Hono<{ Bindings: Bindings; Variables: Variables }>()\n\n// Apply auth middleware to all admin routes\nadminApiRoutes.use('*', requireAuth())\nadminApiRoutes.use('*', requireRole(['admin', 'editor']))\n\n/**\n * Get dashboard statistics\n * GET /admin/api/stats\n */\nadminApiRoutes.get('/stats', async (c) => {\n try {\n const db = c.env.DB\n\n // Get collections count\n let collectionsCount = 0\n try {\n const collectionsStmt = db.prepare('SELECT COUNT(*) as count FROM collections WHERE is_active = 1')\n const collectionsResult = await collectionsStmt.first()\n collectionsCount = (collectionsResult as any)?.count || 0\n } catch (error) {\n console.error('Error fetching collections count:', error)\n }\n\n // Get content count\n let contentCount = 0\n try {\n const contentStmt = db.prepare('SELECT COUNT(*) as count FROM content WHERE deleted_at IS NULL')\n const contentResult = await contentStmt.first()\n contentCount = (contentResult as any)?.count || 0\n } catch (error) {\n console.error('Error fetching content count:', error)\n }\n\n // Get media count and total size\n let mediaCount = 0\n let mediaSize = 0\n try {\n const mediaStmt = db.prepare('SELECT COUNT(*) as count, COALESCE(SUM(size), 0) as total_size FROM media WHERE deleted_at IS NULL')\n const mediaResult = await mediaStmt.first()\n mediaCount = (mediaResult as any)?.count || 0\n mediaSize = (mediaResult as any)?.total_size || 0\n } catch (error) {\n console.error('Error fetching media count:', error)\n }\n\n // Get users count\n let usersCount = 0\n try {\n const usersStmt = db.prepare('SELECT COUNT(*) as count FROM users WHERE is_active = 1')\n const usersResult = await usersStmt.first()\n usersCount = (usersResult as any)?.count || 0\n } catch (error) {\n console.error('Error fetching users count:', error)\n }\n\n return c.json({\n collections: collectionsCount,\n contentItems: contentCount,\n mediaFiles: mediaCount,\n mediaSize: mediaSize,\n users: usersCount,\n timestamp: new Date().toISOString()\n })\n } catch (error) {\n console.error('Error fetching stats:', error)\n return c.json({ error: 'Failed to fetch statistics' }, 500)\n }\n})\n\n/**\n * Get storage usage\n * GET /admin/api/storage\n */\nadminApiRoutes.get('/storage', async (c) => {\n try {\n const db = c.env.DB\n\n // Get database size from D1 metadata\n let databaseSize = 0\n try {\n const result = await db.prepare('SELECT 1').run()\n databaseSize = (result as any)?.meta?.size_after || 0\n } catch (error) {\n console.error('Error fetching database size:', error)\n }\n\n // Get media total size\n let mediaSize = 0\n try {\n const mediaStmt = db.prepare('SELECT COALESCE(SUM(size), 0) as total_size FROM media WHERE deleted_at IS NULL')\n const mediaResult = await mediaStmt.first()\n mediaSize = (mediaResult as any)?.total_size || 0\n } catch (error) {\n console.error('Error fetching media size:', error)\n }\n\n return c.json({\n databaseSize,\n mediaSize,\n totalSize: databaseSize + mediaSize,\n timestamp: new Date().toISOString()\n })\n } catch (error) {\n console.error('Error fetching storage usage:', error)\n return c.json({ error: 'Failed to fetch storage usage' }, 500)\n }\n})\n\n/**\n * Get recent activity\n * GET /admin/api/activity\n */\nadminApiRoutes.get('/activity', async (c) => {\n try {\n const db = c.env.DB\n const limit = parseInt(c.req.query('limit') || '10')\n\n // Get recent activities from activity_logs table\n const activityStmt = db.prepare(`\n SELECT\n a.id,\n a.action,\n a.resource_type,\n a.resource_id,\n a.details,\n a.created_at,\n u.email,\n u.first_name,\n u.last_name\n FROM activity_logs a\n LEFT JOIN users u ON a.user_id = u.id\n WHERE a.resource_type IN ('content', 'collections', 'users', 'media')\n ORDER BY a.created_at DESC\n LIMIT ?\n `)\n\n const { results } = await activityStmt.bind(limit).all()\n\n const recentActivity = (results || []).map((row: any) => {\n const userName = row.first_name && row.last_name\n ? `${row.first_name} ${row.last_name}`\n : row.email || 'System'\n\n let details: any = {}\n try {\n details = row.details ? JSON.parse(row.details) : {}\n } catch (e) {\n console.error('Error parsing activity details:', e)\n }\n\n return {\n id: row.id,\n type: row.resource_type,\n action: row.action,\n resource_id: row.resource_id,\n details,\n timestamp: new Date(Number(row.created_at)).toISOString(),\n user: userName\n }\n })\n\n return c.json({\n data: recentActivity,\n count: recentActivity.length,\n timestamp: new Date().toISOString()\n })\n } catch (error) {\n console.error('Error fetching recent activity:', error)\n return c.json({ error: 'Failed to fetch recent activity' }, 500)\n }\n})\n\n/**\n * Collection management schema\n */\nconst createCollectionSchema = z.object({\n name: z.string().min(1).max(255).regex(/^[a-z0-9_]+$/, 'Must contain only lowercase letters, numbers, and underscores'),\n displayName: z.string().min(1).max(255).optional(),\n display_name: z.string().min(1).max(255).optional(),\n description: z.string().optional()\n}).refine(data => data.displayName || data.display_name, {\n message: 'Either displayName or display_name is required',\n path: ['displayName']\n})\n\nconst updateCollectionSchema = z.object({\n display_name: z.string().min(1).max(255).optional(),\n description: z.string().optional(),\n is_active: z.boolean().optional()\n})\n\n/**\n * Get all collections\n * GET /admin/api/collections\n */\nadminApiRoutes.get('/collections', async (c) => {\n try {\n const db = c.env.DB\n const search = c.req.query('search') || ''\n const includeInactive = c.req.query('includeInactive') === 'true'\n\n let stmt\n let results\n\n if (search) {\n stmt = db.prepare(`\n SELECT id, name, display_name, description, created_at, updated_at, is_active, managed\n FROM collections\n WHERE ${includeInactive ? '1=1' : 'is_active = 1'}\n AND (name LIKE ? OR display_name LIKE ? OR description LIKE ?)\n ORDER BY created_at DESC\n `)\n const searchParam = `%${search}%`\n const queryResults = await stmt.bind(searchParam, searchParam, searchParam).all()\n results = queryResults.results\n } else {\n stmt = db.prepare(`\n SELECT id, name, display_name, description, created_at, updated_at, is_active, managed\n FROM collections\n ${includeInactive ? '' : 'WHERE is_active = 1'}\n ORDER BY created_at DESC\n `)\n const queryResults = await stmt.all()\n results = queryResults.results\n }\n\n // Get field counts\n const fieldCountStmt = db.prepare('SELECT collection_id, COUNT(*) as count FROM content_fields GROUP BY collection_id')\n const { results: fieldCountResults } = await fieldCountStmt.all()\n const fieldCounts = new Map((fieldCountResults || []).map((row: any) => [String(row.collection_id), Number(row.count)]))\n\n const collections = (results || []).map((row: any) => ({\n id: row.id,\n name: row.name,\n display_name: row.display_name,\n description: row.description,\n created_at: Number(row.created_at),\n updated_at: Number(row.updated_at),\n is_active: row.is_active === 1,\n managed: row.managed === 1,\n field_count: fieldCounts.get(String(row.id)) || 0\n }))\n\n return c.json({\n data: collections,\n count: collections.length,\n timestamp: new Date().toISOString()\n })\n } catch (error) {\n console.error('Error fetching collections:', error)\n return c.json({ error: 'Failed to fetch collections' }, 500)\n }\n})\n\n/**\n * Get single collection\n * GET /admin/api/collections/:id\n */\nadminApiRoutes.get('/collections/:id', async (c) => {\n try {\n const id = c.req.param('id')\n const db = c.env.DB\n\n const stmt = db.prepare('SELECT * FROM collections WHERE id = ?')\n const collection = await stmt.bind(id).first() as any\n\n if (!collection) {\n return c.json({ error: 'Collection not found' }, 404)\n }\n\n // Get collection fields\n const fieldsStmt = db.prepare(`\n SELECT * FROM content_fields\n WHERE collection_id = ?\n ORDER BY field_order ASC\n `)\n const { results: fieldsResults } = await fieldsStmt.bind(id).all()\n\n const fields = (fieldsResults || []).map((row: any) => ({\n id: row.id,\n field_name: row.field_name,\n field_type: row.field_type,\n field_label: row.field_label,\n field_options: row.field_options ? JSON.parse(row.field_options) : {},\n field_order: row.field_order,\n is_required: row.is_required === 1,\n is_searchable: row.is_searchable === 1,\n created_at: Number(row.created_at),\n updated_at: Number(row.updated_at)\n }))\n\n return c.json({\n id: collection.id,\n name: collection.name,\n display_name: collection.display_name,\n description: collection.description,\n is_active: collection.is_active === 1,\n managed: collection.managed === 1,\n schema: collection.schema ? JSON.parse(collection.schema) : null,\n created_at: Number(collection.created_at),\n updated_at: Number(collection.updated_at),\n fields\n })\n } catch (error) {\n console.error('Error fetching collection:', error)\n return c.json({ error: 'Failed to fetch collection' }, 500)\n }\n})\n\n/**\n * Get reference options for a collection\n * GET /admin/api/references?collection=&search=&limit=20&id=\n */\nadminApiRoutes.get('/references', async (c) => {\n try {\n const db = c.env.DB\n const url = new URL(c.req.url)\n const collectionParams = url.searchParams\n .getAll('collection')\n .flatMap((value) => value.split(','))\n .map((value) => value.trim())\n .filter(Boolean)\n const search = c.req.query('search') || ''\n const id = c.req.query('id') || ''\n const limit = Math.min(Number.parseInt(c.req.query('limit') || '20', 10) || 20, 100)\n\n if (collectionParams.length === 0) {\n return c.json({ error: 'Collection is required' }, 400)\n }\n\n const placeholders = collectionParams.map(() => '?').join(', ')\n const collectionStmt = db.prepare(`\n SELECT id, name, display_name\n FROM collections\n WHERE id IN (${placeholders}) OR name IN (${placeholders})\n `)\n const collectionResults = await collectionStmt\n .bind(...collectionParams, ...collectionParams)\n .all()\n const collections = (collectionResults.results || []) as any[]\n\n if (collections.length === 0) {\n return c.json({ error: 'Collection not found' }, 404)\n }\n\n const collectionById = Object.fromEntries(\n collections.map((entry) => [\n entry.id,\n {\n id: entry.id,\n name: entry.name,\n display_name: entry.display_name\n }\n ])\n )\n const collectionIds = collections.map((entry) => entry.id)\n\n if (id) {\n const idPlaceholders = collectionIds.map(() => '?').join(', ')\n const itemStmt = db.prepare(`\n SELECT id, title, slug, collection_id\n FROM content\n WHERE id = ? AND collection_id IN (${idPlaceholders})\n LIMIT 1\n `)\n const item = await itemStmt.bind(id, ...collectionIds).first() as any\n\n if (!item) {\n return c.json({ error: 'Reference not found' }, 404)\n }\n\n return c.json({\n data: {\n id: item.id,\n title: item.title,\n slug: item.slug,\n collection: collectionById[item.collection_id]\n }\n })\n }\n\n let stmt\n let results\n\n const listPlaceholders = collectionIds.map(() => '?').join(', ')\n const statusFilterValues = ['published']\n const statusClause = ` AND status IN (${statusFilterValues.map(() => '?').join(', ')})`\n\n if (search) {\n const searchParam = `%${search}%`\n stmt = db.prepare(`\n SELECT id, title, slug, status, updated_at, collection_id\n FROM content\n WHERE collection_id IN (${listPlaceholders})\n AND (title LIKE ? OR slug LIKE ?)\n ${statusClause}\n ORDER BY updated_at DESC\n LIMIT ?\n `)\n const queryResults = await stmt\n .bind(...collectionIds, searchParam, searchParam, ...statusFilterValues, limit)\n .all()\n results = queryResults.results\n } else {\n stmt = db.prepare(`\n SELECT id, title, slug, status, updated_at, collection_id\n FROM content\n WHERE collection_id IN (${listPlaceholders})\n ${statusClause}\n ORDER BY updated_at DESC\n LIMIT ?\n `)\n const queryResults = await stmt\n .bind(...collectionIds, ...statusFilterValues, limit)\n .all()\n results = queryResults.results\n }\n\n const items = (results || []).map((row: any) => ({\n id: row.id,\n title: row.title,\n slug: row.slug,\n status: row.status,\n updated_at: row.updated_at ? Number(row.updated_at) : null,\n collection: collectionById[row.collection_id]\n }))\n\n return c.json({\n data: items,\n count: items.length\n })\n } catch (error) {\n console.error('Error fetching reference options:', error)\n return c.json({ error: 'Failed to fetch references' }, 500)\n }\n})\n\n/**\n * Create collection\n * POST /admin/api/collections\n */\nadminApiRoutes.post('/collections', async (c) => {\n try {\n // Validate content type\n const contentType = c.req.header('Content-Type')\n if (!contentType || !contentType.includes('application/json')) {\n return c.json({ error: 'Content-Type must be application/json' }, 400)\n }\n\n let body\n try {\n body = await c.req.json()\n } catch (e) {\n return c.json({ error: 'Invalid JSON in request body' }, 400)\n }\n\n const validation = createCollectionSchema.safeParse(body)\n if (!validation.success) {\n return c.json({ error: 'Validation failed', details: validation.error.issues }, 400)\n }\n const validatedData = validation.data\n const db = c.env.DB\n const _user = c.get('user')\n\n // Handle both camelCase and snake_case for display_name\n const displayName = validatedData.displayName || validatedData.display_name || ''\n\n // Check if collection already exists\n const existingStmt = db.prepare('SELECT id FROM collections WHERE name = ?')\n const existing = await existingStmt.bind(validatedData.name).first()\n\n if (existing) {\n return c.json({ error: 'A collection with this name already exists' }, 400)\n }\n\n // Create basic schema\n const basicSchema = {\n type: \"object\",\n properties: {\n title: {\n type: \"string\",\n title: \"Title\",\n required: true\n },\n content: {\n type: \"string\",\n title: \"Content\",\n format: \"richtext\"\n },\n status: {\n type: \"string\",\n title: \"Status\",\n enum: [\"draft\", \"published\", \"archived\"],\n default: \"draft\"\n }\n },\n required: [\"title\"]\n }\n\n const collectionId = crypto.randomUUID()\n const now = Date.now()\n\n const insertStmt = db.prepare(`\n INSERT INTO collections (id, name, display_name, description, schema, is_active, created_at, updated_at)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?)\n `)\n\n await insertStmt.bind(\n collectionId,\n validatedData.name,\n displayName,\n validatedData.description || null,\n JSON.stringify(basicSchema),\n 1, // is_active\n now,\n now\n ).run()\n\n // Clear cache\n try {\n await c.env.CACHE_KV.delete('cache:collections:all')\n await c.env.CACHE_KV.delete(`cache:collection:${validatedData.name}`)\n } catch (e) {\n console.error('Error clearing cache:', e)\n }\n\n return c.json({\n id: collectionId,\n name: validatedData.name,\n displayName: displayName,\n description: validatedData.description,\n created_at: now\n }, 201)\n } catch (error) {\n console.error('Error creating collection:', error)\n return c.json({ error: 'Failed to create collection' }, 500)\n }\n})\n\n/**\n * Update collection\n * PATCH /admin/api/collections/:id\n */\nadminApiRoutes.patch('/collections/:id', async (c) => {\n try {\n const id = c.req.param('id')\n const body = await c.req.json()\n const validation = updateCollectionSchema.safeParse(body)\n if (!validation.success) {\n return c.json({ error: 'Validation failed', details: validation.error.issues }, 400)\n }\n const validatedData = validation.data\n const db = c.env.DB\n\n // Check if collection exists\n const checkStmt = db.prepare('SELECT * FROM collections WHERE id = ?')\n const existing = await checkStmt.bind(id).first() as any\n\n if (!existing) {\n return c.json({ error: 'Collection not found' }, 404)\n }\n\n // Build update query\n const updateFields: string[] = []\n const updateParams: any[] = []\n\n if (validatedData.display_name !== undefined) {\n updateFields.push('display_name = ?')\n updateParams.push(validatedData.display_name)\n }\n\n if (validatedData.description !== undefined) {\n updateFields.push('description = ?')\n updateParams.push(validatedData.description)\n }\n\n if (validatedData.is_active !== undefined) {\n updateFields.push('is_active = ?')\n updateParams.push(validatedData.is_active ? 1 : 0)\n }\n\n if (updateFields.length === 0) {\n return c.json({ error: 'No fields to update' }, 400)\n }\n\n updateFields.push('updated_at = ?')\n updateParams.push(Date.now())\n updateParams.push(id)\n\n const updateStmt = db.prepare(`\n UPDATE collections\n SET ${updateFields.join(', ')}\n WHERE id = ?\n `)\n\n await updateStmt.bind(...updateParams).run()\n\n // Clear cache\n try {\n await c.env.CACHE_KV.delete('cache:collections:all')\n await c.env.CACHE_KV.delete(`cache:collection:${existing.name}`)\n } catch (e) {\n console.error('Error clearing cache:', e)\n }\n\n return c.json({ message: 'Collection updated successfully' })\n } catch (error) {\n console.error('Error updating collection:', error)\n return c.json({ error: 'Failed to update collection' }, 500)\n }\n})\n\n/**\n * Delete collection\n * DELETE /admin/api/collections/:id\n */\nadminApiRoutes.delete('/collections/:id', async (c) => {\n try {\n const id = c.req.param('id')\n const db = c.env.DB\n\n // Check if collection exists\n const collectionStmt = db.prepare('SELECT name FROM collections WHERE id = ?')\n const collection = await collectionStmt.bind(id).first() as any\n\n if (!collection) {\n return c.json({ error: 'Collection not found' }, 404)\n }\n\n // Check if collection has content\n const contentStmt = db.prepare('SELECT COUNT(*) as count FROM content WHERE collection_id = ?')\n const contentResult = await contentStmt.bind(id).first() as any\n\n if (contentResult && contentResult.count > 0) {\n return c.json({\n error: `Cannot delete collection: it contains ${contentResult.count} content item(s). Delete all content first.`\n }, 400)\n }\n\n // Delete collection fields first\n const deleteFieldsStmt = db.prepare('DELETE FROM content_fields WHERE collection_id = ?')\n await deleteFieldsStmt.bind(id).run()\n\n // Delete collection\n const deleteStmt = db.prepare('DELETE FROM collections WHERE id = ?')\n await deleteStmt.bind(id).run()\n\n // Clear cache\n try {\n await c.env.CACHE_KV.delete('cache:collections:all')\n await c.env.CACHE_KV.delete(`cache:collection:${collection.name}`)\n } catch (e) {\n console.error('Error clearing cache:', e)\n }\n\n return c.json({ message: 'Collection deleted successfully' })\n } catch (error) {\n console.error('Error deleting collection:', error)\n return c.json({ error: 'Failed to delete collection' }, 500)\n }\n})\n\n// Migrations API endpoints\n// Get migration status\nadminApiRoutes.get('/migrations/status', async (c) => {\n try {\n const { MigrationService } = await import('../services/migrations')\n const db = c.env.DB\n const migrationService = new MigrationService(db)\n const status = await migrationService.getMigrationStatus()\n\n return c.json({\n success: true,\n data: status\n })\n } catch (error) {\n console.error('Error fetching migration status:', error)\n return c.json({\n success: false,\n error: 'Failed to fetch migration status'\n }, 500)\n }\n})\n\n// Run pending migrations\nadminApiRoutes.post('/migrations/run', async (c) => {\n try {\n const user = c.get('user')\n\n // Only allow admin users to run migrations\n if (!user || user.role !== 'admin') {\n return c.json({\n success: false,\n error: 'Unauthorized. Admin access required.'\n }, 403)\n }\n\n const { MigrationService } = await import('../services/migrations')\n const db = c.env.DB\n const migrationService = new MigrationService(db)\n const result = await migrationService.runPendingMigrations()\n\n return c.json({\n success: result.success,\n message: result.message,\n applied: result.applied\n })\n } catch (error) {\n console.error('Error running migrations:', error)\n return c.json({\n success: false,\n error: 'Failed to run migrations'\n }, 500)\n }\n})\n\n// Validate database schema\nadminApiRoutes.get('/migrations/validate', async (c) => {\n try {\n const { MigrationService } = await import('../services/migrations')\n const db = c.env.DB\n const migrationService = new MigrationService(db)\n const validation = await migrationService.validateSchema()\n\n return c.json({\n success: true,\n data: validation\n })\n } catch (error) {\n console.error('Error validating schema:', error)\n return c.json({\n success: false,\n error: 'Failed to validate schema'\n }, 500)\n }\n})\n\nexport default adminApiRoutes\n","import { renderAlert } from '../alert.template'\n\nexport interface LoginPageData {\n error?: string\n message?: string\n version?: string\n}\n\nexport function renderLoginPage(data: LoginPageData, demoLoginActive: boolean = false): string {\n return `\n \n \n \n \n \n Login - SonicJS AI \n \n \n \n \n \n \n \n \n \n
\n
\n
\n \n \n \n \n \n \n \n \n \n \n
\n
Welcome Back \n
Sign in to your account to continue
\n
\n\n \n
\n
\n \n ${data.error ? `
${renderAlert({ type: 'error', message: data.error })}
` : ''}\n ${data.message ? `
${renderAlert({ type: 'success', message: data.message })}
` : ''}\n\n \n
\n\n \n
\n\n \n
\n
\n\n \n
\n \n v${data.version || '0.1.0'}\n \n
\n
\n
\n\n ${demoLoginActive ? `\n \n ` : ''}\n \n \n `\n}","import { renderAlert } from '../alert.template'\n\nexport interface RegisterPageData {\n error?: string\n}\n\nexport function renderRegisterPage(data: RegisterPageData): string {\n return `\n \n \n \n \n \n Register - SonicJS AI \n \n \n \n \n \n \n \n \n \n
\n
\n
SonicJS AI \n
Create your account and get started
\n
\n\n \n
\n
\n \n ${data.error ? `
${renderAlert({ type: 'error', message: data.error })}
` : ''}\n\n \n
\n\n \n
\n\n
\n
\n
\n
\n \n \n `\n}","/**\n * Auth Validation Service\n *\n * Provides validation schemas for authentication operations\n */\n\nimport { z } from 'zod'\nimport type { D1Database } from '@cloudflare/workers-types'\n\n// In-memory cache for admin existence check (lazy initialization pattern)\nlet adminExistsCache: boolean | null = null\n\nexport interface AuthSettings {\n enablePasswordLogin?: boolean\n enableOAuthLogin?: boolean\n requireEmailVerification?: boolean\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n [key: string]: any\n}\n\n/**\n * Check if user registration is enabled in the auth plugin settings\n * @param db - D1 database instance\n * @returns true if registration is enabled, false if disabled\n */\nexport async function isRegistrationEnabled(db: D1Database): Promise {\n try {\n const plugin = await db.prepare('SELECT settings FROM plugins WHERE id = ?')\n .bind('core-auth')\n .first() as { settings: string } | null\n\n if (plugin?.settings) {\n // Parse settings and check registration.enabled\n // SQLite stores booleans as 0/1, so check for both false and 0\n const settings = JSON.parse(plugin.settings)\n const enabled = settings?.registration?.enabled\n return enabled !== false && enabled !== 0\n }\n return true // Default to enabled if no settings\n } catch {\n return true // Default to enabled on error\n }\n}\n\n/**\n * Check if this would be the first user registration (bootstrap scenario)\n * The first user should always be allowed to register even if registration is disabled\n * @param db - D1 database instance\n * @returns true if no users exist in the database\n */\nexport async function isFirstUserRegistration(db: D1Database): Promise {\n try {\n const result = await db.prepare('SELECT COUNT(*) as count FROM users').first() as { count: number } | null\n return result?.count === 0\n } catch {\n return false // Default to not first user on error\n }\n}\n\n/**\n * Check if an admin user exists in the database (with in-memory caching)\n * Uses lazy initialization - only queries DB on first call, then caches result\n * @param db - D1 database instance\n * @returns true if an admin user exists\n */\nexport async function checkAdminUserExists(db: D1Database): Promise {\n // Return cached value if already checked\n if (adminExistsCache !== null) {\n return adminExistsCache\n }\n\n try {\n const result = await db.prepare('SELECT id FROM users WHERE role = ?')\n .bind('admin')\n .first()\n adminExistsCache = !!result\n return adminExistsCache\n } catch {\n // On error (e.g., table doesn't exist yet), assume no admin exists\n return false\n }\n}\n\n/**\n * Set the admin exists cache to true\n * Call this after successfully creating the first admin user\n */\nexport function setAdminExists(): void {\n adminExistsCache = true\n}\n\n/**\n * Reset the admin exists cache (for testing purposes)\n */\nexport function resetAdminExistsCache(): void {\n adminExistsCache = null\n}\n\n/**\n * Auth Validation Service\n * Provides dynamic validation schemas for registration based on database settings\n */\nconst baseRegistrationSchema = z.object({\n email: z.string().email('Valid email is required'),\n password: z.string().min(8, 'Password must be at least 8 characters'),\n username: z.string().min(3, 'Username must be at least 3 characters').optional(),\n firstName: z.string().min(1, 'First name is required').optional(),\n lastName: z.string().min(1, 'Last name is required').optional()\n})\n\nexport type RegistrationSchema = typeof baseRegistrationSchema\nexport type RegistrationData = z.infer\n\nexport const authValidationService = {\n /**\n * Build registration schema dynamically based on auth settings\n * For now, returns a static schema with standard fields\n */\n async buildRegistrationSchema(_db: D1Database): Promise {\n // TODO: Load settings from database to make fields optional/required dynamically\n // For now, use a static schema with common registration fields\n return baseRegistrationSchema\n },\n\n /**\n * Generate default values for optional fields\n */\n generateDefaultValue(field: string, data: any): string {\n switch (field) {\n case 'username':\n // Generate username from email (part before @)\n return data.email ? data.email.split('@')[0] : `user${Date.now()}`\n case 'firstName':\n return 'User'\n case 'lastName':\n return data.email ? data.email.split('@')[0] : 'Account'\n default:\n return ''\n }\n }\n}\n","import { Hono } from 'hono'\n// import { zValidator } from '@hono/zod-validator'\nimport { z } from 'zod'\nimport { setCookie } from 'hono/cookie'\nimport { html } from 'hono/html'\nimport { AuthManager, requireAuth } from '../middleware'\nimport { renderLoginPage, LoginPageData } from '../templates/pages/auth-login.template'\nimport { renderRegisterPage, RegisterPageData } from '../templates/pages/auth-register.template'\nimport { getCacheService, CACHE_CONFIGS } from '../services'\nimport { authValidationService, isRegistrationEnabled, isFirstUserRegistration } from '../services/auth-validation'\nimport type { RegistrationData } from '../services/auth-validation'\nimport type { Bindings, Variables } from '../app'\n\nconst authRoutes = new Hono<{ Bindings: Bindings; Variables: Variables }>()\n\n// Login page (HTML form)\nauthRoutes.get('/login', async (c) => {\n const error = c.req.query('error')\n const message = c.req.query('message')\n \n const pageData: LoginPageData = {\n error: error || undefined,\n message: message || undefined,\n version: c.get('appVersion')\n }\n \n // Check if demo login plugin is active\n const db = c.env.DB\n let demoLoginActive = false\n try {\n const plugin = await db.prepare('SELECT * FROM plugins WHERE id = ? AND status = ?')\n .bind('demo-login-prefill', 'active')\n .first()\n demoLoginActive = !!plugin\n } catch (error) {\n // Ignore database errors - plugin system might not be initialized\n }\n \n return c.html(renderLoginPage(pageData, demoLoginActive))\n})\n\n// Registration page (HTML form)\nauthRoutes.get('/register', async (c) => {\n const db = c.env.DB\n\n // Check if this is the first user (bootstrap scenario) - always allow\n const isFirstUser = await isFirstUserRegistration(db)\n\n // If not first user, check if registration is enabled\n if (!isFirstUser) {\n const registrationEnabled = await isRegistrationEnabled(db)\n if (!registrationEnabled) {\n return c.redirect('/auth/login?error=Registration is currently disabled')\n }\n }\n\n const error = c.req.query('error')\n\n const pageData: RegisterPageData = {\n error: error || undefined\n }\n\n return c.html(renderRegisterPage(pageData))\n})\n\n// Login schema\nconst loginSchema = z.object({\n email: z.string().email('Valid email is required'),\n password: z.string().min(1, 'Password is required')\n})\n\n// Register new user\nauthRoutes.post('/register',\n async (c) => {\n try {\n const db = c.env.DB\n\n // Check if this is the first user (bootstrap scenario) - always allow\n const isFirstUser = await isFirstUserRegistration(db)\n\n // If not first user, check if registration is enabled\n if (!isFirstUser) {\n const registrationEnabled = await isRegistrationEnabled(db)\n if (!registrationEnabled) {\n return c.json({ error: 'Registration is currently disabled' }, 403)\n }\n }\n\n // Parse JSON with error handling\n let requestData\n try {\n requestData = await c.req.json()\n } catch (parseError) {\n return c.json({ error: 'Invalid JSON in request body' }, 400)\n }\n\n // Build and validate using dynamic schema\n const validationSchema = await authValidationService.buildRegistrationSchema(db)\n\n let validatedData: RegistrationData\n try {\n validatedData = await validationSchema.parseAsync(requestData)\n } catch (validationError: any) {\n return c.json({\n error: 'Validation failed',\n details: validationError.issues?.map((e: any) => e.message) || [validationError.message || 'Invalid request data']\n }, 400)\n }\n\n // Extract fields with defaults for optional ones\n const email = validatedData.email\n const password = validatedData.password\n const username = validatedData.username || authValidationService.generateDefaultValue('username', validatedData)\n const firstName = validatedData.firstName || authValidationService.generateDefaultValue('firstName', validatedData)\n const lastName = validatedData.lastName || authValidationService.generateDefaultValue('lastName', validatedData)\n\n // Normalize email to lowercase\n const normalizedEmail = email.toLowerCase()\n \n // Check if user already exists\n const existingUser = await db.prepare('SELECT id FROM users WHERE email = ? OR username = ?')\n .bind(normalizedEmail, username)\n .first()\n \n if (existingUser) {\n return c.json({ error: 'User with this email or username already exists' }, 400)\n }\n \n // Hash password\n const passwordHash = await AuthManager.hashPassword(password)\n \n // Create user\n const userId = crypto.randomUUID()\n const now = new Date()\n \n await db.prepare(`\n INSERT INTO users (id, email, username, first_name, last_name, password_hash, role, is_active, created_at, updated_at)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\n `).bind(\n userId,\n normalizedEmail,\n username,\n firstName,\n lastName,\n passwordHash,\n 'viewer', // Default role\n 1, // is_active\n now.getTime(),\n now.getTime()\n ).run()\n \n // Generate JWT token\n const token = await AuthManager.generateToken(userId, normalizedEmail, 'viewer')\n \n // Set HTTP-only cookie\n setCookie(c, 'auth_token', token, {\n httpOnly: true,\n secure: true,\n sameSite: 'Strict',\n maxAge: 60 * 60 * 24 // 24 hours\n })\n \n return c.json({\n user: {\n id: userId,\n email: normalizedEmail,\n username,\n firstName,\n lastName,\n role: 'viewer'\n },\n token\n }, 201)\n } catch (error) {\n console.error('Registration error:', error)\n // Return validation errors as 400, other errors as 500\n if (error instanceof Error && error.message.includes('validation')) {\n return c.json({ error: error.message }, 400)\n }\n return c.json({\n error: 'Registration failed',\n details: error instanceof Error ? error.message : String(error)\n }, 500)\n }\n }\n)\n\n// Login user\nauthRoutes.post('/login', async (c) => {\n try {\n const body = await c.req.json()\n const validation = loginSchema.safeParse(body)\n if (!validation.success) {\n return c.json({ error: 'Validation failed', details: validation.error.issues }, 400)\n }\n const { email, password } = validation.data\n const db = c.env.DB\n \n // Normalize email to lowercase\n const normalizedEmail = email.toLowerCase()\n \n // Find user with caching\n const cache = getCacheService(CACHE_CONFIGS.user!)\n let user = await cache.get(cache.generateKey('user', `email:${normalizedEmail}`))\n\n if (!user) {\n user = await db.prepare('SELECT * FROM users WHERE email = ? AND is_active = 1')\n .bind(normalizedEmail)\n .first() as any\n\n if (user) {\n // Cache the user for faster subsequent lookups\n await cache.set(cache.generateKey('user', `email:${normalizedEmail}`), user)\n await cache.set(cache.generateKey('user', user.id), user)\n }\n }\n\n if (!user) {\n return c.json({ error: 'Invalid email or password' }, 401)\n }\n \n // Verify password\n const isValidPassword = await AuthManager.verifyPassword(password, user.password_hash)\n if (!isValidPassword) {\n return c.json({ error: 'Invalid email or password' }, 401)\n }\n \n // Generate JWT token\n const token = await AuthManager.generateToken(user.id, user.email, user.role)\n \n // Set HTTP-only cookie\n setCookie(c, 'auth_token', token, {\n httpOnly: true,\n secure: true,\n sameSite: 'Strict',\n maxAge: 60 * 60 * 24 // 24 hours\n })\n \n // Update last login\n await db.prepare('UPDATE users SET last_login_at = ? WHERE id = ?')\n .bind(new Date().getTime(), user.id)\n .run()\n\n // Invalidate user cache on login\n await cache.delete(cache.generateKey('user', user.id))\n await cache.delete(cache.generateKey('user', `email:${normalizedEmail}`))\n\n return c.json({\n user: {\n id: user.id,\n email: user.email,\n username: user.username,\n firstName: user.first_name,\n lastName: user.last_name,\n role: user.role\n },\n token\n })\n } catch (error) {\n console.error('Login error:', error)\n return c.json({ error: 'Login failed' }, 500)\n }\n})\n\n// Logout user (both GET and POST for convenience)\nauthRoutes.post('/logout', (c) => {\n // Clear the auth cookie\n setCookie(c, 'auth_token', '', {\n httpOnly: true,\n secure: false, // Set to true in production with HTTPS\n sameSite: 'Strict',\n maxAge: 0 // Expire immediately\n })\n \n return c.json({ message: 'Logged out successfully' })\n})\n\nauthRoutes.get('/logout', (c) => {\n // Clear the auth cookie\n setCookie(c, 'auth_token', '', {\n httpOnly: true,\n secure: false, // Set to true in production with HTTPS\n sameSite: 'Strict',\n maxAge: 0 // Expire immediately\n })\n \n return c.redirect('/auth/login?message=You have been logged out successfully')\n})\n\n// Get current user\nauthRoutes.get('/me', requireAuth(), async (c) => {\n try {\n // This would need the auth middleware applied\n const user = c.get('user')\n \n if (!user) {\n return c.json({ error: 'Not authenticated' }, 401)\n }\n \n const db = c.env.DB\n const userData = await db.prepare('SELECT id, email, username, first_name, last_name, role, created_at FROM users WHERE id = ?')\n .bind(user.userId)\n .first()\n \n if (!userData) {\n return c.json({ error: 'User not found' }, 404)\n }\n \n return c.json({ user: userData })\n } catch (error) {\n console.error('Get user error:', error)\n return c.json({ error: 'Failed to get user' }, 500)\n }\n})\n\n// Refresh token\nauthRoutes.post('/refresh', requireAuth(), async (c) => {\n try {\n const user = c.get('user')\n \n if (!user) {\n return c.json({ error: 'Not authenticated' }, 401)\n }\n \n // Generate new token\n const token = await AuthManager.generateToken(user.userId, user.email, user.role)\n \n // Set new cookie\n setCookie(c, 'auth_token', token, {\n httpOnly: true,\n secure: true,\n sameSite: 'Strict',\n maxAge: 60 * 60 * 24 // 24 hours\n })\n \n return c.json({ token })\n } catch (error) {\n console.error('Token refresh error:', error)\n return c.json({ error: 'Token refresh failed' }, 500)\n }\n})\n\n// Form-based registration handler (for HTML forms)\nauthRoutes.post('/register/form', async (c) => {\n try {\n const db = c.env.DB\n\n // Check if this is the first user (bootstrap scenario) - always allow\n const isFirstUser = await isFirstUserRegistration(db)\n\n // If not first user, check if registration is enabled\n if (!isFirstUser) {\n const registrationEnabled = await isRegistrationEnabled(db)\n if (!registrationEnabled) {\n return c.html(html`\n \n Registration is currently disabled. Please contact an administrator.\n
\n `)\n }\n }\n\n const formData = await c.req.formData()\n\n // Extract form data\n const requestData = {\n email: formData.get('email') as string,\n password: formData.get('password') as string,\n username: formData.get('username') as string,\n firstName: formData.get('firstName') as string,\n lastName: formData.get('lastName') as string,\n }\n\n // Normalize email to lowercase\n const normalizedEmail = requestData.email?.toLowerCase()\n requestData.email = normalizedEmail\n\n // Build and validate using dynamic schema\n const validationSchema = await authValidationService.buildRegistrationSchema(db)\n const validation = await validationSchema.safeParseAsync(requestData)\n\n if (!validation.success) {\n return c.html(html`\n \n ${validation.error.issues.map((err: { message: string }) => err.message).join(', ')}\n
\n `)\n }\n\n const validatedData: RegistrationData = validation.data\n\n // Extract fields with defaults for optional ones\n // const email = validatedData.email\n const password = validatedData.password\n const username = validatedData.username || authValidationService.generateDefaultValue('username', validatedData)\n const firstName = validatedData.firstName || authValidationService.generateDefaultValue('firstName', validatedData)\n const lastName = validatedData.lastName || authValidationService.generateDefaultValue('lastName', validatedData)\n \n // Check if user already exists\n const existingUser = await db.prepare('SELECT id FROM users WHERE email = ? OR username = ?')\n .bind(normalizedEmail, username)\n .first()\n \n if (existingUser) {\n return c.html(html`\n \n User with this email or username already exists\n
\n `)\n }\n \n // Hash password\n const passwordHash = await AuthManager.hashPassword(password)\n\n // Determine role: first user gets admin, others get viewer\n const role = isFirstUser ? 'admin' : 'viewer'\n\n // Create user\n const userId = crypto.randomUUID()\n const now = new Date()\n\n await db.prepare(`\n INSERT INTO users (id, email, username, first_name, last_name, password_hash, role, is_active, created_at, updated_at)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\n `).bind(\n userId,\n normalizedEmail,\n username,\n firstName,\n lastName,\n passwordHash,\n role,\n 1, // is_active\n now.getTime(),\n now.getTime()\n ).run()\n\n // Generate JWT token\n const token = await AuthManager.generateToken(userId, normalizedEmail, role)\n\n // Set HTTP-only cookie\n setCookie(c, 'auth_token', token, {\n httpOnly: true,\n secure: false, // Set to true in production with HTTPS\n sameSite: 'Strict',\n maxAge: 60 * 60 * 24 // 24 hours\n })\n\n // Redirect based on role\n const redirectUrl = role === 'admin' ? '/admin/dashboard' : '/admin/dashboard'\n\n return c.html(html`\n \n Account created successfully! Redirecting...\n \n
\n `)\n } catch (error) {\n console.error('Registration error:', error)\n return c.html(html`\n \n Registration failed. Please try again.\n
\n `)\n }\n})\n\n// Form-based login handler (for HTML forms)\nauthRoutes.post('/login/form', async (c) => {\n try {\n const formData = await c.req.formData()\n const email = formData.get('email') as string\n const password = formData.get('password') as string\n\n // Normalize email to lowercase\n const normalizedEmail = email.toLowerCase()\n\n // Validate the data\n const validation = loginSchema.safeParse({ email: normalizedEmail, password })\n\n if (!validation.success) {\n return c.html(html`\n \n ${validation.error.issues.map((err: { message: string }) => err.message).join(', ')}\n
\n `)\n }\n\n const db = c.env.DB\n \n // Find user\n const user = await db.prepare('SELECT * FROM users WHERE email = ? AND is_active = 1')\n .bind(normalizedEmail)\n .first() as any\n \n if (!user) {\n return c.html(html`\n \n Invalid email or password\n
\n `)\n }\n \n // Verify password\n const isValidPassword = await AuthManager.verifyPassword(password, user.password_hash)\n if (!isValidPassword) {\n return c.html(html`\n \n Invalid email or password\n
\n `)\n }\n \n // Generate JWT token\n const token = await AuthManager.generateToken(user.id, user.email, user.role)\n \n // Set HTTP-only cookie\n setCookie(c, 'auth_token', token, {\n httpOnly: true,\n secure: false, // Set to true in production with HTTPS\n sameSite: 'Strict',\n maxAge: 60 * 60 * 24 // 24 hours\n })\n \n // Update last login\n await db.prepare('UPDATE users SET last_login_at = ? WHERE id = ?')\n .bind(new Date().getTime(), user.id)\n .run()\n \n return c.html(html`\n \n `)\n } catch (error) {\n console.error('Login error:', error)\n return c.html(html`\n \n Login failed. Please try again.\n
\n `)\n }\n})\n\n// Test seeding endpoint (only for development/testing)\nauthRoutes.post('/seed-admin', async (c) => {\n try {\n const db = c.env.DB\n \n // First ensure the users table exists\n await db.prepare(`\n CREATE TABLE IF NOT EXISTS users (\n id TEXT PRIMARY KEY,\n email TEXT NOT NULL UNIQUE,\n username TEXT NOT NULL UNIQUE,\n first_name TEXT NOT NULL,\n last_name TEXT NOT NULL,\n password_hash TEXT,\n role TEXT NOT NULL DEFAULT 'viewer',\n avatar TEXT,\n is_active INTEGER NOT NULL DEFAULT 1,\n last_login_at INTEGER,\n created_at INTEGER NOT NULL,\n updated_at INTEGER NOT NULL\n )\n `).run()\n \n // Check if admin user already exists\n const existingAdmin = await db.prepare('SELECT id FROM users WHERE email = ? OR username = ?')\n .bind('admin@sonicjs.com', 'admin')\n .first()\n\n if (existingAdmin) {\n // Update the password to ensure it's correct for testing\n const passwordHash = await AuthManager.hashPassword('sonicjs!')\n await db.prepare('UPDATE users SET password_hash = ?, updated_at = ? WHERE id = ?')\n .bind(passwordHash, Date.now(), existingAdmin.id)\n .run()\n\n return c.json({\n message: 'Admin user already exists (password updated)',\n user: {\n id: existingAdmin.id,\n email: 'admin@sonicjs.com',\n username: 'admin',\n role: 'admin'\n }\n })\n }\n\n // Hash password\n const passwordHash = await AuthManager.hashPassword('sonicjs!')\n \n // Create admin user\n const userId = 'admin-user-id'\n const now = Date.now()\n const adminEmail = 'admin@sonicjs.com'.toLowerCase()\n \n await db.prepare(`\n INSERT INTO users (id, email, username, first_name, last_name, password_hash, role, is_active, created_at, updated_at)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\n `).bind(\n userId,\n adminEmail,\n 'admin',\n 'Admin',\n 'User',\n passwordHash,\n 'admin',\n 1, // is_active\n now,\n now\n ).run()\n \n return c.json({ \n message: 'Admin user created successfully',\n user: {\n id: userId,\n email: adminEmail,\n username: 'admin',\n role: 'admin'\n },\n passwordHash: passwordHash // For debugging\n })\n } catch (error) {\n console.error('Seed admin error:', error)\n return c.json({ error: 'Failed to create admin user', details: error instanceof Error ? error.message : String(error) }, 500)\n }\n})\n\n\n// Accept invitation page\nauthRoutes.get('/accept-invitation', async (c) => {\n try {\n const token = c.req.query('token')\n \n if (!token) {\n return c.html(`\n \n Invalid Invitation \n \n Invalid Invitation \n The invitation link is invalid or has expired.
\n Go to Login \n \n \n `)\n }\n\n const db = c.env.DB\n \n // Check if invitation token is valid\n const userStmt = db.prepare(`\n SELECT id, email, first_name, last_name, role, invited_at\n FROM users \n WHERE invitation_token = ? AND is_active = 0\n `)\n const invitedUser = await userStmt.bind(token).first() as any\n\n if (!invitedUser) {\n return c.html(`\n \n Invalid Invitation \n \n Invalid Invitation \n The invitation link is invalid or has expired.
\n Go to Login \n \n \n `)\n }\n\n // Check if invitation is expired (7 days)\n const invitationAge = Date.now() - invitedUser.invited_at\n const maxAge = 7 * 24 * 60 * 60 * 1000 // 7 days\n \n if (invitationAge > maxAge) {\n return c.html(`\n \n Invitation Expired \n \n Invitation Expired \n This invitation has expired. Please contact your administrator for a new invitation.
\n Go to Login \n \n \n `)\n }\n\n // Show invitation acceptance form\n return c.html(`\n \n \n \n \n \n Accept Invitation - SonicJS AI \n \n \n \n \n \n
\n
\n
\n
Accept Invitation \n
Complete your account setup
\n
\n You've been invited as ${invitedUser.first_name} ${invitedUser.last_name} \n ${invitedUser.email} \n ${invitedUser.role} \n
\n
\n\n
\n
\n
\n \n \n `)\n\n } catch (error) {\n console.error('Accept invitation page error:', error)\n return c.html(`\n \n Error \n \n Error \n An error occurred while processing your invitation.
\n Go to Login \n \n \n `)\n }\n})\n\n// Process invitation acceptance\nauthRoutes.post('/accept-invitation', async (c) => {\n try {\n const formData = await c.req.formData()\n const token = formData.get('token')?.toString()\n const username = formData.get('username')?.toString()?.trim()\n const password = formData.get('password')?.toString()\n const confirmPassword = formData.get('confirm_password')?.toString()\n\n if (!token || !username || !password || !confirmPassword) {\n return c.json({ error: 'All fields are required' }, 400)\n }\n\n if (password !== confirmPassword) {\n return c.json({ error: 'Passwords do not match' }, 400)\n }\n\n if (password.length < 8) {\n return c.json({ error: 'Password must be at least 8 characters long' }, 400)\n }\n\n const db = c.env.DB\n\n // Check if invitation token is valid\n const userStmt = db.prepare(`\n SELECT id, email, first_name, last_name, role, invited_at\n FROM users \n WHERE invitation_token = ? AND is_active = 0\n `)\n const invitedUser = await userStmt.bind(token).first() as any\n\n if (!invitedUser) {\n return c.json({ error: 'Invalid or expired invitation' }, 400)\n }\n\n // Check if invitation is expired (7 days)\n const invitationAge = Date.now() - invitedUser.invited_at\n const maxAge = 7 * 24 * 60 * 60 * 1000 // 7 days\n \n if (invitationAge > maxAge) {\n return c.json({ error: 'Invitation has expired' }, 400)\n }\n\n // Check if username is available\n const existingUsernameStmt = db.prepare(`\n SELECT id FROM users WHERE username = ? AND id != ?\n `)\n const existingUsername = await existingUsernameStmt.bind(username, invitedUser.id).first()\n\n if (existingUsername) {\n return c.json({ error: 'Username is already taken' }, 400)\n }\n\n // Hash password\n const passwordHash = await AuthManager.hashPassword(password)\n\n // Activate user account\n const updateStmt = db.prepare(`\n UPDATE users SET \n username = ?,\n password_hash = ?,\n is_active = 1,\n email_verified = 1,\n invitation_token = NULL,\n accepted_invitation_at = ?,\n updated_at = ?\n WHERE id = ?\n `)\n\n await updateStmt.bind(\n username,\n passwordHash,\n Date.now(),\n Date.now(),\n invitedUser.id\n ).run()\n\n // Generate JWT token for auto-login\n const authToken = await AuthManager.generateToken(invitedUser.id, invitedUser.email, invitedUser.role)\n \n // Set HTTP-only cookie\n setCookie(c, 'auth_token', authToken, {\n httpOnly: true,\n secure: true,\n sameSite: 'Strict',\n maxAge: 60 * 60 * 24 // 24 hours\n })\n\n // Log the activity (TODO: implement activity logging)\n // Activity logging is deferred until utils/log-activity is implemented\n\n // Redirect to admin dashboard\n return c.redirect('/admin/dashboard?welcome=true')\n\n } catch (error) {\n console.error('Accept invitation error:', error)\n return c.json({ error: 'Failed to accept invitation' }, 500)\n }\n})\n\n// Request password reset\nauthRoutes.post('/request-password-reset', async (c) => {\n try {\n const formData = await c.req.formData()\n const email = formData.get('email')?.toString()?.trim()?.toLowerCase()\n\n if (!email) {\n return c.json({ error: 'Email is required' }, 400)\n }\n\n // Validate email format\n const emailRegex = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/\n if (!emailRegex.test(email)) {\n return c.json({ error: 'Please enter a valid email address' }, 400)\n }\n\n const db = c.env.DB\n\n // Check if user exists and is active\n const userStmt = db.prepare(`\n SELECT id, email, first_name, last_name FROM users \n WHERE email = ? AND is_active = 1\n `)\n const user = await userStmt.bind(email).first() as any\n\n // Always return success to prevent email enumeration\n if (!user) {\n return c.json({\n success: true,\n message: 'If an account with this email exists, a password reset link has been sent.'\n })\n }\n\n // Generate password reset token (expires in 1 hour)\n const resetToken = crypto.randomUUID()\n const resetExpires = Date.now() + (60 * 60 * 1000) // 1 hour\n\n // Update user with reset token\n const updateStmt = db.prepare(`\n UPDATE users SET \n password_reset_token = ?,\n password_reset_expires = ?,\n updated_at = ?\n WHERE id = ?\n `)\n\n await updateStmt.bind(\n resetToken,\n resetExpires,\n Date.now(),\n user.id\n ).run()\n\n // Log the activity (TODO: implement activity logging)\n // Activity logging is deferred until utils/log-activity is implemented\n\n // In a real implementation, you would send an email here\n // For now, we'll return the reset link for development\n const resetLink = `${c.req.header('origin') || 'http://localhost:8787'}/auth/reset-password?token=${resetToken}`\n\n return c.json({\n success: true,\n message: 'If an account with this email exists, a password reset link has been sent.',\n reset_link: resetLink // In production, this would be sent via email\n })\n\n } catch (error) {\n console.error('Password reset request error:', error)\n return c.json({ error: 'Failed to process password reset request' }, 500)\n }\n})\n\n// Show password reset form\nauthRoutes.get('/reset-password', async (c) => {\n try {\n const token = c.req.query('token')\n \n if (!token) {\n return c.html(`\n \n Invalid Reset Link \n \n Invalid Reset Link \n The password reset link is invalid or has expired.
\n Go to Login \n \n \n `)\n }\n\n const db = c.env.DB\n \n // Check if reset token is valid and not expired\n const userStmt = db.prepare(`\n SELECT id, email, first_name, last_name, password_reset_expires\n FROM users \n WHERE password_reset_token = ? AND is_active = 1\n `)\n const user = await userStmt.bind(token).first() as any\n\n if (!user) {\n return c.html(`\n \n Invalid Reset Link \n \n Invalid Reset Link \n The password reset link is invalid or has already been used.
\n Go to Login \n \n \n `)\n }\n\n // Check if token is expired\n if (Date.now() > user.password_reset_expires) {\n return c.html(`\n \n Reset Link Expired \n \n Reset Link Expired \n The password reset link has expired. Please request a new one.
\n Go to Login \n \n \n `)\n }\n\n // Show password reset form\n return c.html(`\n \n \n \n \n \n Reset Password - SonicJS AI \n \n \n \n \n \n
\n
\n
\n
Reset Password \n
Choose a new password for your account
\n
\n Reset password for ${user.first_name} ${user.last_name} \n ${user.email} \n
\n
\n\n
\n\n
\n
\n
\n \n \n `)\n\n } catch (error) {\n console.error('Password reset page error:', error)\n return c.html(`\n \n Error \n \n Error \n An error occurred while processing your password reset.
\n Go to Login \n \n \n `)\n }\n})\n\n// Process password reset\nauthRoutes.post('/reset-password', async (c) => {\n try {\n const formData = await c.req.formData()\n const token = formData.get('token')?.toString()\n const password = formData.get('password')?.toString()\n const confirmPassword = formData.get('confirm_password')?.toString()\n\n if (!token || !password || !confirmPassword) {\n return c.json({ error: 'All fields are required' }, 400)\n }\n\n if (password !== confirmPassword) {\n return c.json({ error: 'Passwords do not match' }, 400)\n }\n\n if (password.length < 8) {\n return c.json({ error: 'Password must be at least 8 characters long' }, 400)\n }\n\n const db = c.env.DB\n\n // Check if reset token is valid and not expired\n const userStmt = db.prepare(`\n SELECT id, email, password_hash, password_reset_expires\n FROM users\n WHERE password_reset_token = ? AND is_active = 1\n `)\n const user = await userStmt.bind(token).first() as any\n\n if (!user) {\n return c.json({ error: 'Invalid or expired reset token' }, 400)\n }\n\n // Check if token is expired\n if (Date.now() > user.password_reset_expires) {\n return c.json({ error: 'Reset token has expired' }, 400)\n }\n\n // Hash new password\n const newPasswordHash = await AuthManager.hashPassword(password)\n\n // Store old password in history (skip if table doesn't exist)\n try {\n const historyStmt = db.prepare(`\n INSERT INTO password_history (id, user_id, password_hash, created_at)\n VALUES (?, ?, ?, ?)\n `)\n await historyStmt.bind(\n crypto.randomUUID(),\n user.id,\n user.password_hash,\n Date.now()\n ).run()\n } catch (historyError) {\n // Password history table may not exist yet\n console.warn('Could not store password history:', historyError)\n }\n\n // Update user password and clear reset token\n const updateStmt = db.prepare(`\n UPDATE users SET\n password_hash = ?,\n password_reset_token = NULL,\n password_reset_expires = NULL,\n updated_at = ?\n WHERE id = ?\n `)\n\n await updateStmt.bind(\n newPasswordHash,\n Date.now(),\n user.id\n ).run()\n\n // Log the activity (TODO: implement activity logging)\n // Activity logging is deferred until utils/log-activity is implemented\n\n // Redirect to login with success message\n return c.redirect('/auth/login?message=Password reset successfully. Please log in with your new password.')\n\n } catch (error) {\n console.error('Password reset error:', error)\n return c.json({ error: 'Failed to reset password' }, 500)\n }\n})\n\nexport default authRoutes\n","/**\n * Test Cleanup Routes\n *\n * Provides endpoints to clean up test data after e2e tests\n * WARNING: These endpoints should only be available in development/test environments\n */\n\nimport { Hono } from 'hono'\nimport type { Context } from 'hono'\nimport type { D1Database } from '@cloudflare/workers-types'\n\nconst app = new Hono()\n\n/**\n * Clean up all test data (collections, content, users except admin)\n * POST /test-cleanup\n */\napp.post('/test-cleanup', async (c: Context) => {\n const db = c.env.DB as D1Database\n\n // Only allow in development/test environments\n if (c.env.ENVIRONMENT === 'production') {\n return c.json({ error: 'Cleanup endpoint not available in production' }, 403)\n }\n\n try {\n let deletedCount = 0\n\n // Use pattern-based deletes to avoid SQL variable limits\n // This approach uses subqueries instead of building large IN lists\n\n // Step 1: Delete child data for test content (by pattern)\n await db.prepare(`\n DELETE FROM content_versions\n WHERE content_id IN (\n SELECT id FROM content\n WHERE title LIKE 'Test %' OR title LIKE '%E2E%' OR title LIKE '%Playwright%' OR title LIKE '%Sample%'\n )\n `).run()\n\n await db.prepare(`\n DELETE FROM workflow_history\n WHERE content_id IN (\n SELECT id FROM content\n WHERE title LIKE 'Test %' OR title LIKE '%E2E%' OR title LIKE '%Playwright%' OR title LIKE '%Sample%'\n )\n `).run()\n\n // Note: content_data table may not exist in all schemas\n try {\n await db.prepare(`\n DELETE FROM content_data\n WHERE content_id IN (\n SELECT id FROM content\n WHERE title LIKE 'Test %' OR title LIKE '%E2E%' OR title LIKE '%Playwright%' OR title LIKE '%Sample%'\n )\n `).run()\n } catch (e) {\n // Table doesn't exist, skip\n }\n\n // Step 2: Delete test content by pattern\n const contentResult = await db.prepare(`\n DELETE FROM content\n WHERE title LIKE 'Test %' OR title LIKE '%E2E%' OR title LIKE '%Playwright%' OR title LIKE '%Sample%'\n `).run()\n deletedCount += contentResult.meta?.changes || 0\n\n // Step 3: Delete child data for test users\n await db.prepare(`\n DELETE FROM api_tokens\n WHERE user_id IN (\n SELECT id FROM users\n WHERE email != 'admin@sonicjs.com' AND (email LIKE '%test%' OR email LIKE '%example.com%')\n )\n `).run()\n\n await db.prepare(`\n DELETE FROM media\n WHERE uploaded_by IN (\n SELECT id FROM users\n WHERE email != 'admin@sonicjs.com' AND (email LIKE '%test%' OR email LIKE '%example.com%')\n )\n `).run()\n\n // Step 4: Delete test users\n const usersResult = await db.prepare(`\n DELETE FROM users\n WHERE email != 'admin@sonicjs.com' AND (email LIKE '%test%' OR email LIKE '%example.com%')\n `).run()\n deletedCount += usersResult.meta?.changes || 0\n\n // Step 5: Delete child data for test collections\n try {\n await db.prepare(`\n DELETE FROM collection_fields\n WHERE collection_id IN (\n SELECT id FROM collections\n WHERE name LIKE 'test_%' OR name IN ('blog_posts', 'test_collection', 'products', 'articles')\n )\n `).run()\n } catch (e) {\n // Table doesn't exist\n }\n\n // Delete remaining content from test collections\n await db.prepare(`\n DELETE FROM content\n WHERE collection_id IN (\n SELECT id FROM collections\n WHERE name LIKE 'test_%' OR name IN ('blog_posts', 'test_collection', 'products', 'articles')\n )\n `).run()\n\n // Step 6: Delete test collections\n const collectionsResult = await db.prepare(`\n DELETE FROM collections\n WHERE name LIKE 'test_%' OR name IN ('blog_posts', 'test_collection', 'products', 'articles')\n `).run()\n deletedCount += collectionsResult.meta?.changes || 0\n\n // Step 7: Clean up orphaned data (skip if tables don't exist)\n try {\n await db.prepare(`\n DELETE FROM content_data WHERE content_id NOT IN (SELECT id FROM content)\n `).run()\n } catch (e) {\n // Table doesn't exist\n }\n\n try {\n await db.prepare(`\n DELETE FROM collection_fields WHERE collection_id NOT IN (SELECT id FROM collections)\n `).run()\n } catch (e) {\n // Table doesn't exist\n }\n\n try {\n await db.prepare(`\n DELETE FROM content_versions WHERE content_id NOT IN (SELECT id FROM content)\n `).run()\n } catch (e) {\n // Table doesn't exist\n }\n\n try {\n await db.prepare(`\n DELETE FROM workflow_history WHERE content_id NOT IN (SELECT id FROM content)\n `).run()\n } catch (e) {\n // Table doesn't exist\n }\n\n // Step 8: Delete old activity logs (keep only last 100)\n await db.prepare(`\n DELETE FROM activity_logs\n WHERE id NOT IN (\n SELECT id FROM activity_logs\n ORDER BY created_at DESC\n LIMIT 100\n )\n `).run()\n\n return c.json({\n success: true,\n deletedCount,\n message: 'Test data cleaned up successfully'\n })\n } catch (error) {\n console.error('Test cleanup error:', error)\n return c.json({\n success: false,\n error: error instanceof Error ? error.message : 'Unknown error'\n }, 500)\n }\n})\n\n/**\n * Clean up test users only\n * POST /test-cleanup/users\n */\napp.post('/test-cleanup/users', async (c: Context) => {\n const db = c.env.DB as D1Database\n\n // Only allow in development/test environments\n if (c.env.ENVIRONMENT === 'production') {\n return c.json({ error: 'Cleanup endpoint not available in production' }, 403)\n }\n\n try {\n // Delete test users (preserve admin)\n const result = await db.prepare(`\n DELETE FROM users\n WHERE email != 'admin@sonicjs.com'\n AND (\n email LIKE '%test%'\n OR email LIKE '%example.com%'\n OR first_name = 'Test'\n )\n `).run()\n\n return c.json({\n success: true,\n deletedCount: result.meta?.changes || 0,\n message: 'Test users cleaned up successfully'\n })\n } catch (error) {\n console.error('User cleanup error:', error)\n return c.json({\n success: false,\n error: error instanceof Error ? error.message : 'Unknown error'\n }, 500)\n }\n})\n\n/**\n * Clean up test collections only\n * POST /test-cleanup/collections\n */\napp.post('/test-cleanup/collections', async (c: Context) => {\n const db = c.env.DB as D1Database\n\n // Only allow in development/test environments\n if (c.env.ENVIRONMENT === 'production') {\n return c.json({ error: 'Cleanup endpoint not available in production' }, 403)\n }\n\n try {\n let deletedCount = 0\n\n // Get test collection IDs first\n const collections = await db.prepare(`\n SELECT id FROM collections\n WHERE name LIKE 'test_%'\n OR name IN ('blog_posts', 'test_collection', 'products', 'articles')\n `).all()\n\n if (collections.results && collections.results.length > 0) {\n const collectionIds = collections.results.map((c: any) => c.id)\n\n // Delete associated fields\n for (const id of collectionIds) {\n await db.prepare('DELETE FROM collection_fields WHERE collection_id = ?').bind(id).run()\n }\n\n // Delete associated content\n for (const id of collectionIds) {\n await db.prepare('DELETE FROM content WHERE collection_id = ?').bind(id).run()\n }\n\n // Delete the collections\n const result = await db.prepare(`\n DELETE FROM collections\n WHERE id IN (${collectionIds.map(() => '?').join(',')})\n `).bind(...collectionIds).run()\n\n deletedCount = result.meta?.changes || 0\n }\n\n return c.json({\n success: true,\n deletedCount,\n message: 'Test collections cleaned up successfully'\n })\n } catch (error) {\n console.error('Collection cleanup error:', error)\n return c.json({\n success: false,\n error: error instanceof Error ? error.message : 'Unknown error'\n }, 500)\n }\n})\n\n/**\n * Clean up test content only\n * POST /test-cleanup/content\n */\napp.post('/test-cleanup/content', async (c: Context) => {\n const db = c.env.DB as D1Database\n\n // Only allow in development/test environments\n if (c.env.ENVIRONMENT === 'production') {\n return c.json({ error: 'Cleanup endpoint not available in production' }, 403)\n }\n\n try {\n // Delete test content\n const result = await db.prepare(`\n DELETE FROM content\n WHERE title LIKE 'Test %'\n OR title LIKE '%E2E%'\n OR title LIKE '%Playwright%'\n OR title LIKE '%Sample%'\n `).run()\n\n // Clean up orphaned content_data\n await db.prepare(`\n DELETE FROM content_data\n WHERE content_id NOT IN (SELECT id FROM content)\n `).run()\n\n return c.json({\n success: true,\n deletedCount: result.meta?.changes || 0,\n message: 'Test content cleaned up successfully'\n })\n } catch (error) {\n console.error('Content cleanup error:', error)\n return c.json({\n success: false,\n error: error instanceof Error ? error.message : 'Unknown error'\n }, 500)\n }\n})\n\nexport default app\n","import { renderAdminLayoutCatalyst, AdminLayoutCatalystData } from '../layouts/admin-layout-catalyst.template'\nimport { renderAlert } from '../alert.template'\nimport { renderDynamicField, renderFieldGroup, FieldDefinition } from '../components/dynamic-field.template'\nimport { renderConfirmationDialog, getConfirmationDialogScript } from '../confirmation-dialog.template'\nimport { getTinyMCEScript, getTinyMCEInitScript } from '../../plugins/available/tinymce-plugin'\nimport { getQuillCDN, getQuillInitScript } from '../../plugins/core-plugins/quill-editor'\nimport { getMDXEditorScripts, getMDXEditorInitScript } from '../../plugins/available/easy-mdx'\n\nexport interface Collection {\n id: string\n name: string\n display_name: string\n description?: string\n schema: any\n}\n\nexport interface ContentFormData {\n id?: string\n title?: string\n slug?: string\n data?: any\n status?: string\n scheduled_publish_at?: number\n scheduled_unpublish_at?: number\n review_status?: string\n meta_title?: string\n meta_description?: string\n collection: Collection\n fields: FieldDefinition[]\n isEdit?: boolean\n error?: string\n success?: string\n validationErrors?: Record\n workflowEnabled?: boolean // New flag to indicate if workflow plugin is active\n tinymceEnabled?: boolean // Flag to indicate if TinyMCE plugin is active\n tinymceSettings?: {\n apiKey?: string\n defaultHeight?: number\n defaultToolbar?: string\n skin?: string\n }\n quillEnabled?: boolean // Flag to indicate if Quill plugin is active\n quillSettings?: {\n version?: string\n defaultHeight?: number\n defaultToolbar?: string\n theme?: string\n }\n mdxeditorEnabled?: boolean // Flag to indicate if MDXEditor plugin is active\n mdxeditorSettings?: {\n defaultHeight?: number\n theme?: string\n toolbar?: string\n placeholder?: string\n }\n referrerParams?: string // URL parameters to preserve filters when returning to list\n user?: {\n name: string\n email: string\n role: string\n }\n version?: string\n}\n\nexport function renderContentFormPage(data: ContentFormData): string {\n const isEdit = data.isEdit || !!data.id\n const title = isEdit ? `Edit: ${data.title || 'Content'}` : `New ${data.collection.display_name}`\n\n // Construct back URL with preserved filters\n const backUrl = data.referrerParams\n ? `/admin/content?${data.referrerParams}`\n : `/admin/content?collection=${data.collection.id}`\n\n // Group fields by category\n const coreFields = data.fields.filter(f => ['title', 'slug', 'content'].includes(f.field_name))\n const contentFields = data.fields.filter(f => !['title', 'slug', 'content'].includes(f.field_name) && !f.field_name.startsWith('meta_'))\n const metaFields = data.fields.filter(f => f.field_name.startsWith('meta_'))\n \n // Helper function to get field value - title and slug are stored as columns, others in data JSON\n const getFieldValue = (fieldName: string) => {\n if (fieldName === 'title') return data.title || data.data?.[fieldName] || ''\n if (fieldName === 'slug') return data.slug || data.data?.[fieldName] || ''\n return data.data?.[fieldName] || ''\n }\n\n // Prepare plugin statuses for field rendering\n const pluginStatuses = {\n quillEnabled: data.quillEnabled || false,\n mdxeditorEnabled: data.mdxeditorEnabled || false,\n tinymceEnabled: data.tinymceEnabled || false\n }\n\n // Render field groups\n const coreFieldsHTML = coreFields\n .sort((a, b) => a.field_order - b.field_order)\n .map(field => renderDynamicField(field, {\n value: getFieldValue(field.field_name),\n errors: data.validationErrors?.[field.field_name] || [],\n pluginStatuses,\n collectionId: data.collection.id,\n contentId: data.id // Pass content ID when editing\n }))\n\n const contentFieldsHTML = contentFields\n .sort((a, b) => a.field_order - b.field_order)\n .map(field => renderDynamicField(field, {\n value: getFieldValue(field.field_name),\n errors: data.validationErrors?.[field.field_name] || [],\n pluginStatuses,\n collectionId: data.collection.id,\n contentId: data.id\n }))\n\n const metaFieldsHTML = metaFields\n .sort((a, b) => a.field_order - b.field_order)\n .map(field => renderDynamicField(field, {\n value: getFieldValue(field.field_name),\n errors: data.validationErrors?.[field.field_name] || [],\n pluginStatuses,\n collectionId: data.collection.id,\n contentId: data.id\n }))\n\n const pageContent = `\n \n \n
\n
\n
${isEdit ? 'Edit Content' : 'New Content'} \n
\n ${data.collection.description || `Manage ${data.collection.display_name.toLowerCase()} content`}\n
\n
\n
\n
\n\n \n
\n \n
\n
\n
\n
\n
${data.collection.display_name} \n
${isEdit ? 'Update your content' : 'Create new content'}
\n
\n
\n
\n\n \n
\n
\n ${data.error ? renderAlert({ type: 'error', message: data.error, dismissible: true }) : ''}\n ${data.success ? renderAlert({ type: 'success', message: data.success, dismissible: true }) : ''}\n
\n\n
\n \n
\n\n \n
\n \n
\n
Publishing \n\n ${data.workflowEnabled ? `\n \n
\n
Status \n
\n
\n Draft \n Under Review \n Published \n Archived \n \n
\n \n \n
\n
\n\n \n
\n
Schedule Publish \n
\n
Leave empty to publish immediately
\n
\n\n \n
\n
Schedule Unpublish \n
\n
Automatically unpublish at this time
\n
\n ` : `\n \n
\n
Status \n
\n
\n Draft \n Published \n \n
\n \n \n
\n
Enable Workflow plugin for advanced status management
\n
\n `}\n
\n\n \n ${isEdit ? `\n
\n
Content Info \n\n
\n \n
Created \n ${data.data?.created_at ? new Date(data.data.created_at).toLocaleDateString() : 'Unknown'} \n \n \n
Last Modified \n ${data.data?.updated_at ? new Date(data.data.updated_at).toLocaleDateString() : 'Unknown'} \n \n \n
Author \n ${data.data?.author || 'Unknown'} \n \n ${data.data?.published_at ? `\n \n
Published \n ${new Date(data.data.published_at).toLocaleDateString()} \n \n ` : ''}\n \n\n
\n
\n \n \n \n View Version History\n \n
\n
\n ` : ''}\n\n \n
\n
Quick Actions \n\n
\n
\n \n \n \n \n Preview Content\n \n\n
\n \n \n \n Duplicate Content\n \n\n ${isEdit ? `\n
\n \n \n \n Delete Content\n \n ` : ''}\n
\n
\n
\n\n \n
\n
\n \n \n \n Cancel\n \n\n
\n
\n \n \n \n ${isEdit ? 'Update' : 'Save'}\n \n\n ${data.user?.role !== 'viewer' ? `\n
\n \n \n \n ${isEdit ? 'Update' : 'Save'} & Publish\n \n ` : ''}\n
\n
\n
\n
\n
\n\n \n ${renderConfirmationDialog({\n id: 'duplicate-content-confirm',\n title: 'Duplicate Content',\n message: 'Create a copy of this content?',\n confirmText: 'Duplicate',\n cancelText: 'Cancel',\n iconColor: 'blue',\n confirmClass: 'bg-blue-500 hover:bg-blue-400',\n onConfirm: 'performDuplicateContent()'\n })}\n\n ${renderConfirmationDialog({\n id: 'delete-content-confirm',\n title: 'Delete Content',\n message: 'Are you sure you want to delete this content? This action cannot be undone.',\n confirmText: 'Delete',\n cancelText: 'Cancel',\n iconColor: 'red',\n confirmClass: 'bg-red-500 hover:bg-red-400',\n onConfirm: `performDeleteContent('${data.id}')`\n })}\n\n ${getConfirmationDialogScript()}\n\n ${data.tinymceEnabled ? getTinyMCEScript(data.tinymceSettings?.apiKey) : ''}\n\n ${data.quillEnabled ? getQuillCDN(data.quillSettings?.version) : ''}\n\n ${data.quillEnabled ? getQuillInitScript() : ''}\n\n ${data.mdxeditorEnabled ? getMDXEditorScripts() : ''}\n\n \n \n `\n\n const layoutData: AdminLayoutCatalystData = {\n title: title,\n pageTitle: 'Content Management',\n currentPath: '/admin/content',\n user: data.user,\n content: pageContent,\n version: data.version\n }\n\n return renderAdminLayoutCatalyst(layoutData)\n}\n","export interface DragSortableOptions {\n itemSelector?: string\n handleSelector?: string\n onUpdate?: () => void\n}\n\nexport function getDragSortableScript(): string {\n return `\n \n `;\n}\n","import { getDragSortableScript } from './drag-sortable.template'\n\n/**\n * Returns shared readFieldValue function used by both blocks and structured fields.\n * Uses a window flag to ensure it's only initialized once.\n */\nfunction getReadFieldValueScript(): string {\n return `\n \n `\n}\n\nexport interface FieldDefinition {\n id: string\n field_name: string\n field_type: string\n field_label: string\n field_options: any // JSON options\n field_order: number\n is_required: boolean\n is_searchable: boolean\n}\n\nexport interface FieldRenderOptions {\n value?: any\n errors?: string[]\n disabled?: boolean\n className?: string\n pluginStatuses?: {\n quillEnabled?: boolean\n mdxeditorEnabled?: boolean\n tinymceEnabled?: boolean\n }\n collectionId?: string\n contentId?: string\n}\n\nexport function renderDynamicField(field: FieldDefinition, options: FieldRenderOptions = {}): string {\n const { value = '', errors = [], disabled = false, className = '', pluginStatuses = {}, collectionId = '', contentId = '' } = options\n const opts = field.field_options || {}\n const required = field.is_required ? 'required' : ''\n const baseClasses = `w-full rounded-lg px-3 py-2 text-sm text-zinc-950 dark:text-white bg-white dark:bg-zinc-800 shadow-sm ring-1 ring-inset ring-zinc-950/10 dark:ring-white/10 placeholder:text-zinc-400 dark:placeholder:text-zinc-500 focus:outline-none focus:ring-2 focus:ring-zinc-950 dark:focus:ring-white transition-shadow ${className}`\n const errorClasses = errors.length > 0 ? 'ring-pink-600 dark:ring-pink-500 focus:ring-pink-600 dark:focus:ring-pink-500' : ''\n\n const fieldId = `field-${field.field_name}`\n const fieldName = field.field_name\n\n // Check if this is a plugin-based field type and if the plugin is inactive\n // If so, fall back to textarea with a warning\n let fallbackToTextarea = false\n let fallbackWarning = ''\n\n if (field.field_type === 'quill' && !pluginStatuses.quillEnabled) {\n fallbackToTextarea = true\n fallbackWarning = 'ā ļø Quill Editor plugin is inactive. Using textarea fallback.'\n } else if (field.field_type === 'mdxeditor' && !pluginStatuses.mdxeditorEnabled) {\n fallbackToTextarea = true\n fallbackWarning = 'ā ļø MDXEditor plugin is inactive. Using textarea fallback.'\n } else if (field.field_type === 'tinymce' && !pluginStatuses.tinymceEnabled) {\n fallbackToTextarea = true\n fallbackWarning = 'ā ļø TinyMCE plugin is inactive. Using textarea fallback.'\n }\n\n // If falling back to textarea, render it with a warning\n if (fallbackToTextarea) {\n return `\n
\n ${fallbackWarning ? `
${fallbackWarning}
` : ''}\n
\n
\n `\n }\n\n let fieldHTML = ''\n\n switch (field.field_type) {\n case 'text':\n let patternHelp = ''\n let autoSlugScript = ''\n \n if (opts.pattern) {\n if (opts.pattern === '^[a-z0-9-]+$' || opts.pattern === '^[a-zA-Z0-9_-]+$') {\n patternHelp = '
Use letters, numbers, underscores, and hyphens only
'\n\n // Add auto-slug generation for slug fields\n if (fieldName === 'slug') {\n patternHelp += '
Generate from title '\n autoSlugScript = `\n \n `\n }\n } else {\n patternHelp = '
Must match required format
'\n }\n }\n \n fieldHTML = `\n
\n ${patternHelp}\n ${autoSlugScript}\n ${opts.pattern ? `\n \n ` : ''}\n `\n break\n\n case 'textarea':\n fieldHTML = `\n
\n `\n break\n\n case 'richtext':\n fieldHTML = `\n
\n \n
\n `\n break\n\n case 'quill':\n // Quill WYSIWYG Editor\n fieldHTML = `\n
\n `\n break\n\n case 'mdxeditor':\n // MDXEditor Rich Text Editor - renders same container as richtext\n // The MDXEditor plugin initialization script will handle the editor initialization\n fieldHTML = `\n
\n \n
\n `\n break\n\n case 'number':\n fieldHTML = `\n
\n `\n break\n \n case 'boolean':\n const checked = value === true || value === 'true' || value === '1' ? 'checked' : ''\n fieldHTML = `\n
\n \n \n ${opts.checkboxLabel || field.field_label}\n \n
\n
\n `\n break\n \n case 'date':\n fieldHTML = `\n
\n `\n break\n\n case 'datetime':\n fieldHTML = `\n
\n `\n break\n\n case 'slug':\n // Slug fields with auto-generation and duplicate detection\n const slugPattern = opts.pattern || '^[a-z0-9-]+$'\n const collectionIdValue = collectionId || opts.collectionId || ''\n const contentIdValue = contentId || opts.contentId || ''\n const isEditMode = !!value\n \n fieldHTML = `\n
\n
\n
\n
\n \n \n \n Regenerate from title\n \n
Use lowercase letters, numbers, and hyphens only
\n
\n \n \n `\n break\n\n case 'select':\n const selectOptions = opts.options || []\n const multiple = opts.multiple ? 'multiple' : ''\n const selectedValues = Array.isArray(value) ? value : [value]\n\n fieldHTML = `\n
\n ${!required && !opts.multiple ? 'Choose an option... ' : ''}\n ${selectOptions.map((option: any) => {\n const optionValue = typeof option === 'string' ? option : option.value\n const optionLabel = typeof option === 'string' ? option : option.label\n const selected = selectedValues.includes(optionValue) ? 'selected' : ''\n return `${escapeHtml(optionLabel)} `\n }).join('')}\n \n ${opts.allowCustom ? `\n
\n \n
\n ` : ''}\n `\n break\n\n case 'reference':\n let referenceCollections: string[] = []\n if (Array.isArray(opts.collection)) {\n referenceCollections = opts.collection.filter(Boolean)\n } else if (typeof opts.collection === 'string' && opts.collection) {\n referenceCollections = [opts.collection]\n }\n const referenceCollectionsAttr = referenceCollections.join(',')\n const hasReferenceCollection = referenceCollections.length > 0\n const hasReferenceValue = Boolean(value)\n fieldHTML = `\n
\n
\n
\n
\n ${hasReferenceCollection ? (hasReferenceValue ? 'Loading selection...' : 'No reference selected.') : 'Reference collection not configured.'}\n
\n
\n \n Select reference\n \n \n Remove\n \n
\n
\n
\n `\n break\n\n case 'media':\n // Check if multiple selection is enabled\n const isMultiple = opts.multiple === true\n const mediaValues = isMultiple && value ? (Array.isArray(value) ? value : String(value).split(',').filter(Boolean)) : []\n const singleValue = !isMultiple ? value : ''\n\n // Helper to detect if URL is a video\n const isVideoUrl = (url: string) => {\n const videoExtensions = ['.mp4', '.webm', '.ogg', '.mov', '.avi']\n return videoExtensions.some(ext => url.toLowerCase().endsWith(ext))\n }\n\n // Helper to render media element\n const renderMediaPreview = (url: string, alt: string, classes: string) => {\n if (isVideoUrl(url)) {\n return `
`\n }\n return `
`\n }\n\n fieldHTML = `\n
\n `\n break\n\n case 'object':\n // Structured object field (like SEO with nested properties)\n return renderStructuredObjectField(field, options, baseClasses, errorClasses)\n\n case 'array':\n // Check if this is a blocks field (has discriminator/blocks config) or a regular array\n const itemsConfig = opts.items && typeof opts.items === 'object' ? opts.items : {}\n if (itemsConfig.blocks && typeof itemsConfig.blocks === 'object') {\n // Blocks field with discriminated union\n return renderBlocksField(field, options, baseClasses, errorClasses)\n }\n // Regular structured array field\n return renderStructuredArrayField(field, options, baseClasses, errorClasses)\n\n default:\n fieldHTML = `\n
\n `\n }\n \n const showLabel = field.field_type !== 'boolean'\n\n return `\n
\n `\n}\n\nexport function renderFieldGroup(title: string, fields: string[], collapsible: boolean = false): string {\n const groupId = title.toLowerCase().replace(/\\s+/g, '-')\n\n return `\n
\n \n
\n ${fields.join('')}\n
\n
\n `\n}\n\nfunction renderBlocksField(\n field: FieldDefinition,\n options: FieldRenderOptions,\n baseClasses: string,\n errorClasses: string\n): string {\n const { value = [], pluginStatuses = {} } = options\n const opts = field.field_options || {}\n const itemsConfig = opts.items && typeof opts.items === 'object' ? opts.items : {}\n const blocks = normalizeBlockDefinitions(itemsConfig.blocks)\n const discriminator =\n typeof itemsConfig.discriminator === 'string' && itemsConfig.discriminator\n ? itemsConfig.discriminator\n : 'blockType'\n const blockValues = normalizeBlocksValue(value, discriminator)\n const fieldId = `field-${field.field_name}`\n const fieldName = field.field_name\n const emptyState =\n blockValues.length === 0\n ? `\n
\n No blocks yet. Add your first block to get started.\n
\n `\n : ''\n\n const blockOptions = blocks\n .map((block) => `
${escapeHtml(block.label)} `)\n .join('')\n\n const blockItems = blockValues\n .map((blockValue, index) =>\n renderBlockItem(field, blockValue, blocks, discriminator, index, pluginStatuses)\n )\n .join('')\n\n const templates = blocks\n .map((block) => renderBlockTemplate(field, block, discriminator, pluginStatuses))\n .join('')\n\n return `\n
\n
\n\n
\n
\n \n Choose a block... \n ${blockOptions}\n \n
\n
\n Add Block\n \n
\n\n
\n ${blockItems || emptyState}\n
\n\n ${templates}\n
\n ${getDragSortableScript()}\n ${getBlocksFieldScript()}\n `\n}\n\nfunction renderStructuredObjectField(\n field: FieldDefinition,\n options: FieldRenderOptions,\n baseClasses: string,\n errorClasses: string\n): string {\n const { value = {}, pluginStatuses = {} } = options\n const opts = field.field_options || {}\n const properties = opts.properties && typeof opts.properties === 'object' ? opts.properties : {}\n const fieldId = `field-${field.field_name}`\n const fieldName = field.field_name\n const objectValue = normalizeStructuredObjectValue(value)\n\n const subfields = Object.entries(properties)\n .map(([propertyName, propertyConfig]) =>\n renderStructuredSubfield(\n field,\n propertyName,\n propertyConfig,\n objectValue,\n pluginStatuses,\n field.field_name\n )\n )\n .join('')\n\n return `\n
\n
\n
\n ${subfields}\n
\n
\n ${getStructuredFieldScript()}\n `\n}\n\nfunction renderStructuredArrayField(\n field: FieldDefinition,\n options: FieldRenderOptions,\n baseClasses: string,\n errorClasses: string\n): string {\n const { value = [], pluginStatuses = {} } = options\n const opts = field.field_options || {}\n const itemsConfig = opts.items && typeof opts.items === 'object' ? opts.items : {}\n const fieldId = `field-${field.field_name}`\n const fieldName = field.field_name\n const arrayValue = normalizeStructuredArrayValue(value)\n\n const items = arrayValue\n .map((itemValue, index) =>\n renderStructuredArrayItem(field, itemsConfig, String(index), itemValue, pluginStatuses)\n )\n .join('')\n\n const emptyState =\n arrayValue.length === 0\n ? `\n
\n No items yet. Add the first item to get started.\n
\n `\n : ''\n\n return `\n
\n
\n\n
\n
\n ${escapeHtml(opts.itemLabel || 'Items')}\n
\n
\n Add item\n \n
\n\n
\n ${items || emptyState}\n
\n\n
\n ${renderStructuredArrayItem(field, itemsConfig, '__INDEX__', {}, pluginStatuses)}\n \n
\n ${getDragSortableScript()}\n ${getStructuredFieldScript()}\n `\n}\n\nfunction renderStructuredArrayItem(\n field: FieldDefinition,\n itemConfig: Record
,\n index: string,\n itemValue: any,\n pluginStatuses: FieldRenderOptions['pluginStatuses']\n): string {\n const itemFields = renderStructuredItemFields(field, itemConfig, index, itemValue, pluginStatuses)\n\n return `\n \n
\n
\n
\n
\n \n \n \n \n
\n \n \n \n \n
\n \n \n \n Delete item\n \n
\n
\n
\n ${itemFields}\n
\n
\n `\n}\n\nfunction renderStructuredItemFields(\n field: FieldDefinition,\n itemConfig: Record,\n index: string,\n itemValue: any,\n pluginStatuses: FieldRenderOptions['pluginStatuses']\n): string {\n const itemType = itemConfig?.type || 'string'\n if (itemType === 'object' && itemConfig?.properties && typeof itemConfig.properties === 'object') {\n const fieldPrefix = `array-${field.field_name}-${index}`\n return Object.entries(itemConfig.properties)\n .map(([propertyName, propertyConfig]) =>\n renderStructuredSubfield(\n field,\n propertyName,\n propertyConfig,\n itemValue || {},\n pluginStatuses,\n fieldPrefix\n )\n )\n .join('')\n }\n\n const normalizedField = normalizeBlockField(itemConfig, 'Item')\n const fieldValue = itemValue ?? normalizedField.defaultValue ?? ''\n const fieldDefinition: FieldDefinition = {\n id: `array-${field.field_name}-${index}-value`,\n field_name: `array-${field.field_name}-${index}-value`,\n field_type: normalizedField.type,\n field_label: normalizedField.label,\n field_options: normalizedField.options,\n field_order: 0,\n is_required: normalizedField.required,\n is_searchable: false,\n }\n\n return `\n \n ${renderDynamicField(fieldDefinition, { value: fieldValue, pluginStatuses })}\n
\n `\n}\n\nfunction renderStructuredSubfield(\n field: FieldDefinition,\n propertyName: string,\n propertyConfig: any,\n objectValue: Record,\n pluginStatuses: FieldRenderOptions['pluginStatuses'],\n fieldPrefix: string\n): string {\n const normalizedField = normalizeBlockField(propertyConfig, propertyName)\n const fieldValue = objectValue?.[propertyName] ?? normalizedField.defaultValue ?? ''\n const fieldDefinition: FieldDefinition = {\n id: `${fieldPrefix}-${propertyName}`,\n field_name: `${fieldPrefix}__${propertyName}`,\n field_type: normalizedField.type,\n field_label: normalizedField.label,\n field_options: normalizedField.options,\n field_order: 0,\n is_required: normalizedField.required,\n is_searchable: false,\n }\n\n return `\n \n ${renderDynamicField(fieldDefinition, { value: fieldValue, pluginStatuses })}\n
\n `\n}\n\nfunction normalizeStructuredObjectValue(value: any): Record {\n if (!value) return {}\n if (typeof value === 'string') {\n try {\n const parsed = JSON.parse(value)\n return parsed && typeof parsed === 'object' && !Array.isArray(parsed) ? parsed : {}\n } catch {\n return {}\n }\n }\n if (typeof value === 'object' && !Array.isArray(value)) return value\n return {}\n}\n\nfunction normalizeStructuredArrayValue(value: any): any[] {\n if (!value) return []\n if (Array.isArray(value)) return value\n if (typeof value === 'string') {\n try {\n const parsed = JSON.parse(value)\n return Array.isArray(parsed) ? parsed : []\n } catch {\n return []\n }\n }\n return []\n}\n\nfunction normalizeBlockDefinitions(\n rawBlocks: any\n): Array<{ name: string; label: string; description?: string; properties: Record }> {\n if (!rawBlocks || typeof rawBlocks !== 'object') return []\n\n return Object.entries(rawBlocks)\n .filter(([name, block]) => typeof name === 'string' && block && typeof block === 'object')\n .map(([name, block]: [string, any]) => ({\n name,\n label: block.label || name,\n description: block.description,\n properties: block.properties && typeof block.properties === 'object' ? block.properties : {},\n }))\n}\n\nfunction normalizeBlocksValue(value: any, discriminator: string): any[] {\n const normalizeItem = (item: any) => {\n if (!item || typeof item !== 'object') return null\n if (item[discriminator]) return item\n if (item.blockType && item.data && typeof item.data === 'object') {\n return { [discriminator]: item.blockType, ...item.data }\n }\n return item\n }\n\n const fromArray = (items: any[]) =>\n items.map(normalizeItem).filter((item) => item && typeof item === 'object')\n\n if (Array.isArray(value)) return fromArray(value)\n if (typeof value === 'string' && value.trim()) {\n try {\n const parsed = JSON.parse(value)\n return Array.isArray(parsed) ? fromArray(parsed) : []\n } catch {\n return []\n }\n }\n return []\n}\n\nfunction renderBlockTemplate(\n field: FieldDefinition,\n block: { name: string; label: string; description?: string; properties: Record },\n discriminator: string,\n pluginStatuses: FieldRenderOptions['pluginStatuses']\n): string {\n return `\n \n ${renderBlockCard(field, block, discriminator, '__INDEX__', {}, pluginStatuses)}\n \n `\n}\n\nfunction renderBlockItem(\n field: FieldDefinition,\n blockValue: any,\n blocks: Array<{\n name: string\n label: string\n description?: string\n properties: Record\n }>,\n discriminator: string,\n index: number,\n pluginStatuses: FieldRenderOptions['pluginStatuses']\n): string {\n const blockType = blockValue?.[discriminator] || blockValue?.blockType\n const blockDefinition = blocks.find((block) => block.name === blockType)\n\n if (!blockDefinition) {\n return `\n \n Unknown block type: ${escapeHtml(String(blockType || 'unknown'))} . This block will be preserved as-is.\n
\n `\n }\n\n const data =\n blockValue && typeof blockValue === 'object'\n ? Object.fromEntries(Object.entries(blockValue).filter(([key]) => key !== discriminator))\n : {}\n\n return renderBlockCard(field, blockDefinition, discriminator, String(index), data, pluginStatuses)\n}\n\nfunction renderBlockCard(\n field: FieldDefinition,\n block: { name: string; label: string; description?: string; properties: Record },\n discriminator: string,\n index: string,\n data: Record,\n pluginStatuses: FieldRenderOptions['pluginStatuses']\n): string {\n const blockFields = Object.entries(block.properties)\n .map(([fieldName, fieldConfig]) => {\n if (fieldConfig?.type === 'array' && fieldConfig?.items?.blocks) {\n return `\n \n Nested blocks are not supported yet for \"${escapeHtml(fieldName)}\".\n
\n `\n }\n\n const normalizedField = normalizeBlockField(fieldConfig, fieldName)\n const fieldValue = data?.[fieldName] ?? normalizedField.defaultValue ?? ''\n const fieldDefinition: FieldDefinition = {\n id: `block-${field.field_name}-${index}-${fieldName}`,\n field_name: `block-${field.field_name}-${index}-${fieldName}`,\n field_type: normalizedField.type,\n field_label: normalizedField.label,\n field_options: normalizedField.options,\n field_order: 0,\n is_required: normalizedField.required,\n is_searchable: false,\n }\n\n return `\n \n ${renderDynamicField(fieldDefinition, { value: fieldValue, pluginStatuses })}\n
\n `\n })\n .join('')\n\n return `\n \n
\n
\n
\n
\n
\n ${escapeHtml(block.label)}\n \n
\n ${block.description ? `
${escapeHtml(block.description)}
` : ''}\n
\n
\n
\n
\n \n \n \n \n
\n \n \n \n \n
\n \n \n \n Delete block\n \n
\n
\n
\n ${blockFields}\n
\n
\n `\n}\n\nfunction normalizeBlockField(fieldConfig: any, fieldName: string) {\n const type = fieldConfig?.type || 'text'\n const label = fieldConfig?.title || fieldName\n const required = fieldConfig?.required === true\n const options = { ...fieldConfig }\n\n if (type === 'select' && Array.isArray(fieldConfig?.enum)) {\n options.options = fieldConfig.enum.map((value: string, index: number) => ({\n value,\n label: fieldConfig.enumLabels?.[index] || value,\n }))\n }\n\n return {\n type,\n label,\n required,\n defaultValue: fieldConfig?.default,\n options,\n }\n}\n\nfunction getStructuredFieldScript(): string {\n return `\n ${getReadFieldValueScript()}\n \n `\n}\n\nfunction getBlocksFieldScript(): string {\n return `\n ${getReadFieldValueScript()}\n \n `\n}\n\nfunction escapeHtml(text: string): string {\n if (typeof text !== 'string') return String(text || '')\n return text.replace(/[&<>\"']/g, (char) => ({\n '&': '&',\n '<': '<',\n '>': '>',\n '\"': '"',\n \"'\": '''\n }[char] || char))\n}","import { Plugin } from '../../../types/plugin'\nimport { PluginBuilder } from '../../sdk/plugin-builder'\n\n/**\n * TinyMCE Rich Text Editor Plugin\n *\n * Provides WYSIWYG editing capabilities for richtext fields.\n * When active, this plugin injects the TinyMCE editor into all richtext field types.\n * When inactive, richtext fields fall back to plain textareas.\n */\n\nconst builder = PluginBuilder.create({\n name: 'tinymce-plugin',\n version: '1.0.0',\n description: 'Powerful WYSIWYG rich text editor for content creation'\n})\n\nbuilder.metadata({\n author: {\n name: 'SonicJS Team',\n email: 'team@sonicjs.com'\n },\n license: 'MIT',\n compatibility: '^2.0.0'\n})\n\nbuilder.lifecycle({\n activate: async () => {\n console.info('ā
TinyMCE plugin activated')\n },\n deactivate: async () => {\n console.info('ā TinyMCE plugin deactivated')\n }\n})\n\nconst tinymcePlugin = builder.build() as Plugin\n\nexport default tinymcePlugin\n\n/**\n * Get TinyMCE CDN script tag\n * @param apiKey - Optional TinyMCE API key (defaults to 'no-api-key')\n * @returns HTML script tag for TinyMCE CDN\n */\nexport function getTinyMCEScript(apiKey: string = 'no-api-key'): string {\n return ``\n}\n\n/**\n * Get TinyMCE initialization script\n * @param config - Optional configuration object\n * @returns JavaScript initialization code\n */\nexport function getTinyMCEInitScript(config?: {\n skin?: string\n defaultHeight?: number\n defaultToolbar?: string\n}): string {\n const skin = config?.skin || 'oxide-dark'\n const contentCss = skin.includes('dark') ? 'dark' : 'default'\n const defaultHeight = config?.defaultHeight || 300\n\n return `\n // Initialize TinyMCE for all richtext fields\n function initializeTinyMCE() {\n if (typeof tinymce !== 'undefined') {\n // Find all textareas that need TinyMCE\n document.querySelectorAll('.richtext-container textarea').forEach((textarea) => {\n // Skip if already initialized\n if (tinymce.get(textarea.id)) {\n return;\n }\n\n // Get configuration from data attributes\n const container = textarea.closest('.richtext-container');\n const height = container?.dataset.height || ${defaultHeight};\n const toolbar = container?.dataset.toolbar || 'full';\n\n tinymce.init({\n selector: '#' + textarea.id,\n skin: '${skin}',\n content_css: '${contentCss}',\n height: parseInt(height),\n menubar: false,\n plugins: [\n 'advlist', 'autolink', 'lists', 'link', 'image', 'charmap', 'preview',\n 'anchor', 'searchreplace', 'visualblocks', 'code', 'fullscreen',\n 'insertdatetime', 'media', 'table', 'help', 'wordcount'\n ],\n toolbar: toolbar === 'simple'\n ? 'bold italic underline | bullist numlist | link'\n : toolbar === 'minimal'\n ? 'bold italic | link'\n : 'undo redo | blocks | bold italic forecolor | alignleft aligncenter alignright alignjustify | bullist numlist outdent indent | removeformat | help',\n content_style: 'body { font-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, Oxygen, Ubuntu, Cantarell, sans-serif; font-size: 14px }'\n });\n });\n }\n }\n\n // Initialize on DOMContentLoaded\n if (document.readyState === 'loading') {\n document.addEventListener('DOMContentLoaded', initializeTinyMCE);\n } else {\n // DOM already loaded, initialize immediately\n initializeTinyMCE();\n }\n\n // Also reinitialize after HTMX swaps (for dynamic content)\n document.addEventListener('htmx:afterSwap', function(event) {\n // Give the DOM a moment to settle\n setTimeout(initializeTinyMCE, 100);\n });\n `\n}\n\n/**\n * Check if TinyMCE plugin is active\n * @param pluginService - Plugin service instance\n * @returns Promise\n */\nexport async function isTinyMCEActive(pluginService: any): Promise {\n try {\n const status = await pluginService.getPluginStatus('tinymce-plugin')\n return status?.is_active === true\n } catch (error) {\n console.error('Error checking TinyMCE plugin status:', error)\n return false\n }\n}\n","/**\n * Quill Rich Text Editor Plugin\n *\n * Provides Quill editor integration for rich text editing in SonicJS\n * https://quilljs.com/\n */\n\nimport { PluginBuilder } from '../../sdk/plugin-builder'\nimport type { Plugin } from '@sonicjs-cms/core'\n\n/**\n * Quill Editor Configuration Options\n */\nexport interface QuillOptions {\n theme?: 'snow' | 'bubble'\n placeholder?: string\n height?: number\n toolbar?: 'full' | 'simple' | 'minimal' | string[][]\n modules?: Record\n formats?: string[]\n}\n\n/**\n * Default Quill toolbar configurations\n */\nconst QUILL_TOOLBARS = {\n full: [\n [{ 'header': [1, 2, 3, 4, 5, 6, false] }],\n ['bold', 'italic', 'underline', 'strike'],\n [{ 'color': [] }, { 'background': [] }],\n [{ 'align': [] }],\n [{ 'list': 'ordered'}, { 'list': 'bullet' }],\n [{ 'indent': '-1'}, { 'indent': '+1' }],\n ['blockquote', 'code-block'],\n ['link', 'image', 'video'],\n ['clean']\n ],\n simple: [\n ['bold', 'italic', 'underline'],\n [{ 'list': 'ordered'}, { 'list': 'bullet' }],\n ['link']\n ],\n minimal: [\n ['bold', 'italic'],\n ['link']\n ]\n}\n\n/**\n * Render a Quill editor field\n * @param fieldId - The field ID\n * @param fieldName - The field name\n * @param value - The current value\n * @param options - Quill configuration options\n * @returns HTML string for the Quill editor field\n */\nexport function renderQuillField(\n fieldId: string,\n fieldName: string,\n value: string = '',\n options: QuillOptions = {}\n): string {\n const {\n theme = 'snow',\n placeholder = 'Enter content...',\n height = 300,\n toolbar = 'full'\n } = options\n\n // Escape HTML for hidden input\n const escapeHtml = (str: string) => {\n return str\n .replace(/&/g, '&')\n .replace(//g, '>')\n .replace(/\"/g, '"')\n .replace(/'/g, ''')\n }\n\n return `\n \n `\n}\n\n/**\n * Generate Quill initialization script\n * @returns HTML script tag with Quill initialization code\n */\nexport function getQuillInitScript(): string {\n return `\n \n `\n}\n\n/**\n * Generate Quill CDN links\n * @param version - Quill version (default: 2.0.2)\n * @returns HTML script and link tags for Quill CDN\n */\nexport function getQuillCDN(version: string = '2.0.2'): string {\n return `\n \n \n \n\n \n \n\n \n \n `\n}\n\n/**\n * Create the Quill Editor Plugin\n */\nexport function createQuillEditorPlugin(): Plugin {\n const builder = PluginBuilder.create({\n name: 'quill-editor',\n version: '1.0.0',\n description: 'Quill rich text editor integration for SonicJS'\n })\n\n // Add plugin metadata\n builder.metadata({\n author: {\n name: 'SonicJS Team',\n email: 'team@sonicjs.com'\n },\n license: 'MIT',\n compatibility: '^2.0.0'\n })\n\n // Add lifecycle hooks\n builder.lifecycle({\n activate: async () => {\n console.info('ā
Quill Editor plugin activated')\n },\n\n deactivate: async () => {\n console.info('ā Quill Editor plugin deactivated')\n }\n })\n\n return builder.build() as Plugin\n}\n\n// Export the plugin instance\nexport const quillEditorPlugin = createQuillEditorPlugin()\n","import { Plugin } from '../../../types/plugin'\nimport { PluginBuilder } from '../../sdk/plugin-builder'\n\n/**\n * EasyMDE Markdown Editor Plugin\n *\n * Provides markdown editing capabilities for richtext fields.\n * When active, this plugin injects the EasyMDE editor into all richtext field types.\n * When inactive, richtext fields fall back to plain textareas.\n */\n\nconst builder = PluginBuilder.create({\n name: 'easy-mdx',\n version: '1.0.0',\n description: 'Lightweight markdown editor with live preview'\n})\n\nbuilder.metadata({\n author: {\n name: 'SonicJS Team',\n email: 'team@sonicjs.com'\n },\n license: 'MIT',\n compatibility: '^2.0.0'\n})\n\nbuilder.lifecycle({\n activate: async () => {\n console.info('ā
EasyMDE editor plugin activated')\n },\n deactivate: async () => {\n console.info('ā EasyMDE editor plugin deactivated')\n }\n})\n\nconst easyMdxPlugin = builder.build() as Plugin\n\nexport default easyMdxPlugin\n\n/**\n * Get EasyMDE CDN script tags\n * @returns HTML script and style tags for EasyMDE\n */\nexport function getMDXEditorScripts(): string {\n return `\n \n \n \n \n `\n}\n\n/**\n * Get EasyMDE initialization script\n * @param config - Optional configuration object\n * @returns JavaScript initialization code\n */\nexport function getMDXEditorInitScript(config?: {\n defaultHeight?: number\n toolbar?: string\n placeholder?: string\n}): string {\n const defaultHeight = config?.defaultHeight || 400\n const toolbar = config?.toolbar || 'full'\n const placeholder = config?.placeholder || 'Start writing your content...'\n\n return `\n // Initialize EasyMDE (Markdown Editor) for all richtext fields\n function initializeMDXEditor() {\n if (typeof EasyMDE === 'undefined') {\n console.warn('EasyMDE not loaded yet, retrying...');\n setTimeout(initializeMDXEditor, 100);\n return;\n }\n\n // Find all textareas that need EasyMDE\n document.querySelectorAll('.richtext-container textarea').forEach((textarea) => {\n // Skip if already initialized\n if (textarea.dataset.mdxeditorInitialized === 'true') {\n return;\n }\n\n // Mark as initialized\n textarea.dataset.mdxeditorInitialized = 'true';\n\n // Get configuration from data attributes\n const container = textarea.closest('.richtext-container');\n const height = container?.dataset.height || ${defaultHeight};\n const editorToolbar = container?.dataset.toolbar || '${toolbar}';\n\n // Initialize EasyMDE\n try {\n const toolbarButtons = editorToolbar === 'minimal'\n ? ['bold', 'italic', 'heading', '|', 'quote', 'unordered-list', 'ordered-list', '|', 'link', 'preview']\n : ['bold', 'italic', 'heading', '|', 'quote', 'unordered-list', 'ordered-list', '|', 'link', 'image', 'table', '|', 'preview', 'side-by-side', 'fullscreen', '|', 'guide'];\n\n const easyMDE = new EasyMDE({\n element: textarea,\n placeholder: '${placeholder}',\n spellChecker: false,\n minHeight: height + 'px',\n toolbar: toolbarButtons,\n status: ['lines', 'words', 'cursor'],\n renderingConfig: {\n singleLineBreaks: false,\n codeSyntaxHighlighting: true\n }\n });\n\n // Store reference to editor instance\n textarea.easyMDEInstance = easyMDE;\n\n // Sync changes back to textarea\n easyMDE.codemirror.on(\"change\", () => {\n textarea.value = easyMDE.value();\n textarea.dispatchEvent(new Event(\"input\", { bubbles: true }));\n textarea.dispatchEvent(new Event(\"change\", { bubbles: true }));\n });\n\n console.log('EasyMDE initialized for field:', textarea.id || textarea.name);\n } catch (error) {\n console.error('Error initializing EasyMDE:', error);\n // Show textarea as fallback\n textarea.style.display = 'block';\n }\n });\n }\n\n // Initialize on DOMContentLoaded\n if (document.readyState === 'loading') {\n document.addEventListener('DOMContentLoaded', initializeMDXEditor);\n } else {\n // DOM already loaded, initialize immediately\n initializeMDXEditor();\n }\n\n // Also reinitialize after HTMX swaps (for dynamic content)\n document.addEventListener('htmx:afterSwap', function(event) {\n // Give the DOM a moment to settle\n setTimeout(initializeMDXEditor, 100);\n });\n `\n}\n\n/**\n * Check if EasyMDE editor plugin is active\n * @param pluginService - Plugin service instance\n * @returns Promise\n */\nexport async function isEasyMdxActive(pluginService: any): Promise {\n try {\n const status = await pluginService.getPluginStatus('easy-mdx')\n return status?.is_active === true\n } catch (error) {\n console.error('Error checking EasyMDE editor plugin status:', error)\n return false\n }\n}\n","import { renderAdminLayoutCatalyst, AdminLayoutCatalystData } from '../layouts/admin-layout-catalyst.template'\nimport { renderPagination, PaginationData } from '../pagination.template'\nimport { renderTable, TableData, TableColumn } from '../table.template'\nimport type { FilterBarData } from '../filter-bar.template'\nimport { renderConfirmationDialog, getConfirmationDialogScript } from '../confirmation-dialog.template'\n\nexport interface ContentItem {\n id: string\n title: string\n slug: string\n modelName: string\n statusBadge: string\n authorName: string\n formattedDate: string\n availableActions: string[]\n}\n\nexport interface ContentListPageData {\n modelName: string\n status: string\n page: number\n search?: string\n models: Array<{\n name: string\n displayName: string\n }>\n contentItems: ContentItem[]\n totalItems: number\n itemsPerPage: number\n user?: {\n name: string\n email: string\n role: string\n }\n version?: string\n}\n\nexport function renderContentListPage(data: ContentListPageData): string {\n // Build current URL parameters to pass to edit page\n const urlParams = new URLSearchParams()\n if (data.modelName && data.modelName !== 'all') urlParams.set('model', data.modelName)\n if (data.status && data.status !== 'all') urlParams.set('status', data.status)\n if (data.search) urlParams.set('search', data.search)\n if (data.page && data.page !== 1) urlParams.set('page', data.page.toString())\n const currentParams = urlParams.toString()\n\n // Check if filters are active (not in default state)\n const hasActiveFilters = data.modelName !== 'all' || data.status !== 'all' || !!data.search\n\n // Prepare filter bar data\n const filterBarData: FilterBarData = {\n filters: [\n {\n name: 'model',\n label: 'Model',\n options: [\n { value: 'all', label: 'All Models', selected: data.modelName === 'all' },\n ...data.models.map(model => ({\n value: model.name,\n label: model.displayName,\n selected: data.modelName === model.name\n }))\n ]\n },\n {\n name: 'status',\n label: 'Status',\n options: [\n { value: 'all', label: 'All Status', selected: data.status === 'all' },\n { value: 'draft', label: 'Draft', selected: data.status === 'draft' },\n { value: 'review', label: 'Under Review', selected: data.status === 'review' },\n { value: 'scheduled', label: 'Scheduled', selected: data.status === 'scheduled' },\n { value: 'published', label: 'Published', selected: data.status === 'published' },\n { value: 'archived', label: 'Archived', selected: data.status === 'archived' },\n { value: 'deleted', label: 'Deleted', selected: data.status === 'deleted' }\n ]\n }\n ],\n actions: [\n {\n label: 'Advanced Search',\n className: 'btn-primary',\n onclick: 'openAdvancedSearch()'\n },\n {\n label: 'Refresh',\n className: 'btn-secondary',\n onclick: 'location.reload()'\n }\n ],\n bulkActions: [\n { label: 'Publish', value: 'publish', icon: 'check-circle' },\n { label: 'Unpublish', value: 'unpublish', icon: 'x-circle' },\n { label: 'Delete', value: 'delete', icon: 'trash', className: 'text-pink-600' }\n ]\n }\n\n // Prepare table data\n const tableColumns: TableColumn[] = [\n {\n key: 'title',\n label: 'Title',\n sortable: true,\n sortType: 'string',\n render: (value, row) => `\n \n `\n },\n {\n key: 'modelName',\n label: 'Model',\n sortable: true,\n sortType: 'string',\n className: 'text-sm text-zinc-500 dark:text-zinc-400'\n },\n {\n key: 'statusBadge',\n label: 'Status',\n sortable: true,\n sortType: 'string',\n render: (value) => value\n },\n {\n key: 'authorName',\n label: 'Author',\n sortable: true,\n sortType: 'string',\n className: 'text-sm text-zinc-500 dark:text-zinc-400'\n },\n {\n key: 'formattedDate',\n label: 'Updated',\n sortable: true,\n sortType: 'date',\n className: 'text-sm text-zinc-500 dark:text-zinc-400'\n },\n {\n key: 'actions',\n label: 'Actions',\n sortable: false,\n className: 'text-sm font-medium',\n render: (value, row) => `\n \n
\n \n \n \n \n
\n \n \n \n \n
\n \n \n \n \n
\n `\n }\n ]\n\n const tableData: TableData = {\n tableId: 'content-table',\n columns: tableColumns,\n rows: data.contentItems,\n selectable: true,\n rowClickable: true,\n rowClickUrl: (row: ContentItem) => `/admin/content/${row.id}/edit${currentParams ? `?ref=${encodeURIComponent(currentParams)}` : ''}`,\n emptyMessage: 'No content found. Create your first content item to get started.'\n }\n\n // Prepare pagination data\n const totalPages = Math.ceil(data.totalItems / data.itemsPerPage)\n const startItem = (data.page - 1) * data.itemsPerPage + 1\n const endItem = Math.min(data.page * data.itemsPerPage, data.totalItems)\n\n const paginationData: PaginationData = {\n currentPage: data.page,\n totalPages,\n totalItems: data.totalItems,\n itemsPerPage: data.itemsPerPage,\n startItem,\n endItem,\n baseUrl: '/admin/content',\n queryParams: {\n model: data.modelName,\n status: data.status,\n ...(data.search ? { search: data.search } : {})\n },\n showPageSizeSelector: true,\n pageSizeOptions: [10, 20, 50, 100]\n }\n\n // Generate page content\n const pageContent = `\n \n \n
\n
\n
Content Management \n
Manage and organize your content items
\n
\n
\n
\n \n
\n \n
\n\n
\n
\n
\n
\n \n
\n
Model \n
\n
\n All Models \n ${data.models.map(model => `\n \n ${model.displayName}\n \n `).join('')}\n \n
\n \n \n
\n
\n\n \n
\n
Status \n
\n
\n All Status \n Draft \n Under Review \n Scheduled \n Published \n Archived \n Deleted \n \n
\n \n \n
\n
\n\n \n
\n
\n
\n
${data.totalItems} ${data.totalItems === 1 ? 'item' : 'items'} \n ${filterBarData.actions?.map(action => `\n
\n ${action.label === 'Refresh' ? `\n \n \n \n ` : ''}\n ${action.label}\n \n `).join('') || ''}\n ${filterBarData.bulkActions && filterBarData.bulkActions.length > 0 ? `\n
\n
\n Bulk Actions\n \n \n \n \n\n \n
\n ` : ''}\n
\n
\n
\n
\n
\n \n \n
\n ${renderTable(tableData)}\n ${renderPagination(paginationData)}\n
\n \n
\n \n \n
\n
\n \n \n\n \n ${renderConfirmationDialog({\n id: 'bulk-action-confirm',\n title: 'Confirm Bulk Action',\n message: 'Are you sure you want to perform this action? This operation will affect multiple items.',\n confirmText: 'Confirm',\n cancelText: 'Cancel',\n confirmClass: 'bg-blue-500 hover:bg-blue-400',\n iconColor: 'blue',\n onConfirm: 'executeBulkAction()'\n })}\n\n \n ${getConfirmationDialogScript()}\n\n \n \n
\n \n
\n\n \n
\n
\n \n
\n
\n š Advanced Search\n \n
\n \n \n \n \n
\n\n \n
\n
\n\n \n
\n
\n
\n
\n\n \n `\n\n // Prepare layout data\n const layoutData: AdminLayoutCatalystData = {\n title: 'Content Management',\n pageTitle: 'Content Management',\n currentPath: '/admin/content',\n user: data.user,\n version: data.version,\n content: pageContent\n }\n\n return renderAdminLayoutCatalyst(layoutData)\n}\n","export interface ContentVersion {\n id: string\n version: number\n data: any\n author_id: string\n author_name?: string\n created_at: number\n is_current?: boolean\n}\n\nexport interface VersionHistoryData {\n contentId: string\n versions: ContentVersion[]\n currentVersion: number\n}\n\nexport function renderVersionHistory(data: VersionHistoryData): string {\n return `\n \n
\n \n
\n
\n
\n
Version History \n
\n \n \n \n \n
\n
\n \n \n
\n
\n ${data.versions.map((version, index) => `\n
\n
\n
\n \n Version ${version.version}${version.is_current ? ' (Current)' : ''}\n \n \n ${new Date(version.created_at).toLocaleString()}\n \n
\n
\n ${!version.is_current ? `\n
\n \n \n \n Restore\n \n ` : ''}\n
\n \n \n \n \n Preview\n \n
\n
\n \n \n
\n
\n
\n Title: \n ${escapeHtml(version.data?.title || 'Untitled')} \n
\n
\n Author: \n ${escapeHtml(version.author_name || 'Unknown')} \n
\n ${version.data?.excerpt ? `\n
\n
Excerpt: \n
${escapeHtml(version.data.excerpt.substring(0, 200))}${version.data.excerpt.length > 200 ? '...' : ''}
\n
\n ` : ''}\n
\n
\n \n \n ${!version.is_current && index < data.versions.length - 1 ? `\n
\n
\n \n \n \n View Changes\n \n
\n Change detection coming soon... \n
\n
\n ` : ''}\n
\n `).join('')}\n
\n
\n \n \n
\n
\n \n ${data.versions.length} version${data.versions.length !== 1 ? 's' : ''} total\n \n \n Close\n \n
\n
\n
\n
\n \n \n `\n}\n\nfunction escapeHtml(text: string): string {\n if (typeof text !== 'string') return String(text || '')\n return text.replace(/[&<>\"']/g, (char) => ({\n '&': '&',\n '<': '<',\n '>': '>',\n '\"': '"',\n \"'\": '''\n }[char] || char))\n}","/**\n * Plugin Middleware\n *\n * Provides middleware functions for checking plugin status and enforcing plugin requirements\n */\n\nimport type { D1Database } from '@cloudflare/workers-types'\n\n/**\n * Check if a plugin is active\n * @param db - The D1 database instance\n * @param pluginId - The plugin ID to check\n * @returns Promise - True if the plugin is active, false otherwise\n */\nexport async function isPluginActive(db: D1Database, pluginId: string): Promise {\n try {\n const result = await db\n .prepare('SELECT status FROM plugins WHERE id = ?')\n .bind(pluginId)\n .first()\n\n return result?.status === 'active'\n } catch (error) {\n console.error(`[isPluginActive] Error checking plugin status for ${pluginId}:`, error)\n return false\n }\n}\n\n/**\n * Middleware to require a plugin to be active\n * Throws an error if the plugin is not active\n * @param db - The D1 database instance\n * @param pluginId - The plugin ID to check\n * @throws Error if plugin is not active\n */\nexport async function requireActivePlugin(db: D1Database, pluginId: string): Promise {\n const isActive = await isPluginActive(db, pluginId)\n if (!isActive) {\n throw new Error(`Plugin '${pluginId}' is required but is not active`)\n }\n}\n\n/**\n * Middleware to require multiple plugins to be active\n * Throws an error if any plugin is not active\n * @param db - The D1 database instance\n * @param pluginIds - Array of plugin IDs to check\n * @throws Error if any plugin is not active\n */\nexport async function requireActivePlugins(db: D1Database, pluginIds: string[]): Promise {\n for (const pluginId of pluginIds) {\n await requireActivePlugin(db, pluginId)\n }\n}\n\n/**\n * Get all active plugins\n * @param db - The D1 database instance\n * @returns Promise - Array of active plugin records\n */\nexport async function getActivePlugins(db: D1Database): Promise {\n try {\n const { results } = await db\n .prepare('SELECT * FROM plugins WHERE status = ?')\n .bind('active')\n .all()\n\n return results || []\n } catch (error) {\n console.error('[getActivePlugins] Error fetching active plugins:', error)\n return []\n }\n}\n","import { Hono } from 'hono'\nimport { html } from 'hono/html'\nimport type { D1Database, KVNamespace } from '@cloudflare/workers-types'\nimport { requireAuth } from '../middleware'\nimport { renderContentFormPage, ContentFormData } from '../templates/pages/admin-content-form.template'\nimport { renderContentListPage, ContentListPageData } from '../templates/pages/admin-content-list.template'\nimport { renderVersionHistory, VersionHistoryData, ContentVersion } from '../templates/components/version-history.template'\nimport { isPluginActive } from '../middleware/plugin-middleware'\nimport { getCacheService, CACHE_CONFIGS } from '../services/cache'\nimport type { Bindings, Variables } from '../app'\nimport { PluginService } from '../services/plugin-service'\nimport { getBlocksFieldConfig, parseBlocksValue } from '../utils/blocks'\nimport { FTS5Service } from '../plugins/core-plugins/ai-search-plugin/services/fts5.service'\nimport { SearchCacheService } from '../plugins/core-plugins/ai-search-plugin/services/search-cache.service'\n\nconst adminContentRoutes = new Hono<{ Bindings: Bindings; Variables: Variables }>()\n\n// Field definition type for form processing\ninterface FieldDefinition {\n field_name: string\n field_label: string\n field_type: string\n field_options?: any\n is_required?: boolean\n}\n\n// Result of parsing a single field value\ninterface ParsedFieldResult {\n value: any\n errors: string[]\n}\n\n/**\n * Parse a single field value from form data with validation\n * Centralizes field parsing logic used in POST, PUT, and preview handlers\n */\nfunction parseFieldValue(\n field: FieldDefinition,\n formData: FormData,\n options: { skipValidation?: boolean } = {}\n): ParsedFieldResult {\n const { skipValidation = false } = options\n const value = formData.get(field.field_name)\n const errors: string[] = []\n\n // Handle blocks fields (array with blocks config)\n const blocksConfig = getBlocksFieldConfig(field.field_options)\n if (blocksConfig) {\n const parsed = parseBlocksValue(value, blocksConfig)\n if (!skipValidation && field.is_required && parsed.value.length === 0) {\n parsed.errors.push(`${field.field_label} is required`)\n }\n return { value: parsed.value, errors: parsed.errors }\n }\n\n // Required field validation\n if (!skipValidation && field.is_required && (!value || value.toString().trim() === '')) {\n return { value: null, errors: [`${field.field_label} is required`] }\n }\n\n // Type-specific parsing\n switch (field.field_type) {\n case 'number':\n if (value && isNaN(Number(value))) {\n if (!skipValidation) {\n errors.push(`${field.field_label} must be a valid number`)\n }\n return { value: null, errors }\n }\n return { value: value ? Number(value) : null, errors: [] }\n\n case 'boolean':\n // Check for the hidden _submitted field to determine if checkbox was rendered\n const submitted = formData.get(`${field.field_name}_submitted`)\n return { value: submitted ? value === 'true' : false, errors: [] }\n\n case 'select':\n if (field.field_options?.multiple) {\n return { value: formData.getAll(`${field.field_name}[]`), errors: [] }\n }\n return { value: value, errors: [] }\n\n case 'array': {\n if (!value || value.toString().trim() === '') {\n if (!skipValidation && field.is_required) {\n errors.push(`${field.field_label} is required`)\n }\n return { value: [], errors }\n }\n try {\n const parsed = JSON.parse(value.toString())\n if (!Array.isArray(parsed)) {\n if (!skipValidation) {\n errors.push(`${field.field_label} must be a JSON array`)\n }\n return { value: [], errors }\n }\n if (!skipValidation && field.is_required && parsed.length === 0) {\n errors.push(`${field.field_label} is required`)\n }\n return { value: parsed, errors }\n } catch {\n if (!skipValidation) {\n errors.push(`${field.field_label} must be valid JSON`)\n }\n return { value: [], errors }\n }\n }\n\n case 'object': {\n if (!value || value.toString().trim() === '') {\n if (!skipValidation && field.is_required) {\n errors.push(`${field.field_label} is required`)\n }\n return { value: {}, errors }\n }\n try {\n const parsed = JSON.parse(value.toString())\n if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {\n if (!skipValidation) {\n errors.push(`${field.field_label} must be a JSON object`)\n }\n return { value: {}, errors }\n }\n if (!skipValidation && field.is_required && Object.keys(parsed).length === 0) {\n errors.push(`${field.field_label} is required`)\n }\n return { value: parsed, errors }\n } catch {\n if (!skipValidation) {\n errors.push(`${field.field_label} must be valid JSON`)\n }\n return { value: {}, errors }\n }\n }\n\n case 'json': {\n if (!value || value.toString().trim() === '') {\n if (!skipValidation && field.is_required) {\n errors.push(`${field.field_label} is required`)\n }\n return { value: null, errors }\n }\n try {\n return { value: JSON.parse(value.toString()), errors: [] }\n } catch {\n if (!skipValidation) {\n errors.push(`${field.field_label} must be valid JSON`)\n }\n return { value: null, errors }\n }\n }\n\n default:\n return { value: value, errors: [] }\n }\n}\n\n/**\n * Extract all field values from form data\n */\nfunction extractFieldData(\n fields: FieldDefinition[],\n formData: FormData,\n options: { skipValidation?: boolean } = {}\n): { data: Record; errors: Record } {\n const data: Record = {}\n const errors: Record = {}\n\n for (const field of fields) {\n const result = parseFieldValue(field, formData, options)\n data[field.field_name] = result.value\n if (result.errors.length > 0) {\n errors[field.field_name] = result.errors\n }\n }\n\n return { data, errors }\n}\n\n// Apply authentication middleware\nadminContentRoutes.use('*', requireAuth())\n\n// Get collection fields\nasync function getCollectionFields(db: D1Database, collectionId: string) {\n const cache = getCacheService(CACHE_CONFIGS.collection!)\n\n return cache.getOrSet(\n cache.generateKey('fields', collectionId),\n async () => {\n // First, check if collection has a schema (code-based collection)\n const collectionStmt = db.prepare('SELECT schema FROM collections WHERE id = ?')\n const collectionRow = await collectionStmt.bind(collectionId).first() as any\n\n if (collectionRow && collectionRow.schema) {\n try {\n const schema = typeof collectionRow.schema === 'string' ? JSON.parse(collectionRow.schema) : collectionRow.schema\n if (schema && schema.properties) {\n // Convert schema properties to field format\n let fieldOrder = 0\n return Object.entries(schema.properties).map(([fieldName, fieldConfig]: [string, any]) => {\n // For select fields, convert enum/enumLabels to options array\n let fieldOptions = { ...fieldConfig }\n if (fieldConfig.type === 'select' && fieldConfig.enum) {\n fieldOptions.options = fieldConfig.enum.map((value: string, index: number) => ({\n value: value,\n label: fieldConfig.enumLabels?.[index] || value\n }))\n }\n\n return {\n id: `schema-${fieldName}`,\n field_name: fieldName,\n field_type: fieldConfig.type || 'string',\n field_label: fieldConfig.title || fieldName,\n field_options: fieldOptions,\n field_order: fieldOrder++,\n is_required: fieldConfig.required === true || (schema.required && schema.required.includes(fieldName)),\n is_searchable: false\n }\n })\n }\n } catch (e) {\n console.error('Error parsing collection schema:', e)\n }\n }\n\n // Fall back to content_fields table for legacy collections\n const stmt = db.prepare(`\n SELECT * FROM content_fields\n WHERE collection_id = ?\n ORDER BY field_order ASC\n `)\n const { results } = await stmt.bind(collectionId).all()\n\n return (results || []).map((row: any) => ({\n id: row.id,\n field_name: row.field_name,\n field_type: row.field_type,\n field_label: row.field_label,\n field_options: row.field_options ? JSON.parse(row.field_options) : {},\n field_order: row.field_order,\n is_required: row.is_required === 1,\n is_searchable: row.is_searchable === 1\n }))\n }\n )\n}\n\n// Get collection by ID\nasync function getCollection(db: D1Database, collectionId: string) {\n const cache = getCacheService(CACHE_CONFIGS.collection!)\n\n return cache.getOrSet(\n cache.generateKey('collection', collectionId),\n async () => {\n const stmt = db.prepare('SELECT * FROM collections WHERE id = ? AND is_active = 1')\n const collection = await stmt.bind(collectionId).first() as any\n\n if (!collection) return null\n\n return {\n id: collection.id,\n name: collection.name,\n display_name: collection.display_name,\n description: collection.description,\n schema: collection.schema ? JSON.parse(collection.schema) : {}\n }\n }\n )\n}\n\n// Content list (main page)\nadminContentRoutes.get('/', async (c) => {\n try {\n const user = c.get('user')\n const url = new URL(c.req.url)\n const db = c.env.DB\n \n // Get query parameters\n const page = parseInt(url.searchParams.get('page') || '1')\n const limit = parseInt(url.searchParams.get('limit') || '20')\n const modelName = url.searchParams.get('model') || 'all'\n const status = url.searchParams.get('status') || 'all'\n const search = url.searchParams.get('search') || ''\n const offset = (page - 1) * limit\n \n // Get all collections for filter dropdown\n const collectionsStmt = db.prepare('SELECT id, name, display_name FROM collections WHERE is_active = 1 ORDER BY display_name')\n const { results: collectionsResults } = await collectionsStmt.all()\n const models = (collectionsResults || []).map((row: any) => ({\n name: row.name,\n displayName: row.display_name\n }))\n \n // Build where conditions\n const conditions: string[] = []\n const params: any[] = []\n\n // Always filter out deleted content unless specifically requested\n if (status !== 'deleted') {\n conditions.push(\"c.status != 'deleted'\")\n }\n\n if (search) {\n conditions.push('(c.title LIKE ? OR c.slug LIKE ? OR c.data LIKE ?)')\n params.push(`%${search}%`, `%${search}%`, `%${search}%`)\n }\n\n if (modelName !== 'all') {\n conditions.push('col.name = ?')\n params.push(modelName)\n }\n\n if (status !== 'all' && status !== 'deleted') {\n conditions.push('c.status = ?')\n params.push(status)\n } else if (status === 'deleted') {\n conditions.push(\"c.status = 'deleted'\")\n }\n\n const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(' AND ')}` : ''\n \n // Get total count\n const countStmt = db.prepare(`\n SELECT COUNT(*) as count \n FROM content c\n JOIN collections col ON c.collection_id = col.id\n ${whereClause}\n `)\n const countResult = await countStmt.bind(...params).first() as any\n const totalItems = countResult?.count || 0\n \n // Get content items\n const contentStmt = db.prepare(`\n SELECT c.id, c.title, c.slug, c.status, c.created_at, c.updated_at,\n col.name as collection_name, col.display_name as collection_display_name,\n u.first_name, u.last_name, u.email as author_email\n FROM content c\n JOIN collections col ON c.collection_id = col.id\n LEFT JOIN users u ON c.author_id = u.id\n ${whereClause}\n ORDER BY c.updated_at DESC\n LIMIT ? OFFSET ?\n `)\n const { results } = await contentStmt.bind(...params, limit, offset).all()\n \n // Process content items\n const contentItems = (results || []).map((row: any) => {\n const statusConfig: Record = {\n draft: {\n class: 'bg-zinc-50 dark:bg-zinc-500/10 text-zinc-700 dark:text-zinc-400 ring-1 ring-inset ring-zinc-600/20 dark:ring-zinc-500/20',\n text: 'Draft'\n },\n review: {\n class: 'bg-amber-50 dark:bg-amber-500/10 text-amber-700 dark:text-amber-400 ring-1 ring-inset ring-amber-600/20 dark:ring-amber-500/20',\n text: 'Under Review'\n },\n scheduled: {\n class: 'bg-blue-50 dark:bg-blue-500/10 text-blue-700 dark:text-blue-400 ring-1 ring-inset ring-blue-600/20 dark:ring-blue-500/20',\n text: 'Scheduled'\n },\n published: {\n class: 'bg-green-50 dark:bg-green-500/10 text-green-700 dark:text-green-400 ring-1 ring-inset ring-green-600/20 dark:ring-green-500/20',\n text: 'Published'\n },\n archived: {\n class: 'bg-purple-50 dark:bg-purple-500/10 text-purple-700 dark:text-purple-400 ring-1 ring-inset ring-purple-600/20 dark:ring-purple-500/20',\n text: 'Archived'\n },\n deleted: {\n class: 'bg-red-50 dark:bg-red-500/10 text-red-700 dark:text-red-400 ring-1 ring-inset ring-red-600/20 dark:ring-red-500/20',\n text: 'Deleted'\n }\n }\n\n const config = statusConfig[row.status as keyof typeof statusConfig] || statusConfig.draft\n const statusBadge = `\n \n ${config?.text || row.status}\n \n `\n \n const authorName = row.first_name && row.last_name \n ? `${row.first_name} ${row.last_name}`\n : row.author_email || 'Unknown'\n \n const formattedDate = new Date(row.updated_at).toLocaleDateString()\n \n // Determine available workflow actions based on status\n const availableActions: string[] = []\n switch (row.status) {\n case 'draft':\n availableActions.push('submit_for_review', 'publish')\n break\n case 'review':\n availableActions.push('approve', 'request_changes')\n break\n case 'published':\n availableActions.push('unpublish', 'archive')\n break\n case 'scheduled':\n availableActions.push('unschedule')\n break\n }\n \n return {\n id: row.id,\n title: row.title,\n slug: row.slug,\n modelName: row.collection_display_name,\n statusBadge,\n authorName,\n formattedDate,\n availableActions\n }\n })\n \n const pageData: ContentListPageData = {\n modelName,\n status,\n page,\n search,\n models,\n contentItems,\n totalItems,\n itemsPerPage: limit,\n user: user ? {\n name: user.email,\n email: user.email,\n role: user.role\n } : undefined,\n version: c.get('appVersion')\n }\n\n return c.html(renderContentListPage(pageData))\n } catch (error) {\n console.error('Error fetching content list:', error)\n return c.html(`Error loading content: ${error}
`)\n }\n})\n\n// New content form\nadminContentRoutes.get('/new', async (c) => {\n try {\n const user = c.get('user')\n const url = new URL(c.req.url)\n const collectionId = url.searchParams.get('collection')\n \n if (!collectionId) {\n // Show collection selection page\n const db = c.env.DB\n const collectionsStmt = db.prepare('SELECT id, name, display_name, description FROM collections WHERE is_active = 1 ORDER BY display_name')\n const { results } = await collectionsStmt.all()\n \n const collections = (results || []).map((row: any) => ({\n id: row.id,\n name: row.name,\n display_name: row.display_name,\n description: row.description\n }))\n \n // Render collection selection page\n const selectionHTML = `\n \n \n \n Select Collection - SonicJS AI Admin \n \n \n \n \n
\n
Create New Content \n
Select a collection to create content in:
\n \n
\n \n
\n
\n
\n \n \n `\n \n return c.html(selectionHTML)\n }\n \n const db = c.env.DB\n const collection = await getCollection(db, collectionId)\n \n if (!collection) {\n const formData: ContentFormData = {\n collection: { id: '', name: '', display_name: 'Unknown', schema: {} },\n fields: [],\n error: 'Collection not found.',\n user: user ? {\n name: user.email,\n email: user.email,\n role: user.role\n } : undefined\n }\n return c.html(renderContentFormPage(formData))\n }\n \n const fields = await getCollectionFields(db, collectionId)\n\n // Check if workflow plugin is active\n const workflowEnabled = await isPluginActive(db, 'workflow')\n\n // Check if TinyMCE plugin is active and get settings\n const tinymceEnabled = await isPluginActive(db, 'tinymce-plugin')\n let tinymceSettings\n if (tinymceEnabled) {\n const pluginService = new PluginService(db)\n const tinymcePlugin = await pluginService.getPlugin('tinymce-plugin')\n tinymceSettings = tinymcePlugin?.settings\n }\n\n // Check if Quill plugin is active and get settings\n const quillEnabled = await isPluginActive(db, 'quill-editor')\n let quillSettings\n if (quillEnabled) {\n const pluginService = new PluginService(db)\n const quillPlugin = await pluginService.getPlugin('quill-editor')\n quillSettings = quillPlugin?.settings\n }\n\n // Check if MDXEditor plugin is active and get settings\n const mdxeditorEnabled = await isPluginActive(db, 'easy-mdx')\n let mdxeditorSettings\n if (mdxeditorEnabled) {\n const pluginService = new PluginService(db)\n const mdxeditorPlugin = await pluginService.getPlugin('easy-mdx')\n mdxeditorSettings = mdxeditorPlugin?.settings\n }\n\n console.log('[Content Form /new] Editor plugins status:', {\n tinymce: tinymceEnabled,\n quill: quillEnabled,\n mdxeditor: mdxeditorEnabled,\n mdxeditorSettings\n })\n\n const formData: ContentFormData = {\n collection,\n fields,\n isEdit: false,\n workflowEnabled,\n tinymceEnabled,\n tinymceSettings,\n quillEnabled,\n quillSettings,\n mdxeditorEnabled,\n mdxeditorSettings,\n user: user ? {\n name: user.email,\n email: user.email,\n role: user.role\n } : undefined\n }\n \n return c.html(renderContentFormPage(formData))\n } catch (error) {\n console.error('Error loading new content form:', error)\n const formData: ContentFormData = {\n collection: { id: '', name: '', display_name: 'Unknown', schema: {} },\n fields: [],\n error: 'Failed to load content form.',\n user: c.get('user') ? {\n name: c.get('user')!.email,\n email: c.get('user')!.email,\n role: c.get('user')!.role\n } : undefined\n }\n return c.html(renderContentFormPage(formData))\n }\n})\n\n// Edit content form\nadminContentRoutes.get('/:id/edit', async (c) => {\n try {\n const id = c.req.param('id')\n const user = c.get('user')\n const db = c.env.DB\n const url = new URL(c.req.url)\n\n // Capture referrer parameters to preserve filters when returning to list\n const referrerParams = url.searchParams.get('ref') || ''\n\n // Get content with caching\n const cache = getCacheService(CACHE_CONFIGS.content!)\n const content = await cache.getOrSet(\n cache.generateKey('content', id),\n async () => {\n const contentStmt = db.prepare(`\n SELECT c.*, col.id as collection_id, col.name as collection_name,\n col.display_name as collection_display_name, col.description as collection_description,\n col.schema as collection_schema\n FROM content c\n JOIN collections col ON c.collection_id = col.id\n WHERE c.id = ?\n `)\n return await contentStmt.bind(id).first() as any\n }\n )\n\n if (!content) {\n const formData: ContentFormData = {\n collection: { id: '', name: '', display_name: 'Unknown', schema: {} },\n fields: [],\n error: 'Content not found.',\n user: user ? {\n name: user.email,\n email: user.email,\n role: user.role\n } : undefined\n }\n return c.html(renderContentFormPage(formData))\n }\n \n const collection = {\n id: content.collection_id,\n name: content.collection_name,\n display_name: content.collection_display_name,\n description: content.collection_description,\n schema: content.collection_schema ? JSON.parse(content.collection_schema) : {}\n }\n \n const fields = await getCollectionFields(db, content.collection_id)\n const contentData = content.data ? JSON.parse(content.data) : {}\n\n // Check if workflow plugin is active\n const workflowEnabled = await isPluginActive(db, 'workflow')\n\n // Check if TinyMCE plugin is active and get settings\n const tinymceEnabled = await isPluginActive(db, 'tinymce-plugin')\n let tinymceSettings\n if (tinymceEnabled) {\n const pluginService = new PluginService(db)\n const tinymcePlugin = await pluginService.getPlugin('tinymce-plugin')\n tinymceSettings = tinymcePlugin?.settings\n }\n\n // Check if Quill plugin is active and get settings\n const quillEnabled = await isPluginActive(db, 'quill-editor')\n let quillSettings\n if (quillEnabled) {\n const pluginService = new PluginService(db)\n const quillPlugin = await pluginService.getPlugin('quill-editor')\n quillSettings = quillPlugin?.settings\n }\n\n // Check if MDXEditor plugin is active and get settings\n const mdxeditorEnabled = await isPluginActive(db, 'easy-mdx')\n let mdxeditorSettings\n if (mdxeditorEnabled) {\n const pluginService = new PluginService(db)\n const mdxeditorPlugin = await pluginService.getPlugin('easy-mdx')\n mdxeditorSettings = mdxeditorPlugin?.settings\n }\n\n const formData: ContentFormData = {\n id: content.id,\n title: content.title,\n slug: content.slug,\n data: contentData,\n status: content.status,\n scheduled_publish_at: content.scheduled_publish_at,\n scheduled_unpublish_at: content.scheduled_unpublish_at,\n review_status: content.review_status,\n meta_title: content.meta_title,\n meta_description: content.meta_description,\n collection,\n fields,\n isEdit: true,\n workflowEnabled,\n tinymceEnabled,\n tinymceSettings,\n quillEnabled,\n quillSettings,\n mdxeditorEnabled,\n mdxeditorSettings,\n referrerParams,\n user: user ? {\n name: user.email,\n email: user.email,\n role: user.role\n } : undefined,\n version: c.get('appVersion')\n }\n\n return c.html(renderContentFormPage(formData))\n } catch (error) {\n console.error('Error loading edit content form:', error)\n const formData: ContentFormData = {\n collection: { id: '', name: '', display_name: 'Unknown', schema: {} },\n fields: [],\n error: 'Failed to load content for editing.',\n user: c.get('user') ? {\n name: c.get('user')!.email,\n email: c.get('user')!.email,\n role: c.get('user')!.role\n } : undefined\n }\n return c.html(renderContentFormPage(formData))\n }\n})\n\n// Create content\nadminContentRoutes.post('/', async (c) => {\n try {\n const user = c.get('user')\n const formData = await c.req.formData()\n const collectionId = formData.get('collection_id') as string\n const action = formData.get('action') as string\n \n if (!collectionId) {\n return c.html(html`\n \n Collection ID is required.\n
\n `)\n }\n \n const db = c.env.DB\n const collection = await getCollection(db, collectionId)\n \n if (!collection) {\n return c.html(html`\n \n Collection not found.\n
\n `)\n }\n \n const fields = await getCollectionFields(db, collectionId)\n\n // Extract and validate field data\n const { data, errors } = extractFieldData(fields, formData)\n\n // Check for validation errors\n if (Object.keys(errors).length > 0) {\n const formDataWithErrors: ContentFormData = {\n collection,\n fields,\n data,\n validationErrors: errors,\n error: 'Please fix the validation errors below.',\n user: user ? {\n name: user.email,\n email: user.email,\n role: user.role\n } : undefined\n }\n return c.html(renderContentFormPage(formDataWithErrors))\n }\n \n // Generate slug if not provided\n let slug = data.slug || data.title\n if (slug) {\n slug = slug.toLowerCase()\n .replace(/[^a-z0-9\\s-]/g, '')\n .replace(/\\s+/g, '-')\n .replace(/-+/g, '-')\n .trim('-')\n }\n \n // Determine status\n let status = formData.get('status') as string || 'draft'\n if (action === 'save_and_publish') {\n status = 'published'\n }\n \n // Handle scheduling\n const scheduledPublishAt = formData.get('scheduled_publish_at') as string\n const scheduledUnpublishAt = formData.get('scheduled_unpublish_at') as string\n \n // Create content\n const contentId = crypto.randomUUID()\n const now = Date.now()\n \n const insertStmt = db.prepare(`\n INSERT INTO content (\n id, collection_id, slug, title, data, status,\n author_id, created_at, updated_at\n )\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)\n `)\n\n await insertStmt.bind(\n contentId,\n collectionId,\n slug,\n data.title || 'Untitled',\n JSON.stringify(data),\n status,\n user?.userId || 'unknown',\n now,\n now\n ).run()\n\n // Invalidate collection content list cache\n const cache = getCacheService(CACHE_CONFIGS.content!)\n await cache.invalidate(`content:list:${collectionId}:*`)\n\n // Create initial version\n const versionStmt = db.prepare(`\n INSERT INTO content_versions (id, content_id, version, data, author_id, created_at)\n VALUES (?, ?, ?, ?, ?, ?)\n `)\n \n await versionStmt.bind(\n crypto.randomUUID(),\n contentId,\n 1,\n JSON.stringify(data),\n user?.userId || 'unknown',\n now\n ).run()\n \n // Log workflow action\n const workflowStmt = db.prepare(`\n INSERT INTO workflow_history (id, content_id, action, from_status, to_status, user_id, created_at)\n VALUES (?, ?, ?, ?, ?, ?, ?)\n `)\n \n await workflowStmt.bind(\n crypto.randomUUID(),\n contentId,\n 'created',\n 'none',\n status,\n user?.userId || 'unknown',\n now\n ).run()\n\n // Sync to FTS5 index (non-blocking)\n const fts5Service = new FTS5Service(db)\n c.executionCtx.waitUntil(\n fts5Service.indexContent(contentId).catch(err =>\n console.error('[Content] FTS5 indexing failed:', err)\n )\n )\n\n // Invalidate search result cache (non-blocking)\n if (c.env.CACHE_KV) {\n const searchCache = new SearchCacheService(c.env.CACHE_KV)\n c.executionCtx.waitUntil(searchCache.invalidateAll())\n }\n\n // Handle different actions\n const referrerParams = formData.get('referrer_params') as string\n const redirectUrl = action === 'save_and_continue'\n ? `/admin/content/${contentId}/edit?success=Content saved successfully!${referrerParams ? `&ref=${encodeURIComponent(referrerParams)}` : ''}`\n : referrerParams\n ? `/admin/content?${referrerParams}&success=Content created successfully!`\n : `/admin/content?collection=${collectionId}&success=Content created successfully!`\n\n // Check if this is an HTMX request\n const isHTMX = c.req.header('HX-Request') === 'true'\n \n if (isHTMX) {\n // For HTMX requests, use HX-Redirect header to trigger client-side redirect\n return c.text('', 200, {\n 'HX-Redirect': redirectUrl\n })\n } else {\n // For regular requests, use server-side redirect\n return c.redirect(redirectUrl)\n }\n \n } catch (error) {\n console.error('Error creating content:', error)\n return c.html(html`\n \n Failed to create content. Please try again.\n
\n `)\n }\n})\n\n// Update content\nadminContentRoutes.put('/:id', async (c) => {\n try {\n const id = c.req.param('id')\n const user = c.get('user')\n const formData = await c.req.formData()\n const action = formData.get('action') as string\n \n const db = c.env.DB\n \n // Get existing content\n const contentStmt = db.prepare('SELECT * FROM content WHERE id = ?')\n const existingContent = await contentStmt.bind(id).first() as any\n \n if (!existingContent) {\n return c.html(html`\n \n Content not found.\n
\n `)\n }\n \n const collection = await getCollection(db, existingContent.collection_id)\n if (!collection) {\n return c.html(html`\n \n Collection not found.\n
\n `)\n }\n \n const fields = await getCollectionFields(db, existingContent.collection_id)\n\n // Extract and validate field data\n const { data, errors } = extractFieldData(fields, formData)\n\n if (Object.keys(errors).length > 0) {\n const formDataWithErrors: ContentFormData = {\n id,\n collection,\n fields,\n data,\n validationErrors: errors,\n error: 'Please fix the validation errors below.',\n isEdit: true,\n user: user ? {\n name: user.email,\n email: user.email,\n role: user.role\n } : undefined\n }\n return c.html(renderContentFormPage(formDataWithErrors))\n }\n \n // Update slug if title changed\n let slug = data.slug || data.title\n if (slug) {\n slug = slug.toLowerCase()\n .replace(/[^a-z0-9\\s-]/g, '')\n .replace(/\\s+/g, '-')\n .replace(/-+/g, '-')\n .trim('-')\n }\n \n // Determine status\n let status = formData.get('status') as string || existingContent.status\n if (action === 'save_and_publish') {\n status = 'published'\n }\n \n // Handle scheduling\n const scheduledPublishAt = formData.get('scheduled_publish_at') as string\n const scheduledUnpublishAt = formData.get('scheduled_unpublish_at') as string\n \n // Update content\n const now = Date.now()\n \n const updateStmt = db.prepare(`\n UPDATE content SET\n slug = ?, title = ?, data = ?, status = ?,\n scheduled_publish_at = ?, scheduled_unpublish_at = ?,\n meta_title = ?, meta_description = ?, updated_at = ?\n WHERE id = ?\n `)\n \n await updateStmt.bind(\n slug,\n data.title || 'Untitled',\n JSON.stringify(data),\n status,\n scheduledPublishAt ? new Date(scheduledPublishAt).getTime() : null,\n scheduledUnpublishAt ? new Date(scheduledUnpublishAt).getTime() : null,\n data.meta_title || null,\n data.meta_description || null,\n now,\n id\n ).run()\n\n // Invalidate content cache\n const cache = getCacheService(CACHE_CONFIGS.content!)\n await cache.delete(cache.generateKey('content', id))\n await cache.invalidate(`content:list:${existingContent.collection_id}:*`)\n\n // Create new version if content changed\n const existingData = JSON.parse(existingContent.data || '{}')\n if (JSON.stringify(existingData) !== JSON.stringify(data)) {\n // Get next version number\n const versionCountStmt = db.prepare('SELECT MAX(version) as max_version FROM content_versions WHERE content_id = ?')\n const versionResult = await versionCountStmt.bind(id).first() as any\n const nextVersion = (versionResult?.max_version || 0) + 1\n \n const versionStmt = db.prepare(`\n INSERT INTO content_versions (id, content_id, version, data, author_id, created_at)\n VALUES (?, ?, ?, ?, ?, ?)\n `)\n \n await versionStmt.bind(\n crypto.randomUUID(),\n id,\n nextVersion,\n JSON.stringify(data),\n user?.userId || 'unknown',\n now\n ).run()\n }\n \n // Log workflow action if status changed\n if (status !== existingContent.status) {\n const workflowStmt = db.prepare(`\n INSERT INTO workflow_history (id, content_id, action, from_status, to_status, user_id, created_at)\n VALUES (?, ?, ?, ?, ?, ?, ?)\n `)\n \n await workflowStmt.bind(\n crypto.randomUUID(),\n id,\n 'status_changed',\n existingContent.status,\n status,\n user?.userId || 'unknown',\n now\n ).run()\n }\n\n // Sync to FTS5 index (non-blocking)\n const fts5Service = new FTS5Service(db)\n c.executionCtx.waitUntil(\n fts5Service.indexContent(id).catch(err =>\n console.error('[Content] FTS5 reindexing failed:', err)\n )\n )\n\n // Invalidate search result cache (non-blocking)\n if (c.env.CACHE_KV) {\n const searchCache = new SearchCacheService(c.env.CACHE_KV)\n c.executionCtx.waitUntil(searchCache.invalidateAll())\n }\n\n // Handle different actions\n const referrerParams = formData.get('referrer_params') as string\n const redirectUrl = action === 'save_and_continue'\n ? `/admin/content/${id}/edit?success=Content updated successfully!${referrerParams ? `&ref=${encodeURIComponent(referrerParams)}` : ''}`\n : referrerParams\n ? `/admin/content?${referrerParams}&success=Content updated successfully!`\n : `/admin/content?collection=${existingContent.collection_id}&success=Content updated successfully!`\n\n // Check if this is an HTMX request\n const isHTMX = c.req.header('HX-Request') === 'true'\n \n if (isHTMX) {\n // For HTMX requests, use HX-Redirect header to trigger client-side redirect\n return c.text('', 200, {\n 'HX-Redirect': redirectUrl\n })\n } else {\n // For regular requests, use server-side redirect\n return c.redirect(redirectUrl)\n }\n \n } catch (error) {\n console.error('Error updating content:', error)\n return c.html(html`\n \n Failed to update content. Please try again.\n
\n `)\n }\n})\n\n// Content preview\nadminContentRoutes.post('/preview', async (c) => {\n try {\n const formData = await c.req.formData()\n const collectionId = formData.get('collection_id') as string\n \n const db = c.env.DB\n const collection = await getCollection(db, collectionId)\n \n if (!collection) {\n return c.html('Collection not found
')\n }\n \n const fields = await getCollectionFields(db, collectionId)\n\n // Extract field data for preview (skip validation)\n const { data } = extractFieldData(fields, formData, { skipValidation: true })\n\n // Generate preview HTML\n const previewHTML = `\n \n \n \n \n \n Preview: ${data.title || 'Untitled'} \n \n \n \n ${data.title || 'Untitled'} \n \n Collection: ${collection.display_name} \n Status: ${formData.get('status') || 'draft'} \n ${data.meta_description ? `Description: ${data.meta_description} ` : ''}\n
\n \n ${data.content || '
No content provided.
'}\n
\n \n All Fields: \n \n Field Value \n ${fields.map(field => `\n \n ${field.field_label} \n ${data[field.field_name] || 'empty '} \n \n `).join('')}\n
\n \n \n `\n \n return c.html(previewHTML)\n } catch (error) {\n console.error('Error generating preview:', error)\n return c.html('Error generating preview
')\n }\n})\n\n// Duplicate content\nadminContentRoutes.post('/duplicate', async (c) => {\n try {\n const user = c.get('user')\n const formData = await c.req.formData()\n const originalId = formData.get('id') as string\n \n if (!originalId) {\n return c.json({ success: false, error: 'Content ID required' })\n }\n \n const db = c.env.DB\n \n // Get original content\n const contentStmt = db.prepare('SELECT * FROM content WHERE id = ?')\n const original = await contentStmt.bind(originalId).first() as any\n \n if (!original) {\n return c.json({ success: false, error: 'Content not found' })\n }\n \n // Create duplicate\n const newId = crypto.randomUUID()\n const now = Date.now()\n const originalData = JSON.parse(original.data || '{}')\n \n // Modify title to indicate it's a copy\n originalData.title = `${originalData.title || 'Untitled'} (Copy)`\n \n const insertStmt = db.prepare(`\n INSERT INTO content (\n id, collection_id, slug, title, data, status,\n author_id, created_at, updated_at\n )\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)\n `)\n\n await insertStmt.bind(\n newId,\n original.collection_id,\n `${original.slug}-copy-${Date.now()}`,\n originalData.title,\n JSON.stringify(originalData),\n 'draft', // Always start as draft\n user?.userId || 'unknown',\n now,\n now\n ).run()\n \n return c.json({ success: true, id: newId })\n } catch (error) {\n console.error('Error duplicating content:', error)\n return c.json({ success: false, error: 'Failed to duplicate content' })\n }\n})\n\n// Get bulk actions modal\nadminContentRoutes.get('/bulk-actions', async (c) => {\n const bulkActionsModal = `\n \n
\n
\n
Bulk Actions \n
\n \n \n \n \n
\n
\n Select items from the table below to perform bulk actions.\n
\n
\n
\n \n \n \n Publish Selected\n \n
\n \n \n \n Move to Draft\n \n
\n \n \n \n Delete Selected\n \n
\n
\n
\n \n `\n\n return c.html(bulkActionsModal)\n})\n\n// Perform bulk action\nadminContentRoutes.post('/bulk-action', async (c) => {\n try {\n const user = c.get('user')\n const body = await c.req.json()\n const { action, ids } = body\n\n if (!action || !ids || ids.length === 0) {\n return c.json({ success: false, error: 'Action and IDs required' })\n }\n\n const db = c.env.DB\n const now = Date.now()\n\n if (action === 'delete') {\n // Soft delete by setting status to 'deleted'\n const placeholders = ids.map(() => '?').join(',')\n const stmt = db.prepare(`\n UPDATE content\n SET status = 'deleted', updated_at = ?\n WHERE id IN (${placeholders})\n `)\n await stmt.bind(now, ...ids).run()\n } else if (action === 'publish' || action === 'draft') {\n // Update status\n const placeholders = ids.map(() => '?').join(',')\n const publishedAt = action === 'publish' ? now : null\n const stmt = db.prepare(`\n UPDATE content\n SET status = ?, published_at = ?, updated_at = ?\n WHERE id IN (${placeholders})\n `)\n await stmt.bind(action, publishedAt, now, ...ids).run()\n } else {\n return c.json({ success: false, error: 'Invalid action' })\n }\n\n // Invalidate cache for all affected content items\n const cache = getCacheService(CACHE_CONFIGS.content!)\n for (const contentId of ids) {\n await cache.delete(cache.generateKey('content', contentId))\n }\n // Also invalidate list caches (they contain content from potentially multiple collections)\n await cache.invalidate('content:list:*')\n\n return c.json({ success: true, count: ids.length })\n } catch (error) {\n console.error('Bulk action error:', error)\n return c.json({ success: false, error: 'Failed to perform bulk action' })\n }\n})\n\n// Delete content\nadminContentRoutes.delete('/:id', async (c) => {\n try {\n const id = c.req.param('id')\n const db = c.env.DB\n const user = c.get('user')\n\n // Check if content exists\n const contentStmt = db.prepare('SELECT id, title FROM content WHERE id = ?')\n const content = await contentStmt.bind(id).first() as any\n\n if (!content) {\n return c.json({ success: false, error: 'Content not found' }, 404)\n }\n\n // Soft delete by setting status to 'deleted'\n const now = Date.now()\n const deleteStmt = db.prepare(`\n UPDATE content\n SET status = 'deleted', updated_at = ?\n WHERE id = ?\n `)\n await deleteStmt.bind(now, id).run()\n\n // Remove from FTS5 index (non-blocking)\n const fts5Service = new FTS5Service(db)\n c.executionCtx.waitUntil(\n fts5Service.removeFromIndex(id).catch(err =>\n console.error('[Content] FTS5 removal failed:', err)\n )\n )\n\n // Invalidate search result cache (non-blocking)\n if (c.env.CACHE_KV) {\n const searchCache = new SearchCacheService(c.env.CACHE_KV)\n c.executionCtx.waitUntil(searchCache.invalidateAll())\n }\n\n // Invalidate cache\n const cache = getCacheService(CACHE_CONFIGS.content!)\n await cache.delete(cache.generateKey('content', id))\n await cache.invalidate('content:list:*')\n\n // Return success - let HTMX reload the page\n return c.html(`\n \n
\n
\n
\n \n \n
Content deleted successfully. Refreshing...
\n
\n
\n
\n `)\n } catch (error) {\n console.error('Delete content error:', error)\n return c.json({ success: false, error: 'Failed to delete content' }, 500)\n }\n})\n\n// Get version history\nadminContentRoutes.get('/:id/versions', async (c) => {\n try {\n const id = c.req.param('id')\n const db = c.env.DB\n \n // Get current content\n const contentStmt = db.prepare('SELECT * FROM content WHERE id = ?')\n const content = await contentStmt.bind(id).first() as any\n \n if (!content) {\n return c.html('Content not found
')\n }\n \n // Get all versions with author info\n const versionsStmt = db.prepare(`\n SELECT cv.*, u.first_name, u.last_name, u.email\n FROM content_versions cv\n LEFT JOIN users u ON cv.author_id = u.id\n WHERE cv.content_id = ?\n ORDER BY cv.version DESC\n `)\n const { results } = await versionsStmt.bind(id).all()\n \n const versions: ContentVersion[] = (results || []).map((row: any) => ({\n id: row.id,\n version: row.version,\n data: JSON.parse(row.data || '{}'),\n author_id: row.author_id,\n author_name: row.first_name && row.last_name ? `${row.first_name} ${row.last_name}` : row.email,\n created_at: row.created_at,\n is_current: false // Will be set below\n }))\n \n // Mark the latest version as current\n if (versions.length > 0) {\n versions[0]!.is_current = true\n }\n \n const data: VersionHistoryData = {\n contentId: id,\n versions,\n currentVersion: versions.length > 0 ? versions[0]!.version : 1\n }\n \n return c.html(renderVersionHistory(data))\n } catch (error) {\n console.error('Error loading version history:', error)\n return c.html('Error loading version history
')\n }\n})\n\n// Restore version\nadminContentRoutes.post('/:id/restore/:version', async (c) => {\n try {\n const id = c.req.param('id')\n const version = parseInt(c.req.param('version'))\n const user = c.get('user')\n const db = c.env.DB\n \n // Get the specific version\n const versionStmt = db.prepare(`\n SELECT * FROM content_versions \n WHERE content_id = ? AND version = ?\n `)\n const versionData = await versionStmt.bind(id, version).first() as any\n \n if (!versionData) {\n return c.json({ success: false, error: 'Version not found' })\n }\n \n // Get current content\n const contentStmt = db.prepare('SELECT * FROM content WHERE id = ?')\n const currentContent = await contentStmt.bind(id).first() as any\n \n if (!currentContent) {\n return c.json({ success: false, error: 'Content not found' })\n }\n \n const restoredData = JSON.parse(versionData.data)\n const now = Date.now()\n \n // Update content with restored data\n const updateStmt = db.prepare(`\n UPDATE content SET\n title = ?, data = ?, updated_at = ?\n WHERE id = ?\n `)\n \n await updateStmt.bind(\n restoredData.title || 'Untitled',\n versionData.data,\n now,\n id\n ).run()\n \n // Create new version for the restoration\n const nextVersionStmt = db.prepare('SELECT MAX(version) as max_version FROM content_versions WHERE content_id = ?')\n const nextVersionResult = await nextVersionStmt.bind(id).first() as any\n const nextVersion = (nextVersionResult?.max_version || 0) + 1\n \n const newVersionStmt = db.prepare(`\n INSERT INTO content_versions (id, content_id, version, data, author_id, created_at)\n VALUES (?, ?, ?, ?, ?, ?)\n `)\n \n await newVersionStmt.bind(\n crypto.randomUUID(),\n id,\n nextVersion,\n versionData.data,\n user?.userId || 'unknown',\n now\n ).run()\n \n // Log workflow action\n const workflowStmt = db.prepare(`\n INSERT INTO workflow_history (id, content_id, action, from_status, to_status, user_id, comment, created_at)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?)\n `)\n \n await workflowStmt.bind(\n crypto.randomUUID(),\n id,\n 'version_restored',\n currentContent.status,\n currentContent.status,\n user?.userId || 'unknown',\n `Restored to version ${version}`,\n now\n ).run()\n \n return c.json({ success: true })\n } catch (error) {\n console.error('Error restoring version:', error)\n return c.json({ success: false, error: 'Failed to restore version' })\n }\n})\n\n// Preview specific version\nadminContentRoutes.get('/:id/version/:version/preview', async (c) => {\n try {\n const id = c.req.param('id')\n const version = parseInt(c.req.param('version'))\n const db = c.env.DB\n \n // Get the specific version\n const versionStmt = db.prepare(`\n SELECT cv.*, c.collection_id, col.display_name as collection_name\n FROM content_versions cv\n JOIN content c ON cv.content_id = c.id\n JOIN collections col ON c.collection_id = col.id\n WHERE cv.content_id = ? AND cv.version = ?\n `)\n const versionData = await versionStmt.bind(id, version).first() as any\n \n if (!versionData) {\n return c.html('Version not found
')\n }\n \n const data = JSON.parse(versionData.data || '{}')\n \n // Generate preview HTML\n const previewHTML = `\n \n \n \n \n \n Version ${version} Preview: ${data.title || 'Untitled'} \n \n \n \n \n Version ${version} \n Collection: ${versionData.collection_name} \n Created: ${new Date(versionData.created_at).toLocaleString()} \n This is a historical version preview \n
\n \n ${data.title || 'Untitled'} \n \n \n ${data.content || '
No content provided.
'}\n
\n \n ${data.excerpt ? `Excerpt: ${data.excerpt}
` : ''}\n \n All Field Data: \n \n${JSON.stringify(data, null, 2)}\n \n \n \n `\n \n return c.html(previewHTML)\n } catch (error) {\n console.error('Error generating version preview:', error)\n return c.html('Error generating preview
')\n }\n})\nexport default adminContentRoutes\n","import { renderAdminLayoutCatalyst, AdminLayoutCatalystData } from '../layouts/admin-layout-catalyst.template'\nimport { renderAlert } from '../alert.template'\n\nexport interface UserProfile {\n id: string\n email: string\n username: string\n first_name: string\n last_name: string\n phone?: string\n bio?: string\n avatar_url?: string\n timezone: string\n language: string\n theme: string\n email_notifications: boolean\n two_factor_enabled: boolean\n role: string\n created_at: number\n last_login_at?: number\n}\n\nexport interface ProfilePageData {\n profile: UserProfile\n timezones: Array<{ value: string; label: string }>\n languages: Array<{ value: string; label: string }>\n error?: string\n success?: string\n user?: {\n name: string\n email: string\n role: string\n }\n version?: string\n}\n\nexport function renderAvatarImage(avatarUrl: string | undefined, firstName: string, lastName: string): string {\n return `\n ${avatarUrl\n ? `
`\n : `
${firstName.charAt(0)}${lastName.charAt(0)} `\n }\n
`\n}\n\nexport function renderProfilePage(data: ProfilePageData): string {\n const pageContent = `\n \n \n
\n
\n
User Profile \n
\n Manage your account settings and preferences\n
\n
\n
\n\n \n ${data.error ? renderAlert({ type: 'error', message: data.error, dismissible: true }) : ''}\n ${data.success ? renderAlert({ type: 'success', message: data.success, dismissible: true }) : ''}\n\n \n
\n \n
\n
\n \n
\n
\n
\n
\n
Profile Information \n
Update your account details
\n
\n
\n
\n\n \n
\n
\n
\n\n \n
\n \n
\n
Profile Picture \n\n
\n ${renderAvatarImage(data.profile.avatar_url, data.profile.first_name, data.profile.last_name)}\n\n
\n \n \n \n \n \n \n Change Picture\n \n \n\n
\n
\n
\n\n \n
\n
Account Information \n\n
\n \n
Role \n \n \n ${data.profile.role}\n \n \n \n \n
Member Since \n ${new Date(data.profile.created_at).toLocaleDateString()} \n \n ${data.profile.last_login_at ? `\n \n
Last Login \n ${new Date(data.profile.last_login_at).toLocaleDateString()} \n \n ` : ''}\n \n
Two-Factor Auth \n \n ${data.profile.two_factor_enabled\n ? 'Enabled '\n : 'Disabled '\n }\n \n \n \n
\n\n \n
\n
Security \n\n
\n
\n \n \n \n Change Password \n \n\n
\n \n \n \n ${data.profile.two_factor_enabled ? 'Disable' : 'Enable'} 2FA \n \n
\n
\n
\n
\n
\n\n \n \n
\n
\n
\n
Change Password \n
\n \n \n \n \n
\n
\n\n
\n
\n\n \n Current Password \n \n
\n\n \n
New Password \n
\n
Must be at least 8 characters
\n
\n\n \n Confirm New Password \n \n
\n\n \n
\n Cancel\n \n
\n \n \n \n Update Password\n \n
\n \n
\n
\n\n \n `\n\n const layoutData: AdminLayoutCatalystData = {\n title: 'User Profile',\n pageTitle: 'Profile',\n currentPath: '/admin/profile',\n user: data.user,\n version: data.version,\n content: pageContent\n }\n\n return renderAdminLayoutCatalyst(layoutData)\n}\n","export type AlertType = 'success' | 'error' | 'warning' | 'info'\n\nexport interface AlertData {\n type: AlertType\n title?: string\n message: string\n dismissible?: boolean\n className?: string\n icon?: boolean\n}\n\nexport function renderAlert(data: AlertData): string {\n const typeClasses = {\n success: 'bg-green-50 dark:bg-green-500/10 border border-green-600/20 dark:border-green-500/20',\n error: 'bg-error/10 border border-red-600/20 dark:border-red-500/20',\n warning: 'bg-amber-50 dark:bg-amber-500/10 border border-amber-600/20 dark:border-amber-500/20',\n info: 'bg-blue-50 dark:bg-blue-500/10 border border-blue-600/20 dark:border-blue-500/20'\n }\n\n const iconClasses = {\n success: 'text-green-600 dark:text-green-400',\n error: 'text-red-600 dark:text-red-400',\n warning: 'text-amber-600 dark:text-amber-400',\n info: 'text-blue-600 dark:text-blue-400'\n }\n\n const textClasses = {\n success: 'text-green-900 dark:text-green-300',\n error: 'text-red-900 dark:text-red-300',\n warning: 'text-amber-900 dark:text-amber-300',\n info: 'text-blue-900 dark:text-blue-300'\n }\n\n const messageTextClasses = {\n success: 'text-green-700 dark:text-green-400',\n error: 'text-red-700 dark:text-red-400',\n warning: 'text-amber-700 dark:text-amber-400',\n info: 'text-blue-700 dark:text-blue-400'\n }\n\n const icons = {\n success: ` `,\n error: ` `,\n warning: ` `,\n info: ` `\n }\n\n return `\n \n
\n ${data.icon !== false ? `\n
\n \n ${icons[data.type]}\n \n
\n ` : ''}\n
\n ${data.title ? `\n
\n ${data.title}\n \n ` : ''}\n
\n
\n ${data.dismissible ? `\n
\n
\n
\n Dismiss \n \n \n \n \n
\n
\n ` : ''}\n
\n
\n `\n}\n\nexport function renderSuccessAlert(message: string, title?: string): string {\n return renderAlert({ type: 'success', message, title })\n}\n\nexport function renderErrorAlert(message: string, title?: string): string {\n return renderAlert({ type: 'error', message, title })\n}\n\nexport function renderWarningAlert(message: string, title?: string): string {\n return renderAlert({ type: 'warning', message, title })\n}\n\nexport function renderInfoAlert(message: string, title?: string): string {\n return renderAlert({ type: 'info', message, title })\n}\n","import { renderAdminLayout, AdminLayoutData } from '../layouts/admin-layout-v2.template'\n\nexport interface ActivityLog {\n id: string\n user_id: string\n action: string\n resource_type?: string\n resource_id?: string\n details?: any\n ip_address?: string\n user_agent?: string\n created_at: number\n user_email?: string\n user_name?: string\n}\n\nexport interface ActivityLogsPageData {\n logs: ActivityLog[]\n pagination: {\n page: number\n limit: number\n total: number\n pages: number\n }\n filters: {\n user_id?: string\n action?: string\n resource_type?: string\n date_from?: string\n date_to?: string\n }\n user?: {\n name: string\n email: string\n role: string\n }\n}\n\nexport function renderActivityLogsPage(data: ActivityLogsPageData): string {\n const pageContent = `\n \n \n
\n
\n
Activity Logs \n
Monitor user actions and system activity
\n
\n
\n\n \n
\n \n \n \n \n \n \n \n \n \n \n \n \n Activity Logs \n \n \n \n\n \n
\n
Filters \n \n
\n \n Action \n \n All Actions \n User Login \n User Logout \n User Invited \n Invitation Accepted \n Profile Update \n Password Change \n Content Created \n Content Updated \n Content Deleted \n Collection Created \n Collection Updated \n \n
\n\n \n Resource Type \n \n All Resources \n Users \n Content \n Collections \n Media \n Settings \n \n
\n\n \n From Date \n \n
\n\n \n To Date \n \n
\n\n \n \n
\n\n \n
\n
\n
\n
\n
Recent Activity \n
\n Showing ${data.logs.length} of ${data.pagination.total} logs\n
\n
\n
\n\n
\n
\n \n \n Timestamp \n User \n Action \n Resource \n IP Address \n Details \n \n \n \n ${data.logs.map(log => `\n \n \n ${new Date(log.created_at).toLocaleString()}\n \n \n ${log.user_name || 'Unknown'}
\n ${log.user_email || 'N/A'}
\n \n \n \n ${formatAction(log.action)}\n \n \n \n ${log.resource_type ? `\n ${log.resource_type}
\n ${log.resource_id ? `${log.resource_id}
` : ''}\n ` : 'N/A'}\n \n \n ${log.ip_address || 'N/A'}\n \n \n ${log.details ? `\n \n View Details \n ${JSON.stringify(log.details, null, 2)} \n \n ` : 'N/A'}\n \n \n `).join('')}\n \n
\n
\n\n ${data.logs.length === 0 ? `\n
\n
\n \n \n
No activity logs found \n
Try adjusting your filters or check back later.
\n
\n ` : ''}\n\n \n ${data.pagination.pages > 1 ? `\n
\n
\n Page ${data.pagination.page} of ${data.pagination.pages} (${data.pagination.total} total logs)\n
\n
\n
\n ` : ''}\n
\n
\n `\n\n const layoutData: AdminLayoutData = {\n title: 'Activity Logs',\n pageTitle: 'Activity Logs',\n currentPath: '/admin/activity-logs',\n user: data.user,\n content: pageContent\n }\n\n return renderAdminLayout(layoutData)\n}\n\nfunction getActionBadgeClass(action: string): string {\n if (action.includes('login') || action.includes('logout')) {\n return 'bg-blue-500/20 text-blue-300'\n } else if (action.includes('create') || action.includes('invite')) {\n return 'bg-green-500/20 text-green-300'\n } else if (action.includes('update') || action.includes('change')) {\n return 'bg-yellow-500/20 text-yellow-300'\n } else if (action.includes('delete') || action.includes('cancel')) {\n return 'bg-red-500/20 text-red-300'\n } else {\n return 'bg-gray-500/20 text-gray-300'\n }\n}\n\nfunction formatAction(action: string): string {\n // Convert action from dot notation to readable format\n return action\n .split('.')\n .map(part => part.replace(/_/g, ' ').replace(/\\b\\w/g, l => l.toUpperCase()))\n .join(' - ')\n}","import { renderAdminLayoutCatalyst, AdminLayoutCatalystData } from '../layouts/admin-layout-catalyst.template'\nimport { renderAlert } from '../alert.template'\nimport { renderConfirmationDialog, getConfirmationDialogScript } from '../components/confirmation-dialog.template'\nimport { escapeHtml } from '../../utils/sanitize'\n\nexport interface UserProfileData {\n displayName?: string\n bio?: string\n company?: string\n jobTitle?: string\n website?: string\n location?: string\n dateOfBirth?: number\n}\n\nexport interface UserEditData {\n id: string\n email: string\n username: string\n firstName: string\n lastName: string\n phone?: string\n avatarUrl?: string\n role: string\n isActive: boolean\n emailVerified: boolean\n twoFactorEnabled: boolean\n createdAt: number\n lastLoginAt?: number\n profile?: UserProfileData\n}\n\nexport interface UserEditPageData {\n userToEdit: UserEditData\n roles: Array<{ value: string; label: string }>\n error?: string\n success?: string\n user?: {\n name: string\n email: string\n role: string\n }\n}\n\nexport function renderUserEditPage(data: UserEditPageData): string {\n const pageContent = `\n \n \n
\n
\n
\n
Update user account and permissions
\n
\n
\n
\n\n \n
\n ${data.error ? renderAlert({ type: 'error', message: data.error, dismissible: true }) : ''}\n ${data.success ? renderAlert({ type: 'success', message: data.success, dismissible: true }) : ''}\n
\n\n \n
\n \n
\n
\n
\n\n \n \n
Basic Information \n
\n
\n First Name \n \n
\n\n
\n Last Name \n \n
\n\n
\n Username \n \n
\n\n
\n Email \n \n
\n\n
\n Phone \n \n
\n\n
\n
Role \n
\n
\n ${data.roles.map(role => `\n ${escapeHtml(role.label)} \n `).join('')}\n \n
\n \n \n
\n
\n
\n
\n\n \n \n
Profile Information \n
Extended profile data for this user
\n
\n\n
\n Bio \n ${escapeHtml(data.userToEdit.profile?.bio || '')} \n
\n
\n\n \n \n
Account Status \n
\n
\n
\n
\n
Account Active \n
User can sign in and access the system
\n
\n
\n\n
\n
\n
\n
Email Verified \n
User has verified their email address
\n
\n
\n
\n
\n\n \n
\n
\n\n \n
\n \n
\n
User Details \n
\n \n
User ID \n ${data.userToEdit.id} \n \n \n
Created \n ${new Date(data.userToEdit.createdAt).toLocaleDateString()} \n \n ${data.userToEdit.lastLoginAt ? `\n \n
Last Login \n ${new Date(data.userToEdit.lastLoginAt).toLocaleDateString()} \n \n ` : ''}\n \n
Status \n \n ${data.userToEdit.isActive\n ? 'Active '\n : 'Inactive '\n }\n \n \n ${data.userToEdit.twoFactorEnabled ? `\n \n
Security \n \n 2FA Enabled \n \n \n ` : ''}\n \n
\n\n \n
\n
Danger Zone \n
Irreversible and destructive actions
\n\n
\n
\n
\n
Hard Delete (Permanent) \n
Permanently remove from database. Unchecked performs soft delete (deactivate only).
\n
\n
\n\n
\n \n \n \n Delete User\n \n
\n
\n
\n
\n\n \n\n \n ${renderConfirmationDialog({\n id: 'delete-user-confirm',\n title: 'Delete User',\n message: 'Are you sure you want to delete this user? Check the \"Hard Delete\" option to permanently remove all data from the database. This action cannot be undone!',\n confirmText: 'Delete',\n cancelText: 'Cancel',\n iconColor: 'red',\n confirmClass: 'bg-red-500 hover:bg-red-400',\n onConfirm: 'performDeleteUser()'\n })}\n\n ${getConfirmationDialogScript()}\n `\n\n const layoutData: AdminLayoutCatalystData = {\n title: 'Edit User',\n pageTitle: `Edit User - ${data.userToEdit.firstName} ${data.userToEdit.lastName}`,\n currentPath: '/admin/users',\n user: data.user,\n content: pageContent\n }\n\n return renderAdminLayoutCatalyst(layoutData)\n}\n","export interface ConfirmationDialogOptions {\n id: string\n title: string\n message: string\n confirmText?: string\n cancelText?: string\n confirmClass?: string\n iconColor?: 'red' | 'yellow' | 'blue'\n onConfirm?: string // JavaScript code to execute on confirm\n}\n\nexport function renderConfirmationDialog(options: ConfirmationDialogOptions): string {\n const {\n id,\n title,\n message,\n confirmText = 'Confirm',\n cancelText = 'Cancel',\n confirmClass = 'bg-red-500 hover:bg-red-400',\n iconColor = 'red',\n onConfirm = ''\n } = options\n\n const iconColorClasses = {\n red: 'bg-red-500/10 text-red-400',\n yellow: 'bg-yellow-500/10 text-yellow-400',\n blue: 'bg-blue-500/10 text-blue-400'\n }\n\n return `\n \n \n \n\n \n
\n \n \n \n ${confirmText}\n \n \n ${cancelText}\n \n
\n \n
\n \n \n `\n}\n\n/**\n * Helper function to show a confirmation dialog programmatically\n * Usage in templates: Add this script and call showConfirmDialog()\n */\nexport function getConfirmationDialogScript(): string {\n return `\n \n \n `\n}\n","import { renderAdminLayoutCatalyst, AdminLayoutCatalystData } from '../layouts/admin-layout-catalyst.template'\nimport { renderAlert } from '../alert.template'\n\nexport interface UserNewPageData {\n roles: Array<{ value: string; label: string }>\n error?: string\n success?: string\n user?: {\n name: string\n email: string\n role: string\n }\n}\n\nexport function renderUserNewPage(data: UserNewPageData): string {\n const pageContent = `\n \n \n
\n
\n
\n
Add a new user account to the system
\n
\n
\n
\n\n \n
\n ${data.error ? renderAlert({ type: 'error', message: data.error, dismissible: true }) : ''}\n ${data.success ? renderAlert({ type: 'success', message: data.success, dismissible: true }) : ''}\n
\n\n \n
\n \n
\n
\n
\n\n \n \n
Basic Information \n
\n
\n \n First Name * \n \n \n
\n\n
\n \n Last Name * \n \n \n
\n\n
\n \n Username * \n \n \n
\n\n
\n \n Email * \n \n \n
\n\n
\n Phone \n \n
\n\n
\n
\n Role * \n \n
\n
\n ${data.roles.map(role => `\n ${role.label} \n `).join('')}\n \n
\n \n \n
\n
\n
\n\n
\n Bio \n \n
\n
\n\n \n \n\n \n \n
Account Status \n
\n
\n
\n
\n
Account Active \n
User can sign in and access the system
\n
\n
\n\n
\n
\n
\n
Email Verified \n
Mark email as verified
\n
\n
\n
\n
\n\n \n
\n
\n\n \n
\n \n
\n
Creating a User \n
\n
Fill in the required fields marked with * to create a new user account.
\n
The password must be at least 8 characters long.
\n
By default, new users are created as active and can sign in immediately.
\n
You can edit user details and permissions after creation.
\n
\n
\n\n \n
\n
Role Descriptions \n
\n \n
Administrator \n Full system access and permissions \n \n \n
Editor \n Can create and edit content \n \n \n
Author \n Can create own content \n \n \n
Viewer \n Read-only access \n \n \n
\n
\n
\n
\n `\n\n const layoutData: AdminLayoutCatalystData = {\n title: 'Create User',\n pageTitle: 'Create New User',\n currentPath: '/admin/users',\n user: data.user,\n content: pageContent\n }\n\n return renderAdminLayoutCatalyst(layoutData)\n}\n","import { renderAdminLayoutCatalyst, AdminLayoutCatalystData } from '../layouts/admin-layout-catalyst.template'\nimport { renderPagination, PaginationData } from '../pagination.template'\nimport { renderAlert } from '../alert.template'\nimport { renderTable, TableColumn, TableData } from '../table.template'\nimport { renderConfirmationDialog, getConfirmationDialogScript } from '../components/confirmation-dialog.template'\n\nexport interface User {\n id: string\n email: string\n username: string\n firstName: string\n lastName: string\n role: string\n avatar?: string\n isActive: boolean\n lastLoginAt?: number\n createdAt: number\n updatedAt: number\n formattedLastLogin?: string\n formattedCreatedAt?: string\n}\n\nexport interface UsersListPageData {\n users: User[]\n pagination?: PaginationData\n currentPage: number\n totalPages: number\n totalUsers: number\n statusFilter?: string\n roleFilter?: string\n searchFilter?: string\n error?: string\n success?: string\n user?: {\n name: string\n email: string\n role: string\n }\n version?: string\n}\n\nexport function renderUsersListPage(data: UsersListPageData): string {\n const columns: TableColumn[] = [\n {\n key: 'avatar',\n label: '',\n className: 'w-12',\n sortable: false,\n render: (value: string | null, row: User) => {\n const initials = `${row.firstName.charAt(0)}${row.lastName.charAt(0)}`.toUpperCase()\n if (value) {\n return ` `\n }\n return `\n \n ${initials} \n
\n `\n }\n },\n {\n key: 'name',\n label: 'Name',\n sortable: true,\n sortType: 'string',\n render: (_value: any, row: User) => {\n const escapeHtml = (text: string) => text.replace(/[&<>\"']/g, (char) => ({\n '&': '&',\n '<': '<',\n '>': '>',\n '\"': '"',\n \"'\": '''\n }[char] || char))\n \n const truncatedFirstName = row.firstName.length > 25 ? row.firstName.substring(0, 25) + '...' : row.firstName\n const truncatedLastName = row.lastName.length > 25 ? row.lastName.substring(0, 25) + '...' : row.lastName\n const fullName = escapeHtml(`${truncatedFirstName} ${truncatedLastName}`)\n const truncatedUsername = row.username.length > 100 ? row.username.substring(0, 100) + '...' : row.username\n const username = escapeHtml(truncatedUsername)\n const statusBadge = row.isActive ?\n 'Active ' :\n 'Inactive '\n return `\n \n
${fullName}${statusBadge}
\n
@${username}
\n
\n `\n }\n },\n {\n key: 'email',\n label: 'Email',\n sortable: true,\n sortType: 'string',\n render: (value: string) => {\n const escapeHtml = (text: string) => text.replace(/[&<>\"']/g, (char) => ({\n '&': '&',\n '<': '<',\n '>': '>',\n '\"': '"',\n \"'\": '''\n }[char] || char))\n const escapedEmail = escapeHtml(value)\n return `${escapedEmail} `\n }\n },\n {\n key: 'role',\n label: 'Role',\n sortable: true,\n sortType: 'string',\n render: (value: string) => {\n const roleColors = {\n admin: 'bg-red-50 dark:bg-red-500/10 text-red-700 dark:text-red-400 ring-1 ring-inset ring-red-700/10 dark:ring-red-500/20',\n editor: 'bg-blue-50 dark:bg-blue-500/10 text-blue-700 dark:text-blue-400 ring-1 ring-inset ring-blue-700/10 dark:ring-blue-500/20',\n author: 'bg-cyan-50 dark:bg-cyan-500/10 text-cyan-700 dark:text-cyan-400 ring-1 ring-inset ring-cyan-700/10 dark:ring-cyan-500/20',\n viewer: 'bg-zinc-50 dark:bg-zinc-800 text-zinc-600 dark:text-zinc-400 ring-1 ring-inset ring-zinc-500/10 dark:ring-zinc-400/20'\n }\n const colorClass = roleColors[value as keyof typeof roleColors] || 'bg-zinc-50 dark:bg-zinc-800 text-zinc-600 dark:text-zinc-400 ring-1 ring-inset ring-zinc-500/10 dark:ring-zinc-400/20'\n return `${value.charAt(0).toUpperCase() + value.slice(1)} `\n }\n },\n {\n key: 'lastLoginAt',\n label: 'Last Login',\n sortable: true,\n sortType: 'date',\n render: (value: number | null) => {\n if (!value) return 'Never '\n return `${new Date(value).toLocaleDateString()} `\n }\n },\n {\n key: 'createdAt',\n label: 'Created',\n sortable: true,\n sortType: 'date',\n render: (value: number) => `${new Date(value).toLocaleDateString()} `\n },\n {\n key: 'actions',\n label: 'Actions',\n className: 'text-right',\n sortable: false,\n render: (_value: any, row: User) => `\n \n ${row.isActive ?\n `
\n \n \n \n ` :\n `
\n \n \n \n `\n }\n
\n `\n }\n ]\n\n const tableData: TableData = {\n tableId: 'users-table',\n columns,\n rows: data.users,\n selectable: false,\n rowClickable: true,\n rowClickUrl: (row: User) => `/admin/users/${row.id}/edit`,\n emptyMessage: 'No users found'\n }\n\n const pageContent = `\n \n \n
\n
\n
User Management \n
Manage user accounts and permissions
\n
\n
\n
\n\n \n ${data.error ? renderAlert({ type: 'error', message: data.error, dismissible: true }) : ''}\n ${data.success ? renderAlert({ type: 'success', message: data.success, dismissible: true }) : ''}\n\n \n
\n
User Statistics \n
\n \n
Total Users \n
\n \n ${data.totalUsers}\n
\n \n
\n \n \n
Increased by \n 5.2%\n
\n \n
\n \n
Active Users \n
\n \n ${data.users.filter(u => u.isActive).length}\n
\n \n
\n \n \n
Increased by \n 3.1%\n
\n \n
\n \n
Administrators \n
\n \n ${data.users.filter(u => u.role === 'admin').length}\n
\n \n
\n \n \n
Increased by \n 1.8%\n
\n \n
\n \n
Active This Week \n
\n \n ${data.users.filter(u => u.lastLoginAt && u.lastLoginAt > Date.now() - 7 * 24 * 60 * 60 * 1000).length}\n
\n \n
\n \n \n
Decreased by \n 2.3%\n
\n \n
\n \n
\n\n \n
\n \n
\n\n \n
\n
\n
\n \n
\n
Search \n
\n
{\n input.focus();\n input.setSelectionRange(len, len);\n }, 10);\n }\n \"\n >\n \n
\n
\n
\n\n
\n
Role \n
\n
\n All Roles \n Admin \n Editor \n Author \n Viewer \n \n
\n \n \n
\n
\n\n
\n
Status \n
\n
\n Active \n Inactive \n All Users \n \n
\n \n \n
\n
\n\n
\n
\n
\n
\n \n \n \n Clear Filters\n \n
\n
\n
\n
\n
\n
\n\n \n ${renderTable(tableData)}\n\n \n ${data.pagination ? renderPagination(data.pagination) : ''}\n
\n\n \n\n \n ${renderConfirmationDialog({\n id: 'toggle-user-status-confirm',\n title: 'Toggle User Status',\n message: 'Are you sure you want to activate/deactivate this user?',\n confirmText: 'Confirm',\n cancelText: 'Cancel',\n iconColor: 'yellow',\n confirmClass: 'bg-yellow-500 hover:bg-yellow-400',\n onConfirm: 'performToggleUserStatus()'\n })}\n\n ${getConfirmationDialogScript()}\n `\n\n const layoutData: AdminLayoutCatalystData = {\n title: 'Users',\n pageTitle: 'User Management',\n currentPath: '/admin/users',\n user: data.user,\n version: data.version,\n content: pageContent\n }\n\n return renderAdminLayoutCatalyst(layoutData)\n} ","import { Hono } from 'hono'\nimport { requireAuth, logActivity, AuthManager } from '../middleware'\nimport { sanitizeInput } from '../utils/sanitize'\nimport { renderProfilePage, renderAvatarImage, type UserProfile, type ProfilePageData } from '../templates/pages/admin-profile.template'\nimport { renderAlert } from '../templates/components/alert.template'\nimport { renderActivityLogsPage, type ActivityLogsPageData, type ActivityLog } from '../templates/pages/admin-activity-logs.template'\nimport { renderUserEditPage, type UserEditPageData, type UserEditData, type UserProfileData } from '../templates/pages/admin-user-edit.template'\nimport { renderUserNewPage, type UserNewPageData } from '../templates/pages/admin-user-new.template'\nimport { renderUsersListPage, type UsersListPageData, type User } from '../templates/pages/admin-users-list.template'\nimport type { Bindings, Variables } from '../app'\n\nconst userRoutes = new Hono<{ Bindings: Bindings; Variables: Variables }>()\n\n// Apply authentication middleware to all routes\nuserRoutes.use('*', requireAuth())\n\n// Redirect /admin to /admin/dashboard\nuserRoutes.get('/', (c) => {\n return c.redirect('/admin/dashboard')\n})\n\n// Timezone options for profile form\nconst TIMEZONES = [\n { value: 'UTC', label: 'UTC' },\n { value: 'America/New_York', label: 'Eastern Time' },\n { value: 'America/Chicago', label: 'Central Time' },\n { value: 'America/Denver', label: 'Mountain Time' },\n { value: 'America/Los_Angeles', label: 'Pacific Time' },\n { value: 'Europe/London', label: 'London' },\n { value: 'Europe/Paris', label: 'Paris' },\n { value: 'Europe/Berlin', label: 'Berlin' },\n { value: 'Asia/Tokyo', label: 'Tokyo' },\n { value: 'Asia/Shanghai', label: 'Shanghai' },\n { value: 'Australia/Sydney', label: 'Sydney' }\n]\n\n// Language options for profile form\nconst LANGUAGES = [\n { value: 'en', label: 'English' },\n { value: 'es', label: 'Spanish' },\n { value: 'fr', label: 'French' },\n { value: 'de', label: 'German' },\n { value: 'it', label: 'Italian' },\n { value: 'pt', label: 'Portuguese' },\n { value: 'ja', label: 'Japanese' },\n { value: 'ko', label: 'Korean' },\n { value: 'zh', label: 'Chinese' }\n]\n\n// Role options for user form\nconst ROLES = [\n { value: 'admin', label: 'Administrator' },\n { value: 'editor', label: 'Editor' },\n { value: 'author', label: 'Author' },\n { value: 'viewer', label: 'Viewer' }\n]\n\n/**\n * GET /admin/profile - Show user profile page\n */\nuserRoutes.get('/profile', async (c) => {\n const user = c.get('user')\n const db = c.env.DB\n\n try {\n // Get user profile data\n const userStmt = db.prepare(`\n SELECT id, email, username, first_name, last_name, phone, bio, avatar_url,\n timezone, language, theme, email_notifications, two_factor_enabled,\n role, created_at, last_login_at\n FROM users \n WHERE id = ? AND is_active = 1\n `)\n \n const userProfile = await userStmt.bind(user!.userId).first() as any\n\n if (!userProfile) {\n return c.json({ error: 'User not found' }, 404)\n }\n\n // Convert to UserProfile interface\n const profile: UserProfile = {\n id: userProfile.id,\n email: userProfile.email,\n username: userProfile.username || '',\n first_name: userProfile.first_name || '',\n last_name: userProfile.last_name || '',\n phone: userProfile.phone,\n bio: userProfile.bio,\n avatar_url: userProfile.avatar_url,\n timezone: userProfile.timezone || 'UTC',\n language: userProfile.language || 'en',\n theme: userProfile.theme || 'dark',\n email_notifications: Boolean(userProfile.email_notifications),\n two_factor_enabled: Boolean(userProfile.two_factor_enabled),\n role: userProfile.role,\n created_at: userProfile.created_at,\n last_login_at: userProfile.last_login_at\n }\n\n const pageData: ProfilePageData = {\n profile,\n timezones: TIMEZONES,\n languages: LANGUAGES,\n user: {\n name: `${profile.first_name} ${profile.last_name}`.trim() || profile.username || user!.email,\n email: user!.email,\n role: user!.role\n }\n }\n\n return c.html(renderProfilePage(pageData))\n } catch (error) {\n console.error('Profile page error:', error)\n \n const pageData: ProfilePageData = {\n profile: {} as UserProfile,\n timezones: TIMEZONES,\n languages: LANGUAGES,\n error: 'Failed to load profile. Please try again.',\n user: {\n name: user!.email,\n email: user!.email,\n role: user!.role\n }\n }\n\n return c.html(renderProfilePage(pageData))\n }\n})\n\n/**\n * PUT /admin/profile - Update user profile\n */\nuserRoutes.put('/profile', async (c) => {\n const user = c.get('user')\n const db = c.env.DB\n\n try {\n const formData = await c.req.formData()\n\n // Sanitize all user inputs to prevent XSS attacks\n const firstName = sanitizeInput(formData.get('first_name')?.toString())\n const lastName = sanitizeInput(formData.get('last_name')?.toString())\n const username = sanitizeInput(formData.get('username')?.toString())\n const email = formData.get('email')?.toString()?.trim().toLowerCase() || ''\n const phone = sanitizeInput(formData.get('phone')?.toString()) || null\n const bio = sanitizeInput(formData.get('bio')?.toString()) || null\n const timezone = formData.get('timezone')?.toString() || 'UTC'\n const language = formData.get('language')?.toString() || 'en'\n const emailNotifications = formData.get('email_notifications') === '1'\n\n // Validate required fields\n if (!firstName || !lastName || !username || !email) {\n return c.html(renderAlert({\n type: 'error',\n message: 'First name, last name, username, and email are required.',\n dismissible: true\n }))\n }\n\n // Validate email format\n const emailRegex = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/\n if (!emailRegex.test(email)) {\n return c.html(renderAlert({ \n type: 'error', \n message: 'Please enter a valid email address.',\n dismissible: true \n }))\n }\n\n // Check if username/email are taken by another user\n const checkStmt = db.prepare(`\n SELECT id FROM users \n WHERE (username = ? OR email = ?) AND id != ? AND is_active = 1\n `)\n const existingUser = await checkStmt.bind(username, email, user!.userId).first()\n\n if (existingUser) {\n return c.html(renderAlert({ \n type: 'error', \n message: 'Username or email is already taken by another user!.',\n dismissible: true \n }))\n }\n\n // Update user profile\n const updateStmt = db.prepare(`\n UPDATE users SET \n first_name = ?, last_name = ?, username = ?, email = ?,\n phone = ?, bio = ?, timezone = ?, language = ?,\n email_notifications = ?, updated_at = ?\n WHERE id = ?\n `)\n\n await updateStmt.bind(\n firstName, lastName, username, email,\n phone, bio, timezone, language,\n emailNotifications ? 1 : 0, Date.now(),\n user!.userId\n ).run()\n\n // Log the activity\n await logActivity(\n db, user!.userId, 'profile.update', 'users', user!.userId,\n { fields: ['first_name', 'last_name', 'username', 'email', 'phone', 'bio', 'timezone', 'language', 'email_notifications'] },\n c.req.header('x-forwarded-for') || c.req.header('cf-connecting-ip'),\n c.req.header('user-agent')\n )\n\n return c.html(renderAlert({ \n type: 'success', \n message: 'Profile updated successfully!',\n dismissible: true \n }))\n\n } catch (error) {\n console.error('Profile update error:', error)\n return c.html(renderAlert({ \n type: 'error', \n message: 'Failed to update profile. Please try again.',\n dismissible: true \n }))\n }\n})\n\n/**\n * POST /admin/profile/avatar - Upload user avatar\n */\nuserRoutes.post('/profile/avatar', async (c) => {\n const user = c.get('user')\n const db = c.env.DB\n\n try {\n const formData = await c.req.formData()\n const avatarFile = formData.get('avatar') as File | null\n\n if (!avatarFile || typeof avatarFile === 'string' || !avatarFile.name) {\n return c.html(renderAlert({\n type: 'error',\n message: 'Please select an image file.',\n dismissible: true\n }))\n }\n\n // Validate file type\n const allowedTypes = ['image/jpeg', 'image/png', 'image/gif', 'image/webp']\n if (!allowedTypes.includes(avatarFile.type)) {\n return c.html(renderAlert({ \n type: 'error', \n message: 'Please upload a valid image file (JPEG, PNG, GIF, or WebP).',\n dismissible: true \n }))\n }\n\n // Validate file size (5MB max)\n const maxSize = 5 * 1024 * 1024\n if (avatarFile.size > maxSize) {\n return c.html(renderAlert({ \n type: 'error', \n message: 'Image file must be smaller than 5MB.',\n dismissible: true \n }))\n }\n\n // For now, we'll simulate storing the avatar\n // In a real implementation, you'd upload to cloud storage (R2, S3, etc.)\n const avatarUrl = `/uploads/avatars/${user!.userId}-${Date.now()}.${avatarFile.type.split('/')[1]}`\n\n // Update user avatar URL in database\n const updateStmt = db.prepare(`\n UPDATE users SET avatar_url = ?, updated_at = ?\n WHERE id = ?\n `)\n\n await updateStmt.bind(avatarUrl, Date.now(), user!.userId).run()\n\n // Get updated user data to render the avatar\n const userStmt = db.prepare(`\n SELECT first_name, last_name FROM users WHERE id = ?\n `)\n const userData = await userStmt.bind(user!.userId).first() as any\n\n // Log the activity\n await logActivity(\n db, user!.userId, 'profile.avatar_update', 'users', user!.userId,\n { avatar_url: avatarUrl },\n c.req.header('x-forwarded-for') || c.req.header('cf-connecting-ip'),\n c.req.header('user-agent')\n )\n\n // Return both the alert message and the updated avatar image using HTMX out-of-band swap\n const alertHtml = renderAlert({\n type: 'success',\n message: 'Profile picture updated successfully!',\n dismissible: true\n })\n\n // Add timestamp to avatar URL to bust cache\n const avatarUrlWithCache = `${avatarUrl}?t=${Date.now()}`\n const avatarImageHtml = renderAvatarImage(avatarUrlWithCache, userData.first_name, userData.last_name)\n\n // Use hx-swap-oob to update the avatar image container\n const avatarImageWithOob = avatarImageHtml.replace(\n 'id=\"avatar-image-container\"',\n 'id=\"avatar-image-container\" hx-swap-oob=\"true\"'\n )\n\n return c.html(alertHtml + avatarImageWithOob)\n\n } catch (error) {\n console.error('Avatar upload error:', error)\n return c.html(renderAlert({ \n type: 'error', \n message: 'Failed to upload profile picture. Please try again.',\n dismissible: true \n }))\n }\n})\n\n/**\n * POST /admin/profile/password - Change user password\n */\nuserRoutes.post('/profile/password', async (c) => {\n const user = c.get('user')\n const db = c.env.DB\n\n try {\n const formData = await c.req.formData()\n \n const currentPassword = formData.get('current_password')?.toString() || ''\n const newPassword = formData.get('new_password')?.toString() || ''\n const confirmPassword = formData.get('confirm_password')?.toString() || ''\n\n // Validate input\n if (!currentPassword || !newPassword || !confirmPassword) {\n return c.html(renderAlert({ \n type: 'error', \n message: 'All password fields are required.',\n dismissible: true \n }))\n }\n\n if (newPassword !== confirmPassword) {\n return c.html(renderAlert({ \n type: 'error', \n message: 'New passwords do not match.',\n dismissible: true \n }))\n }\n\n if (newPassword.length < 8) {\n return c.html(renderAlert({ \n type: 'error', \n message: 'New password must be at least 8 characters long.',\n dismissible: true \n }))\n }\n\n // Get current user data\n const userStmt = db.prepare(`\n SELECT password_hash FROM users WHERE id = ? AND is_active = 1\n `)\n const userData = await userStmt.bind(user!.userId).first() as any\n\n if (!userData) {\n return c.html(renderAlert({ \n type: 'error', \n message: 'User not found.',\n dismissible: true \n }))\n }\n\n // Verify current password\n const validPassword = await AuthManager.verifyPassword(currentPassword, userData.password_hash)\n if (!validPassword) {\n return c.html(renderAlert({ \n type: 'error', \n message: 'Current password is incorrect.',\n dismissible: true \n }))\n }\n\n // Hash new password\n const newPasswordHash = await AuthManager.hashPassword(newPassword)\n\n // Store old password in history\n const historyStmt = db.prepare(`\n INSERT INTO password_history (id, user_id, password_hash, created_at)\n VALUES (?, ?, ?, ?)\n `)\n await historyStmt.bind(\n crypto.randomUUID(),\n user!.userId,\n userData.password_hash,\n Date.now()\n ).run()\n\n // Update user password\n const updateStmt = db.prepare(`\n UPDATE users SET password_hash = ?, updated_at = ?\n WHERE id = ?\n `)\n await updateStmt.bind(newPasswordHash, Date.now(), user!.userId).run()\n\n // Log the activity\n await logActivity(\n db, user!.userId, 'profile.password_change', 'users', user!.userId,\n null,\n c.req.header('x-forwarded-for') || c.req.header('cf-connecting-ip'),\n c.req.header('user-agent')\n )\n\n return c.html(renderAlert({ \n type: 'success', \n message: 'Password updated successfully!',\n dismissible: true \n }))\n\n } catch (error) {\n console.error('Password change error:', error)\n return c.html(renderAlert({ \n type: 'error', \n message: 'Failed to update password. Please try again.',\n dismissible: true \n }))\n }\n})\n\n/**\n * GET /admin/users - List all users\n * Returns HTML for browser requests and JSON for API requests\n * Note: Already protected by requireAuth() and requireRole(['admin', 'editor'])\n */\nuserRoutes.get('/users', async (c) => {\n const db = c.env.DB\n const user = c.get('user')\n\n try {\n // Get pagination parameters\n const page = parseInt(c.req.query('page') || '1')\n const limit = parseInt(c.req.query('limit') || '20')\n const search = c.req.query('search') || ''\n const roleFilter = c.req.query('role') || ''\n const statusFilter = c.req.query('status') || 'active'\n const offset = (page - 1) * limit\n\n // Build search query\n let whereClause = ''\n let params: any[] = []\n\n // Handle status filter\n if (statusFilter === 'active') {\n whereClause = 'WHERE u.is_active = 1'\n } else if (statusFilter === 'inactive') {\n whereClause = 'WHERE u.is_active = 0'\n } else {\n // 'all' - no filter\n whereClause = 'WHERE 1=1'\n }\n\n if (search) {\n whereClause += ' AND (u.first_name LIKE ? OR u.last_name LIKE ? OR u.email LIKE ? OR u.username LIKE ?)'\n const searchParam = `%${search}%`\n params.push(searchParam, searchParam, searchParam, searchParam)\n }\n\n if (roleFilter) {\n whereClause += ' AND u.role = ?'\n params.push(roleFilter)\n }\n\n // Get users\n const usersStmt = db.prepare(`\n SELECT u.id, u.email, u.username, u.first_name, u.last_name,\n u.role, u.avatar_url, u.created_at, u.last_login_at, u.updated_at,\n u.email_verified, u.two_factor_enabled, u.is_active\n FROM users u\n ${whereClause}\n ORDER BY u.created_at DESC\n LIMIT ? OFFSET ?\n `)\n\n const { results: usersData } = await usersStmt.bind(...params, limit, offset).all()\n\n // Get total count\n const countStmt = db.prepare(`\n SELECT COUNT(*) as total FROM users u ${whereClause}\n `)\n const countResult = await countStmt.bind(...params).first() as any\n const totalUsers = countResult?.total || 0\n\n // Log the activity\n await logActivity(\n db, user!.userId, 'users.list_view', 'users', undefined,\n { search, page, limit },\n c.req.header('x-forwarded-for') || c.req.header('cf-connecting-ip'),\n c.req.header('user-agent')\n )\n\n // Check if this is an API request (accept header contains 'application/json')\n const acceptHeader = c.req.header('accept') || ''\n const isApiRequest = acceptHeader.includes('application/json')\n\n if (isApiRequest) {\n // Return JSON for API requests\n return c.json({\n users: usersData || [],\n pagination: {\n page,\n limit,\n total: totalUsers,\n pages: Math.ceil(totalUsers / limit)\n }\n })\n }\n\n // Return HTML for browser requests\n const users: User[] = (usersData || []).map((u: any) => ({\n id: u.id,\n email: u.email,\n username: u.username || '',\n firstName: u.first_name || '',\n lastName: u.last_name || '',\n role: u.role,\n avatar: u.avatar_url,\n isActive: Boolean(u.is_active),\n lastLoginAt: u.last_login_at,\n createdAt: u.created_at,\n updatedAt: u.updated_at,\n formattedLastLogin: u.last_login_at ? new Date(u.last_login_at).toLocaleDateString() : undefined,\n formattedCreatedAt: new Date(u.created_at).toLocaleDateString()\n }))\n\n const pageData: UsersListPageData = {\n users,\n currentPage: page,\n totalPages: Math.ceil(totalUsers / limit),\n totalUsers,\n searchFilter: search,\n roleFilter,\n statusFilter,\n pagination: {\n currentPage: page,\n totalPages: Math.ceil(totalUsers / limit),\n totalItems: totalUsers,\n itemsPerPage: limit,\n startItem: offset + 1,\n endItem: Math.min(offset + limit, totalUsers),\n baseUrl: '/admin/users'\n },\n user: {\n name: user!.email.split('@')[0] || user!.email,\n email: user!.email,\n role: user!.role\n }\n }\n\n return c.html(renderUsersListPage(pageData))\n\n } catch (error) {\n console.error('Users list error:', error)\n\n const acceptHeader = c.req.header('accept') || ''\n const isApiRequest = acceptHeader.includes('application/json')\n\n if (isApiRequest) {\n return c.json({ error: 'Failed to load users' }, 500)\n }\n\n return c.html(renderAlert({\n type: 'error',\n message: 'Failed to load users. Please try again.',\n dismissible: true\n }), 500)\n }\n})\n\n/**\n * GET /admin/users/new - Show new user creation page\n */\nuserRoutes.get('/users/new', async (c) => {\n const user = c.get('user')\n\n try {\n const pageData: UserNewPageData = {\n roles: ROLES,\n user: {\n name: user!.email.split('@')[0] || user!.email,\n email: user!.email,\n role: user!.role\n }\n }\n\n return c.html(renderUserNewPage(pageData))\n } catch (error) {\n console.error('User new page error:', error)\n\n return c.html(renderAlert({\n type: 'error',\n message: 'Failed to load user creation page. Please try again.',\n dismissible: true\n }), 500)\n }\n})\n\n/**\n * POST /admin/users/new - Create new user\n */\nuserRoutes.post('/users/new', async (c) => {\n const db = c.env.DB\n const user = c.get('user')\n\n try {\n const formData = await c.req.formData()\n\n // Sanitize all user inputs to prevent XSS attacks\n const firstName = sanitizeInput(formData.get('first_name')?.toString())\n const lastName = sanitizeInput(formData.get('last_name')?.toString())\n const username = sanitizeInput(formData.get('username')?.toString())\n const email = formData.get('email')?.toString()?.trim().toLowerCase() || ''\n const phone = sanitizeInput(formData.get('phone')?.toString()) || null\n const bio = sanitizeInput(formData.get('bio')?.toString()) || null\n const role = formData.get('role')?.toString() || 'viewer'\n const password = formData.get('password')?.toString() || ''\n const confirmPassword = formData.get('confirm_password')?.toString() || ''\n const isActive = formData.get('is_active') === '1'\n const emailVerified = formData.get('email_verified') === '1'\n\n // Validate required fields\n if (!firstName || !lastName || !username || !email || !password) {\n return c.html(renderAlert({\n type: 'error',\n message: 'First name, last name, username, email, and password are required.',\n dismissible: true\n }))\n }\n\n // Validate email format\n const emailRegex = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/\n if (!emailRegex.test(email)) {\n return c.html(renderAlert({\n type: 'error',\n message: 'Please enter a valid email address.',\n dismissible: true\n }))\n }\n\n // Validate password\n if (password.length < 8) {\n return c.html(renderAlert({\n type: 'error',\n message: 'Password must be at least 8 characters long.',\n dismissible: true\n }))\n }\n\n if (password !== confirmPassword) {\n return c.html(renderAlert({\n type: 'error',\n message: 'Passwords do not match.',\n dismissible: true\n }))\n }\n\n // Check if username/email are already taken\n const checkStmt = db.prepare(`\n SELECT id FROM users\n WHERE username = ? OR email = ?\n `)\n const existingUser = await checkStmt.bind(username, email).first()\n\n if (existingUser) {\n return c.html(renderAlert({\n type: 'error',\n message: 'Username or email is already taken.',\n dismissible: true\n }))\n }\n\n // Hash password\n const passwordHash = await AuthManager.hashPassword(password)\n\n // Create user\n const userId = crypto.randomUUID()\n const createStmt = db.prepare(`\n INSERT INTO users (\n id, email, username, first_name, last_name, phone, bio,\n password_hash, role, is_active, email_verified, created_at, updated_at\n ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\n `)\n\n await createStmt.bind(\n userId, email, username, firstName, lastName, phone, bio,\n passwordHash, role, isActive ? 1 : 0, emailVerified ? 1 : 0,\n Date.now(), Date.now()\n ).run()\n\n // Log the activity\n await logActivity(\n db, user!.userId, 'user!.create', 'users', userId,\n { email, username, role },\n c.req.header('x-forwarded-for') || c.req.header('cf-connecting-ip'),\n c.req.header('user-agent')\n )\n\n // Redirect to user edit page\n return c.redirect(`/admin/users/${userId}/edit?success=User created successfully`)\n\n } catch (error) {\n console.error('User creation error:', error)\n return c.html(renderAlert({\n type: 'error',\n message: 'Failed to create user!. Please try again.',\n dismissible: true\n }))\n }\n})\n\n/**\n * GET /admin/users/:id - Get user by ID\n * Note: This endpoint returns users regardless of is_active status for admin purposes\n */\nuserRoutes.get('/users/:id', async (c) => {\n // Check if this is actually the edit route\n if (c.req.path.endsWith('/edit')) {\n return c.notFound()\n }\n\n const db = c.env.DB\n const user = c.get('user')\n const userId = c.req.param('id')\n\n try {\n // Get user data (including inactive users for admin access)\n const userStmt = db.prepare(`\n SELECT id, email, username, first_name, last_name, phone, bio, avatar_url,\n role, is_active, email_verified, two_factor_enabled, created_at, last_login_at\n FROM users\n WHERE id = ?\n `)\n\n const userRecord = await userStmt.bind(userId).first() as any\n\n if (!userRecord) {\n return c.json({ error: 'User not found' }, 404)\n }\n\n // Log the activity\n await logActivity(\n db, user!.userId, 'user!.view', 'users', userId,\n null,\n c.req.header('x-forwarded-for') || c.req.header('cf-connecting-ip'),\n c.req.header('user-agent')\n )\n\n return c.json({\n user: {\n id: userRecord.id,\n email: userRecord.email,\n username: userRecord.username,\n first_name: userRecord.first_name,\n last_name: userRecord.last_name,\n phone: userRecord.phone,\n bio: userRecord.bio,\n avatar_url: userRecord.avatar_url,\n role: userRecord.role,\n is_active: userRecord.is_active,\n email_verified: userRecord.email_verified,\n two_factor_enabled: userRecord.two_factor_enabled,\n created_at: userRecord.created_at,\n last_login_at: userRecord.last_login_at\n }\n })\n\n } catch (error) {\n console.error('User fetch error:', error)\n return c.json({ error: 'Failed to fetch user' }, 500)\n }\n})\n\n/**\n * GET /admin/users/:id/edit - Show user edit page\n */\nuserRoutes.get('/users/:id/edit', async (c) => {\n const db = c.env.DB\n const user = c.get('user')\n const userId = c.req.param('id')\n\n try {\n // Get user data (removed bio - now in profile)\n const userStmt = db.prepare(`\n SELECT id, email, username, first_name, last_name, phone, avatar_url,\n role, is_active, email_verified, two_factor_enabled, created_at, last_login_at\n FROM users\n WHERE id = ?\n `)\n\n const userToEdit = await userStmt.bind(userId).first() as any\n\n if (!userToEdit) {\n return c.html(renderAlert({\n type: 'error',\n message: 'User not found',\n dismissible: true\n }), 404)\n }\n\n // Get user profile data\n const profileStmt = db.prepare(`\n SELECT display_name, bio, company, job_title, website, location, date_of_birth\n FROM user_profiles\n WHERE user_id = ?\n `)\n const profileData = await profileStmt.bind(userId).first() as any\n\n // Convert profile to UserProfileData interface\n const profile: UserProfileData | undefined = profileData ? {\n displayName: profileData.display_name,\n bio: profileData.bio,\n company: profileData.company,\n jobTitle: profileData.job_title,\n website: profileData.website,\n location: profileData.location,\n dateOfBirth: profileData.date_of_birth\n } : undefined\n\n // Convert to UserEditData interface\n const editData: UserEditData = {\n id: userToEdit.id,\n email: userToEdit.email,\n username: userToEdit.username || '',\n firstName: userToEdit.first_name || '',\n lastName: userToEdit.last_name || '',\n phone: userToEdit.phone,\n avatarUrl: userToEdit.avatar_url,\n role: userToEdit.role,\n isActive: Boolean(userToEdit.is_active),\n emailVerified: Boolean(userToEdit.email_verified),\n twoFactorEnabled: Boolean(userToEdit.two_factor_enabled),\n createdAt: userToEdit.created_at,\n lastLoginAt: userToEdit.last_login_at,\n profile\n }\n\n const pageData: UserEditPageData = {\n userToEdit: editData,\n roles: ROLES,\n user: {\n name: user!.email.split('@')[0] || user!.email,\n email: user!.email,\n role: user!.role\n }\n }\n\n return c.html(renderUserEditPage(pageData))\n } catch (error) {\n console.error('User edit page error:', error)\n\n return c.html(renderAlert({\n type: 'error',\n message: 'Failed to load user. Please try again.',\n dismissible: true\n }), 500)\n }\n})\n\n/**\n * PUT /admin/users/:id - Update user\n */\nuserRoutes.put('/users/:id', async (c) => {\n const db = c.env.DB\n const user = c.get('user')\n const userId = c.req.param('id')\n\n try {\n const formData = await c.req.formData()\n\n // Sanitize all user inputs to prevent XSS attacks\n const firstName = sanitizeInput(formData.get('first_name')?.toString())\n const lastName = sanitizeInput(formData.get('last_name')?.toString())\n const username = sanitizeInput(formData.get('username')?.toString())\n const email = formData.get('email')?.toString()?.trim().toLowerCase() || ''\n const phone = sanitizeInput(formData.get('phone')?.toString()) || null\n const role = formData.get('role')?.toString() || 'viewer'\n const isActive = formData.get('is_active') === '1'\n const emailVerified = formData.get('email_verified') === '1'\n\n // Extract profile fields\n const profileDisplayName = sanitizeInput(formData.get('profile_display_name')?.toString()) || null\n const profileBio = sanitizeInput(formData.get('profile_bio')?.toString()) || null\n const profileCompany = sanitizeInput(formData.get('profile_company')?.toString()) || null\n const profileJobTitle = sanitizeInput(formData.get('profile_job_title')?.toString()) || null\n const profileWebsite = formData.get('profile_website')?.toString()?.trim() || null\n const profileLocation = sanitizeInput(formData.get('profile_location')?.toString()) || null\n const profileDateOfBirthStr = formData.get('profile_date_of_birth')?.toString()?.trim() || null\n const profileDateOfBirth = profileDateOfBirthStr ? new Date(profileDateOfBirthStr).getTime() : null\n\n // Validate required fields\n if (!firstName || !lastName || !username || !email) {\n return c.html(renderAlert({\n type: 'error',\n message: 'First name, last name, username, and email are required.',\n dismissible: true\n }))\n }\n\n // Validate email format\n const emailRegex = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/\n if (!emailRegex.test(email)) {\n return c.html(renderAlert({\n type: 'error',\n message: 'Please enter a valid email address.',\n dismissible: true\n }))\n }\n\n // Validate website URL if provided\n if (profileWebsite) {\n try {\n new URL(profileWebsite)\n } catch {\n return c.html(renderAlert({\n type: 'error',\n message: 'Please enter a valid website URL.',\n dismissible: true\n }))\n }\n }\n\n // Check if username/email are taken by another user\n const checkStmt = db.prepare(`\n SELECT id FROM users\n WHERE (username = ? OR email = ?) AND id != ?\n `)\n const existingUser = await checkStmt.bind(username, email, userId).first()\n\n if (existingUser) {\n return c.html(renderAlert({\n type: 'error',\n message: 'Username or email is already taken by another user.',\n dismissible: true\n }))\n }\n\n // Update user (removed bio - now in profile)\n const updateStmt = db.prepare(`\n UPDATE users SET\n first_name = ?, last_name = ?, username = ?, email = ?,\n phone = ?, role = ?, is_active = ?, email_verified = ?,\n updated_at = ?\n WHERE id = ?\n `)\n\n await updateStmt.bind(\n firstName, lastName, username, email,\n phone, role, isActive ? 1 : 0, emailVerified ? 1 : 0,\n Date.now(), userId\n ).run()\n\n // Check if any profile field has data\n const hasProfileData = profileDisplayName || profileBio || profileCompany ||\n profileJobTitle || profileWebsite || profileLocation || profileDateOfBirth\n\n if (hasProfileData) {\n const now = Date.now()\n\n // Check if profile exists\n const profileCheckStmt = db.prepare(`SELECT id FROM user_profiles WHERE user_id = ?`)\n const existingProfile = await profileCheckStmt.bind(userId).first() as any\n\n if (existingProfile) {\n // Update existing profile\n const updateProfileStmt = db.prepare(`\n UPDATE user_profiles SET\n display_name = ?, bio = ?, company = ?, job_title = ?,\n website = ?, location = ?, date_of_birth = ?, updated_at = ?\n WHERE user_id = ?\n `)\n await updateProfileStmt.bind(\n profileDisplayName, profileBio, profileCompany, profileJobTitle,\n profileWebsite, profileLocation, profileDateOfBirth, now, userId\n ).run()\n } else {\n // Create new profile\n const profileId = `profile_${Date.now()}_${Math.random().toString(36).substring(2, 9)}`\n const insertProfileStmt = db.prepare(`\n INSERT INTO user_profiles (id, user_id, display_name, bio, company, job_title, website, location, date_of_birth, created_at, updated_at)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\n `)\n await insertProfileStmt.bind(\n profileId, userId, profileDisplayName, profileBio, profileCompany, profileJobTitle,\n profileWebsite, profileLocation, profileDateOfBirth, now, now\n ).run()\n }\n }\n\n // Log the activity\n await logActivity(\n db, user!.userId, 'user.update', 'users', userId,\n { fields: ['first_name', 'last_name', 'username', 'email', 'phone', 'role', 'is_active', 'email_verified', 'profile'] },\n c.req.header('x-forwarded-for') || c.req.header('cf-connecting-ip'),\n c.req.header('user-agent')\n )\n\n return c.html(renderAlert({\n type: 'success',\n message: 'User updated successfully!',\n dismissible: true\n }))\n\n } catch (error) {\n console.error('User update error:', error)\n return c.html(renderAlert({\n type: 'error',\n message: 'Failed to update user. Please try again.',\n dismissible: true\n }))\n }\n})\n\n/**\n * POST /admin/users/:id/toggle - Toggle user active status\n */\nuserRoutes.post('/users/:id/toggle', async (c) => {\n const db = c.env.DB\n const user = c.get('user')\n const userId = c.req.param('id')\n\n try {\n const body = await c.req.json().catch(() => ({ active: true }))\n const active = body.active === true\n\n // Prevent self-deactivation\n if (userId === user!.userId && !active) {\n return c.json({ error: 'You cannot deactivate your own account' }, 400)\n }\n\n // Check if user exists\n const userStmt = db.prepare(`\n SELECT id, email FROM users WHERE id = ?\n `)\n const userToToggle = await userStmt.bind(userId).first() as any\n\n if (!userToToggle) {\n return c.json({ error: 'User not found' }, 404)\n }\n\n // Toggle user status\n const toggleStmt = db.prepare(`\n UPDATE users SET is_active = ?, updated_at = ? WHERE id = ?\n `)\n await toggleStmt.bind(active ? 1 : 0, Date.now(), userId).run()\n\n // Log the activity\n await logActivity(\n db, user!.userId, active ? 'user.activate' : 'user.deactivate', 'users', userId,\n { email: userToToggle.email },\n c.req.header('x-forwarded-for') || c.req.header('cf-connecting-ip'),\n c.req.header('user-agent')\n )\n\n return c.json({\n success: true,\n message: active ? 'User activated successfully' : 'User deactivated successfully'\n })\n\n } catch (error) {\n console.error('User toggle error:', error)\n return c.json({ error: 'Failed to toggle user status' }, 500)\n }\n})\n\n/**\n * DELETE /admin/users/:id - Delete user\n */\nuserRoutes.delete('/users/:id', async (c) => {\n const db = c.env.DB\n const user = c.get('user')\n const userId = c.req.param('id')\n\n try {\n // Get request body to check for hard delete option\n const body = await c.req.json().catch(() => ({ hardDelete: false }))\n const hardDelete = body.hardDelete === true\n\n // Prevent self-deletion\n if (userId === user!.userId) {\n return c.json({ error: 'You cannot delete your own account' }, 400)\n }\n\n // Check if user exists\n const userStmt = db.prepare(`\n SELECT id, email FROM users WHERE id = ?\n `)\n const userToDelete = await userStmt.bind(userId).first() as any\n\n if (!userToDelete) {\n return c.json({ error: 'User not found' }, 404)\n }\n\n if (hardDelete) {\n // Hard delete - permanently remove from database\n const deleteStmt = db.prepare(`\n DELETE FROM users WHERE id = ?\n `)\n await deleteStmt.bind(userId).run()\n\n // Log the activity\n await logActivity(\n db, user!.userId, 'user!.hard_delete', 'users', userId,\n { email: userToDelete.email, permanent: true },\n c.req.header('x-forwarded-for') || c.req.header('cf-connecting-ip'),\n c.req.header('user-agent')\n )\n\n return c.json({\n success: true,\n message: 'User permanently deleted'\n })\n } else {\n // Soft delete - deactivate by setting is_active = 0\n const deleteStmt = db.prepare(`\n UPDATE users SET is_active = 0, updated_at = ? WHERE id = ?\n `)\n await deleteStmt.bind(Date.now(), userId).run()\n\n // Log the activity\n await logActivity(\n db, user!.userId, 'user!.soft_delete', 'users', userId,\n { email: userToDelete.email },\n c.req.header('x-forwarded-for') || c.req.header('cf-connecting-ip'),\n c.req.header('user-agent')\n )\n\n return c.json({\n success: true,\n message: 'User deactivated successfully'\n })\n }\n\n } catch (error) {\n console.error('User deletion error:', error)\n return c.json({ error: 'Failed to delete user' }, 500)\n }\n})\n\n/**\n * POST /admin/invite-user - Invite a new user\n */\nuserRoutes.post('/invite-user', async (c) => {\n const db = c.env.DB\n const user = c.get('user')\n\n try {\n const formData = await c.req.formData()\n\n // Sanitize all user inputs to prevent XSS attacks\n const email = formData.get('email')?.toString()?.trim().toLowerCase() || ''\n const role = formData.get('role')?.toString()?.trim() || 'viewer'\n const firstName = sanitizeInput(formData.get('first_name')?.toString())\n const lastName = sanitizeInput(formData.get('last_name')?.toString())\n\n // Validate input\n if (!email || !firstName || !lastName) {\n return c.json({ error: 'Email, first name, and last name are required' }, 400)\n }\n\n // Validate email format\n const emailRegex = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/\n if (!emailRegex.test(email)) {\n return c.json({ error: 'Please enter a valid email address' }, 400)\n }\n\n // Check if user already exists\n const existingUserStmt = db.prepare(`\n SELECT id FROM users WHERE email = ?\n `)\n const existingUser = await existingUserStmt.bind(email).first()\n\n if (existingUser) {\n return c.json({ error: 'A user with this email already exists' }, 400)\n }\n\n // Generate invitation token\n const invitationToken = crypto.randomUUID()\n // const invitationExpires = Date.now() + (7 * 24 * 60 * 60 * 1000) // 7 days\n\n // Create user record with invitation\n const userId = crypto.randomUUID()\n const createUserStmt = db.prepare(`\n INSERT INTO users (\n id, email, first_name, last_name, role, \n invitation_token, invited_by, invited_at,\n is_active, email_verified, created_at, updated_at\n ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\n `)\n\n await createUserStmt.bind(\n userId, email, firstName, lastName, role,\n invitationToken, user!.userId, Date.now(),\n 0, 0, Date.now(), Date.now()\n ).run()\n\n // Log the activity\n await logActivity(\n db, user!.userId, 'user!.invite_sent', 'users', userId,\n { email, role, invited_user_id: userId },\n c.req.header('x-forwarded-for') || c.req.header('cf-connecting-ip'),\n c.req.header('user-agent')\n )\n\n // In a real implementation, you would send an email here\n // For now, we'll return the invitation link\n const invitationLink = `${c.req.header('origin') || 'http://localhost:8787'}/auth/accept-invitation?token=${invitationToken}`\n\n return c.json({\n success: true,\n message: 'User invitation sent successfully',\n user: {\n id: userId,\n email,\n first_name: firstName,\n last_name: lastName,\n role\n },\n invitation_link: invitationLink // In production, this would be sent via email\n })\n\n } catch (error) {\n console.error('User invitation error:', error)\n return c.json({ error: 'Failed to send user invitation' }, 500)\n }\n})\n\n/**\n * POST /admin/resend-invitation/:id - Resend invitation\n */\nuserRoutes.post('/resend-invitation/:id', async (c) => {\n const db = c.env.DB\n const user = c.get('user')\n const userId = c.req.param('id')\n\n try {\n // Check if user exists and is invited but not active\n const userStmt = db.prepare(`\n SELECT id, email, first_name, last_name, role, invitation_token\n FROM users \n WHERE id = ? AND is_active = 0 AND invitation_token IS NOT NULL\n `)\n const invitedUser = await userStmt.bind(userId).first() as any\n\n if (!invitedUser) {\n return c.json({ error: 'User not found or invitation not valid' }, 404)\n }\n\n // Generate new invitation token\n const newInvitationToken = crypto.randomUUID()\n\n // Update invitation token and date\n const updateStmt = db.prepare(`\n UPDATE users SET \n invitation_token = ?, \n invited_at = ?, \n updated_at = ?\n WHERE id = ?\n `)\n\n await updateStmt.bind(\n newInvitationToken,\n Date.now(),\n Date.now(),\n userId\n ).run()\n\n // Log the activity\n await logActivity(\n db, user!.userId, 'user!.invitation_resent', 'users', userId,\n { email: invitedUser.email },\n c.req.header('x-forwarded-for') || c.req.header('cf-connecting-ip'),\n c.req.header('user-agent')\n )\n\n // Generate new invitation link\n const invitationLink = `${c.req.header('origin') || 'http://localhost:8787'}/auth/accept-invitation?token=${newInvitationToken}`\n\n return c.json({\n success: true,\n message: 'Invitation resent successfully',\n invitation_link: invitationLink\n })\n\n } catch (error) {\n console.error('Resend invitation error:', error)\n return c.json({ error: 'Failed to resend invitation' }, 500)\n }\n})\n\n/**\n * DELETE /admin/cancel-invitation/:id - Cancel invitation\n */\nuserRoutes.delete('/cancel-invitation/:id', async (c) => {\n const db = c.env.DB\n const user = c.get('user')\n const userId = c.req.param('id')\n\n try {\n // Check if user exists and is invited but not active\n const userStmt = db.prepare(`\n SELECT id, email FROM users \n WHERE id = ? AND is_active = 0 AND invitation_token IS NOT NULL\n `)\n const invitedUser = await userStmt.bind(userId).first() as any\n\n if (!invitedUser) {\n return c.json({ error: 'User not found or invitation not valid' }, 404)\n }\n\n // Delete the user record (since they haven't activated yet)\n const deleteStmt = db.prepare(`DELETE FROM users WHERE id = ?`)\n await deleteStmt.bind(userId).run()\n\n // Log the activity\n await logActivity(\n db, user!.userId, 'user!.invitation_cancelled', 'users', userId,\n { email: invitedUser.email },\n c.req.header('x-forwarded-for') || c.req.header('cf-connecting-ip'),\n c.req.header('user-agent')\n )\n\n return c.json({\n success: true,\n message: 'Invitation cancelled successfully'\n })\n\n } catch (error) {\n console.error('Cancel invitation error:', error)\n return c.json({ error: 'Failed to cancel invitation' }, 500)\n }\n})\n\n/**\n * GET /admin/activity-logs - View activity logs\n */\nuserRoutes.get('/activity-logs', async (c) => {\n const db = c.env.DB\n const user = c.get('user')\n\n try {\n // Get pagination and filter parameters\n const page = parseInt(c.req.query('page') || '1')\n const limit = parseInt(c.req.query('limit') || '50')\n const offset = (page - 1) * limit\n\n const filters = {\n action: c.req.query('action') || '',\n resource_type: c.req.query('resource_type') || '',\n date_from: c.req.query('date_from') || '',\n date_to: c.req.query('date_to') || '',\n user_id: c.req.query('user_id') || ''\n }\n\n // Build where clause\n let whereConditions: string[] = []\n let params: any[] = []\n\n if (filters.action) {\n whereConditions.push('al.action = ?')\n params.push(filters.action)\n }\n\n if (filters.resource_type) {\n whereConditions.push('al.resource_type = ?')\n params.push(filters.resource_type)\n }\n\n if (filters.user_id) {\n whereConditions.push('al.user_id = ?')\n params.push(filters.user_id)\n }\n\n if (filters.date_from) {\n const fromTimestamp = new Date(filters.date_from).getTime()\n whereConditions.push('al.created_at >= ?')\n params.push(fromTimestamp)\n }\n\n if (filters.date_to) {\n const toTimestamp = new Date(filters.date_to + ' 23:59:59').getTime()\n whereConditions.push('al.created_at <= ?')\n params.push(toTimestamp)\n }\n\n const whereClause = whereConditions.length > 0 ? `WHERE ${whereConditions.join(' AND ')}` : ''\n\n // Get activity logs with user information\n const logsStmt = db.prepare(`\n SELECT \n al.id, al.user_id, al.action, al.resource_type, al.resource_id,\n al.details, al.ip_address, al.user_agent, al.created_at,\n u.email as user_email,\n COALESCE(u.first_name || ' ' || u.last_name, u.username, u.email) as user_name\n FROM activity_logs al\n LEFT JOIN users u ON al.user_id = u.id\n ${whereClause}\n ORDER BY al.created_at DESC\n LIMIT ? OFFSET ?\n `)\n\n const { results: logs } = await logsStmt.bind(...params, limit, offset).all()\n\n // Get total count for pagination\n const countStmt = db.prepare(`\n SELECT COUNT(*) as total \n FROM activity_logs al\n LEFT JOIN users u ON al.user_id = u.id\n ${whereClause}\n `)\n const countResult = await countStmt.bind(...params).first() as any\n const totalLogs = countResult?.total || 0\n\n // Parse details JSON for each log\n const formattedLogs: ActivityLog[] = (logs || []).map((log: any) => ({\n ...log,\n details: log.details ? JSON.parse(log.details) : null\n }))\n\n // Log the activity\n await logActivity(\n db, user!.userId, 'activity.logs_viewed', undefined, undefined,\n { filters, page, limit },\n c.req.header('x-forwarded-for') || c.req.header('cf-connecting-ip'),\n c.req.header('user-agent')\n )\n\n const pageData: ActivityLogsPageData = {\n logs: formattedLogs,\n pagination: {\n page,\n limit,\n total: totalLogs,\n pages: Math.ceil(totalLogs / limit)\n },\n filters,\n user: {\n name: user!.email.split('@')[0] || user!.email, // Use email username as fallback\n email: user!.email,\n role: user!.role\n }\n }\n\n return c.html(renderActivityLogsPage(pageData))\n\n } catch (error) {\n console.error('Activity logs error:', error)\n \n const pageData: ActivityLogsPageData = {\n logs: [],\n pagination: { page: 1, limit: 50, total: 0, pages: 0 },\n filters: {},\n user: {\n name: user!.email,\n email: user!.email,\n role: user!.role\n }\n }\n\n return c.html(renderActivityLogsPage(pageData))\n }\n})\n\n/**\n * GET /admin/activity-logs/export - Export activity logs to CSV\n */\nuserRoutes.get('/activity-logs/export', async (c) => {\n const db = c.env.DB\n const user = c.get('user')\n\n try {\n // Get filter parameters (same as list view)\n const filters = {\n action: c.req.query('action') || '',\n resource_type: c.req.query('resource_type') || '',\n date_from: c.req.query('date_from') || '',\n date_to: c.req.query('date_to') || '',\n user_id: c.req.query('user_id') || ''\n }\n\n // Build where clause\n let whereConditions: string[] = []\n let params: any[] = []\n\n if (filters.action) {\n whereConditions.push('al.action = ?')\n params.push(filters.action)\n }\n\n if (filters.resource_type) {\n whereConditions.push('al.resource_type = ?')\n params.push(filters.resource_type)\n }\n\n if (filters.user_id) {\n whereConditions.push('al.user_id = ?')\n params.push(filters.user_id)\n }\n\n if (filters.date_from) {\n const fromTimestamp = new Date(filters.date_from).getTime()\n whereConditions.push('al.created_at >= ?')\n params.push(fromTimestamp)\n }\n\n if (filters.date_to) {\n const toTimestamp = new Date(filters.date_to + ' 23:59:59').getTime()\n whereConditions.push('al.created_at <= ?')\n params.push(toTimestamp)\n }\n\n const whereClause = whereConditions.length > 0 ? `WHERE ${whereConditions.join(' AND ')}` : ''\n\n // Get all matching activity logs (limit to 10,000 for performance)\n const logsStmt = db.prepare(`\n SELECT \n al.id, al.user_id, al.action, al.resource_type, al.resource_id,\n al.details, al.ip_address, al.user_agent, al.created_at,\n u.email as user_email,\n COALESCE(u.first_name || ' ' || u.last_name, u.username, u.email) as user_name\n FROM activity_logs al\n LEFT JOIN users u ON al.user_id = u.id\n ${whereClause}\n ORDER BY al.created_at DESC\n LIMIT 10000\n `)\n\n const { results: logs } = await logsStmt.bind(...params).all()\n\n // Generate CSV content\n const csvHeaders = ['Timestamp', 'User', 'Email', 'Action', 'Resource Type', 'Resource ID', 'IP Address', 'Details']\n const csvRows = [csvHeaders.join(',')]\n\n for (const log of (logs || [])) {\n const row = [\n `\"${new Date((log as any).created_at).toISOString()}\"`,\n `\"${(log as any).user_name || 'Unknown'}\"`,\n `\"${(log as any).user_email || 'N/A'}\"`,\n `\"${(log as any).action}\"`,\n `\"${(log as any).resource_type || 'N/A'}\"`,\n `\"${(log as any).resource_id || 'N/A'}\"`,\n `\"${(log as any).ip_address || 'N/A'}\"`,\n `\"${(log as any).details ? JSON.stringify(JSON.parse((log as any).details)) : 'N/A'}\"`\n ]\n csvRows.push(row.join(','))\n }\n\n const csvContent = csvRows.join('\\n')\n\n // Log the export activity\n await logActivity(\n db, user!.userId, 'activity.logs_exported', undefined, undefined,\n { filters, count: logs?.length || 0 },\n c.req.header('x-forwarded-for') || c.req.header('cf-connecting-ip'),\n c.req.header('user-agent')\n )\n\n // Return CSV file\n const filename = `activity-logs-${new Date().toISOString().split('T')[0]}.csv`\n \n return new Response(csvContent, {\n headers: {\n 'Content-Type': 'text/csv',\n 'Content-Disposition': `attachment; filename=\"${filename}\"`\n }\n })\n\n } catch (error) {\n console.error('Activity logs export error:', error)\n return c.json({ error: 'Failed to export activity logs' }, 500)\n }\n})\n\nexport { userRoutes }","export interface MediaFile {\n id: string;\n filename: string;\n original_name: string;\n mime_type: string;\n size: number;\n public_url: string;\n thumbnail_url?: string;\n alt?: string;\n caption?: string;\n tags: string[];\n uploaded_at: string;\n fileSize: string;\n uploadedAt: string;\n isImage: boolean;\n isVideo: boolean;\n isDocument: boolean;\n}\n\nexport interface MediaGridData {\n files: MediaFile[];\n viewMode?: \"grid\" | \"list\";\n selectable?: boolean;\n emptyMessage?: string;\n className?: string;\n}\n\nexport function renderMediaGrid(data: MediaGridData): string {\n if (data.files.length === 0) {\n return `\n \n
\n \n \n
No media files \n
${\n data.emptyMessage || \"Get started by uploading your first file.\"\n }
\n
\n `;\n }\n\n const gridClass = data.viewMode === \"list\" ? \"space-y-4\" : \"media-grid\";\n\n return `\n \n ${data.files\n .map((file) =>\n renderMediaFileCard(file, data.viewMode, data.selectable)\n )\n .join(\"\")}\n
\n `;\n}\n\nexport function renderMediaFileCard(\n file: MediaFile,\n viewMode: \"grid\" | \"list\" = \"grid\",\n selectable: boolean = false\n): string {\n if (viewMode === \"list\") {\n return `\n \n `;\n }\n\n // Grid view\n return `\n \n `;\n}\n\nfunction getFileIcon(mimeType: string): string {\n if (mimeType.startsWith(\"image/\")) {\n return `\n \n \n \n `;\n } else if (mimeType.startsWith(\"video/\")) {\n return `\n \n \n \n `;\n } else if (mimeType === \"application/pdf\") {\n return `\n \n \n \n `;\n } else {\n return `\n \n \n \n `;\n }\n}\n","import {\n getConfirmationDialogScript,\n renderConfirmationDialog,\n} from \"../components/confirmation-dialog.template\";\nimport { MediaFile, renderMediaGrid } from \"../components/media-grid.template\";\nimport {\n AdminLayoutCatalystData,\n renderAdminLayoutCatalyst,\n} from \"../layouts/admin-layout-catalyst.template\";\n\nexport interface FolderStats {\n folder: string;\n count: number;\n totalSize: number;\n}\n\nexport interface TypeStats {\n type: string;\n count: number;\n}\n\nexport interface MediaLibraryPageData {\n files: MediaFile[];\n folders: FolderStats[];\n types: TypeStats[];\n currentFolder: string;\n currentType: string;\n currentView: \"grid\" | \"list\";\n currentPage: number;\n totalFiles: number;\n hasNextPage: boolean;\n user?: {\n name: string;\n email: string;\n role: string;\n };\n version?: string;\n}\n\nexport function renderMediaLibraryPage(data: MediaLibraryPageData): string {\n const pageContent = `\n \n \n
\n
\n
Media Library \n
Manage your media files and assets
\n
\n
\n
\n \n \n \n Upload Media\n \n
\n
\n \n
\n \n
\n
\n \n
\n \n Upload Files\n \n
\n\n \n
\n\n \n
\n\n \n
\n
Quick Actions \n
\n \n Create Folder\n \n \n Cleanup Unused\n \n
\n
\n
\n
\n \n \n
\n \n
\n \n
\n\n
\n
\n
\n
\n
\n
View: \n
\n
\n Grid \n List \n \n
\n \n \n
\n
\n\n
\n
\n\n
\n
${\n data.files.length\n } files \n
\n Select All\n \n
\n
\n Bulk Actions\n \n \n \n \n\n \n
\n
\n
\n
\n
\n
\n \n \n
\n ${renderMediaGrid({\n files: data.files,\n viewMode: data.currentView,\n selectable: true,\n emptyMessage:\n \"No media files found. Upload your first file to get started.\",\n })}\n
\n \n \n ${\n data.hasNextPage\n ? `\n
\n
\n ${\n data.currentPage > 1\n ? `\n
\n Previous\n \n `\n : \"\"\n }\n
Page ${\n data.currentPage\n } \n
\n Next\n \n
\n
\n `\n : \"\"\n }\n
\n
\n
\n \n \n \n
\n
\n
Upload Files \n
\n \n \n \n \n
\n \n \n
{ window.location.href = '/admin/media?t=' + Date.now(); }, 1500); }\"\n class=\"space-y-4\"\n >\n \n \n
\n \n \n
\n
Drop files here or click to upload
\n
PNG, JPG, GIF, PDF up to 10MB
\n
\n
\n \n \n \n \n \n Upload to folder: \n \n uploads \n images \n documents \n \n
\n\n \n \n\n \n \n \n Cancel\n \n \n Upload Files\n \n
\n \n \n \n
\n
\n
\n \n \n \n\n \n \n
\n
\n
Move to Folder \n
\n \n \n \n \n
\n\n
\n Select a folder to move 0 selected file(s) to:\n
\n\n
\n ${\n data.folders.length > 0\n ? data.folders\n .map(\n (folder) => `\n
\n \n ${folder.folder} \n ${folder.count} files \n
\n \n `\n )\n .join(\"\")\n : '
No folders available
'\n }\n
\n\n
\n \n Cancel\n \n
\n
\n
\n\n \n \n
\n
\n
Create New Folder \n
\n \n \n \n \n
\n\n
\n \n
\n Folder Name\n \n
\n
\n Use lowercase letters, numbers, hyphens, and underscores only\n
\n
\n\n \n \n Cancel\n \n \n Create Folder\n \n
\n \n
\n
\n\n \n \n \n\n \n ${renderConfirmationDialog({\n id: \"media-bulk-delete-confirm\",\n title: \"Delete Selected Files\",\n message: `Are you sure you want to delete ${\n data.files.length > 0 ? \"the selected files\" : \"these files\"\n }? This action cannot be undone and the files will be permanently removed.`,\n confirmText: \"Delete Files\",\n cancelText: \"Cancel\",\n confirmClass: \"bg-red-500 hover:bg-red-400\",\n iconColor: \"red\",\n onConfirm: \"performBulkDelete()\",\n })}\n\n \n ${getConfirmationDialogScript()}\n `;\n\n function buildPageUrl(page: number, folder: string, type: string): string {\n const params = new URLSearchParams();\n params.set(\"page\", page.toString());\n if (folder !== \"all\") params.set(\"folder\", folder);\n if (type !== \"all\") params.set(\"type\", type);\n return `/admin/media?${params.toString()}`;\n }\n\n const layoutData: AdminLayoutCatalystData = {\n title: \"Media Library\",\n pageTitle: \"Media Library\",\n currentPath: \"/admin/media\",\n user: data.user,\n version: data.version,\n content: pageContent,\n };\n\n return renderAdminLayoutCatalyst(layoutData);\n}\n","import { MediaFile } from './media-grid.template'\n\nexport interface MediaFileDetailsData {\n file: MediaFile & {\n width?: number\n height?: number\n folder: string\n uploadedAt: string\n }\n}\n\nexport function renderMediaFileDetails(data: MediaFileDetailsData): string {\n const { file } = data\n \n return `\n \n
File Details \n
\n \n \n \n \n
\n \n \n \n
\n
\n ${file.isImage ? `\n
\n ` : file.isVideo ? `\n
\n ` : `\n
\n `}\n
\n\n
\n
\n Copy URL\n \n
\n Open Original\n \n
\n
\n \n \n
\n
\n
Filename \n
${file.original_name}
\n
\n\n
\n
\n
Size \n
${file.fileSize}
\n
\n
\n
Type \n
${file.mime_type}
\n
\n
\n\n ${file.width && file.height ? `\n
\n
\n
Width \n
${file.width}px
\n
\n
\n
Height \n
${file.height}px
\n
\n
\n ` : ''}\n\n
\n
Folder \n
${file.folder}
\n
\n\n
\n
Uploaded \n
${file.uploadedAt}
\n
\n\n \n
\n \n Alt Text \n \n
\n\n \n Caption \n ${file.caption || ''} \n
\n\n \n Tags \n \n
\n\n \n \n Save Changes\n \n \n Delete File\n \n
\n \n
\n
\n `\n}","import { Hono } from 'hono'\nimport { html, raw } from 'hono/html'\nimport { z } from 'zod'\nimport type { D1Database, KVNamespace, R2Bucket } from '@cloudflare/workers-types'\nimport { requireAuth, requireRole } from '../middleware'\nimport { renderMediaLibraryPage, MediaLibraryPageData, FolderStats, TypeStats } from '../templates/pages/admin-media-library.template'\nimport { renderMediaFileDetails, MediaFileDetailsData } from '../templates/components/media-file-details.template'\nimport { MediaFile, renderMediaFileCard } from '../templates/components/media-grid.template'\nimport type { Bindings, Variables } from '../app'\n\n// File validation schema\nconst fileValidationSchema = z.object({\n name: z.string().min(1).max(255),\n type: z.string().refine(\n (type) => {\n const allowedTypes = [\n // Images\n 'image/jpeg', 'image/jpg', 'image/png', 'image/gif', 'image/webp', 'image/svg+xml',\n // Documents\n 'application/pdf', 'text/plain', 'application/msword', \n 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',\n // Videos\n 'video/mp4', 'video/webm', 'video/ogg', 'video/avi', 'video/mov',\n // Audio\n 'audio/mp3', 'audio/wav', 'audio/ogg', 'audio/m4a'\n ]\n return allowedTypes.includes(type)\n },\n { message: 'Unsupported file type' }\n ),\n size: z.number().min(1).max(50 * 1024 * 1024) // 50MB max\n})\n\nconst adminMediaRoutes = new Hono<{ Bindings: Bindings; Variables: Variables }>()\n\n// Apply authentication middleware\nadminMediaRoutes.use('*', requireAuth())\n\n// Media library main page\nadminMediaRoutes.get('/', async (c) => {\n try {\n const user = c.get('user')\n const { searchParams } = new URL(c.req.url)\n const folder = searchParams.get('folder') || 'all'\n const type = searchParams.get('type') || 'all'\n const view = searchParams.get('view') || 'grid'\n const page = parseInt(searchParams.get('page') || '1')\n const _cacheBust = searchParams.get('t') // Cache-busting parameter\n const limit = 24\n const offset = (page - 1) * limit\n\n const db = c.env.DB\n\n // TODO: Cache implementation removed during migration - will be added back when cache plugin is migrated\n\n // Build query for media files\n let query = 'SELECT * FROM media'\n const params: any[] = []\n const conditions: string[] = ['deleted_at IS NULL']\n \n if (folder !== 'all') {\n conditions.push('folder = ?')\n params.push(folder)\n }\n \n if (type !== 'all') {\n switch (type) {\n case 'images':\n conditions.push('mime_type LIKE ?')\n params.push('image/%')\n break\n case 'documents':\n conditions.push('mime_type IN (?, ?, ?)')\n params.push('application/pdf', 'text/plain', 'application/msword')\n break\n case 'videos':\n conditions.push('mime_type LIKE ?')\n params.push('video/%')\n break\n }\n }\n \n if (conditions.length > 0) {\n query += ` WHERE ${conditions.join(' AND ')}`\n }\n \n query += ` ORDER BY uploaded_at DESC LIMIT ${limit} OFFSET ${offset}`\n \n const stmt = db.prepare(query)\n const { results } = await stmt.bind(...params).all()\n \n // Get folder statistics\n const foldersStmt = db.prepare(`\n SELECT folder, COUNT(*) as count, SUM(size) as totalSize\n FROM media\n WHERE deleted_at IS NULL\n GROUP BY folder\n ORDER BY folder\n `)\n const { results: folders } = await foldersStmt.all()\n \n // Get type statistics\n const typesStmt = db.prepare(`\n SELECT\n CASE\n WHEN mime_type LIKE 'image/%' THEN 'images'\n WHEN mime_type LIKE 'video/%' THEN 'videos'\n WHEN mime_type IN ('application/pdf', 'text/plain') THEN 'documents'\n ELSE 'other'\n END as type,\n COUNT(*) as count\n FROM media\n WHERE deleted_at IS NULL\n GROUP BY type\n `)\n const { results: types } = await typesStmt.all()\n \n // Process media files with local serving URLs\n const mediaFiles: MediaFile[] = results.map((row: any) => ({\n id: row.id,\n filename: row.filename,\n original_name: row.original_name,\n mime_type: row.mime_type,\n size: row.size,\n public_url: `/files/${row.r2_key}`,\n thumbnail_url: row.mime_type.startsWith('image/') ? `/files/${row.r2_key}` : undefined,\n alt: row.alt,\n caption: row.caption,\n tags: row.tags ? JSON.parse(row.tags) : [],\n uploaded_at: row.uploaded_at,\n fileSize: formatFileSize(row.size),\n uploadedAt: new Date(row.uploaded_at).toLocaleDateString(),\n isImage: row.mime_type.startsWith('image/'),\n isVideo: row.mime_type.startsWith('video/'),\n isDocument: !row.mime_type.startsWith('image/') && !row.mime_type.startsWith('video/')\n }))\n \n const pageData: MediaLibraryPageData = {\n files: mediaFiles,\n folders: folders.map((f: any) => ({\n folder: f.folder,\n count: f.count,\n totalSize: f.totalSize\n })) as FolderStats[],\n types: types.map((t: any) => ({\n type: t.type,\n count: t.count\n })) as TypeStats[],\n currentFolder: folder,\n currentType: type,\n currentView: view as 'grid' | 'list',\n currentPage: page,\n totalFiles: results.length,\n hasNextPage: results.length === limit,\n user: {\n name: user!.email,\n email: user!.email,\n role: user!.role\n },\n version: c.get('appVersion')\n }\n\n // TODO: Cache implementation removed during migration\n\n return c.html(renderMediaLibraryPage(pageData))\n } catch (error) {\n console.error('Error loading media library:', error)\n return c.html(html`Error loading media library
`)\n }\n})\n\n// Media selector endpoint (HTMX endpoint for content form media selection)\nadminMediaRoutes.get('/selector', async (c) => {\n try {\n const { searchParams } = new URL(c.req.url)\n const search = searchParams.get('search') || ''\n const db = c.env.DB\n\n // Build search query\n let query = 'SELECT * FROM media WHERE deleted_at IS NULL'\n const params: any[] = []\n\n if (search.trim()) {\n query += ' AND (filename LIKE ? OR original_name LIKE ? OR alt LIKE ?)'\n const searchTerm = `%${search}%`\n params.push(searchTerm, searchTerm, searchTerm)\n }\n\n query += ' ORDER BY uploaded_at DESC LIMIT 24'\n\n const stmt = db.prepare(query)\n const { results } = await stmt.bind(...params).all()\n\n const mediaFiles = results.map((row: any) => ({\n id: row.id,\n filename: row.filename,\n original_name: row.original_name,\n mime_type: row.mime_type,\n size: row.size,\n public_url: `/files/${row.r2_key}`,\n thumbnail_url: row.mime_type.startsWith('image/') ? `/files/${row.r2_key}` : undefined,\n alt: row.alt,\n tags: row.tags ? JSON.parse(row.tags) : [],\n uploaded_at: row.uploaded_at,\n fileSize: formatFileSize(row.size),\n uploadedAt: new Date(row.uploaded_at).toLocaleDateString(),\n isImage: row.mime_type.startsWith('image/'),\n isVideo: row.mime_type.startsWith('video/'),\n isDocument: !row.mime_type.startsWith('image/') && !row.mime_type.startsWith('video/')\n }))\n\n // Render media selector grid\n return c.html(html`\n \n \n
\n\n \n\n ${mediaFiles.length === 0 ? html`\n \n
\n \n \n
No media files found
\n
\n ` : ''}\n `)\n } catch (error) {\n console.error('Error loading media selector:', error)\n return c.html(html`Error loading media files
`)\n }\n})\n\n// Search media files (HTMX endpoint)\nadminMediaRoutes.get('/search', async (c) => {\n try {\n const { searchParams } = new URL(c.req.url)\n const search = searchParams.get('search') || ''\n const folder = searchParams.get('folder') || 'all'\n const type = searchParams.get('type') || 'all'\n const db = c.env.DB\n \n // Build search query\n let query = 'SELECT * FROM media'\n const params: any[] = []\n const conditions: string[] = []\n \n if (search.trim()) {\n conditions.push('(filename LIKE ? OR original_name LIKE ? OR alt LIKE ?)')\n const searchTerm = `%${search}%`\n params.push(searchTerm, searchTerm, searchTerm)\n }\n \n if (folder !== 'all') {\n conditions.push('folder = ?')\n params.push(folder)\n }\n \n if (type !== 'all') {\n switch (type) {\n case 'images':\n conditions.push('mime_type LIKE ?')\n params.push('image/%')\n break\n case 'documents':\n conditions.push('mime_type IN (?, ?, ?)')\n params.push('application/pdf', 'text/plain', 'application/msword')\n break\n case 'videos':\n conditions.push('mime_type LIKE ?')\n params.push('video/%')\n break\n }\n }\n \n if (conditions.length > 0) {\n query += ` WHERE ${conditions.join(' AND ')}`\n }\n \n query += ` ORDER BY uploaded_at DESC LIMIT 24`\n \n const stmt = db.prepare(query)\n const { results } = await stmt.bind(...params).all()\n \n const mediaFiles = results.map((row: any) => ({\n ...row,\n public_url: `/files/${row.r2_key}`,\n thumbnail_url: row.mime_type.startsWith('image/') ? `/files/${row.r2_key}` : undefined,\n tags: row.tags ? JSON.parse(row.tags) : [],\n uploadedAt: new Date(row.uploaded_at).toLocaleDateString(),\n fileSize: formatFileSize(row.size),\n isImage: row.mime_type.startsWith('image/'),\n isVideo: row.mime_type.startsWith('video/'),\n isDocument: !row.mime_type.startsWith('image/') && !row.mime_type.startsWith('video/')\n }))\n \n const gridHTML = mediaFiles.map(file => generateMediaItemHTML(file)).join('')\n \n return c.html(raw(gridHTML))\n } catch (error) {\n console.error('Error searching media:', error)\n return c.html('Error searching files
')\n }\n})\n\n// Get file details modal (HTMX endpoint)\nadminMediaRoutes.get('/:id/details', async (c) => {\n try {\n const id = c.req.param('id')\n const db = c.env.DB\n \n const stmt = db.prepare('SELECT * FROM media WHERE id = ?')\n const result = await stmt.bind(id).first() as any\n \n if (!result) {\n return c.html('File not found
')\n }\n \n const file: MediaFile & { width?: number; height?: number; folder: string; uploadedAt: string } = {\n id: result.id,\n filename: result.filename,\n original_name: result.original_name,\n mime_type: result.mime_type,\n size: result.size,\n public_url: `/files/${result.r2_key}`,\n thumbnail_url: result.mime_type.startsWith('image/') ? `/files/${result.r2_key}` : undefined,\n alt: result.alt,\n caption: result.caption,\n tags: result.tags ? JSON.parse(result.tags) : [],\n uploaded_at: result.uploaded_at,\n fileSize: formatFileSize(result.size),\n uploadedAt: new Date(result.uploaded_at).toLocaleString(),\n isImage: result.mime_type.startsWith('image/'),\n isVideo: result.mime_type.startsWith('video/'),\n isDocument: !result.mime_type.startsWith('image/') && !result.mime_type.startsWith('video/'),\n width: result.width,\n height: result.height,\n folder: result.folder\n }\n \n const detailsData: MediaFileDetailsData = { file }\n \n return c.html(renderMediaFileDetails(detailsData))\n } catch (error) {\n console.error('Error fetching file details:', error)\n return c.html('Error loading file details
')\n }\n})\n\n// Upload files endpoint (HTMX compatible)\nadminMediaRoutes.post('/upload', async (c) => {\n try {\n const user = c.get('user')\n const formData = await c.req.formData()\n const fileEntries = formData.getAll('files') as unknown[]\n const files: File[] = []\n\n for (const entry of fileEntries) {\n if (entry instanceof File) {\n files.push(entry)\n }\n }\n \n if (!files || files.length === 0) {\n return c.html(html`\n \n No files provided\n
\n `)\n }\n\n const uploadResults = []\n const errors = []\n\n // Check if MEDIA_BUCKET is available\n console.log('[MEDIA UPLOAD] c.env keys:', Object.keys(c.env))\n console.log('[MEDIA UPLOAD] MEDIA_BUCKET defined?', !!c.env.MEDIA_BUCKET)\n console.log('[MEDIA UPLOAD] MEDIA_BUCKET type:', typeof c.env.MEDIA_BUCKET)\n\n if (!c.env.MEDIA_BUCKET) {\n console.error('[MEDIA UPLOAD] MEDIA_BUCKET is not available! Available env keys:', Object.keys(c.env))\n return c.html(html`\n \n Media storage (R2) is not configured. Please check your wrangler.toml configuration.\n Debug: Available bindings: ${Object.keys(c.env).join(', ')} \n
\n `)\n }\n\n for (const file of files) {\n try {\n // Validate file\n const validation = fileValidationSchema.safeParse({\n name: file.name,\n type: file.type,\n size: file.size\n })\n\n if (!validation.success) {\n errors.push({\n filename: file.name,\n error: validation.error.issues[0]?.message || 'Validation failed'\n })\n continue\n }\n\n // Generate unique filename and R2 key\n const fileId = crypto.randomUUID()\n const fileExtension = file.name.split('.').pop() || ''\n const filename = `${fileId}.${fileExtension}`\n const folder = formData.get('folder') as string || 'uploads'\n const r2Key = `${folder}/${filename}`\n\n // Upload to R2\n const arrayBuffer = await file.arrayBuffer()\n const uploadResult = await c.env.MEDIA_BUCKET.put(r2Key, arrayBuffer, {\n httpMetadata: {\n contentType: file.type,\n contentDisposition: `inline; filename=\"${file.name}\"`\n },\n customMetadata: {\n originalName: file.name,\n uploadedBy: user!.userId,\n uploadedAt: new Date().toISOString()\n }\n })\n\n if (!uploadResult) {\n errors.push({\n filename: file.name,\n error: 'Failed to upload to storage'\n })\n continue\n }\n\n // Extract image dimensions if it's an image\n let width: number | undefined\n let height: number | undefined\n \n if (file.type.startsWith('image/') && !file.type.includes('svg')) {\n try {\n const dimensions = await getImageDimensions(arrayBuffer)\n width = dimensions.width\n height = dimensions.height\n } catch (error) {\n console.warn('Failed to extract image dimensions:', error)\n }\n }\n\n // Generate URLs - use public serving route\n const publicUrl = `/files/${r2Key}`\n const thumbnailUrl = file.type.startsWith('image/') ? publicUrl : undefined\n\n // Save to database\n const stmt = c.env.DB.prepare(`\n INSERT INTO media (\n id, filename, original_name, mime_type, size, width, height, \n folder, r2_key, public_url, thumbnail_url, uploaded_by, uploaded_at\n ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\n `)\n \n await stmt.bind(\n fileId,\n filename,\n file.name,\n file.type,\n file.size,\n width,\n height,\n folder,\n r2Key,\n publicUrl,\n thumbnailUrl,\n user!.userId,\n Math.floor(Date.now() / 1000)\n ).run()\n\n uploadResults.push({\n id: fileId,\n filename: filename,\n originalName: file.name,\n mimeType: file.type,\n size: file.size,\n publicUrl: publicUrl\n })\n } catch (error) {\n errors.push({\n filename: file.name,\n error: 'Upload failed: ' + (error instanceof Error ? error.message : 'Unknown error')\n })\n }\n }\n\n // TODO: Cache invalidation removed during migration\n\n // Fetch updated media list to include in response\n let mediaGridHTML = ''\n if (uploadResults.length > 0) {\n try {\n const folderEntry = formData.get('folder')\n const folder = typeof folderEntry === 'string' ? folderEntry : 'uploads'\n const query = 'SELECT * FROM media WHERE deleted_at IS NULL ORDER BY uploaded_at DESC LIMIT 24'\n const stmt = c.env.DB.prepare(query)\n const { results } = await stmt.all()\n\n const mediaFiles = results.map((row: any) => ({\n id: row.id,\n filename: row.filename,\n original_name: row.original_name,\n mime_type: row.mime_type,\n size: row.size,\n public_url: `/files/${row.r2_key}`,\n thumbnail_url: row.mime_type.startsWith('image/') ? `/files/${row.r2_key}` : undefined,\n tags: row.tags ? JSON.parse(row.tags) : [],\n uploaded_at: row.uploaded_at,\n fileSize: formatFileSize(row.size),\n uploadedAt: new Date(row.uploaded_at).toLocaleDateString(),\n isImage: row.mime_type.startsWith('image/'),\n isVideo: row.mime_type.startsWith('video/'),\n isDocument: !row.mime_type.startsWith('image/') && !row.mime_type.startsWith('video/')\n }))\n\n mediaGridHTML = mediaFiles.map(file => renderMediaFileCard(file, 'grid', true)).join('')\n } catch (error) {\n console.error('Error fetching updated media list:', error)\n }\n }\n\n // Return HTMX response with results\n return c.html(html`\n ${uploadResults.length > 0 ? html`\n \n Successfully uploaded ${uploadResults.length} file${uploadResults.length > 1 ? 's' : ''}\n
\n ` : ''}\n\n ${errors.length > 0 ? html`\n \n
Upload errors:
\n
\n ${errors.map(error => html`\n ${error.filename}: ${error.error} \n `)}\n \n
\n ` : ''}\n\n ${uploadResults.length > 0 ? html`\n \n ` : ''}\n `)\n } catch (error) {\n console.error('Upload error:', error)\n return c.html(html`\n \n Upload failed: ${error instanceof Error ? error.message : 'Unknown error'}\n
\n `)\n }\n})\n\n// Serve files from R2 storage\nadminMediaRoutes.get('/file/*', async (c) => {\n try {\n const r2Key = c.req.path.replace('/admin/media/file/', '')\n \n if (!r2Key) {\n return c.notFound()\n }\n\n // Get file from R2\n const object = await c.env.MEDIA_BUCKET.get(r2Key)\n \n if (!object) {\n return c.notFound()\n }\n\n // Set appropriate headers\n const headers = new Headers()\n object.httpMetadata?.contentType && headers.set('Content-Type', object.httpMetadata.contentType)\n object.httpMetadata?.contentDisposition && headers.set('Content-Disposition', object.httpMetadata.contentDisposition)\n headers.set('Cache-Control', 'public, max-age=31536000') // 1 year cache\n \n return new Response(object.body as any, {\n headers\n })\n } catch (error) {\n console.error('Error serving file:', error)\n return c.notFound()\n }\n})\n\n// Update media file metadata (HTMX compatible)\nadminMediaRoutes.put('/:id', async (c) => {\n try {\n const user = c.get('user')\n const fileId = c.req.param('id')\n const formData = await c.req.formData()\n \n // Get file record\n const stmt = c.env.DB.prepare('SELECT * FROM media WHERE id = ? AND deleted_at IS NULL')\n const fileRecord = await stmt.bind(fileId).first() as any\n \n if (!fileRecord) {\n return c.html(html`\n \n File not found\n
\n `)\n }\n\n // Check permissions (only allow updates by uploader or admin)\n if (fileRecord.uploaded_by !== user!.userId && user!.role !== 'admin') {\n return c.html(html`\n \n Permission denied\n
\n `)\n }\n\n // Extract form data\n const alt = formData.get('alt') as string || null\n const caption = formData.get('caption') as string || null\n const tagsString = formData.get('tags') as string || ''\n const tags = tagsString ? tagsString.split(',').map(tag => tag.trim()).filter(tag => tag) : []\n\n // Update database\n const updateStmt = c.env.DB.prepare(`\n UPDATE media \n SET alt = ?, caption = ?, tags = ?, updated_at = ?\n WHERE id = ?\n `)\n await updateStmt.bind(\n alt,\n caption,\n JSON.stringify(tags),\n Math.floor(Date.now() / 1000),\n fileId\n ).run()\n\n // TODO: Cache invalidation removed during migration\n\n return c.html(html`\n \n File updated successfully\n
\n \n `)\n } catch (error) {\n console.error('Update error:', error)\n return c.html(html`\n \n Update failed: ${error instanceof Error ? error.message : 'Unknown error'}\n
\n `)\n }\n})\n\n// Cleanup unused media files (HTMX compatible)\nadminMediaRoutes.delete('/cleanup', requireRole('admin'), async (c) => {\n try {\n const db = c.env.DB\n\n // Find all media files\n const allMediaStmt = db.prepare('SELECT id, r2_key, filename FROM media WHERE deleted_at IS NULL')\n const { results: allMedia } = await allMediaStmt.all<{ id: string; r2_key: string; filename: string }>()\n\n // Find media files referenced in content\n // Content can reference media in various JSON fields like data, hero_image, etc.\n const contentStmt = db.prepare('SELECT data FROM content')\n const { results: contentRecords } = await contentStmt.all<{ data: unknown }>()\n\n // Extract all media URLs from content\n const referencedUrls = new Set()\n for (const record of contentRecords || []) {\n if (record.data) {\n const dataStr = typeof record.data === 'string' ? record.data : JSON.stringify(record.data)\n // Find all /files/ URLs in the content\n const urlMatches = dataStr.matchAll(/\\/files\\/([^\\s\"',]+)/g)\n for (const match of urlMatches) {\n referencedUrls.add(match[1]!)\n }\n }\n }\n\n // Find unreferenced media files\n const mediaRows = allMedia || []\n const unusedFiles = mediaRows.filter((file) => !referencedUrls.has(file.r2_key))\n\n if (unusedFiles.length === 0) {\n return c.html(html`\n \n No unused media files found. All files are referenced in content.\n
\n \n `)\n }\n\n // Delete unused files from R2 and database\n let deletedCount = 0\n const errors = []\n\n for (const file of unusedFiles) {\n try {\n // Delete from R2\n await c.env.MEDIA_BUCKET.delete(file.r2_key)\n\n // Soft delete in database\n const deleteStmt = db.prepare('UPDATE media SET deleted_at = ? WHERE id = ?')\n await deleteStmt.bind(Math.floor(Date.now() / 1000), file.id).run()\n\n deletedCount++\n } catch (error) {\n console.error(`Failed to delete ${file.filename}:`, error)\n errors.push({\n filename: file.filename,\n error: error instanceof Error ? error.message : 'Unknown error'\n })\n }\n }\n\n // Return success response\n return c.html(html`\n \n Successfully cleaned up ${deletedCount} unused media file${deletedCount !== 1 ? 's' : ''}.\n ${errors.length > 0 ? html`\n Failed to delete ${errors.length} file${errors.length !== 1 ? 's' : ''}. \n ` : ''}\n
\n\n ${errors.length > 0 ? html`\n \n
Cleanup errors:
\n
\n ${errors.map(error => html`\n ${error.filename}: ${error.error} \n `)}\n \n
\n ` : ''}\n\n \n `)\n } catch (error) {\n console.error('Cleanup error:', error)\n return c.html(html`\n \n Cleanup failed: ${error instanceof Error ? error.message : 'Unknown error'}\n
\n `)\n }\n})\n\n// Delete media file (HTMX compatible)\nadminMediaRoutes.delete('/:id', async (c) => {\n try {\n const user = c.get('user')\n const fileId = c.req.param('id')\n\n // Get file record\n const stmt = c.env.DB.prepare('SELECT * FROM media WHERE id = ? AND deleted_at IS NULL')\n const fileRecord = await stmt.bind(fileId).first() as any\n\n if (!fileRecord) {\n return c.html(html`\n \n File not found\n
\n `)\n }\n\n // Check permissions (only allow deletion by uploader or admin)\n if (fileRecord.uploaded_by !== user!.userId && user!.role !== 'admin') {\n return c.html(html`\n \n Permission denied\n
\n `)\n }\n\n // Delete from R2\n try {\n await c.env.MEDIA_BUCKET.delete(fileRecord.r2_key)\n } catch (error) {\n console.warn('Failed to delete from R2:', error)\n // Continue with database deletion even if R2 deletion fails\n }\n\n // Soft delete in database\n const deleteStmt = c.env.DB.prepare('UPDATE media SET deleted_at = ? WHERE id = ?')\n await deleteStmt.bind(Math.floor(Date.now() / 1000), fileId).run()\n\n // TODO: Cache invalidation removed during migration\n\n // Return HTMX response that redirects to media library\n return c.html(html`\n \n `)\n } catch (error) {\n console.error('Delete error:', error)\n return c.html(html`\n \n Delete failed: ${error instanceof Error ? error.message : 'Unknown error'}\n
\n `)\n }\n})\n\n// Helper function to extract image dimensions\nasync function getImageDimensions(arrayBuffer: ArrayBuffer): Promise<{ width: number; height: number }> {\n const uint8Array = new Uint8Array(arrayBuffer)\n \n // Check for JPEG\n if (uint8Array[0] === 0xFF && uint8Array[1] === 0xD8) {\n return getJPEGDimensions(uint8Array)\n }\n \n // Check for PNG\n if (uint8Array[0] === 0x89 && uint8Array[1] === 0x50 && uint8Array[2] === 0x4E && uint8Array[3] === 0x47) {\n return getPNGDimensions(uint8Array)\n }\n \n // Default fallback\n return { width: 0, height: 0 }\n}\n\nfunction getJPEGDimensions(uint8Array: Uint8Array): { width: number; height: number } {\n let i = 2\n while (i < uint8Array.length - 8) {\n if (uint8Array[i] === 0xFF && uint8Array[i + 1] === 0xC0) {\n return {\n height: (uint8Array[i + 5]! << 8) | uint8Array[i + 6]!,\n width: (uint8Array[i + 7]! << 8) | uint8Array[i + 8]!\n }\n }\n const segmentLength = (uint8Array[i + 2]! << 8) | uint8Array[i + 3]!\n i += 2 + segmentLength\n }\n return { width: 0, height: 0 }\n}\n\nfunction getPNGDimensions(uint8Array: Uint8Array): { width: number; height: number } {\n if (uint8Array.length < 24) {\n return { width: 0, height: 0 }\n }\n return {\n width: (uint8Array[16]! << 24) | (uint8Array[17]! << 16) | (uint8Array[18]! << 8) | uint8Array[19]!,\n height: (uint8Array[20]! << 24) | (uint8Array[21]! << 16) | (uint8Array[22]! << 8) | uint8Array[23]!\n }\n}\n\n// Helper function to generate media item HTML\nfunction generateMediaItemHTML(file: any): string {\n const isImage = file.isImage\n const isVideo = file.isVideo\n \n return `\n \n `\n}\n\n// Helper function to format file size\nfunction formatFileSize(bytes: number): string {\n if (bytes === 0) return '0 Bytes'\n const k = 1024\n const sizes = ['Bytes', 'KB', 'MB', 'GB']\n const i = Math.floor(Math.log(bytes) / Math.log(k))\n return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i]\n}\n\nexport { adminMediaRoutes }\n","import { renderAdminLayoutCatalyst, AdminLayoutCatalystData } from '../layouts/admin-layout-catalyst.template'\nimport { renderConfirmationDialog, getConfirmationDialogScript } from '../components/confirmation-dialog.template'\n\nexport interface Plugin {\n id: string\n name: string\n displayName: string\n description: string\n version: string\n author: string\n status: 'active' | 'inactive' | 'error' | 'uninstalled'\n category: string\n icon: string\n downloadCount?: number\n rating?: number\n lastUpdated: string\n dependencies?: string[]\n permissions?: string[]\n isCore?: boolean\n}\n\nexport interface PluginsListPageData {\n plugins: Plugin[]\n stats?: {\n total: number\n active: number\n inactive: number\n errors: number\n uninstalled: number\n }\n user?: {\n name: string\n email: string\n role: string\n }\n version?: string\n}\n\nexport function renderPluginsListPage(data: PluginsListPageData): string {\n const categories = [\n { value: 'content', label: 'Content Management' },\n { value: 'media', label: 'Media' },\n { value: 'editor', label: 'Editors' },\n { value: 'seo', label: 'SEO & Analytics' },\n { value: 'security', label: 'Security' },\n { value: 'utilities', label: 'Utilities' },\n { value: 'system', label: 'System' },\n { value: 'development', label: 'Development' },\n { value: 'demo', label: 'Demo' }\n ];\n\n const statuses = [\n { value: 'active', label: 'Active' },\n { value: 'inactive', label: 'Inactive' },\n { value: 'uninstalled', label: 'Available to Install' },\n { value: 'error', label: 'Error' }\n ];\n\n // Calculate counts\n const categoryCounts: Record = {};\n categories.forEach(cat => {\n categoryCounts[cat.value] = data.plugins.filter(p => p.category === cat.value).length;\n });\n\n // Sort categories by count (descending)\n categories.sort((a, b) => (categoryCounts[b.value] || 0) - (categoryCounts[a.value] || 0));\n\n const statusCounts: Record = {};\n statuses.forEach(status => {\n statusCounts[status.value] = data.plugins.filter(p => p.status === status.value).length;\n });\n\n // Sort statuses by count (descending)\n statuses.sort((a, b) => (statusCounts[b.value] || 0) - (statusCounts[a.value] || 0));\n\n const pageContent = `\n \n \n
\n
\n
Plugins \n
Manage and extend functionality with plugins
\n
\n
\n\n \n
\n
\n
\n
\n
\n Experimental Feature\n \n
\n
\n Plugin management is currently under active development. While functional, some features may change or have limitations.\n Please report any issues you encounter on our Discord community .\n
\n
\n
\n
\n
\n\n
\n \n
\n \n \n
Categories \n
\n ${categories.map(cat => {\n const count = categoryCounts[cat.value] || 0;\n const isDisabled = count === 0;\n return `\n
\n \n \n ${cat.label} (${count}) \n \n
\n `}).join('')}\n
\n
\n\n
\n\n \n \n
Status \n
\n ${statuses.map(status => {\n const count = statusCounts[status.value] || 0;\n const isDisabled = count === 0;\n let colorClass = '';\n let ringClass = '';\n let dotClass = '';\n \n switch(status.value) {\n case 'active':\n colorClass = 'text-emerald-700 dark:text-emerald-400 bg-emerald-50 dark:bg-emerald-500/10';\n ringClass = 'ring-emerald-600/20';\n dotClass = 'bg-emerald-500 dark:bg-emerald-400';\n break;\n case 'inactive':\n colorClass = 'text-zinc-700 dark:text-zinc-400 bg-zinc-50 dark:bg-zinc-500/10';\n ringClass = 'ring-zinc-600/20';\n dotClass = 'bg-zinc-500 dark:bg-zinc-400';\n break;\n case 'error':\n colorClass = 'text-red-700 dark:text-red-400 bg-red-50 dark:bg-red-500/10';\n ringClass = 'ring-red-600/20';\n dotClass = 'bg-red-500 dark:bg-red-400';\n break;\n case 'uninstalled':\n colorClass = 'text-yellow-700 dark:text-yellow-400 bg-yellow-50 dark:bg-yellow-500/10';\n ringClass = 'ring-yellow-600/20';\n dotClass = 'bg-yellow-500 dark:bg-yellow-400';\n break;\n default:\n colorClass = 'text-zinc-700 dark:text-zinc-400 bg-zinc-50 dark:bg-zinc-500/10';\n ringClass = 'ring-zinc-600/20';\n dotClass = 'bg-zinc-500 dark:bg-zinc-400';\n }\n\n return `\n
\n \n \n \n \n ${status.label}\n \n (${count}) \n \n
\n `}).join('')}\n
\n
\n \n\n \n
\n \n
\n
\n
Total
\n
${data.stats?.total || 0}
\n
\n
\n
Active
\n
${data.stats?.active || 0}
\n
\n
\n
Available
\n
${data.stats?.uninstalled || 0}
\n
\n
\n
Errors
\n
${data.stats?.errors || 0}
\n
\n
\n\n \n
\n
\n\n
\n
\n Name (A-Z) \n Name (Z-A) \n Newest Installed \n Recently Updated \n Popularity \n Highest Rated \n \n\n
\n \n \n \n \n
\n
\n\n \n
\n ${data.plugins.map(plugin => renderPluginCard(plugin)).join('')}\n
\n
\n
\n
\n\n \n\n \n ${renderConfirmationDialog({\n id: 'uninstall-plugin-confirm',\n title: 'Uninstall Plugin',\n message: 'Are you sure you want to uninstall this plugin? This action cannot be undone.',\n confirmText: 'Uninstall',\n cancelText: 'Cancel',\n iconColor: 'red',\n confirmClass: 'bg-red-500 hover:bg-red-400',\n onConfirm: 'performUninstallPlugin()'\n })}\n\n ${getConfirmationDialogScript()}\n `\n\n const layoutData: AdminLayoutCatalystData = {\n title: 'Plugins',\n pageTitle: 'Plugin Management',\n currentPath: '/admin/plugins',\n user: data.user,\n version: data.version,\n content: pageContent\n }\n\n return renderAdminLayoutCatalyst(layoutData)\n}\n\nfunction renderPluginCard(plugin: Plugin): string {\n const statusColors = {\n active: 'bg-emerald-50 dark:bg-emerald-500/10 text-emerald-700 dark:text-emerald-400 ring-emerald-600/20',\n inactive: 'bg-zinc-50 dark:bg-zinc-500/10 text-zinc-700 dark:text-zinc-400 ring-zinc-600/20',\n error: 'bg-red-50 dark:bg-red-500/10 text-red-700 dark:text-red-400 ring-red-600/20',\n uninstalled: 'bg-zinc-50 dark:bg-zinc-500/10 text-zinc-600 dark:text-zinc-500 ring-zinc-600/20'\n }\n\n const statusIcons = {\n active: '
',\n inactive: '
',\n error: '
',\n uninstalled: '
'\n }\n\n // Core system plugins that cannot be deactivated\n const criticalCorePlugins = ['core-auth', 'core-media']\n const canToggle = !criticalCorePlugins.includes(plugin.id)\n\n let actionButton = ''\n if (plugin.status === 'uninstalled') {\n actionButton = `Install `\n } else {\n const isActive = plugin.status === 'active';\n const action = isActive ? 'deactivate' : 'activate';\n // Use bg-emerald-600 for active, bg-zinc-200 (light) / bg-zinc-700 (dark) for inactive\n const bgClass = isActive ? 'bg-emerald-600' : 'bg-zinc-200 dark:bg-zinc-700';\n const translateClass = isActive ? 'translate-x-5' : 'translate-x-0';\n \n if (canToggle) {\n actionButton = `\n \n Toggle plugin \n \n \n `\n } else {\n // Critical core plugins cannot be toggled\n actionButton = `\n \n \n
\n `\n }\n }\n\n return `\n \n
\n
\n
\n ${plugin.icon || getDefaultPluginIcon(plugin.category)}\n
\n
\n
\n
${plugin.displayName} \n \n ${statusIcons[plugin.status]}${plugin.status.charAt(0).toUpperCase() + plugin.status.slice(1)}\n \n \n
v${plugin.version} ⢠${plugin.author}
\n
\n
\n \n
\n ${!plugin.isCore && plugin.status !== 'uninstalled' ? `\n
\n \n \n \n \n ` : ''}\n
\n
\n\n
${plugin.description}
\n\n
\n \n ${plugin.category}\n \n ${plugin.isCore ? 'Core ' : ''}\n \n ${plugin.dependencies && plugin.dependencies.map(dep => `\n \n ${dep}\n \n `).join('') || ''}\n
\n\n
\n
\n ${actionButton}\n
\n
\n
\n `\n}\n\nfunction getDefaultPluginIcon(category: string): string {\n const iconColor = 'text-zinc-600 dark:text-zinc-400'\n\n const icons: Record = {\n 'content': `\n \n \n \n `,\n 'media': `\n \n \n \n `,\n 'seo': `\n \n \n \n `,\n 'analytics': `\n \n \n \n `,\n 'ecommerce': `\n \n \n \n `,\n 'email': `\n \n \n \n `,\n 'workflow': `\n \n \n \n `,\n 'security': `\n \n \n \n `,\n 'social': `\n \n \n \n `,\n 'utility': `\n \n \n \n \n `,\n }\n\n const iconKey = category.toLowerCase() as keyof typeof icons\n return icons[iconKey] || icons['utility'] || ''\n}\n\n// Mock data generator\nexport function generateMockPlugins(): Plugin[] {\n return [\n {\n id: '1',\n name: 'seo-optimizer',\n displayName: 'SEO Optimizer',\n description: 'Advanced SEO optimization tools including meta tag management, sitemap generation, and analytics integration. Boost your search engine rankings with automated optimizations.',\n version: '2.1.4',\n author: 'SonicJS Team',\n status: 'active',\n category: 'seo',\n icon: ` `,\n downloadCount: 15420,\n rating: 4.8,\n lastUpdated: '2 days ago',\n dependencies: ['analytics-plugin'],\n permissions: ['read:content', 'write:meta'],\n isCore: true\n },\n {\n id: '2',\n name: 'image-optimizer',\n displayName: 'Image Optimizer',\n description: 'Automatically compress and optimize images on upload. Supports WebP conversion, lazy loading, and responsive image generation for better performance.',\n version: '1.5.2',\n author: 'MediaPro',\n status: 'active',\n category: 'media',\n icon: ` `,\n downloadCount: 8930,\n rating: 4.6,\n lastUpdated: '1 week ago',\n dependencies: [],\n permissions: ['write:media', 'read:settings']\n },\n {\n id: '3',\n name: 'backup-manager',\n displayName: 'Backup Manager',\n description: 'Automated backup solution for content and media files. Schedule regular backups to cloud storage with encryption and restore capabilities.',\n version: '3.0.1',\n author: 'BackupCorp',\n status: 'inactive',\n category: 'utilities',\n icon: ` `,\n downloadCount: 12450,\n rating: 4.9,\n lastUpdated: '3 days ago',\n dependencies: ['cloud-storage'],\n permissions: ['read:all', 'write:backups']\n },\n {\n id: '4',\n name: 'security-scanner',\n displayName: 'Security Scanner',\n description: 'Real-time security monitoring and vulnerability scanning. Detects malware, suspicious activities, and provides security recommendations.',\n version: '1.2.8',\n author: 'SecureWeb',\n status: 'error',\n category: 'security',\n icon: ` `,\n downloadCount: 5680,\n rating: 4.3,\n lastUpdated: '5 days ago',\n dependencies: ['security-core'],\n permissions: ['read:logs', 'read:files', 'write:security']\n },\n {\n id: '5',\n name: 'social-share',\n displayName: 'Social Share',\n description: 'Easy social media sharing buttons and Open Graph meta tag generation. Supports all major social platforms with customizable styling.',\n version: '2.3.0',\n author: 'SocialPlus',\n status: 'active',\n category: 'content',\n icon: ` `,\n downloadCount: 22100,\n rating: 4.7,\n lastUpdated: '4 days ago',\n dependencies: [],\n permissions: ['read:content', 'write:meta']\n },\n {\n id: '6',\n name: 'analytics-pro',\n displayName: 'Analytics Pro',\n description: 'Advanced analytics dashboard with custom tracking events, conversion funnels, and detailed visitor insights. GDPR compliant with privacy controls.',\n version: '4.1.2',\n author: 'AnalyticsPro Inc',\n status: 'active',\n category: 'seo',\n icon: ` `,\n downloadCount: 18750,\n rating: 4.9,\n lastUpdated: '1 day ago',\n dependencies: ['gdpr-compliance'],\n permissions: ['read:analytics', 'write:tracking', 'read:users']\n },\n {\n id: '7',\n name: 'form-builder',\n displayName: 'Advanced Form Builder',\n description: 'Drag-and-drop form builder with conditional logic, file uploads, payment integration, and email notifications. Perfect for contact forms and surveys.',\n version: '1.8.5',\n author: 'FormWorks',\n status: 'inactive',\n category: 'content',\n icon: ` `,\n downloadCount: 9870,\n rating: 4.4,\n lastUpdated: '1 week ago',\n dependencies: ['email-service'],\n permissions: ['write:forms', 'read:submissions', 'send:emails']\n },\n {\n id: '8',\n name: 'cache-optimizer',\n displayName: 'Cache Optimizer',\n description: 'Intelligent caching system with Redis support, CDN integration, and automatic cache invalidation. Dramatically improves site performance.',\n version: '2.7.3',\n author: 'SpeedBoost',\n status: 'active',\n category: 'utilities',\n icon: ` `,\n downloadCount: 13240,\n rating: 4.8,\n lastUpdated: '6 days ago',\n dependencies: ['redis-connector'],\n permissions: ['read:cache', 'write:cache', 'manage:cdn'],\n isCore: true\n },\n {\n id: '9',\n name: 'multilingual',\n displayName: 'Multilingual Support',\n description: 'Complete internationalization solution with automatic translation, language detection, and localized content management for global websites.',\n version: '3.2.1',\n author: 'GlobalWeb',\n status: 'active',\n category: 'content',\n icon: ` `,\n downloadCount: 7650,\n rating: 4.5,\n lastUpdated: '2 weeks ago',\n dependencies: ['translation-api'],\n permissions: ['read:content', 'write:translations', 'manage:languages']\n }\n ]\n}\n","import type { AuthSettings } from '../../services/auth-validation'\n\nexport function renderAuthSettingsForm(settings: AuthSettings): string {\n const fields = settings.requiredFields\n const validation = settings.validation\n const registration = settings.registration\n\n return `\n \n \n
\n
Registration Fields \n
Configure which fields are required during user registration and their minimum lengths.
\n\n
\n ${Object.entries(fields).map(([fieldName, config]: [string, any]) => `\n
\n
\n
\n
${config.label} \n
Field type: ${config.type}
\n
\n
\n \n
\n Required \n \n
\n\n
\n
\n `).join('')}\n
\n
\n\n \n
\n
Password Requirements \n
Additional password complexity requirements.
\n\n
\n
\n
\n
Require Uppercase Letter \n
Password must contain at least one uppercase letter (A-Z)
\n
\n
\n \n
\n \n
\n\n
\n
\n
Require Lowercase Letter \n
Password must contain at least one lowercase letter (a-z)
\n
\n
\n \n
\n \n
\n\n
\n
\n
Require Numbers \n
Password must contain at least one number (0-9)
\n
\n
\n \n
\n \n
\n\n
\n
\n
Require Special Characters \n
Password must contain at least one special character (!@#$%^&*)
\n
\n
\n \n
\n \n
\n
\n
\n\n \n
\n
Registration Settings \n
General registration behavior.
\n\n
\n
\n
\n
Allow User Registration \n
Enable or disable public user registration
\n
\n
\n \n
\n \n
\n\n
\n
\n
Require Email Verification \n
Users must verify their email before accessing the system
\n
\n
\n \n
\n \n
\n\n
\n
Default User Role \n
\n Viewer \n Editor \n Admin \n \n
Role assigned to new users upon registration
\n
\n
\n
\n\n \n
\n
Validation Settings \n
Additional validation rules.
\n\n
\n
\n
\n
Enforce Email Format \n
Validate that email addresses are in correct format
\n
\n
\n \n
\n \n
\n\n
\n
\n
Prevent Duplicate Usernames \n
Ensure usernames are unique across all users
\n
\n
\n \n
\n \n
\n
\n
\n
\n `\n}\n","import { renderAdminLayout, AdminLayoutData } from '../layouts/admin-layout-v2.template'\nimport { renderAuthSettingsForm } from '../components/auth-settings-form.template'\nimport type { AuthSettings } from '../../services/auth-validation'\n\n/**\n * Escape HTML attribute values to prevent XSS\n */\nfunction escapeHtmlAttr(value: string): string {\n return value\n .replace(/&/g, '&')\n .replace(/\"/g, '"')\n .replace(/'/g, ''')\n .replace(//g, '>')\n}\n\nexport interface PluginSettings {\n [key: string]: any\n}\n\nexport interface PluginActivity {\n id: string\n action: string\n message: string\n timestamp: number\n user?: string\n}\n\nexport interface PluginSettingsPageData {\n plugin: {\n id: string\n name: string\n displayName: string\n description: string\n version: string\n author: string\n status: 'active' | 'inactive' | 'error'\n category: string\n icon: string\n downloadCount?: number\n rating?: number\n lastUpdated: string\n dependencies?: string[]\n permissions?: string[]\n isCore?: boolean\n settings?: PluginSettings\n }\n activity?: PluginActivity[]\n user?: {\n name: string\n email: string\n role: string\n }\n}\n\nexport function renderPluginSettingsPage(data: PluginSettingsPageData): string {\n const { plugin, activity = [], user } = data\n \n const pageContent = `\n \n \n
\n
\n
Plugin Settings \n
\n ${plugin.description}\n
\n
\n
\n
\n\n \n
\n
\n
\n
\n ${plugin.icon || plugin.displayName.charAt(0).toUpperCase()}\n
\n
\n
${plugin.displayName} \n
\n v${plugin.version} \n by ${plugin.author} \n ${plugin.category} \n ${plugin.downloadCount ? `${plugin.downloadCount.toLocaleString()} downloads ` : ''}\n ${plugin.rating ? `ā
${plugin.rating} ` : ''}\n
\n
\n
\n\n
\n ${renderStatusBadge(plugin.status)}\n ${renderToggleButton(plugin)}\n
\n
\n
\n\n \n
\n \n \n Settings\n \n \n Activity Log\n \n \n Information\n \n \n
\n\n \n
\n \n
\n ${renderSettingsTab(plugin)}\n
\n\n \n
\n ${renderActivityTab(activity)}\n
\n\n \n
\n ${renderInformationTab(plugin)}\n
\n
\n
\n\n \n `\n\n const layoutData: AdminLayoutData = {\n title: `${plugin.displayName} Settings`,\n pageTitle: `${plugin.displayName} Settings`,\n currentPath: `/admin/plugins/${plugin.id}`,\n user,\n content: pageContent\n }\n\n return renderAdminLayout(layoutData)\n}\n\nfunction renderStatusBadge(status: string): string {\n const statusColors: Record = {\n active: 'bg-green-900/50 text-green-300 border-green-600/30',\n inactive: 'bg-gray-800/50 text-gray-400 border-gray-600/30',\n error: 'bg-red-900/50 text-red-300 border-red-600/30'\n }\n\n const statusIcons: Record = {\n active: '
',\n inactive: '
',\n error: '
'\n }\n\n return `\n \n ${statusIcons[status] || statusIcons.inactive}${status.charAt(0).toUpperCase() + status.slice(1)}\n \n `\n}\n\nfunction renderToggleButton(plugin: any): string {\n if (plugin.isCore) {\n return 'Core Plugin '\n }\n\n return plugin.status === 'active' \n ? `Deactivate `\n : `Activate `\n}\n\nfunction renderSettingsTab(plugin: any): string {\n const settings = plugin.settings || {}\n const pluginId = plugin.id || plugin.name\n\n // Check for custom settings component first\n const customRenderer = pluginSettingsComponents[pluginId]\n if (customRenderer) {\n return `\n \n ${customRenderer(plugin, settings)}\n\n
\n \n Save Settings\n \n
\n
\n `\n }\n\n const isSeedDataPlugin = plugin.id === 'seed-data' || plugin.name === 'seed-data'\n const isAuthPlugin = plugin.id === 'core-auth' || plugin.name === 'core-auth'\n const isTurnstilePlugin = plugin.id === 'turnstile' || plugin.name === 'turnstile'\n\n return `\n ${isSeedDataPlugin ? `\n \n \n ` : ''}\n\n \n ${isAuthPlugin ? `\n
Authentication Settings \n
Configure user registration fields and validation rules.
\n ` : isTurnstilePlugin ? `\n
Cloudflare Turnstile Settings \n
Configure CAPTCHA-free bot protection for your forms.
\n ` : `\n
Plugin Settings \n `}\n\n
\n ${isAuthPlugin && Object.keys(settings).length > 0\n ? renderAuthSettingsForm(settings as AuthSettings)\n : isTurnstilePlugin && Object.keys(settings).length > 0\n ? renderTurnstileSettingsForm(settings)\n : Object.keys(settings).length > 0\n ? renderSettingsFields(settings)\n : renderNoSettings(plugin)\n }\n\n ${Object.keys(settings).length > 0 ? `\n \n \n Save Settings\n \n
\n ` : ''}\n \n
\n `\n}\n\nfunction renderSettingsFields(settings: PluginSettings): string {\n return Object.entries(settings).map(([key, value]) => {\n const fieldId = `setting_${key}`\n const displayName = key.replace(/([A-Z])/g, ' $1').replace(/^./, str => str.toUpperCase())\n \n if (typeof value === 'boolean') {\n return `\n \n
\n
${displayName} \n
Enable or disable this feature
\n
\n
\n \n
\n \n
\n `\n } else if (typeof value === 'number') {\n return `\n \n ${displayName} \n \n
\n `\n } else {\n return `\n \n ${displayName} \n \n
\n `\n }\n }).join('')\n}\n\nfunction renderTurnstileSettingsForm(settings: any): string {\n const inputClass = \"backdrop-blur-sm bg-white/10 border border-white/20 rounded-lg px-3 py-2 text-white placeholder-gray-300 focus:border-blue-400 focus:outline-none transition-colors w-full\"\n const selectClass = \"backdrop-blur-sm bg-zinc-800 border border-white/20 rounded-lg px-3 py-2 text-white focus:border-blue-400 focus:outline-none transition-colors w-full [&>option]:bg-zinc-800 [&>option]:text-white\"\n \n return `\n \n \n
\n
Enable Turnstile \n
Enable or disable Turnstile verification globally
\n
\n
\n \n
\n \n
\n\n \n \n
Site Key \n
\n
Your Cloudflare Turnstile site key (public)
\n
\n\n \n \n
Secret Key \n
\n
Your Cloudflare Turnstile secret key (private)
\n
\n\n \n \n
Widget Theme \n
\n Auto (matches page theme) \n Light \n Dark \n \n
Visual appearance of the Turnstile widget
\n
\n\n \n \n
Widget Size \n
\n Normal (300x65px) \n Compact (130x120px) \n \n
Size of the Turnstile challenge widget
\n
\n\n \n \n
Widget Mode \n
\n Managed (Recommended) - Adaptive challenge \n Non-Interactive - Always visible, minimal friction \n Invisible - No visible widget \n \n
Managed: Shows challenge only when needed. Non-Interactive: Always shows but doesn't require interaction. Invisible: Runs in background without UI.
\n
\n\n \n \n
Pre-clearance / Appearance \n
\n Always - Pre-clearance enabled (verifies immediately) \n Execute - Challenge on form submit \n Interaction Only - Only after user interaction \n \n
Controls when Turnstile verification occurs. Always: Verifies immediately (pre-clearance). Execute: Verifies on form submit. Interaction Only: Only after user interaction.
\n
\n `\n}\n\nfunction renderNoSettings(plugin: any): string {\n // Special handling for seed-data plugin\n if (plugin.id === 'seed-data' || plugin.name === 'seed-data') {\n return `\n \n
\n \n \n
Seed Data Generator \n
Generate realistic example data for testing and development.
\n
\n \n \n \n Generate Seed Data\n \n
\n `\n }\n\n return `\n \n
\n \n \n \n
No Settings Available \n
This plugin doesn't have any configurable settings.
\n
\n `\n}\n\nfunction renderActivityTab(activity: PluginActivity[]): string {\n return `\n \n
Activity Log \n \n ${activity.length > 0 ? `\n
\n ${activity.map(item => `\n
\n
\n
\n
\n ${item.action} \n ${formatTimestamp(item.timestamp)} \n
\n
${item.message}
\n ${item.user ? `
by ${item.user}
` : ''}\n
\n
\n `).join('')}\n
\n ` : `\n
\n
\n \n \n
No Activity \n
No recent activity for this plugin.
\n
\n `}\n
\n `\n}\n\nfunction renderInformationTab(plugin: any): string {\n return `\n \n \n
\n
Plugin Details \n
\n
\n Name: \n ${plugin.displayName} \n
\n
\n Version: \n ${plugin.version} \n
\n
\n Author: \n ${plugin.author} \n
\n
\n Category: \n ${plugin.category} \n
\n
\n Status: \n ${plugin.status} \n
\n
\n Last Updated: \n ${plugin.lastUpdated} \n
\n
\n
\n\n \n
\n
Dependencies & Permissions \n \n ${plugin.dependencies && plugin.dependencies.length > 0 ? `\n
\n
Dependencies: \n
\n ${plugin.dependencies.map((dep: string) => `\n
${dep}
\n `).join('')}\n
\n
\n ` : ''}\n\n ${plugin.permissions && plugin.permissions.length > 0 ? `\n
\n
Permissions: \n
\n ${plugin.permissions.map((perm: string) => `\n
${perm}
\n `).join('')}\n
\n
\n ` : ''}\n\n ${(!plugin.dependencies || plugin.dependencies.length === 0) && (!plugin.permissions || plugin.permissions.length === 0) ? `\n
No dependencies or special permissions required.
\n ` : ''}\n
\n
\n `\n}\n\nfunction formatTimestamp(timestamp: number): string {\n const date = new Date(timestamp * 1000)\n return date.toLocaleString()\n}\n\n// ==================== Plugin Settings Components ====================\n// These render just the settings content, embedded within the shared layout\n\n/**\n * Registry of custom plugin settings components\n * Plugins with custom settings UI register their render functions here\n */\ntype PluginSettingsRenderer = (plugin: any, settings: PluginSettings) => string\n\nconst pluginSettingsComponents: Record = {\n 'otp-login': renderOTPLoginSettingsContent,\n 'email': renderEmailSettingsContent,\n}\n\n/**\n * OTP Login plugin settings content\n */\nfunction renderOTPLoginSettingsContent(plugin: any, settings: PluginSettings): string {\n const siteName = settings.siteName || 'SonicJS'\n const emailConfigured = settings._emailConfigured || false\n const codeLength = settings.codeLength || 6\n const codeExpiryMinutes = settings.codeExpiryMinutes || 10\n const maxAttempts = settings.maxAttempts || 3\n const rateLimitPerHour = settings.rateLimitPerHour || 5\n const allowNewUserRegistration = settings.allowNewUserRegistration || false\n\n return `\n \n \n
\n
\n š§ Test OTP Email\n \n\n ${!emailConfigured ? `\n
\n
\n ā ļø Email not configured. \n Configure the Email plugin \n to send real emails. Dev mode will show codes in the response.\n
\n
\n ` : `\n
\n
\n ā
Email configured. Test emails will be sent via Resend.\n
\n
\n `}\n\n
\n \n \n Email Address\n \n \n
\n\n \n Send Test Code \n \n \n \n \n \n \n \n \n\n
\n\n \n
\n
Verify Code \n
\n \n \n Enter the code you received\n \n \n
\n \n Verify Code\n \n \n
\n
\n
\n\n \n
\n
Code Settings \n\n
\n \n
\n
\n Code Length\n \n
\n
Number of digits (4-8)
\n
\n\n
\n
\n Code Expiry (minutes)\n \n
\n
How long codes remain valid
\n
\n\n
\n
\n Maximum Attempts\n \n
\n
Max verification attempts
\n
\n\n
\n
\n Rate Limit (per hour)\n \n
\n
Max requests per email per hour
\n
\n
\n\n \n \n \n Allow new user registration via OTP\n \n
\n \n
\n\n \n
\n
\n šļø Email Preview\n \n
\n This is how the OTP email will appear to users. The site name \"${siteName} \" is configured in\n General Settings .\n
\n\n
\n
\n
Your Login Code \n
Enter this code to sign in to ${siteName}
\n
\n\n
\n
\n\n
\n
\n ā ļø This code expires in ${codeExpiryMinutes} minutes \n
\n
\n\n
\n
\n š Security Notice\n
\n
\n Never share this code with anyone. ${siteName} will never ask you for this code via phone, email, or social media.\n
\n
\n
\n
\n
\n\n \n
\n
š¢ Features \n
\n ā Passwordless authentication \n ā Secure random code generation \n ā Rate limiting protection \n ā Brute force prevention \n ā Mobile-friendly UX \n \n
\n\n \n
\n
\n\n \n `\n}\n\n/**\n * Email plugin settings content\n */\nfunction renderEmailSettingsContent(plugin: any, settings: PluginSettings): string {\n const apiKey = settings.apiKey || ''\n const fromEmail = settings.fromEmail || ''\n const fromName = settings.fromName || ''\n const replyTo = settings.replyTo || ''\n const logoUrl = settings.logoUrl || ''\n\n return `\n \n \n
\n
Resend Configuration \n\n
\n \n \n\n \n \n
\n From Email * \n \n
\n
Must be a verified domain in Resend
\n
\n\n \n \n \n From Name * \n \n \n
\n\n \n \n \n Reply-To Email\n \n \n
\n\n \n \n
\n Logo URL\n \n
\n
Logo to display in email templates
\n
\n \n
\n\n \n
\n
Send Test Email \n
\n \n \n Send Test\n \n
\n
\n
\n\n \n
\n
š§ Email Templates Included \n
\n ā Registration confirmation \n ā Email verification \n ā Password reset \n ā One-time code (2FA) \n \n
\n Templates are code-based and can be customized by editing the plugin files.\n
\n
\n
\n\n \n `\n}\n\n/**\n * Check if a plugin has a custom settings component\n */\nexport function hasCustomSettingsComponent(pluginId: string): boolean {\n return pluginId in pluginSettingsComponents\n}\n\n/**\n * Get the custom settings component for a plugin\n */\nexport function getCustomSettingsComponent(pluginId: string): PluginSettingsRenderer | undefined {\n return pluginSettingsComponents[pluginId]\n}","import { Hono } from 'hono'\nimport { requireAuth } from '../middleware'\nimport { renderPluginsListPage, PluginsListPageData, Plugin } from '../templates/pages/admin-plugins-list.template'\nimport { renderPluginSettingsPage, PluginSettingsPageData } from '../templates/pages/admin-plugin-settings.template'\nimport { PluginService } from '../services'\n// TODO: authValidationService not yet migrated - commented out temporarily\n// import { authValidationService } from '../services/auth-validation'\nimport type { Bindings, Variables } from '../app'\n\nconst adminPluginRoutes = new Hono<{ Bindings: Bindings; Variables: Variables }>()\n\n// Apply authentication middleware\nadminPluginRoutes.use('*', requireAuth())\n\n// Available plugins registry - plugins that can be installed\nconst AVAILABLE_PLUGINS = [\n {\n id: 'third-party-faq',\n name: 'faq-plugin',\n display_name: 'FAQ System',\n description: 'Frequently Asked Questions management system with categories, search, and custom styling',\n version: '2.0.0',\n author: 'Community Developer',\n category: 'content',\n icon: 'ā',\n permissions: ['manage:faqs'],\n dependencies: [],\n is_core: false\n },\n {\n id: 'demo-login-prefill',\n name: 'demo-login-plugin',\n display_name: 'Demo Login Prefill',\n description: 'Prefills login form with demo credentials (admin@sonicjs.com/sonicjs!) for easy site demonstration',\n version: '1.0.0-beta.1',\n author: 'SonicJS',\n category: 'demo',\n icon: 'šÆ',\n permissions: [],\n dependencies: [],\n is_core: false\n },\n {\n id: 'database-tools',\n name: 'database-tools',\n display_name: 'Database Tools',\n description: 'Database management tools including truncate, backup, and validation',\n version: '1.0.0-beta.1',\n author: 'SonicJS Team',\n category: 'system',\n icon: 'šļø',\n permissions: ['manage:database', 'admin'],\n dependencies: [],\n is_core: false\n },\n {\n id: 'seed-data',\n name: 'seed-data',\n display_name: 'Seed Data',\n description: 'Generate realistic example users and content for testing and development',\n version: '1.0.0-beta.1',\n author: 'SonicJS Team',\n category: 'development',\n icon: 'š±',\n permissions: ['admin'],\n dependencies: [],\n is_core: false\n },\n {\n id: 'quill-editor',\n name: 'quill-editor',\n display_name: 'Quill Rich Text Editor',\n description: 'Quill WYSIWYG editor integration for rich text editing. Lightweight, modern editor with customizable toolbars and dark mode support.',\n version: '1.0.0',\n author: 'SonicJS Team',\n category: 'editor',\n icon: 'āļø',\n permissions: [],\n dependencies: [],\n is_core: true\n },\n {\n id: 'tinymce-plugin',\n name: 'tinymce-plugin',\n display_name: 'TinyMCE Rich Text Editor',\n description: 'Powerful WYSIWYG rich text editor for content creation. Provides a full-featured editor with formatting, media embedding, and customizable toolbars for richtext fields.',\n version: '1.0.0',\n author: 'SonicJS Team',\n category: 'editor',\n icon: 'š',\n permissions: [],\n dependencies: [],\n is_core: false\n },\n {\n id: 'easy-mdx',\n name: 'easy-mdx',\n display_name: 'EasyMDE Markdown Editor',\n description: 'Lightweight markdown editor with live preview. Provides a simple and efficient editor with markdown support for richtext fields.',\n version: '1.0.0',\n author: 'SonicJS Team',\n category: 'editor',\n icon: 'š',\n permissions: [],\n dependencies: [],\n is_core: false\n },\n {\n id: 'turnstile',\n name: 'turnstile-plugin',\n display_name: 'Cloudflare Turnstile',\n description: 'CAPTCHA-free bot protection for forms using Cloudflare Turnstile. Provides seamless spam prevention with configurable modes, themes, and pre-clearance options.',\n version: '1.0.0',\n author: 'SonicJS Team',\n category: 'security',\n icon: 'š”ļø',\n permissions: [],\n dependencies: [],\n is_core: true\n },\n {\n id: 'ai-search',\n name: 'ai-search-plugin',\n display_name: 'AI Search',\n description: 'Advanced search with Cloudflare AI Search. Full-text search, semantic search, and advanced filtering across all content collections.',\n version: '1.0.0',\n author: 'SonicJS Team',\n category: 'search',\n icon: 'š',\n permissions: [],\n dependencies: [],\n is_core: true\n }\n]\n\n// Plugin list page\nadminPluginRoutes.get('/', async (c) => {\n try {\n const user = c.get('user')\n const db = c.env.DB\n \n // Temporarily skip permission check for admin users\n // TODO: Fix permission system\n if (user?.role !== 'admin') {\n return c.text('Access denied', 403)\n }\n \n const pluginService = new PluginService(db)\n\n // Get all installed plugins with error handling\n let installedPlugins: any[] = []\n let stats = { total: 0, active: 0, inactive: 0, errors: 0, uninstalled: 0 }\n\n try {\n installedPlugins = await pluginService.getAllPlugins()\n stats = await pluginService.getPluginStats()\n } catch (error) {\n console.error('Error loading plugins:', error)\n // Continue with empty data\n }\n\n // Get list of installed plugin IDs\n const installedPluginIds = new Set(installedPlugins.map(p => p.id))\n\n // Find uninstalled plugins\n const uninstalledPlugins = AVAILABLE_PLUGINS.filter(p => !installedPluginIds.has(p.id))\n\n // Map installed plugins to template format\n const templatePlugins: Plugin[] = installedPlugins.map(p => ({\n id: p.id,\n name: p.name,\n displayName: p.display_name,\n description: p.description,\n version: p.version,\n author: p.author,\n status: p.status,\n category: p.category,\n icon: p.icon,\n downloadCount: p.download_count,\n rating: p.rating,\n lastUpdated: formatLastUpdated(p.last_updated),\n dependencies: p.dependencies,\n permissions: p.permissions,\n isCore: p.is_core\n }))\n\n // Add uninstalled plugins to the list\n const uninstalledTemplatePlugins: Plugin[] = uninstalledPlugins.map(p => ({\n id: p.id,\n name: p.name,\n displayName: p.display_name,\n description: p.description,\n version: p.version,\n author: p.author,\n status: 'uninstalled' as const,\n category: p.category,\n icon: p.icon,\n downloadCount: 0,\n rating: 0,\n lastUpdated: 'Not installed',\n dependencies: p.dependencies,\n permissions: p.permissions,\n isCore: p.is_core\n }))\n\n // Combine installed and uninstalled plugins\n const allPlugins = [...templatePlugins, ...uninstalledTemplatePlugins]\n\n // Update stats with uninstalled count\n stats.uninstalled = uninstalledPlugins.length\n stats.total = installedPlugins.length + uninstalledPlugins.length\n\n const pageData: PluginsListPageData = {\n plugins: allPlugins,\n stats,\n user: {\n name: user?.email || 'User',\n email: user?.email || '',\n role: user?.role || 'user'\n },\n version: c.get('appVersion')\n }\n\n return c.html(renderPluginsListPage(pageData))\n } catch (error) {\n console.error('Error loading plugins page:', error)\n return c.text('Internal server error', 500)\n }\n})\n\n// Get plugin settings page\nadminPluginRoutes.get('/:id', async (c) => {\n try {\n const user = c.get('user')\n const db = c.env.DB\n const pluginId = c.req.param('id')\n\n // Skip plugins that have their own custom settings pages (not using component system)\n const pluginsWithCustomPages = ['ai-search']\n if (pluginsWithCustomPages.includes(pluginId)) {\n // Let the plugin's own route handle this\n return c.text('', 404) // Return 404 so Hono continues to next route\n }\n\n // Check authorization\n if (user?.role !== 'admin') {\n return c.redirect('/admin/plugins')\n }\n\n const pluginService = new PluginService(db)\n const plugin = await pluginService.getPlugin(pluginId)\n\n if (!plugin) {\n return c.text('Plugin not found', 404)\n }\n\n // Get activity log\n const activity = await pluginService.getPluginActivity(pluginId, 20)\n\n // Load additional context for plugins with custom settings components\n let enrichedSettings = plugin.settings || {}\n\n // For OTP Login plugin, add site name and email config status\n if (pluginId === 'otp-login') {\n // Get site name from general settings\n const generalSettings = await db.prepare(`\n SELECT value FROM settings WHERE key = 'general'\n `).first() as { value: string } | null\n\n let siteName = 'SonicJS'\n if (generalSettings?.value) {\n try {\n const parsed = JSON.parse(generalSettings.value)\n siteName = parsed.siteName || 'SonicJS'\n } catch (e) { /* ignore */ }\n }\n\n // Check if email plugin is configured\n const emailPlugin = await db.prepare(`\n SELECT settings FROM plugins WHERE id = 'email'\n `).first() as { settings: string | null } | null\n\n let emailConfigured = false\n if (emailPlugin?.settings) {\n try {\n const emailSettings = JSON.parse(emailPlugin.settings)\n emailConfigured = !!(emailSettings.apiKey && emailSettings.fromEmail && emailSettings.fromName)\n } catch (e) { /* ignore */ }\n }\n\n enrichedSettings = {\n ...enrichedSettings,\n siteName,\n _emailConfigured: emailConfigured\n }\n }\n\n // Map plugin data to template format\n const templatePlugin = {\n id: plugin.id,\n name: plugin.name,\n displayName: plugin.display_name,\n description: plugin.description,\n version: plugin.version,\n author: plugin.author,\n status: plugin.status,\n category: plugin.category,\n icon: plugin.icon,\n downloadCount: plugin.download_count,\n rating: plugin.rating,\n lastUpdated: formatLastUpdated(plugin.last_updated),\n dependencies: plugin.dependencies,\n permissions: plugin.permissions,\n isCore: plugin.is_core,\n settings: enrichedSettings\n }\n \n // Map activity data\n const templateActivity = (activity || []).map(item => ({\n id: item.id,\n action: item.action,\n message: item.message,\n timestamp: item.timestamp,\n user: item.user_email\n }))\n \n const pageData: PluginSettingsPageData = {\n plugin: templatePlugin,\n activity: templateActivity,\n user: {\n name: user?.email || 'User',\n email: user?.email || '',\n role: user?.role || 'user'\n }\n }\n \n return c.html(renderPluginSettingsPage(pageData))\n } catch (error) {\n console.error('Error getting plugin settings page:', error)\n return c.text('Internal server error', 500)\n }\n})\n\n// Activate plugin\nadminPluginRoutes.post('/:id/activate', async (c) => {\n try {\n const user = c.get('user')\n const db = c.env.DB\n const pluginId = c.req.param('id')\n \n // Temporarily skip permission check for admin users\n if (user?.role !== 'admin') {\n return c.json({ error: 'Access denied' }, 403)\n }\n \n const pluginService = new PluginService(db)\n await pluginService.activatePlugin(pluginId)\n \n return c.json({ success: true })\n } catch (error) {\n console.error('Error activating plugin:', error)\n const message = error instanceof Error ? error.message : 'Failed to activate plugin'\n return c.json({ error: message }, 400)\n }\n})\n\n// Deactivate plugin\nadminPluginRoutes.post('/:id/deactivate', async (c) => {\n try {\n const user = c.get('user')\n const db = c.env.DB\n const pluginId = c.req.param('id')\n \n // Temporarily skip permission check for admin users\n if (user?.role !== 'admin') {\n return c.json({ error: 'Access denied' }, 403)\n }\n \n const pluginService = new PluginService(db)\n await pluginService.deactivatePlugin(pluginId)\n \n return c.json({ success: true })\n } catch (error) {\n console.error('Error deactivating plugin:', error)\n const message = error instanceof Error ? error.message : 'Failed to deactivate plugin'\n return c.json({ error: message }, 400)\n }\n})\n\n// Install plugin\nadminPluginRoutes.post('/install', async (c) => {\n try {\n const user = c.get('user')\n const db = c.env.DB\n \n // Temporarily skip permission check for admin users\n if (user?.role !== 'admin') {\n return c.json({ error: 'Access denied' }, 403)\n }\n \n const body = await c.req.json()\n \n const pluginService = new PluginService(db)\n \n // Handle FAQ plugin installation\n if (body.name === 'faq-plugin') {\n const faqPlugin = await pluginService.installPlugin({\n id: 'third-party-faq',\n name: 'faq-plugin',\n display_name: 'FAQ System',\n description: 'Frequently Asked Questions management system with categories, search, and custom styling',\n version: '2.0.0',\n author: 'Community Developer',\n category: 'content',\n icon: 'ā',\n permissions: ['manage:faqs'],\n dependencies: [],\n settings: {\n enableSearch: true,\n enableCategories: true,\n questionsPerPage: 10\n }\n })\n\n return c.json({ success: true, plugin: faqPlugin })\n }\n\n // Handle Demo Login plugin installation\n if (body.name === 'demo-login-plugin') {\n const demoPlugin = await pluginService.installPlugin({\n id: 'demo-login-prefill',\n name: 'demo-login-plugin',\n display_name: 'Demo Login Prefill',\n description: 'Prefills login form with demo credentials (admin@sonicjs.com/sonicjs!) for easy site demonstration',\n version: '1.0.0-beta.1',\n author: 'SonicJS',\n category: 'demo',\n icon: 'šÆ',\n permissions: [],\n dependencies: [],\n settings: {\n enableNotice: true,\n demoEmail: 'admin@sonicjs.com',\n demoPassword: 'sonicjs!'\n }\n })\n\n return c.json({ success: true, plugin: demoPlugin })\n }\n\n // Handle core Authentication System plugin installation\n if (body.name === 'core-auth') {\n const authPlugin = await pluginService.installPlugin({\n id: 'core-auth',\n name: 'core-auth',\n display_name: 'Authentication System',\n description: 'Core authentication and user management system',\n version: '1.0.0-beta.1',\n author: 'SonicJS Team',\n category: 'security',\n icon: 'š',\n permissions: ['manage:users', 'manage:roles', 'manage:permissions'],\n dependencies: [],\n is_core: true,\n settings: {}\n })\n\n return c.json({ success: true, plugin: authPlugin })\n }\n\n // Handle core Media Manager plugin installation\n if (body.name === 'core-media') {\n const mediaPlugin = await pluginService.installPlugin({\n id: 'core-media',\n name: 'core-media',\n display_name: 'Media Manager',\n description: 'Core media upload and management system',\n version: '1.0.0-beta.1',\n author: 'SonicJS Team',\n category: 'media',\n icon: 'šø',\n permissions: ['manage:media', 'upload:files'],\n dependencies: [],\n is_core: true,\n settings: {}\n })\n\n return c.json({ success: true, plugin: mediaPlugin })\n }\n\n // Handle core Workflow Engine plugin installation\n if (body.name === 'core-workflow') {\n const workflowPlugin = await pluginService.installPlugin({\n id: 'core-workflow',\n name: 'core-workflow',\n display_name: 'Workflow Engine',\n description: 'Content workflow and approval system',\n version: '1.0.0-beta.1',\n author: 'SonicJS Team',\n category: 'content',\n icon: 'š',\n permissions: ['manage:workflows', 'approve:content'],\n dependencies: [],\n is_core: true,\n settings: {}\n })\n\n return c.json({ success: true, plugin: workflowPlugin })\n }\n\n // Handle Database Tools plugin installation\n if (body.name === 'database-tools') {\n const databaseToolsPlugin = await pluginService.installPlugin({\n id: 'database-tools',\n name: 'database-tools',\n display_name: 'Database Tools',\n description: 'Database management tools including truncate, backup, and validation',\n version: '1.0.0-beta.1',\n author: 'SonicJS Team',\n category: 'system',\n icon: 'šļø',\n permissions: ['manage:database', 'admin'],\n dependencies: [],\n is_core: false,\n settings: {\n enableTruncate: true,\n enableBackup: true,\n enableValidation: true,\n requireConfirmation: true\n }\n })\n\n return c.json({ success: true, plugin: databaseToolsPlugin })\n }\n\n // Handle Seed Data plugin installation\n if (body.name === 'seed-data') {\n const seedDataPlugin = await pluginService.installPlugin({\n id: 'seed-data',\n name: 'seed-data',\n display_name: 'Seed Data',\n description: 'Generate realistic example users and content for testing and development',\n version: '1.0.0-beta.1',\n author: 'SonicJS Team',\n category: 'development',\n icon: 'š±',\n permissions: ['admin'],\n dependencies: [],\n is_core: false,\n settings: {\n userCount: 20,\n contentCount: 200,\n defaultPassword: 'password123'\n }\n })\n\n return c.json({ success: true, plugin: seedDataPlugin })\n }\n\n // Handle Quill Editor plugin installation\n if (body.name === 'quill-editor') {\n const quillPlugin = await pluginService.installPlugin({\n id: 'quill-editor',\n name: 'quill-editor',\n display_name: 'Quill Rich Text Editor',\n description: 'Quill WYSIWYG editor integration for rich text editing. Lightweight, modern editor with customizable toolbars and dark mode support.',\n version: '1.0.0',\n author: 'SonicJS Team',\n category: 'editor',\n icon: 'āļø',\n permissions: [],\n dependencies: [],\n is_core: true,\n settings: {\n version: '2.0.2',\n defaultHeight: 300,\n defaultToolbar: 'full',\n theme: 'snow'\n }\n })\n\n return c.json({ success: true, plugin: quillPlugin })\n }\n\n // Handle TinyMCE plugin installation\n if (body.name === 'tinymce-plugin') {\n const tinymcePlugin = await pluginService.installPlugin({\n id: 'tinymce-plugin',\n name: 'tinymce-plugin',\n display_name: 'TinyMCE Rich Text Editor',\n description: 'Powerful WYSIWYG rich text editor for content creation. Provides a full-featured editor with formatting, media embedding, and customizable toolbars for richtext fields.',\n version: '1.0.0',\n author: 'SonicJS Team',\n category: 'editor',\n icon: 'š',\n permissions: [],\n dependencies: [],\n is_core: false,\n settings: {\n apiKey: 'no-api-key',\n defaultHeight: 300,\n defaultToolbar: 'full',\n skin: 'oxide-dark'\n }\n })\n\n return c.json({ success: true, plugin: tinymcePlugin })\n }\n\n // Handle Easy MDX plugin installation\n if (body.name === 'easy-mdx') {\n const easyMdxPlugin = await pluginService.installPlugin({\n id: 'easy-mdx',\n name: 'easy-mdx',\n display_name: 'EasyMDE Markdown Editor',\n description: 'Lightweight markdown editor with live preview. Provides a simple and efficient editor with markdown support for richtext fields.',\n version: '1.0.0',\n author: 'SonicJS Team',\n category: 'editor',\n icon: 'š',\n permissions: [],\n dependencies: [],\n is_core: false,\n settings: {\n defaultHeight: 400,\n theme: 'dark',\n toolbar: 'full',\n placeholder: 'Start writing your content...'\n }\n })\n\n return c.json({ success: true, plugin: easyMdxPlugin })\n }\n\n // Handle AI Search plugin installation\n if (body.name === 'ai-search-plugin' || body.name === 'ai-search') {\n const defaultSettings = {\n enabled: true,\n ai_mode_enabled: true,\n selected_collections: [],\n dismissed_collections: [],\n autocomplete_enabled: true,\n cache_duration: 1,\n results_limit: 20,\n index_media: false,\n }\n\n const aiSearchPlugin = await pluginService.installPlugin({\n id: 'ai-search',\n name: 'ai-search-plugin',\n display_name: 'AI Search',\n description: 'Advanced search with Cloudflare AI Search. Full-text search, semantic search, and advanced filtering across all content collections.',\n version: '1.0.0',\n author: 'SonicJS Team',\n category: 'search',\n icon: 'š',\n permissions: [],\n dependencies: [],\n is_core: true,\n settings: defaultSettings\n })\n\n return c.json({ success: true, plugin: aiSearchPlugin })\n }\n\n // Handle Turnstile plugin installation\n if (body.name === 'turnstile-plugin') {\n const turnstilePlugin = await pluginService.installPlugin({\n id: 'turnstile',\n name: 'turnstile-plugin',\n display_name: 'Cloudflare Turnstile',\n description: 'CAPTCHA-free bot protection for forms using Cloudflare Turnstile. Provides seamless spam prevention with configurable modes, themes, and pre-clearance options.',\n version: '1.0.0',\n author: 'SonicJS Team',\n category: 'security',\n icon: 'š”ļø',\n permissions: [],\n dependencies: [],\n is_core: true,\n settings: {\n siteKey: '',\n secretKey: '',\n theme: 'auto',\n size: 'normal',\n mode: 'managed',\n appearance: 'always',\n preClearanceEnabled: false,\n preClearanceLevel: 'managed',\n enabled: false\n }\n })\n\n return c.json({ success: true, plugin: turnstilePlugin })\n }\n\n return c.json({ error: 'Plugin not found in registry' }, 404)\n } catch (error) {\n console.error('Error installing plugin:', error)\n const message = error instanceof Error ? error.message : 'Failed to install plugin'\n return c.json({ error: message }, 400)\n }\n})\n\n// Uninstall plugin\nadminPluginRoutes.post('/:id/uninstall', async (c) => {\n try {\n const user = c.get('user')\n const db = c.env.DB\n const pluginId = c.req.param('id')\n \n // Temporarily skip permission check for admin users\n if (user?.role !== 'admin') {\n return c.json({ error: 'Access denied' }, 403)\n }\n \n const pluginService = new PluginService(db)\n await pluginService.uninstallPlugin(pluginId)\n \n return c.json({ success: true })\n } catch (error) {\n console.error('Error uninstalling plugin:', error)\n const message = error instanceof Error ? error.message : 'Failed to uninstall plugin'\n return c.json({ error: message }, 400)\n }\n})\n\n// Update plugin settings\nadminPluginRoutes.post('/:id/settings', async (c) => {\n try {\n const user = c.get('user')\n const db = c.env.DB\n const pluginId = c.req.param('id')\n\n // Temporarily skip permission check for admin users\n if (user?.role !== 'admin') {\n return c.json({ error: 'Access denied' }, 403)\n }\n\n const settings = await c.req.json()\n\n const pluginService = new PluginService(db)\n await pluginService.updatePluginSettings(pluginId, settings)\n\n // TODO: Clear auth validation cache if updating core-auth plugin\n // Commented out until authValidationService is migrated\n // if (pluginId === 'core-auth') {\n // authValidationService.clearCache()\n // console.log('[AuthSettings] Cache cleared after updating authentication settings')\n // }\n\n return c.json({ success: true })\n } catch (error) {\n console.error('Error updating plugin settings:', error)\n const message = error instanceof Error ? error.message : 'Failed to update settings'\n return c.json({ error: message }, 400)\n }\n})\n\n// Helper function to format last updated time\nfunction formatLastUpdated(timestamp: number): string {\n const now = Date.now() / 1000\n const diff = now - timestamp\n\n if (diff < 60) return 'just now'\n if (diff < 3600) return `${Math.floor(diff / 60)} minutes ago`\n if (diff < 86400) return `${Math.floor(diff / 3600)} hours ago`\n if (diff < 604800) return `${Math.floor(diff / 86400)} days ago`\n if (diff < 2592000) return `${Math.floor(diff / 604800)} weeks ago`\n return `${Math.floor(diff / 2592000)} months ago`\n}\n\nexport { adminPluginRoutes }\n","import { renderAdminLayoutCatalyst, AdminLayoutCatalystData } from '../layouts/admin-layout-catalyst.template'\n\ninterface BaseUser {\n name: string\n email: string\n role: string\n}\n\nexport interface LogEntry {\n id: string\n level: string\n category: string\n message: string\n data?: any\n userId?: string\n sessionId?: string\n requestId?: string\n ipAddress?: string\n userAgent?: string\n method?: string\n url?: string\n statusCode?: number\n duration?: number\n stackTrace?: string\n tags: string[]\n source?: string\n createdAt: Date\n formattedDate: string\n formattedDuration?: string\n levelClass: string\n categoryClass: string\n}\n\nexport interface LogsListPageData {\n logs: LogEntry[]\n pagination: {\n currentPage: number\n totalPages: number\n totalItems: number\n itemsPerPage: number\n startItem: number\n endItem: number\n baseUrl: string\n }\n filters: {\n level: string\n category: string\n search: string\n startDate: string\n endDate: string\n source: string\n }\n user?: BaseUser\n}\n\nexport function renderLogsListPage(data: LogsListPageData) {\n const { logs, pagination, filters, user } = data\n\n const content = `\n \n
\n
\n
System Logs \n
\n Monitor and analyze system activity, errors, and performance metrics.\n
\n
\n
\n
\n\n \n
\n \n
\n\n
\n
\n
\n \n
\n\n
\n Level \n \n All Levels \n Debug \n Info \n Warning \n Error \n Fatal \n \n
\n\n
\n Category \n \n All Categories \n Authentication \n API \n Workflow \n Plugin \n Media \n System \n Security \n Error \n \n
\n\n
\n Source \n \n
\n\n
\n Start Date \n \n
\n\n
\n End Date \n \n
\n\n
\n
\n\n \n ${pagination.totalItems} ${pagination.totalItems === 1 ? 'entry' : 'entries'} \n
\n \n
\n
\n
\n\n \n
\n
\n
\n \n \n \n Level\n \n \n Category\n \n \n Message\n \n \n Source\n \n \n Time\n \n \n Actions \n \n \n \n \n ${logs.map(log => `\n \n \n \n ${log.level}\n \n \n \n \n ${log.category}\n \n \n \n \n
${log.message}
\n ${log.url ? `
${log.method} ${log.url}
` : ''}\n ${log.duration ? `
${log.formattedDuration}
` : ''}\n
\n \n \n ${log.source || '-'}\n \n \n ${log.formattedDate}\n \n \n \n View Details\n \n \n \n `).join('')}\n \n
\n
\n\n ${logs.length === 0 ? `\n
\n
\n \n \n
No log entries \n
No log entries found matching your criteria.
\n
\n ` : ''}\n
\n\n \n ${pagination.totalPages > 1 ? `\n
\n
\n ${pagination.currentPage > 1 ? `\n
\n Previous\n \n ` : `\n
\n Previous\n \n `}\n ${pagination.currentPage < pagination.totalPages ? `\n
\n Next\n \n ` : `\n
\n Next\n \n `}\n
\n
\n
\n
\n Showing ${pagination.startItem} to ${pagination.endItem} of{' '}\n ${pagination.totalItems} results\n
\n
\n
\n
\n ${pagination.currentPage > 1 ? `\n \n Previous \n \n \n \n \n ` : ''}\n\n ${Array.from({ length: Math.min(10, pagination.totalPages) }, (_, i) => {\n const page = Math.max(1, Math.min(pagination.totalPages - 9, pagination.currentPage - 5)) + i\n if (page > pagination.totalPages) return ''\n\n return `\n \n ${page}\n \n `\n }).join('')}\n\n ${pagination.currentPage < pagination.totalPages ? `\n \n Next \n \n \n \n \n ` : ''}\n \n
\n
\n
\n ` : ''}\n
\n `\n\n const layoutData: AdminLayoutCatalystData = {\n title: 'System Logs',\n pageTitle: 'System Logs',\n currentPath: '/admin/logs',\n user,\n content\n }\n\n return renderAdminLayoutCatalyst(layoutData)\n}","import { html } from 'hono/html'\nimport { adminLayoutV2 } from '../layouts/admin-layout-v2.template'\nimport { LogEntry } from './admin-logs-list.template'\n\ninterface BaseUser {\n name: string\n email: string\n role: string\n}\n\nexport interface LogDetailsPageData {\n log: LogEntry\n user?: BaseUser\n}\n\nexport function renderLogDetailsPage(data: LogDetailsPageData) {\n const { log, user } = data\n\n const content = html`\n \n
\n\n
\n
\n
\n
Log Entry Information \n
\n \n ${log.level}\n \n \n ${log.category}\n \n
\n
\n
\n \n
\n
\n \n
ID \n ${log.id} \n \n \n \n
Timestamp \n ${log.formattedDate} \n \n \n \n
Level \n \n \n ${log.level}\n \n \n \n \n \n
Category \n \n \n ${log.category}\n \n \n \n \n ${log.source ? html`\n \n
Source \n ${log.source} \n \n ` : ''}\n \n ${log.userId ? html`\n \n
User ID \n ${log.userId} \n \n ` : ''}\n \n ${log.sessionId ? html`\n \n
Session ID \n ${log.sessionId} \n \n ` : ''}\n \n ${log.requestId ? html`\n \n
Request ID \n ${log.requestId} \n \n ` : ''}\n \n ${log.ipAddress ? html`\n \n
IP Address \n ${log.ipAddress} \n \n ` : ''}\n \n ${log.method && log.url ? html`\n \n
HTTP Request \n \n ${log.method} ${log.url}\n ${log.statusCode ? html`(${log.statusCode}) ` : ''}\n \n \n ` : ''}\n \n ${log.duration ? html`\n \n
Duration \n ${log.formattedDuration} \n \n ` : ''}\n \n ${log.userAgent ? html`\n \n
User Agent \n ${log.userAgent} \n \n ` : ''}\n \n
\n
\n\n \n
\n
\n
Message \n \n
\n
\n ${log.message}\n
\n
\n
\n\n \n ${log.tags && log.tags.length > 0 ? html`\n
\n
\n
Tags \n \n
\n
\n ${log.tags.map(tag => html`\n \n ${tag}\n \n `).join('')}\n
\n
\n
\n ` : ''}\n\n \n ${log.data ? html`\n
\n
\n
Additional Data \n \n
\n
${JSON.stringify(log.data, null, 2)}\n
\n
\n ` : ''}\n\n \n ${log.stackTrace ? html`\n
\n
\n
Stack Trace \n \n
\n
\n ` : ''}\n\n \n
\n
\n ā Back to Logs\n \n \n
\n ${log.level === 'error' || log.level === 'fatal' ? html`\n \n Report Issue\n \n ` : ''}\n \n alert('Log details copied to clipboard'))\"\n >\n Copy Details\n \n
\n
\n
\n `\n\n return adminLayoutV2({\n title: `Log Details - ${log.id}`,\n user,\n content: content as string\n })\n}","import { html } from 'hono/html'\nimport { adminLayoutV2 } from '../layouts/admin-layout-v2.template'\nimport type { LogConfig } from '../../db/schema'\n\ninterface BaseUser {\n name: string\n email: string\n role: string\n}\n\nexport interface LogConfigPageData {\n configs: LogConfig[]\n user?: BaseUser\n}\n\nexport function renderLogConfigPage(data: LogConfigPageData) {\n const { configs, user } = data\n\n const content = html`\n \n
\n
\n
\n \n ā Back to Logs\n \n \n
Log Configuration \n
\n Configure logging settings for different categories and manage log retention policies.\n
\n
\n
\n \n Run Cleanup\n \n
\n
\n\n
\n\n \n
\n
\n
Log Levels Reference \n \n
\n
\n
\n
\n debug\n \n
Detailed diagnostic information
\n
\n
\n
\n info\n \n
General information messages
\n
\n
\n
\n warn\n \n
Warning conditions
\n
\n
\n
\n error\n \n
Error conditions
\n
\n
\n
\n fatal\n \n
Critical system errors
\n
\n
\n
\n
\n\n \n
\n ${configs.map(config => html`\n
\n
\n
\n
${config.category} \n
\n ${config.enabled ? html`\n \n Enabled\n \n ` : html`\n \n Disabled\n \n `}\n
\n
\n
\n \n
\n \n
\n
\n
\n \n Enable logging for this category\n \n
\n
\n \n
\n
\n Minimum Log Level\n \n
\n Debug \n Info \n Warning \n Error \n Fatal \n \n
Only logs at this level or higher will be stored
\n
\n \n
\n
\n Retention Period (days)\n \n
\n
Logs older than this will be deleted
\n
\n \n
\n
\n Maximum Log Count\n \n
\n
Maximum number of logs to keep for this category
\n
\n
\n \n \n
\n
\n Update Configuration\n \n
\n \n \n
\n
\n
Created: ${new Date(config.createdAt).toLocaleDateString()}
\n
Updated: ${new Date(config.updatedAt).toLocaleDateString()}
\n
\n
\n
\n `).join('')}\n
\n\n \n
\n
\n
Global Log Settings \n \n
\n
\n
\n
Storage Information \n
\n
\n
-
\n
Total Log Entries
\n
\n
\n
\n
\n
\n \n
\n
Log Categories \n
\n
\n auth - Authentication and authorization events \n api - API requests and responses \n workflow - Content workflow state changes \n plugin - Plugin-related activities \n media - File upload and media operations \n system - General system events \n security - Security-related events and alerts \n error - General error conditions \n \n
\n
\n
\n
\n
\n
\n\n \n `\n\n return adminLayoutV2({\n title: 'Log Configuration',\n user,\n content: content as string\n })\n}","import { Hono } from 'hono'\nimport { html } from 'hono/html'\nimport type { D1Database, KVNamespace } from '@cloudflare/workers-types'\nimport { requireAuth } from '../middleware'\nimport { getLogger, type LogLevel, type LogCategory, type LogFilter } from '../services'\nimport { renderLogsListPage, type LogsListPageData } from '../templates/pages/admin-logs-list.template'\nimport { renderLogDetailsPage, type LogDetailsPageData } from '../templates/pages/admin-log-details.template'\nimport { renderLogConfigPage, type LogConfigPageData } from '../templates/pages/admin-log-config.template'\nimport type { Bindings, Variables } from '../app'\n\nconst adminLogsRoutes = new Hono<{ Bindings: Bindings; Variables: Variables }>()\n\n// Apply authentication middleware\nadminLogsRoutes.use('*', requireAuth())\n\n// Main logs listing page\nadminLogsRoutes.get('/', async (c) => {\n try {\n const user = c.get('user')\n const logger = getLogger(c.env.DB)\n \n // Use Hono's built-in query method instead of parsing URL\n const query = c.req.query()\n \n // Parse query parameters\n const page = parseInt(query.page || '1')\n const limit = parseInt(query.limit || '50')\n const level = query.level\n const category = query.category\n const search = query.search\n const startDate = query.start_date\n const endDate = query.end_date\n const source = query.source\n \n // Build filter\n const filter: LogFilter = {\n limit,\n offset: (page - 1) * limit,\n sortBy: 'created_at',\n sortOrder: 'desc'\n }\n \n if (level) {\n filter.level = level.split(',') as LogLevel[]\n }\n \n if (category) {\n filter.category = category.split(',') as LogCategory[]\n }\n \n if (search) {\n filter.search = search\n }\n \n if (startDate) {\n filter.startDate = new Date(startDate)\n }\n \n if (endDate) {\n filter.endDate = new Date(endDate)\n }\n \n if (source) {\n filter.source = source\n }\n \n // Get logs and total count\n const { logs, total } = await logger.getLogs(filter)\n \n // Format logs for display\n const formattedLogs = logs.map(log => ({\n ...log,\n data: log.data ? JSON.parse(log.data) : null,\n tags: log.tags ? JSON.parse(log.tags) : [],\n formattedDate: new Date(log.createdAt).toLocaleString(),\n formattedDuration: log.duration ? `${log.duration}ms` : null,\n levelClass: getLevelClass(log.level),\n categoryClass: getCategoryClass(log.category)\n }))\n \n const totalPages = Math.ceil(total / limit)\n \n const pageData: LogsListPageData = {\n logs: formattedLogs,\n pagination: {\n currentPage: page,\n totalPages,\n totalItems: total,\n itemsPerPage: limit,\n startItem: (page - 1) * limit + 1,\n endItem: Math.min(page * limit, total),\n baseUrl: '/admin/logs'\n },\n filters: {\n level: level || '',\n category: category || '',\n search: search || '',\n startDate: startDate || '',\n endDate: endDate || '',\n source: source || ''\n },\n user: user ? {\n name: user.email,\n email: user.email,\n role: user.role\n } : undefined\n }\n \n return c.html(renderLogsListPage(pageData))\n } catch (error) {\n console.error('Error fetching logs:', error)\n return c.html(html`Error loading logs: ${error}
`)\n }\n})\n\n// Log details page\nadminLogsRoutes.get('/:id', async (c) => {\n try {\n const id = c.req.param('id')\n const user = c.get('user')\n const logger = getLogger(c.env.DB)\n \n // Get single log by ID\n const { logs } = await logger.getLogs({ \n limit: 1, \n offset: 0,\n search: id // Using search to find by ID - this is a simplification\n })\n \n const log = logs.find(l => l.id === id)\n \n if (!log) {\n return c.html(html`Log entry not found
`)\n }\n \n const formattedLog = {\n ...log,\n data: log.data ? JSON.parse(log.data) : null,\n tags: log.tags ? JSON.parse(log.tags) : [],\n formattedDate: new Date(log.createdAt).toLocaleString(),\n formattedDuration: log.duration ? `${log.duration}ms` : null,\n levelClass: getLevelClass(log.level),\n categoryClass: getCategoryClass(log.category)\n }\n \n const pageData: LogDetailsPageData = {\n log: formattedLog,\n user: user ? {\n name: user.email,\n email: user.email,\n role: user.role\n } : undefined\n }\n \n return c.html(renderLogDetailsPage(pageData))\n } catch (error) {\n console.error('Error fetching log details:', error)\n return c.html(html`Error loading log details: ${error}
`)\n }\n})\n\n// Log configuration page\nadminLogsRoutes.get('/config', async (c) => {\n try {\n const user = c.get('user')\n const logger = getLogger(c.env.DB)\n \n // Get all log configurations\n const configs = await logger.getAllConfigs()\n \n const pageData: LogConfigPageData = {\n configs,\n user: user ? {\n name: user.email,\n email: user.email,\n role: user.role\n } : undefined\n }\n \n return c.html(renderLogConfigPage(pageData))\n } catch (error) {\n console.error('Error fetching log config:', error)\n return c.html(html`Error loading log configuration: ${error}
`)\n }\n})\n\n// Update log configuration\nadminLogsRoutes.post('/config/:category', async (c) => {\n try {\n const category = c.req.param('category') as LogCategory\n const formData = await c.req.formData()\n \n const enabled = formData.get('enabled') === 'on'\n const level = formData.get('level') as string\n const retention = parseInt(formData.get('retention') as string)\n const maxSize = parseInt(formData.get('max_size') as string)\n \n const logger = getLogger(c.env.DB)\n await logger.updateConfig(category, {\n enabled,\n level,\n retention,\n maxSize\n })\n \n return c.html(html`\n \n Configuration updated successfully!\n
\n `)\n } catch (error) {\n console.error('Error updating log config:', error)\n return c.html(html`\n \n Failed to update configuration. Please try again.\n
\n `)\n }\n})\n\n// Export logs\nadminLogsRoutes.get('/export', async (c) => {\n try {\n const query = c.req.query()\n const format = query.format || 'csv'\n const level = query.level\n const category = query.category\n const startDate = query.start_date\n const endDate = query.end_date\n \n const logger = getLogger(c.env.DB)\n \n // Build filter for export\n const filter: LogFilter = {\n limit: 10000, // Export up to 10k logs\n offset: 0,\n sortBy: 'created_at',\n sortOrder: 'desc'\n }\n \n if (level) {\n filter.level = level.split(',') as LogLevel[]\n }\n \n if (category) {\n filter.category = category.split(',') as LogCategory[]\n }\n \n if (startDate) {\n filter.startDate = new Date(startDate)\n }\n \n if (endDate) {\n filter.endDate = new Date(endDate)\n }\n \n const { logs } = await logger.getLogs(filter)\n \n if (format === 'json') {\n return c.json(logs, 200, {\n 'Content-Disposition': 'attachment; filename=\"logs-export.json\"'\n })\n } else {\n // Default to CSV\n const headers = [\n 'ID', 'Level', 'Category', 'Message', 'Source', 'User ID', \n 'IP Address', 'Method', 'URL', 'Status Code', 'Duration', \n 'Created At'\n ]\n const csvRows = [headers.join(',')]\n \n logs.forEach(log => {\n const row = [\n log.id,\n log.level,\n log.category,\n `\"${log.message.replace(/\"/g, '\"\"')}\"`, // Escape quotes\n log.source || '',\n log.userId || '',\n log.ipAddress || '',\n log.method || '',\n log.url || '',\n log.statusCode || '',\n log.duration || '',\n new Date(log.createdAt).toISOString()\n ]\n csvRows.push(row.join(','))\n })\n \n const csv = csvRows.join('\\n')\n \n return new Response(csv, {\n headers: {\n 'Content-Type': 'text/csv',\n 'Content-Disposition': 'attachment; filename=\"logs-export.csv\"'\n }\n })\n }\n } catch (error) {\n console.error('Error exporting logs:', error)\n return c.json({ error: 'Failed to export logs' }, 500)\n }\n})\n\n// Clean up old logs\nadminLogsRoutes.post('/cleanup', async (c) => {\n try {\n const user = c.get('user')\n \n // Only allow admin users to run cleanup\n if (!user || user.role !== 'admin') {\n return c.json({ \n success: false, \n error: 'Unauthorized. Admin access required.' \n }, 403)\n }\n \n const logger = getLogger(c.env.DB)\n await logger.cleanupByRetention()\n \n return c.html(html`\n \n Log cleanup completed successfully!\n
\n `)\n } catch (error) {\n console.error('Error cleaning up logs:', error)\n return c.html(html`\n \n Failed to clean up logs. Please try again.\n
\n `)\n }\n})\n\n// Search logs (HTMX endpoint)\nadminLogsRoutes.post('/search', async (c) => {\n try {\n const formData = await c.req.formData()\n const search = formData.get('search') as string\n const level = formData.get('level') as string\n const category = formData.get('category') as string\n \n const logger = getLogger(c.env.DB)\n \n const filter: LogFilter = {\n limit: 20,\n offset: 0,\n sortBy: 'created_at',\n sortOrder: 'desc'\n }\n \n if (search) filter.search = search\n if (level) filter.level = [level] as LogLevel[]\n if (category) filter.category = [category] as LogCategory[]\n \n const { logs } = await logger.getLogs(filter)\n \n // Return just the logs table rows for HTMX\n const rows = logs.map(log => {\n const formattedLog = {\n ...log,\n formattedDate: new Date(log.createdAt).toLocaleString(),\n levelClass: getLevelClass(log.level),\n categoryClass: getCategoryClass(log.category)\n }\n\n return `\n \n \n \n ${formattedLog.level}\n \n \n \n \n ${formattedLog.category}\n \n \n \n ${formattedLog.message}
\n \n ${formattedLog.source || '-'} \n ${formattedLog.formattedDate} \n \n View \n \n \n `\n }).join('')\n\n return c.html(rows)\n } catch (error) {\n console.error('Error searching logs:', error)\n return c.html(html`Error searching logs `)\n }\n})\n\n// Helper functions\nfunction getLevelClass(level: string): string {\n switch (level) {\n case 'debug': return 'bg-gray-100 text-gray-800'\n case 'info': return 'bg-blue-100 text-blue-800'\n case 'warn': return 'bg-yellow-100 text-yellow-800'\n case 'error': return 'bg-red-100 text-red-800'\n case 'fatal': return 'bg-purple-100 text-purple-800'\n default: return 'bg-gray-100 text-gray-800'\n }\n}\n\nfunction getCategoryClass(category: string): string {\n switch (category) {\n case 'auth': return 'bg-green-100 text-green-800'\n case 'api': return 'bg-blue-100 text-blue-800'\n case 'workflow': return 'bg-purple-100 text-purple-800'\n case 'plugin': return 'bg-indigo-100 text-indigo-800'\n case 'media': return 'bg-pink-100 text-pink-800'\n case 'system': return 'bg-gray-100 text-gray-800'\n case 'security': return 'bg-red-100 text-red-800'\n case 'error': return 'bg-red-100 text-red-800'\n default: return 'bg-gray-100 text-gray-800'\n }\n}\n\nexport { adminLogsRoutes }","import { Hono } from 'hono'\nimport { renderDesignPage, DesignPageData } from '../templates/pages/admin-design.template'\n\ntype Bindings = {\n DB: D1Database\n KV: KVNamespace\n}\n\ntype Variables = {\n user: {\n userId: string\n email: string\n role: string\n }\n}\n\nexport const adminDesignRoutes = new Hono<{ Bindings: Bindings; Variables: Variables }>()\n\nadminDesignRoutes.get('/', (c) => {\n const user = c.get('user')\n \n const pageData: DesignPageData = {\n user: user ? {\n name: user.email,\n email: user.email,\n role: user.role\n } : undefined\n }\n \n return c.html(renderDesignPage(pageData))\n})","import { Hono } from 'hono'\nimport { renderCheckboxPage, CheckboxPageData } from '../templates/pages/admin-checkboxes.template'\n\ntype Bindings = {\n DB: D1Database\n KV: KVNamespace\n}\n\ntype Variables = {\n user: {\n userId: string\n email: string\n role: string\n }\n}\n\nexport const adminCheckboxRoutes = new Hono<{ Bindings: Bindings; Variables: Variables }>()\n\nadminCheckboxRoutes.get('/', (c) => {\n const user = c.get('user')\n\n const pageData: CheckboxPageData = {\n user: user ? {\n name: user.email,\n email: user.email,\n role: user.role\n } : undefined\n }\n\n return c.html(renderCheckboxPage(pageData))\n})\n","import { renderAdminLayout, AdminLayoutData } from '../layouts/admin-layout-v2.template'\nimport { renderAlert } from '../alert.template'\n\ninterface Testimonial {\n id?: number\n authorName: string\n authorTitle?: string\n authorCompany?: string\n testimonialText: string\n rating?: number\n isPublished: boolean\n sortOrder: number\n}\n\ninterface TestimonialsFormData {\n testimonial?: Testimonial\n isEdit: boolean\n errors?: Record\n user?: { name: string; email: string; role: string }\n message?: string\n messageType?: 'success' | 'error' | 'warning' | 'info'\n}\n\nexport function renderTestimonialsForm(data: TestimonialsFormData): string {\n const { testimonial, isEdit, errors, message, messageType } = data\n const pageTitle = isEdit ? 'Edit Testimonial' : 'New Testimonial'\n\n const pageContent = `\n \n \n
\n
\n
${pageTitle} \n
\n ${isEdit ? 'Update the testimonial details below' : 'Create a new customer testimonial'}\n
\n
\n
\n
\n\n ${message ? renderAlert({ type: messageType || 'info', message, dismissible: true }) : ''}\n\n \n
\n
\n\n \n \n
Author Information \n\n \n
\n
\n Author Name * \n \n
\n \n
\n ${errors?.authorName ? `\n
\n ${errors.authorName.map(error => `\n
${escapeHtml(error)}
\n `).join('')}\n
\n ` : ''}\n
\n\n
\n \n
\n
Title/Position \n
\n \n
\n ${errors?.authorTitle ? `\n
\n ${errors.authorTitle.map(error => `\n
${escapeHtml(error)}
\n `).join('')}\n
\n ` : ''}\n
\n\n \n
\n
Company \n
\n \n
\n ${errors?.authorCompany ? `\n
\n ${errors.authorCompany.map(error => `\n
${escapeHtml(error)}
\n `).join('')}\n
\n ` : ''}\n
\n
\n
\n\n \n \n
Testimonial \n\n \n
\n
\n Testimonial * \n \n
\n
${testimonial?.testimonialText || ''} \n
\n 0 /1000 characters\n
\n
\n ${errors?.testimonialText ? `\n
\n ${errors.testimonialText.map(error => `\n
${escapeHtml(error)}
\n `).join('')}\n
\n ` : ''}\n
\n\n \n
\n
Rating (Optional) \n
\n \n No rating \n āāāāā (5 stars) \n āāāā (4 stars) \n āāā (3 stars) \n āā (2 stars) \n ā (1 star) \n \n
\n ${errors?.rating ? `\n
\n ${errors.rating.map(error => `\n
${escapeHtml(error)}
\n `).join('')}\n
\n ` : ''}\n
\n
\n\n \n \n \n
\n\n \n
\n
Sort Order \n
\n
\n
Lower numbers appear first (0 = highest priority)
\n
\n ${errors?.sortOrder ? `\n
\n ${errors.sortOrder.map(error => `\n
${escapeHtml(error)}
\n `).join('')}\n
\n ` : ''}\n
\n
\n\n \n \n
\n Cancel\n \n
\n \n \n \n ${isEdit ? 'Update Testimonial' : 'Create Testimonial'}\n \n
\n \n
\n
\n\n \n `\n\n const layoutData: AdminLayoutData = {\n title: `${pageTitle} - Admin`,\n pageTitle,\n currentPath: isEdit ? `/admin/testimonials/${testimonial?.id}` : '/admin/testimonials/new',\n user: data.user,\n content: pageContent\n }\n\n return renderAdminLayout(layoutData)\n}\n\nfunction escapeHtml(unsafe: string): string {\n return unsafe\n .replace(/&/g, \"&\")\n .replace(//g, \">\")\n .replace(/\"/g, \""\")\n .replace(/'/g, \"'\")\n}\n","import { Hono } from 'hono'\nimport { z } from 'zod'\nimport { renderTestimonialsList } from '../templates/pages/admin-testimonials-list.template'\nimport { renderTestimonialsForm } from '../templates/pages/admin-testimonials-form.template'\n\ntype Bindings = {\n DB: D1Database\n KV: KVNamespace\n}\n\ntype Variables = {\n user?: {\n userId: string\n email: string\n role: string\n exp: number\n iat: number\n }\n}\n\nconst testimonialSchema = z.object({\n authorName: z.string().min(1, 'Author name is required').max(100, 'Author name must be under 100 characters'),\n authorTitle: z.string().optional(),\n authorCompany: z.string().optional(),\n testimonialText: z.string().min(1, 'Testimonial is required').max(1000, 'Testimonial must be under 1000 characters'),\n rating: z.string().transform(val => val ? parseInt(val, 10) : undefined).pipe(z.number().min(1).max(5).optional()),\n isPublished: z.string().transform(val => val === 'true'),\n sortOrder: z.string().transform(val => parseInt(val, 10)).pipe(z.number().min(0))\n})\n\nconst adminTestimonialsRoutes = new Hono<{ Bindings: Bindings; Variables: Variables }>()\n\nadminTestimonialsRoutes.get('/', async (c) => {\n try {\n const user = c.get('user')\n const { published, minRating, search, page = '1' } = c.req.query()\n const currentPage = parseInt(page, 10) || 1\n const limit = 20\n const offset = (currentPage - 1) * limit\n\n const db = (c as any).env?.DB\n if (!db) {\n return c.html(renderTestimonialsList({\n testimonials: [],\n totalCount: 0,\n currentPage: 1,\n totalPages: 1,\n user: user ? {\n name: user.email,\n email: user.email,\n role: user.role\n } : undefined,\n message: 'Database not available',\n messageType: 'error'\n }))\n }\n\n let whereClause = 'WHERE 1=1'\n const params: any[] = []\n\n if (published !== undefined) {\n whereClause += ' AND isPublished = ?'\n params.push(published === 'true' ? 1 : 0)\n }\n\n if (minRating) {\n whereClause += ' AND rating >= ?'\n params.push(parseInt(minRating, 10))\n }\n\n if (search) {\n whereClause += ' AND (author_name LIKE ? OR testimonial_text LIKE ? OR author_company LIKE ?)'\n const searchTerm = `%${search}%`\n params.push(searchTerm, searchTerm, searchTerm)\n }\n\n const countQuery = `SELECT COUNT(*) as count FROM testimonials ${whereClause}`\n const { results: countResults } = await db.prepare(countQuery).bind(...params).all()\n const totalCount = countResults?.[0]?.count || 0\n\n const dataQuery = `\n SELECT * FROM testimonials\n ${whereClause}\n ORDER BY sortOrder ASC, created_at DESC\n LIMIT ? OFFSET ?\n `\n const { results: testimonials } = await db.prepare(dataQuery).bind(...params, limit, offset).all()\n\n const totalPages = Math.ceil(totalCount / limit)\n\n return c.html(renderTestimonialsList({\n testimonials: testimonials || [],\n totalCount,\n currentPage,\n totalPages,\n user: user ? {\n name: user.email,\n email: user.email,\n role: user.role\n } : undefined\n }))\n } catch (error) {\n console.error('Error fetching testimonials:', error)\n const user = c.get('user')\n return c.html(renderTestimonialsList({\n testimonials: [],\n totalCount: 0,\n currentPage: 1,\n totalPages: 1,\n user: user ? {\n name: user.email,\n email: user.email,\n role: user.role\n } : undefined,\n message: 'Failed to load testimonials',\n messageType: 'error'\n }))\n }\n})\n\nadminTestimonialsRoutes.get('/new', async (c) => {\n const user = c.get('user')\n return c.html(renderTestimonialsForm({\n isEdit: false,\n user: user ? {\n name: user.email,\n email: user.email,\n role: user.role\n } : undefined\n }))\n})\n\nadminTestimonialsRoutes.post('/', async (c) => {\n try {\n const formData = await c.req.formData()\n const data = Object.fromEntries(formData.entries())\n\n const validatedData = testimonialSchema.parse(data)\n const user = c.get('user')\n const db = (c as any).env?.DB\n\n if (!db) {\n return c.html(renderTestimonialsForm({\n isEdit: false,\n user: user ? {\n name: user.email,\n email: user.email,\n role: user.role\n } : undefined,\n message: 'Database not available',\n messageType: 'error'\n }))\n }\n\n const { results } = await db.prepare(`\n INSERT INTO testimonials (author_name, author_title, author_company, testimonial_text, rating, isPublished, sortOrder)\n VALUES (?, ?, ?, ?, ?, ?, ?)\n RETURNING *\n `).bind(\n validatedData.authorName,\n validatedData.authorTitle || null,\n validatedData.authorCompany || null,\n validatedData.testimonialText,\n validatedData.rating || null,\n validatedData.isPublished ? 1 : 0,\n validatedData.sortOrder\n ).all()\n\n if (results && results.length > 0) {\n return c.redirect('/admin/testimonials?message=Testimonial created successfully')\n } else {\n return c.html(renderTestimonialsForm({\n isEdit: false,\n user: user ? {\n name: user.email,\n email: user.email,\n role: user.role\n } : undefined,\n message: 'Failed to create testimonial',\n messageType: 'error'\n }))\n }\n } catch (error) {\n console.error('Error creating testimonial:', error)\n const user = c.get('user')\n\n if (error instanceof z.ZodError) {\n const errors: Record = {}\n error.issues.forEach(err => {\n const field = err.path[0] as string\n if (!errors[field]) errors[field] = []\n errors[field].push(err.message)\n })\n\n return c.html(renderTestimonialsForm({\n isEdit: false,\n user: user ? {\n name: user.email,\n email: user.email,\n role: user.role\n } : undefined,\n errors,\n message: 'Please correct the errors below',\n messageType: 'error'\n }))\n }\n\n return c.html(renderTestimonialsForm({\n isEdit: false,\n user: user ? {\n name: user.email,\n email: user.email,\n role: user.role\n } : undefined,\n message: 'Failed to create testimonial',\n messageType: 'error'\n }))\n }\n})\n\nadminTestimonialsRoutes.get('/:id', async (c) => {\n try {\n const id = parseInt(c.req.param('id'))\n const user = c.get('user')\n const db = (c as any).env?.DB\n\n if (!db) {\n return c.html(renderTestimonialsForm({\n isEdit: true,\n user: user ? {\n name: user.email,\n email: user.email,\n role: user.role\n } : undefined,\n message: 'Database not available',\n messageType: 'error'\n }))\n }\n\n const { results } = await db.prepare('SELECT * FROM testimonials WHERE id = ?').bind(id).all()\n\n if (!results || results.length === 0) {\n return c.redirect('/admin/testimonials?message=Testimonial not found&type=error')\n }\n\n const testimonial = results[0] as any\n\n return c.html(renderTestimonialsForm({\n testimonial: {\n id: testimonial.id,\n authorName: testimonial.author_name,\n authorTitle: testimonial.author_title,\n authorCompany: testimonial.author_company,\n testimonialText: testimonial.testimonial_text,\n rating: testimonial.rating,\n isPublished: Boolean(testimonial.isPublished),\n sortOrder: testimonial.sortOrder\n },\n isEdit: true,\n user: user ? {\n name: user.email,\n email: user.email,\n role: user.role\n } : undefined\n }))\n } catch (error) {\n console.error('Error fetching testimonial:', error)\n const user = c.get('user')\n return c.html(renderTestimonialsForm({\n isEdit: true,\n user: user ? {\n name: user.email,\n email: user.email,\n role: user.role\n } : undefined,\n message: 'Failed to load testimonial',\n messageType: 'error'\n }))\n }\n})\n\nadminTestimonialsRoutes.put('/:id', async (c) => {\n try {\n const id = parseInt(c.req.param('id'))\n const formData = await c.req.formData()\n const data = Object.fromEntries(formData.entries())\n\n const validatedData = testimonialSchema.parse(data)\n const user = c.get('user')\n const db = (c as any).env?.DB\n\n if (!db) {\n return c.html(renderTestimonialsForm({\n isEdit: true,\n user: user ? {\n name: user.email,\n email: user.email,\n role: user.role\n } : undefined,\n message: 'Database not available',\n messageType: 'error'\n }))\n }\n\n const { results } = await db.prepare(`\n UPDATE testimonials\n SET author_name = ?, author_title = ?, author_company = ?, testimonial_text = ?, rating = ?, isPublished = ?, sortOrder = ?\n WHERE id = ?\n RETURNING *\n `).bind(\n validatedData.authorName,\n validatedData.authorTitle || null,\n validatedData.authorCompany || null,\n validatedData.testimonialText,\n validatedData.rating || null,\n validatedData.isPublished ? 1 : 0,\n validatedData.sortOrder,\n id\n ).all()\n\n if (results && results.length > 0) {\n return c.redirect('/admin/testimonials?message=Testimonial updated successfully')\n } else {\n return c.html(renderTestimonialsForm({\n testimonial: {\n id,\n authorName: validatedData.authorName,\n authorTitle: validatedData.authorTitle,\n authorCompany: validatedData.authorCompany,\n testimonialText: validatedData.testimonialText,\n rating: validatedData.rating,\n isPublished: validatedData.isPublished,\n sortOrder: validatedData.sortOrder\n },\n isEdit: true,\n user: user ? {\n name: user.email,\n email: user.email,\n role: user.role\n } : undefined,\n message: 'Testimonial not found',\n messageType: 'error'\n }))\n }\n } catch (error) {\n console.error('Error updating testimonial:', error)\n const user = c.get('user')\n const id = parseInt(c.req.param('id'))\n\n if (error instanceof z.ZodError) {\n const errors: Record = {}\n error.issues.forEach(err => {\n const field = err.path[0] as string\n if (!errors[field]) errors[field] = []\n errors[field].push(err.message)\n })\n\n return c.html(renderTestimonialsForm({\n testimonial: {\n id,\n authorName: '',\n authorTitle: '',\n authorCompany: '',\n testimonialText: '',\n rating: undefined,\n isPublished: true,\n sortOrder: 0\n },\n isEdit: true,\n user: user ? {\n name: user.email,\n email: user.email,\n role: user.role\n } : undefined,\n errors,\n message: 'Please correct the errors below',\n messageType: 'error'\n }))\n }\n\n return c.html(renderTestimonialsForm({\n testimonial: {\n id,\n authorName: '',\n authorTitle: '',\n authorCompany: '',\n testimonialText: '',\n rating: undefined,\n isPublished: true,\n sortOrder: 0\n },\n isEdit: true,\n user: user ? {\n name: user.email,\n email: user.email,\n role: user.role\n } : undefined,\n message: 'Failed to update testimonial',\n messageType: 'error'\n }))\n }\n})\n\nadminTestimonialsRoutes.delete('/:id', async (c) => {\n try {\n const id = parseInt(c.req.param('id'))\n const db = (c as any).env?.DB\n\n if (!db) {\n return c.json({ error: 'Database not available' }, 500)\n }\n\n const { changes } = await db.prepare('DELETE FROM testimonials WHERE id = ?').bind(id).run()\n\n if (changes === 0) {\n return c.json({ error: 'Testimonial not found' }, 404)\n }\n\n return c.redirect('/admin/testimonials?message=Testimonial deleted successfully')\n } catch (error) {\n console.error('Error deleting testimonial:', error)\n return c.json({ error: 'Failed to delete testimonial' }, 500)\n }\n})\n\nexport default adminTestimonialsRoutes\n","import { renderAdminLayout, AdminLayoutData } from '../layouts/admin-layout-v2.template'\nimport { renderAlert } from '../alert.template'\n\ninterface CodeExample {\n id?: number\n title: string\n description?: string\n code: string\n language: string\n category?: string\n tags?: string\n isPublished: boolean\n sortOrder: number\n}\n\ninterface CodeExamplesFormData {\n codeExample?: CodeExample\n isEdit: boolean\n errors?: Record\n user?: { name: string; email: string; role: string }\n message?: string\n messageType?: 'success' | 'error' | 'warning' | 'info'\n}\n\nexport function renderCodeExamplesForm(data: CodeExamplesFormData): string {\n const { codeExample, isEdit, errors, message, messageType } = data\n const pageTitle = isEdit ? 'Edit Code Example' : 'New Code Example'\n\n const pageContent = `\n \n \n
\n
\n
${pageTitle} \n
\n ${isEdit ? 'Update the code example details below' : 'Create a new code snippet or example'}\n
\n
\n
\n
\n\n ${message ? renderAlert({ type: messageType || 'info', message, dismissible: true }) : ''}\n\n \n
\n
\n\n \n \n
Basic Information \n\n \n
\n
\n Title * \n \n
\n \n
\n ${errors?.title ? `\n
\n ${errors.title.map(error => `\n
${escapeHtml(error)}
\n `).join('')}\n
\n ` : ''}\n
\n\n \n
\n
Description \n
\n
${codeExample?.description || ''} \n
\n 0 /500 characters\n
\n
\n ${errors?.description ? `\n
\n ${errors.description.map(error => `\n
${escapeHtml(error)}
\n `).join('')}\n
\n ` : ''}\n
\n\n
\n \n
\n
\n Language * \n \n
\n \n Select language... \n JavaScript \n TypeScript \n Python \n Go \n Rust \n Java \n PHP \n Ruby \n SQL \n \n
\n ${errors?.language ? `\n
\n ${errors.language.map(error => `\n
${escapeHtml(error)}
\n `).join('')}\n
\n ` : ''}\n
\n\n \n
\n
Category \n
\n \n
\n ${errors?.category ? `\n
\n ${errors.category.map(error => `\n
${escapeHtml(error)}
\n `).join('')}\n
\n ` : ''}\n
\n\n \n
\n
Tags \n
\n
\n
Comma-separated tags
\n
\n ${errors?.tags ? `\n
\n ${errors.tags.map(error => `\n
${escapeHtml(error)}
\n `).join('')}\n
\n ` : ''}\n
\n
\n
\n\n \n \n
Code \n\n \n
\n
\n Code * \n \n
\n
${codeExample?.code || ''} \n
\n 0 characters\n
\n
\n ${errors?.code ? `\n
\n ${errors.code.map(error => `\n
${escapeHtml(error)}
\n `).join('')}\n
\n ` : ''}\n
\n
\n\n \n \n \n
\n\n \n
\n
Sort Order \n
\n
\n
Lower numbers appear first (0 = highest priority)
\n
\n ${errors?.sortOrder ? `\n
\n ${errors.sortOrder.map(error => `\n
${escapeHtml(error)}
\n `).join('')}\n
\n ` : ''}\n
\n
\n\n \n \n
\n Cancel\n \n
\n \n \n \n ${isEdit ? 'Update Code Example' : 'Create Code Example'}\n \n
\n \n
\n
\n\n \n `\n\n const layoutData: AdminLayoutData = {\n title: `${pageTitle} - Admin`,\n pageTitle,\n currentPath: isEdit ? `/admin/code-examples/${codeExample?.id}` : '/admin/code-examples/new',\n user: data.user,\n content: pageContent\n }\n\n return renderAdminLayout(layoutData)\n}\n\nfunction escapeHtml(unsafe: string): string {\n return unsafe\n .replace(/&/g, \"&\")\n .replace(//g, \">\")\n .replace(/\"/g, \""\")\n .replace(/'/g, \"'\")\n}\n","import { Hono } from 'hono'\nimport { z } from 'zod'\nimport { renderCodeExamplesList } from '../templates/pages/admin-code-examples-list.template'\nimport { renderCodeExamplesForm } from '../templates/pages/admin-code-examples-form.template'\n\ntype Bindings = {\n DB: D1Database\n KV: KVNamespace\n}\n\ntype Variables = {\n user?: {\n userId: string\n email: string\n role: string\n exp: number\n iat: number\n }\n}\n\nconst codeExampleSchema = z.object({\n title: z.string().min(1, 'Title is required').max(200, 'Title must be under 200 characters'),\n description: z.string().max(500, 'Description must be under 500 characters').optional(),\n code: z.string().min(1, 'Code is required'),\n language: z.string().min(1, 'Language is required'),\n category: z.string().max(50, 'Category must be under 50 characters').optional(),\n tags: z.string().max(200, 'Tags must be under 200 characters').optional(),\n isPublished: z.string().transform(val => val === 'true'),\n sortOrder: z.string().transform(val => parseInt(val, 10)).pipe(z.number().min(0))\n})\n\nconst adminCodeExamplesRoutes = new Hono<{ Bindings: Bindings; Variables: Variables }>()\n\nadminCodeExamplesRoutes.get('/', async (c) => {\n try {\n const user = c.get('user')\n const { published, language, search, page = '1' } = c.req.query()\n const currentPage = parseInt(page, 10) || 1\n const limit = 20\n const offset = (currentPage - 1) * limit\n\n const db = (c as any).env?.DB\n if (!db) {\n return c.html(renderCodeExamplesList({\n codeExamples: [],\n totalCount: 0,\n currentPage: 1,\n totalPages: 1,\n user: user ? {\n name: user.email,\n email: user.email,\n role: user.role\n } : undefined,\n message: 'Database not available',\n messageType: 'error'\n }))\n }\n\n let whereClause = 'WHERE 1=1'\n const params: any[] = []\n\n if (published !== undefined) {\n whereClause += ' AND isPublished = ?'\n params.push(published === 'true' ? 1 : 0)\n }\n\n if (language) {\n whereClause += ' AND language = ?'\n params.push(language)\n }\n\n if (search) {\n whereClause += ' AND (title LIKE ? OR description LIKE ? OR code LIKE ? OR tags LIKE ?)'\n const searchTerm = `%${search}%`\n params.push(searchTerm, searchTerm, searchTerm, searchTerm)\n }\n\n const countQuery = `SELECT COUNT(*) as count FROM code_examples ${whereClause}`\n const { results: countResults } = await db.prepare(countQuery).bind(...params).all()\n const totalCount = countResults?.[0]?.count || 0\n\n const dataQuery = `\n SELECT * FROM code_examples\n ${whereClause}\n ORDER BY sortOrder ASC, created_at DESC\n LIMIT ? OFFSET ?\n `\n const { results: codeExamples } = await db.prepare(dataQuery).bind(...params, limit, offset).all()\n\n const totalPages = Math.ceil(totalCount / limit)\n\n return c.html(renderCodeExamplesList({\n codeExamples: codeExamples || [],\n totalCount,\n currentPage,\n totalPages,\n user: user ? {\n name: user.email,\n email: user.email,\n role: user.role\n } : undefined\n }))\n } catch (error) {\n console.error('Error fetching code examples:', error)\n const user = c.get('user')\n return c.html(renderCodeExamplesList({\n codeExamples: [],\n totalCount: 0,\n currentPage: 1,\n totalPages: 1,\n user: user ? {\n name: user.email,\n email: user.email,\n role: user.role\n } : undefined,\n message: 'Failed to load code examples',\n messageType: 'error'\n }))\n }\n})\n\nadminCodeExamplesRoutes.get('/new', async (c) => {\n const user = c.get('user')\n return c.html(renderCodeExamplesForm({\n isEdit: false,\n user: user ? {\n name: user.email,\n email: user.email,\n role: user.role\n } : undefined\n }))\n})\n\nadminCodeExamplesRoutes.post('/', async (c) => {\n try {\n const formData = await c.req.formData()\n const data = Object.fromEntries(formData.entries())\n\n const validatedData = codeExampleSchema.parse(data)\n const user = c.get('user')\n const db = (c as any).env?.DB\n\n if (!db) {\n return c.html(renderCodeExamplesForm({\n isEdit: false,\n user: user ? {\n name: user.email,\n email: user.email,\n role: user.role\n } : undefined,\n message: 'Database not available',\n messageType: 'error'\n }))\n }\n\n const { results } = await db.prepare(`\n INSERT INTO code_examples (title, description, code, language, category, tags, isPublished, sortOrder)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?)\n RETURNING *\n `).bind(\n validatedData.title,\n validatedData.description || null,\n validatedData.code,\n validatedData.language,\n validatedData.category || null,\n validatedData.tags || null,\n validatedData.isPublished ? 1 : 0,\n validatedData.sortOrder\n ).all()\n\n if (results && results.length > 0) {\n return c.redirect('/admin/code-examples?message=Code example created successfully')\n } else {\n return c.html(renderCodeExamplesForm({\n isEdit: false,\n user: user ? {\n name: user.email,\n email: user.email,\n role: user.role\n } : undefined,\n message: 'Failed to create code example',\n messageType: 'error'\n }))\n }\n } catch (error) {\n console.error('Error creating code example:', error)\n const user = c.get('user')\n\n if (error instanceof z.ZodError) {\n const errors: Record = {}\n error.issues.forEach(err => {\n const field = err.path[0] as string\n if (!errors[field]) errors[field] = []\n errors[field].push(err.message)\n })\n\n return c.html(renderCodeExamplesForm({\n isEdit: false,\n user: user ? {\n name: user.email,\n email: user.email,\n role: user.role\n } : undefined,\n errors,\n message: 'Please correct the errors below',\n messageType: 'error'\n }))\n }\n\n return c.html(renderCodeExamplesForm({\n isEdit: false,\n user: user ? {\n name: user.email,\n email: user.email,\n role: user.role\n } : undefined,\n message: 'Failed to create code example',\n messageType: 'error'\n }))\n }\n})\n\nadminCodeExamplesRoutes.get('/:id', async (c) => {\n try {\n const id = parseInt(c.req.param('id'))\n const user = c.get('user')\n const db = (c as any).env?.DB\n\n if (!db) {\n return c.html(renderCodeExamplesForm({\n isEdit: true,\n user: user ? {\n name: user.email,\n email: user.email,\n role: user.role\n } : undefined,\n message: 'Database not available',\n messageType: 'error'\n }))\n }\n\n const { results } = await db.prepare('SELECT * FROM code_examples WHERE id = ?').bind(id).all()\n\n if (!results || results.length === 0) {\n return c.redirect('/admin/code-examples?message=Code example not found&type=error')\n }\n\n const example = results[0] as any\n\n return c.html(renderCodeExamplesForm({\n codeExample: {\n id: example.id,\n title: example.title,\n description: example.description,\n code: example.code,\n language: example.language,\n category: example.category,\n tags: example.tags,\n isPublished: Boolean(example.isPublished),\n sortOrder: example.sortOrder\n },\n isEdit: true,\n user: user ? {\n name: user.email,\n email: user.email,\n role: user.role\n } : undefined\n }))\n } catch (error) {\n console.error('Error fetching code example:', error)\n const user = c.get('user')\n return c.html(renderCodeExamplesForm({\n isEdit: true,\n user: user ? {\n name: user.email,\n email: user.email,\n role: user.role\n } : undefined,\n message: 'Failed to load code example',\n messageType: 'error'\n }))\n }\n})\n\nadminCodeExamplesRoutes.put('/:id', async (c) => {\n try {\n const id = parseInt(c.req.param('id'))\n const formData = await c.req.formData()\n const data = Object.fromEntries(formData.entries())\n\n const validatedData = codeExampleSchema.parse(data)\n const user = c.get('user')\n const db = (c as any).env?.DB\n\n if (!db) {\n return c.html(renderCodeExamplesForm({\n isEdit: true,\n user: user ? {\n name: user.email,\n email: user.email,\n role: user.role\n } : undefined,\n message: 'Database not available',\n messageType: 'error'\n }))\n }\n\n const { results } = await db.prepare(`\n UPDATE code_examples\n SET title = ?, description = ?, code = ?, language = ?, category = ?, tags = ?, isPublished = ?, sortOrder = ?\n WHERE id = ?\n RETURNING *\n `).bind(\n validatedData.title,\n validatedData.description || null,\n validatedData.code,\n validatedData.language,\n validatedData.category || null,\n validatedData.tags || null,\n validatedData.isPublished ? 1 : 0,\n validatedData.sortOrder,\n id\n ).all()\n\n if (results && results.length > 0) {\n return c.redirect('/admin/code-examples?message=Code example updated successfully')\n } else {\n return c.html(renderCodeExamplesForm({\n codeExample: {\n id,\n title: validatedData.title,\n description: validatedData.description,\n code: validatedData.code,\n language: validatedData.language,\n category: validatedData.category,\n tags: validatedData.tags,\n isPublished: validatedData.isPublished,\n sortOrder: validatedData.sortOrder\n },\n isEdit: true,\n user: user ? {\n name: user.email,\n email: user.email,\n role: user.role\n } : undefined,\n message: 'Code example not found',\n messageType: 'error'\n }))\n }\n } catch (error) {\n console.error('Error updating code example:', error)\n const user = c.get('user')\n const id = parseInt(c.req.param('id'))\n\n if (error instanceof z.ZodError) {\n const errors: Record = {}\n error.issues.forEach(err => {\n const field = err.path[0] as string\n if (!errors[field]) errors[field] = []\n errors[field].push(err.message)\n })\n\n return c.html(renderCodeExamplesForm({\n codeExample: {\n id,\n title: '',\n description: '',\n code: '',\n language: '',\n category: '',\n tags: '',\n isPublished: true,\n sortOrder: 0\n },\n isEdit: true,\n user: user ? {\n name: user.email,\n email: user.email,\n role: user.role\n } : undefined,\n errors,\n message: 'Please correct the errors below',\n messageType: 'error'\n }))\n }\n\n return c.html(renderCodeExamplesForm({\n codeExample: {\n id,\n title: '',\n description: '',\n code: '',\n language: '',\n category: '',\n tags: '',\n isPublished: true,\n sortOrder: 0\n },\n isEdit: true,\n user: user ? {\n name: user.email,\n email: user.email,\n role: user.role\n } : undefined,\n message: 'Failed to update code example',\n messageType: 'error'\n }))\n }\n})\n\nadminCodeExamplesRoutes.delete('/:id', async (c) => {\n try {\n const id = parseInt(c.req.param('id'))\n const db = (c as any).env?.DB\n\n if (!db) {\n return c.json({ error: 'Database not available' }, 500)\n }\n\n const { changes } = await db.prepare('DELETE FROM code_examples WHERE id = ?').bind(id).run()\n\n if (changes === 0) {\n return c.json({ error: 'Code example not found' }, 404)\n }\n\n return c.redirect('/admin/code-examples?message=Code example deleted successfully')\n } catch (error) {\n console.error('Error deleting code example:', error)\n return c.json({ error: 'Failed to delete code example' }, 500)\n }\n})\n\nexport default adminCodeExamplesRoutes\n","import {\n AdminLayoutData,\n renderAdminLayout,\n} from \"../layouts/admin-layout-v2.template\";\n\nexport interface DashboardStats {\n collections: number;\n contentItems: number;\n mediaFiles: number;\n users: number;\n databaseSize?: number; // Size in bytes\n mediaSize?: number; // Total size of all media files in bytes\n recentActivity?: ActivityItem[];\n analytics?: AnalyticsData;\n}\n\nexport interface ActivityItem {\n id: string;\n type: \"content\" | \"media\" | \"user\" | \"collection\";\n action: string;\n description: string;\n timestamp: string;\n user: string;\n}\n\nexport interface AnalyticsData {\n pageViews: number;\n uniqueVisitors: number;\n contentPublished: number;\n mediaUploaded: number;\n weeklyGrowth: {\n pageViews: number;\n visitors: number;\n content: number;\n media: number;\n };\n}\n\nexport interface DashboardPageData {\n user?: {\n name: string;\n email: string;\n role: string;\n };\n stats?: DashboardStats;\n version?: string;\n enableExperimentalFeatures?: boolean;\n}\n\nexport function renderDashboardPage(data: DashboardPageData): string {\n const pageContent = `\n \n
\n
Dashboard \n
Welcome to your SonicJS AI admin dashboard
\n
\n
\n
\n\n \n \n ${renderStatsCardsSkeleton()}\n
\n\n \n \n \n
\n ${renderAnalyticsChart()}\n
\n\n \n
\n ${renderRecentActivitySkeleton()}\n
\n
\n\n \n \n \n ${renderQuickActions()}\n\n \n ${renderSystemStatus()}\n\n \n
\n ${renderStorageUsage()}\n
\n
\n\n \n `;\n\n const layoutData: AdminLayoutData = {\n title: \"Dashboard\",\n pageTitle: \"Dashboard\",\n currentPath: \"/admin\",\n user: data.user,\n version: data.version,\n content: pageContent,\n };\n\n return renderAdminLayout(layoutData);\n}\n\nexport function renderDashboardPageWithDynamicMenu(\n data: DashboardPageData,\n dynamicMenuItems: Array<{ label: string; path: string; icon: string }>\n): string {\n const pageContent = `\n \n
\n
Dashboard \n
Welcome to your SonicJS AI admin dashboard
\n
\n
\n
\n\n \n ${renderStatsCards({\n collections: 0,\n contentItems: 0,\n mediaFiles: 0,\n users: 0,\n })}\n
\n\n \n \n
\n ${renderAnalyticsChart()}\n
\n\n \n
\n ${renderRecentActivitySkeleton()}\n
\n
\n\n \n \n ${renderQuickActions()}\n\n \n ${renderSystemStatus()}\n\n \n
\n ${renderStorageUsage()}\n
\n
\n\n \n `;\n\n const layoutData: AdminLayoutData = {\n title: \"Dashboard\",\n pageTitle: \"Dashboard\",\n currentPath: \"/admin\",\n user: data.user,\n version: data.version,\n enableExperimentalFeatures: data.enableExperimentalFeatures,\n content: pageContent,\n dynamicMenuItems,\n };\n\n return renderAdminLayout(layoutData);\n}\n\nexport function renderStatsCards(stats: DashboardStats): string {\n const cards = [\n {\n title: \"Total Collections\",\n value: stats.collections.toString(),\n change: \"12.5\",\n isPositive: true,\n },\n {\n title: \"Content Items\",\n value: stats.contentItems.toString(),\n change: \"8.2\",\n isPositive: true,\n },\n {\n title: \"Media Files\",\n value: stats.mediaFiles.toString(),\n change: \"15.3\",\n isPositive: true,\n },\n {\n title: \"Active Users\",\n value: stats.users.toString(),\n change: \"2.4\",\n isPositive: false,\n },\n ];\n\n const cardColors = ['text-cyan-400', 'text-lime-400', 'text-pink-400', 'text-purple-400'];\n\n return `\n \n
Last 30 days \n
\n ${cards.map((card, index) => `\n \n
${card.title} \n
\n \n ${card.value}\n
\n \n
\n ${card.isPositive\n ? ' '\n : ' '\n }\n \n
${card.isPositive ? 'Increased' : 'Decreased'} by \n ${card.change}%\n
\n \n
\n `).join('')}\n \n
\n `;\n}\n\nfunction renderStatsCardsSkeleton(): string {\n return `\n \n
\n
\n ${Array(4)\n .fill(0)\n .map(\n () => `\n
\n `\n )\n .join(\"\")}\n
\n
\n `;\n}\n\nfunction renderAnalyticsChart(): string {\n return `\n \n
\n
\n
\n
Real-Time Analytics \n
Requests per second (live)
\n
\n
\n
\n
\n 0 \n req/s \n
\n
\n\n
\n \n
\n\n \n
\n
\n\n \n `;\n}\n\nexport function renderRecentActivitySkeleton(): string {\n return `\n \n
\n
\n
\n ${Array(3).fill(0).map(() => `\n
\n `).join('')}\n
\n
\n
\n `\n}\n\nexport function renderRecentActivity(activities?: ActivityItem[]): string {\n // Helper to get user initials\n const getInitials = (user: string): string => {\n const parts = user.split(' ').filter(p => p.length > 0)\n if (parts.length >= 2) {\n const first = parts[0]?.[0] || ''\n const second = parts[1]?.[0] || ''\n return (first + second).toUpperCase()\n }\n return user.substring(0, 2).toUpperCase()\n }\n\n // Helper to get relative time\n const getRelativeTime = (timestamp: string): string => {\n const date = new Date(timestamp)\n const now = new Date()\n const diffMs = now.getTime() - date.getTime()\n const diffMins = Math.floor(diffMs / 60000)\n const diffHours = Math.floor(diffMins / 60)\n const diffDays = Math.floor(diffHours / 24)\n\n if (diffMins < 1) return 'just now'\n if (diffMins < 60) return `${diffMins} minute${diffMins > 1 ? 's' : ''} ago`\n if (diffHours < 24) return `${diffHours} hour${diffHours > 1 ? 's' : ''} ago`\n return `${diffDays} day${diffDays > 1 ? 's' : ''} ago`\n }\n\n // Helper to get color classes based on activity type\n const getColorClasses = (type: string): { bgColor: string; textColor: string } => {\n switch (type) {\n case 'content':\n return {\n bgColor: 'bg-lime-500/10 dark:bg-lime-400/10',\n textColor: 'text-lime-700 dark:text-lime-300'\n }\n case 'media':\n return {\n bgColor: 'bg-cyan-500/10 dark:bg-cyan-400/10',\n textColor: 'text-cyan-700 dark:text-cyan-300'\n }\n case 'user':\n return {\n bgColor: 'bg-pink-500/10 dark:bg-pink-400/10',\n textColor: 'text-pink-700 dark:text-pink-300'\n }\n case 'collection':\n return {\n bgColor: 'bg-purple-500/10 dark:bg-purple-400/10',\n textColor: 'text-purple-700 dark:text-purple-300'\n }\n default:\n return {\n bgColor: 'bg-gray-500/10 dark:bg-gray-400/10',\n textColor: 'text-gray-700 dark:text-gray-300'\n }\n }\n }\n\n // Format activities with colors and times\n const formattedActivities = (activities || []).map(activity => {\n const colors = getColorClasses(activity.type)\n return {\n ...activity,\n initials: getInitials(activity.user),\n time: getRelativeTime(activity.timestamp),\n ...colors\n }\n })\n\n // If no activities, show empty state\n if (formattedActivities.length === 0) {\n formattedActivities.push({\n type: 'content' as const,\n description: 'No recent activity',\n user: 'System',\n time: '',\n initials: 'SY',\n bgColor: 'bg-gray-500/10 dark:bg-gray-400/10',\n textColor: 'text-gray-700 dark:text-gray-300',\n id: '0',\n action: '',\n timestamp: new Date().toISOString()\n })\n }\n\n return `\n \n
\n
\n
Recent Activity \n \n View all\n \n \n
\n\n
\n
\n `;\n}\n\nfunction renderQuickActions(): string {\n const actions = [\n {\n title: \"Create Content\",\n description: \"Add new blog post or page\",\n href: \"/admin/content/new\",\n icon: `\n \n `,\n },\n {\n title: \"Upload Media\",\n description: \"Add images and files\",\n href: \"/admin/media\",\n icon: `\n \n `,\n },\n {\n title: \"Manage Users\",\n description: \"Add or edit user accounts\",\n href: \"/admin/users\",\n icon: `\n \n `,\n },\n ];\n\n return `\n \n
\n
Quick Actions \n \n\n
\n
\n `;\n}\n\nfunction renderSystemStatus(): string {\n return `\n \n
\n\n
\n \n
\n ${[\n { color: 'from-blue-500/20 to-cyan-500/20', darkColor: 'dark:from-blue-500/10 dark:to-cyan-500/10' },\n { color: 'from-purple-500/20 to-pink-500/20', darkColor: 'dark:from-purple-500/10 dark:to-pink-500/10' },\n { color: 'from-amber-500/20 to-orange-500/20', darkColor: 'dark:from-amber-500/10 dark:to-orange-500/10' },\n { color: 'from-lime-500/20 to-emerald-500/20', darkColor: 'dark:from-lime-500/10 dark:to-emerald-500/10' }\n ].map((gradient, i) => `\n
\n `).join('')}\n
\n
\n
\n\n \n `;\n}\n\nexport function renderStorageUsage(databaseSizeBytes?: number, mediaSizeBytes?: number): string {\n // Helper to format bytes to human readable\n const formatBytes = (bytes: number): string => {\n if (bytes === 0) return '0 B'\n const k = 1024\n const sizes = ['B', 'KB', 'MB', 'GB']\n const i = Math.floor(Math.log(bytes) / Math.log(k))\n return `${(bytes / Math.pow(k, i)).toFixed(2)} ${sizes[i]}`\n }\n\n const dbSizeGB = databaseSizeBytes ? databaseSizeBytes / (1024 ** 3) : 0\n const dbMaxGB = 10\n const dbPercentageRaw = (dbSizeGB / dbMaxGB) * 100\n // Ensure minimum 0.5% visibility for progress bar, max 100%\n const dbPercentage = Math.min(Math.max(dbPercentageRaw, 0.5), 100)\n const dbUsedFormatted = databaseSizeBytes ? formatBytes(databaseSizeBytes) : 'Unknown'\n\n const mediaUsedFormatted = mediaSizeBytes ? formatBytes(mediaSizeBytes) : '0 B'\n\n const storageItems = [\n {\n label: \"Database\",\n used: dbUsedFormatted,\n total: \"10 GB\",\n percentage: dbPercentage,\n color: dbPercentage > 80 ? \"bg-red-500 dark:bg-red-400\" : dbPercentage > 60 ? \"bg-amber-500 dark:bg-amber-400\" : \"bg-cyan-500 dark:bg-cyan-400\",\n },\n {\n label: \"Media Files\",\n used: mediaUsedFormatted,\n total: \"ā\",\n percentage: 0,\n color: \"bg-lime-500 dark:bg-lime-400\",\n note: \"Stored in R2\"\n },\n {\n label: \"Cache (KV)\",\n used: \"N/A\",\n total: \"ā\",\n percentage: 0,\n color: \"bg-purple-500 dark:bg-purple-400\",\n note: \"Unlimited\"\n },\n ];\n\n return `\n \n
\n
Storage Usage \n \n\n
\n
\n ${storageItems\n .map(\n (item: any) => `\n \n
\n
\n ${item.label}\n ${item.note ? `(${item.note}) ` : ''}\n \n ${item.used} / ${item.total} \n \n
\n
\n `\n )\n .join(\"\")}\n \n
\n
\n `;\n}","import { Hono } from 'hono'\nimport type { D1Database, KVNamespace, R2Bucket } from '@cloudflare/workers-types'\nimport { requireAuth } from '../middleware'\nimport {\n renderDashboardPage,\n type DashboardPageData,\n renderStatsCards,\n renderStorageUsage,\n renderRecentActivity,\n type ActivityItem\n} from '../templates/pages/admin-dashboard.template'\nimport { getCoreVersion } from '../utils/version'\nimport { metricsTracker } from '../utils/metrics'\n\nconst VERSION = getCoreVersion()\n\ntype Bindings = {\n DB: D1Database\n CACHE_KV: KVNamespace\n MEDIA_BUCKET: R2Bucket\n}\n\ntype Variables = {\n user?: {\n userId: string\n email: string\n role: string\n }\n}\n\nconst router = new Hono<{ Bindings: Bindings; Variables: Variables }>()\n\n// Apply authentication middleware\nrouter.use('*', requireAuth())\n\n/**\n * GET /admin - Admin Dashboard\n */\nrouter.get('/', async (c) => {\n const user = c.get('user')\n\n try {\n const pageData: DashboardPageData = {\n user: {\n name: user!.email.split('@')[0] || user!.email,\n email: user!.email,\n role: user!.role\n },\n version: VERSION\n }\n\n return c.html(renderDashboardPage(pageData))\n } catch (error) {\n console.error('Dashboard error:', error)\n\n // Return dashboard with error state\n const pageData: DashboardPageData = {\n user: {\n name: user!.email,\n email: user!.email,\n role: user!.role\n },\n version: VERSION\n }\n\n return c.html(renderDashboardPage(pageData))\n }\n})\n\n/**\n * GET /admin/dashboard/stats - Dashboard stats HTML fragment (HTMX endpoint)\n */\nrouter.get('/stats', async (c) => {\n try {\n const db = c.env.DB\n\n // Get collections count\n let collectionsCount = 0\n try {\n const collectionsStmt = db.prepare('SELECT COUNT(*) as count FROM collections WHERE is_active = 1')\n const collectionsResult = await collectionsStmt.first()\n collectionsCount = (collectionsResult as any)?.count || 0\n } catch (error) {\n console.error('Error fetching collections count:', error)\n }\n\n // Get content count\n let contentCount = 0\n try {\n const contentStmt = db.prepare('SELECT COUNT(*) as count FROM content')\n const contentResult = await contentStmt.first()\n contentCount = (contentResult as any)?.count || 0\n } catch (error) {\n console.error('Error fetching content count:', error)\n }\n\n // Get media count and total size\n let mediaCount = 0\n let mediaSize = 0\n try {\n const mediaStmt = db.prepare('SELECT COUNT(*) as count, COALESCE(SUM(size), 0) as total_size FROM media WHERE deleted_at IS NULL')\n const mediaResult = await mediaStmt.first()\n mediaCount = (mediaResult as any)?.count || 0\n mediaSize = (mediaResult as any)?.total_size || 0\n } catch (error) {\n console.error('Error fetching media count:', error)\n }\n\n // Get users count\n let usersCount = 0\n try {\n const usersStmt = db.prepare('SELECT COUNT(*) as count FROM users WHERE is_active = 1')\n const usersResult = await usersStmt.first()\n usersCount = (usersResult as any)?.count || 0\n } catch (error) {\n console.error('Error fetching users count:', error)\n }\n\n const html = renderStatsCards({\n collections: collectionsCount,\n contentItems: contentCount,\n mediaFiles: mediaCount,\n users: usersCount,\n mediaSize: mediaSize\n })\n\n return c.html(html)\n } catch (error) {\n console.error('Error fetching stats:', error)\n return c.html('Failed to load statistics
')\n }\n})\n\n/**\n * GET /admin/dashboard/storage - Storage usage HTML fragment (HTMX endpoint)\n */\nrouter.get('/storage', async (c) => {\n try {\n const db = c.env.DB\n\n // Get database size from D1 metadata\n let databaseSize = 0\n try {\n const result = await db.prepare('SELECT 1').run()\n databaseSize = (result as any)?.meta?.size_after || 0\n } catch (error) {\n console.error('Error fetching database size:', error)\n }\n\n // Get media total size\n let mediaSize = 0\n try {\n const mediaStmt = db.prepare('SELECT COALESCE(SUM(size), 0) as total_size FROM media WHERE deleted_at IS NULL')\n const mediaResult = await mediaStmt.first()\n mediaSize = (mediaResult as any)?.total_size || 0\n } catch (error) {\n console.error('Error fetching media size:', error)\n }\n\n const html = renderStorageUsage(databaseSize, mediaSize)\n return c.html(html)\n } catch (error) {\n console.error('Error fetching storage usage:', error)\n return c.html('Failed to load storage information
')\n }\n})\n\n/**\n * GET /admin/dashboard/recent-activity - Recent activity HTML fragment (HTMX endpoint)\n */\nrouter.get('/recent-activity', async (c) => {\n try {\n const db = c.env.DB\n const limit = parseInt(c.req.query('limit') || '5')\n\n // Get recent activities from activity_logs table\n const activityStmt = db.prepare(`\n SELECT\n a.id,\n a.action,\n a.resource_type,\n a.resource_id,\n a.details,\n a.created_at,\n u.email,\n u.first_name,\n u.last_name\n FROM activity_logs a\n LEFT JOIN users u ON a.user_id = u.id\n WHERE a.resource_type IN ('content', 'collections', 'users', 'media')\n ORDER BY a.created_at DESC\n LIMIT ?\n `)\n\n const { results } = await activityStmt.bind(limit).all()\n\n const activities: ActivityItem[] = (results || []).map((row: any) => {\n const userName = row.first_name && row.last_name\n ? `${row.first_name} ${row.last_name}`\n : row.email || 'System'\n\n // Format description based on action and resource type\n let description = ''\n if (row.action === 'create') {\n description = `Created new ${row.resource_type}`\n } else if (row.action === 'update') {\n description = `Updated ${row.resource_type}`\n } else if (row.action === 'delete') {\n description = `Deleted ${row.resource_type}`\n } else {\n description = `${row.action} ${row.resource_type}`\n }\n\n return {\n id: row.id,\n type: row.resource_type,\n action: row.action,\n description,\n timestamp: new Date(Number(row.created_at)).toISOString(),\n user: userName\n }\n })\n\n const html = renderRecentActivity(activities)\n return c.html(html)\n } catch (error) {\n console.error('Error fetching recent activity:', error)\n const html = renderRecentActivity([])\n return c.html(html)\n }\n})\n\n/**\n * GET /admin/api/metrics - Real-time metrics for analytics chart\n * Returns JSON with current requests per second from the metrics tracker\n */\nrouter.get('/api/metrics', async (c) => {\n return c.json({\n requestsPerSecond: metricsTracker.getRequestsPerSecond(),\n totalRequests: metricsTracker.getTotalRequests(),\n averageRPS: Number(metricsTracker.getAverageRPS().toFixed(2)),\n timestamp: new Date().toISOString()\n })\n})\n\n/**\n * GET /admin/dashboard/system-status - System status HTML fragment (HTMX endpoint)\n */\nrouter.get('/system-status', async (c) => {\n try {\n const html = `\n \n `\n return c.html(html)\n } catch (error) {\n console.error('Error fetching system status:', error)\n return c.html('Failed to load system status
')\n }\n})\n\nexport { router as adminDashboardRoutes }\n","import { renderAdminLayoutCatalyst, AdminLayoutCatalystData } from '../layouts/admin-layout-catalyst.template'\nimport { renderTable } from '../components/table.template'\n\nexport interface Collection {\n id: string\n name: string\n display_name: string\n description?: string\n created_at: number\n formattedDate: string\n field_count?: number\n managed?: boolean\n}\n\nexport interface CollectionsListPageData {\n collections: Collection[]\n search?: string\n user?: {\n name: string\n email: string\n role: string\n }\n version?: string\n}\n\nexport function renderCollectionsListPage(data: CollectionsListPageData): string {\n const tableData: any = {\n tableId: 'collections-table',\n rowClickable: true,\n rowClickUrl: (collection: Collection) => `/admin/collections/${collection.id}`,\n columns: [\n {\n key: 'name',\n label: 'Name',\n sortable: true,\n sortType: 'string',\n render: (_value: any, collection: any) => `\n \n
\n ${collection.name}\n \n ${collection.managed ? `\n
\n \n \n \n Config\n \n ` : ''}\n
\n `\n },\n {\n key: 'display_name',\n label: 'Display Name',\n sortable: true,\n sortType: 'string'\n },\n {\n key: 'description',\n label: 'Description',\n sortable: true,\n sortType: 'string',\n render: (_value: any, collection: any) => collection.description || '- '\n },\n {\n key: 'field_count',\n label: 'Fields',\n sortable: true,\n sortType: 'number',\n render: (_value: any, collection: any) => {\n const count = collection.field_count || 0\n return `\n \n \n ${count} ${count === 1 ? 'field' : 'fields'}\n \n
\n `\n }\n },\n {\n key: 'managed',\n label: 'Source',\n sortable: true,\n sortType: 'string',\n render: (_value: any, collection: any) => {\n if (collection.managed) {\n return `\n \n `\n } else {\n return `\n \n
\n \n \n \n \n
Database \n
\n `\n }\n }\n },\n {\n key: 'formattedDate',\n label: 'Created',\n sortable: true,\n sortType: 'date'\n },\n {\n key: 'actions',\n label: 'Content',\n sortable: false,\n render: (_value: any, collection: any) => {\n if (!collection || !collection.id) return '- '\n return `\n \n `\n }\n }\n ],\n rows: data.collections,\n emptyMessage: 'No collections found.'\n }\n\n const pageContent = `\n \n \n
\n
\n
Collections \n
Manage your content collections and their schemas
\n
\n
\n
\n\n \n
\n \n
\n\n
\n
\n
\n
\n
\n \n \n \n \n \n Search\n \n \n \n
\n
\n
${data.collections.length} ${data.collections.length === 1 ? 'collection' : 'collections'} \n
\n \n \n \n Refresh\n \n
\n
\n
\n
\n
\n\n \n
\n ${renderTable(tableData)}\n
\n\n \n ${data.collections.length === 0 ? `\n
\n
\n \n \n
No collections found \n
Get started by creating your first collection
\n
\n
\n ` : ''}\n
\n `\n\n const layoutData: AdminLayoutCatalystData = {\n title: 'Collections',\n pageTitle: 'Collections',\n currentPath: '/admin/collections',\n user: data.user,\n version: data.version,\n content: pageContent\n }\n\n return renderAdminLayoutCatalyst(layoutData)\n}","export interface TableColumn {\n key: string\n label: string\n sortable?: boolean\n className?: string\n sortType?: 'string' | 'number' | 'date' | 'boolean'\n render?: (value: any, row: any) => string\n}\n\nexport interface TableData {\n columns: TableColumn[]\n rows: T[]\n selectable?: boolean\n className?: string\n emptyMessage?: string\n tableId?: string\n title?: string\n rowClickable?: boolean\n rowClickUrl?: (row: T) => string\n}\n\nexport function renderTable(data: TableData): string {\n const tableId = data.tableId || `table-${Math.random().toString(36).substr(2, 9)}`\n\n if (data.rows.length === 0) {\n return `\n \n
\n
\n \n \n
${data.emptyMessage || 'No data available'}
\n
\n
\n `\n }\n\n return `\n \n ${data.title ? `\n
\n
${data.title} \n \n ` : ''}\n
\n
\n \n \n ${data.selectable ? `\n \n \n \n ` : ''}\n ${data.columns.map((column, index) => {\n const isFirst = index === 0 && !data.selectable\n const isLast = index === data.columns.length - 1\n return `\n \n ${column.sortable ? `\n \n ${column.label} \n \n \n ` : column.label}\n \n `}).join('')}\n \n \n \n ${data.rows.map((row, rowIndex) => {\n if (!row) return ''\n const clickableClass = data.rowClickable ? 'cursor-pointer' : ''\n const clickHandler = data.rowClickable && data.rowClickUrl ? `onclick=\"window.location.href='${data.rowClickUrl(row)}'\"` : ''\n return `\n \n ${data.selectable ? `\n \n \n \n ` : ''}\n ${data.columns.map((column, colIndex) => {\n const value = (row as any)[column.key]\n const displayValue = column.render ? column.render(value, row) : value\n const stopPropagation = column.key === 'actions' ? 'onclick=\"event.stopPropagation()\"' : ''\n const isFirst = colIndex === 0 && !data.selectable\n const isLast = colIndex === data.columns.length - 1\n return `\n \n ${displayValue || ''}\n \n `\n }).join('')}\n \n `\n }).join('')}\n \n
\n
\n\n \n
\n `\n}","import { renderAdminLayoutCatalyst, AdminLayoutCatalystData } from '../layouts/admin-layout-catalyst.template'\nimport { renderForm, FormData, FormField } from '../form.template'\nimport { renderAlert } from '../components/alert.template'\nimport { renderConfirmationDialog, getConfirmationDialogScript } from '../components/confirmation-dialog.template'\n\nexport interface CollectionField {\n id: string\n field_name: string\n field_type: string\n field_label: string\n field_options: any\n field_order: number\n is_required: boolean\n is_searchable: boolean\n}\n\nexport interface CollectionFormData {\n id?: string\n name?: string\n display_name?: string\n description?: string\n fields?: CollectionField[]\n managed?: boolean\n isEdit?: boolean\n error?: string\n success?: string\n user?: {\n name: string\n email: string\n role: string\n }\n version?: string\n editorPlugins?: {\n tinymce: boolean\n quill: boolean\n easyMdx: boolean\n }\n}\n\n// Helper function to get field type badge with color\nfunction getFieldTypeBadge(fieldType: string): string {\n const typeLabels: Record = {\n 'text': 'Text',\n 'slug': 'URL Slug',\n 'richtext': 'Rich Text (TinyMCE)',\n 'quill': 'Rich Text (Quill)',\n 'mdxeditor': 'EasyMDX',\n 'number': 'Number',\n 'boolean': 'Boolean',\n 'date': 'Date',\n 'select': 'Select',\n 'media': 'Media',\n 'reference': 'Reference'\n }\n const typeColors: Record = {\n 'text': 'bg-blue-500/10 dark:bg-blue-400/10 text-blue-700 dark:text-blue-300 ring-blue-500/20 dark:ring-blue-400/20',\n 'slug': 'bg-sky-500/10 dark:bg-sky-400/10 text-sky-700 dark:text-sky-300 ring-sky-500/20 dark:ring-sky-400/20',\n 'richtext': 'bg-purple-500/10 dark:bg-purple-400/10 text-purple-700 dark:text-purple-300 ring-purple-500/20 dark:ring-purple-400/20',\n 'quill': 'bg-purple-500/10 dark:bg-purple-400/10 text-purple-700 dark:text-purple-300 ring-purple-500/20 dark:ring-purple-400/20',\n 'mdxeditor': 'bg-purple-500/10 dark:bg-purple-400/10 text-purple-700 dark:text-purple-300 ring-purple-500/20 dark:ring-purple-400/20',\n 'number': 'bg-green-500/10 dark:bg-green-400/10 text-green-700 dark:text-green-300 ring-green-500/20 dark:ring-green-400/20',\n 'boolean': 'bg-amber-500/10 dark:bg-amber-400/10 text-amber-700 dark:text-amber-300 ring-amber-500/20 dark:ring-amber-400/20',\n 'date': 'bg-cyan-500/10 dark:bg-cyan-400/10 text-cyan-700 dark:text-cyan-300 ring-cyan-500/20 dark:ring-cyan-400/20',\n 'select': 'bg-indigo-500/10 dark:bg-indigo-400/10 text-indigo-700 dark:text-indigo-300 ring-indigo-500/20 dark:ring-indigo-400/20',\n 'media': 'bg-rose-500/10 dark:bg-rose-400/10 text-rose-700 dark:text-rose-300 ring-rose-500/20 dark:ring-rose-400/20',\n 'reference': 'bg-teal-500/10 dark:bg-teal-400/10 text-teal-700 dark:text-teal-300 ring-teal-500/20 dark:ring-teal-400/20'\n }\n const label = typeLabels[fieldType] || fieldType\n const color = typeColors[fieldType] || 'bg-zinc-500/10 dark:bg-zinc-400/10 text-zinc-700 dark:text-zinc-300 ring-zinc-500/20 dark:ring-zinc-400/20'\n return `${label} `\n}\n\nexport function renderCollectionFormPage(data: CollectionFormData): string {\n console.log('[renderCollectionFormPage] editorPlugins:', data.editorPlugins)\n\n const isEdit = data.isEdit || !!data.id\n const title = isEdit ? 'Edit Collection' : 'Create New Collection'\n const subtitle = isEdit\n ? `Update collection: ${data.display_name}`\n : 'Define a new content collection with custom fields and settings.'\n\n // Pre-compute data attribute for all fields (without badge HTML to avoid escaping issues)\n const fieldsWithData = (data.fields || []).map(field => ({\n ...field,\n dataFieldJSON: JSON.stringify(JSON.stringify(field))\n }))\n\n const fields: FormField[] = [\n {\n name: 'displayName',\n label: 'Display Name',\n type: 'text',\n value: data.display_name || '',\n placeholder: 'Blog Posts',\n required: true,\n readonly: data.managed,\n className: data.managed ? 'bg-zinc-100 dark:bg-zinc-800 text-zinc-500 dark:text-zinc-400 cursor-not-allowed' : ''\n },\n {\n name: 'name',\n label: 'Collection Name',\n type: 'text',\n value: data.name || '',\n placeholder: 'blog_posts',\n required: true,\n readonly: isEdit,\n helpText: isEdit ? 'Collection name cannot be changed' : 'Lowercase letters, numbers, and underscores only',\n className: isEdit ? 'bg-zinc-100 dark:bg-zinc-800 text-zinc-500 dark:text-zinc-400 cursor-not-allowed' : ''\n },\n {\n name: 'description',\n label: 'Description',\n type: 'textarea',\n value: data.description || '',\n placeholder: 'Description of this collection...',\n rows: 3,\n readonly: data.managed,\n className: data.managed ? 'bg-zinc-100 dark:bg-zinc-800 text-zinc-500 dark:text-zinc-400 cursor-not-allowed' : ''\n }\n ]\n\n\n const formData: FormData = {\n id: 'collection-form',\n ...(isEdit\n ? { hxPut: `/admin/collections/${data.id}`, action: `/admin/collections/${data.id}`, method: 'PUT' }\n : { hxPost: '/admin/collections', action: '/admin/collections' }\n ),\n hxTarget: '#form-messages',\n fields: fields,\n submitButtons: data.managed ? [] : [\n {\n label: isEdit ? 'Update Collection' : 'Create Collection',\n type: 'submit',\n className: 'btn-primary'\n }\n ]\n }\n\n const pageContent = `\n \n \n ${data.managed ? `\n
\n
\n
\n \n \n
\n
\n Config-Managed Collection\n \n
\n
This collection is managed by a configuration file and cannot be edited through the admin interface.
\n
\n Config file: \n \n src/collections/${data.name}.collection.ts\n \n
\n
\n To modify this collection's schema, edit the configuration file directly in your code editor.\n
\n
\n
\n
\n
\n ` : ''}\n\n \n
\n
\n
${title} \n
${subtitle}
\n
\n
\n
\n\n \n
\n \n
\n
\n
\n
\n
Collection Details \n
Configure your collection settings below
\n
\n
\n
\n\n \n
\n
\n ${data.error ? renderAlert({ type: 'error', message: data.error, dismissible: true }) : ''}\n ${data.success ? renderAlert({ type: 'success', message: data.success, dismissible: true }) : ''}\n\n \n \n \n ${renderForm(formData)}\n\n ${isEdit && data.managed ? `\n \n
\n
\n
Collection Fields \n
Fields defined in the configuration file (read-only)
\n
\n\n \n
\n ${fieldsWithData.map(field => `\n
\n
\n
\n
\n
\n ${field.field_label} \n ${getFieldTypeBadge(field.field_type)}\n ${field.is_required ? `\n \n Required\n \n ` : ''}\n ${field.is_searchable ? `\n \n Searchable\n \n ` : ''}\n
\n
\n ${field.field_name}\n
\n
\n
\n
\n
\n `).join('')}\n\n ${(data.fields || []).length === 0 ? `\n
\n
\n \n \n
No fields defined
\n
Add fields to your collection configuration file to see them here.
\n
\n ` : ''}\n
\n
\n ` : ''}\n\n ${isEdit && !data.managed ? `\n \n
\n
\n
\n
Collection Fields \n
Define the fields that content in this collection will have
\n
\n
\n \n \n \n Add Field\n \n
\n\n \n
\n ${fieldsWithData.map(field => `\n
\n
\n
\n
\n
\n
\n ${field.field_label} \n ${getFieldTypeBadge(field.field_type)}\n ${field.is_required ? `\n \n Required\n \n ` : ''}\n ${field.is_searchable ? `\n \n Searchable\n \n ` : ''}\n
\n
\n Field name: ${field.field_name}\n
\n
\n
\n
\n
\n \n \n \n Edit\n \n
\n \n \n \n Delete\n \n
\n
\n
\n `).join('')}\n\n ${(data.fields || []).length === 0 ? `\n
\n
\n \n \n
No fields defined
\n
Add your first field to get started
\n
\n ` : ''}\n
\n
\n ` : ''}\n\n ${!isEdit ? `\n
\n
\n
\n \n \n
\n
\n Create Collection First\n \n
\n After creating the collection, you'll be able to add and configure custom fields.\n
\n
\n
\n
\n ` : ''}\n \n \n
\n
\n
\n
\n\n \n \n
\n
\n
\n
Add Field \n
\n \n \n \n \n
\n
\n\n
\n \n\n \n
Field Name \n
\n
Lowercase letters, numbers, and underscores only
\n
\n\n \n
Field Type \n
\n
\n Select field type... \n Text \n URL Slug \n ${data.editorPlugins?.quill ? 'Rich Text (Quill) ' : ''}\n ${data.editorPlugins?.tinymce ? 'Rich Text (TinyMCE) ' : ''}\n ${data.editorPlugins?.easyMdx ? 'EasyMDX ' : ''}\n Number \n Boolean \n Date \n Select \n Media \n Reference \n \n
\n \n \n
\n
\n
\n\n \n Field Label \n \n
\n\n \n\n \n
Field Options (JSON) \n
\n
JSON configuration for field-specific options
\n
\n\n \n \n Cancel\n \n \n Add Field \n \n
\n \n
\n
\n\n \n\n \n ${renderConfirmationDialog({\n id: 'delete-field-confirm',\n title: 'Delete Field',\n message: 'Are you sure you want to delete this field? This action cannot be undone.',\n confirmText: 'Delete',\n cancelText: 'Cancel',\n iconColor: 'red',\n confirmClass: 'bg-red-500 hover:bg-red-400',\n onConfirm: 'performDeleteField()'\n })}\n\n ${getConfirmationDialogScript()}\n `\n\n const layoutData: AdminLayoutCatalystData = {\n title: title,\n pageTitle: 'Collections',\n currentPath: '/admin/collections',\n user: data.user,\n version: data.version,\n content: pageContent\n }\n\n return renderAdminLayoutCatalyst(layoutData)\n}","import { Hono } from 'hono'\nimport { html } from 'hono/html'\nimport { requireAuth } from '../middleware'\nimport { isPluginActive } from '../middleware/plugin-middleware'\nimport { renderCollectionsListPage } from '../templates/pages/admin-collections-list.template'\nimport { renderCollectionFormPage } from '../templates/pages/admin-collections-form.template'\n\n// Type definitions for collections\ninterface Collection {\n id: string\n name: string\n display_name: string\n description?: string\n created_at: number\n formattedDate: string\n field_count?: number\n managed?: boolean\n}\n\ninterface CollectionFormData {\n id?: string\n name?: string\n display_name?: string\n description?: string\n fields?: CollectionField[]\n managed?: boolean\n isEdit?: boolean\n error?: string\n success?: string\n user?: {\n name: string\n email: string\n role: string\n }\n version?: string\n editorPlugins?: {\n tinymce: boolean\n quill: boolean\n easyMdx: boolean\n }\n}\n\ninterface CollectionField {\n id: string\n field_name: string\n field_type: string\n field_label: string\n field_options: any\n field_order: number\n is_required: boolean\n is_searchable: boolean\n}\n\ninterface CollectionsListPageData {\n collections: Collection[]\n search?: string\n user?: {\n name: string\n email: string\n role: string\n }\n version?: string\n}\n\ntype Bindings = {\n DB: D1Database\n CACHE_KV: KVNamespace\n MEDIA_BUCKET: R2Bucket\n ASSETS: Fetcher\n EMAIL_QUEUE?: Queue\n SENDGRID_API_KEY?: string\n DEFAULT_FROM_EMAIL?: string\n IMAGES_ACCOUNT_ID?: string\n IMAGES_API_TOKEN?: string\n ENVIRONMENT?: string\n}\n\ntype Variables = {\n user?: {\n userId: string\n email: string\n role: string\n exp: number\n iat: number\n }\n requestId?: string\n startTime?: number\n appVersion?: string\n}\n\nexport const adminCollectionsRoutes = new Hono<{ Bindings: Bindings; Variables: Variables }>()\n\n// Apply authentication middleware\nadminCollectionsRoutes.use('*', requireAuth())\n\n// Collections management - List all collections\nadminCollectionsRoutes.get('/', async (c) => {\n try {\n const user = c.get('user')\n const db = c.env.DB\n const url = new URL(c.req.url)\n const search = url.searchParams.get('search') || ''\n\n // Build query based on search\n let stmt\n let results\n if (search) {\n stmt = db.prepare(`\n SELECT id, name, display_name, description, created_at, managed, schema\n FROM collections\n WHERE is_active = 1\n AND (name LIKE ? OR display_name LIKE ? OR description LIKE ?)\n ORDER BY created_at DESC\n `)\n const searchParam = `%${search}%`\n const queryResults = await stmt.bind(searchParam, searchParam, searchParam).all()\n results = queryResults.results\n } else {\n stmt = db.prepare('SELECT id, name, display_name, description, created_at, managed, schema FROM collections WHERE is_active = 1 ORDER BY created_at DESC')\n const queryResults = await stmt.all()\n results = queryResults.results\n }\n\n // Fetch field counts for all collections from content_fields table (legacy)\n const fieldCountStmt = db.prepare('SELECT collection_id, COUNT(*) as count FROM content_fields GROUP BY collection_id')\n const { results: fieldCountResults } = await fieldCountStmt.all()\n const fieldCounts = new Map((fieldCountResults || []).map((row: any) => [String(row.collection_id), Number(row.count)]))\n\n const collections: Collection[] = (results || [])\n .filter((row: any) => row && row.id)\n .map((row: any) => {\n // Calculate field count: use schema if available, otherwise use content_fields table\n let fieldCount = 0\n if (row.schema) {\n try {\n const schema = typeof row.schema === 'string' ? JSON.parse(row.schema) : row.schema\n if (schema && schema.properties) {\n fieldCount = Object.keys(schema.properties).length\n }\n } catch (e) {\n // If schema parsing fails, fall back to content_fields count\n fieldCount = fieldCounts.get(String(row.id)) || 0\n }\n } else {\n fieldCount = fieldCounts.get(String(row.id)) || 0\n }\n\n return {\n id: String(row.id || ''),\n name: String(row.name || ''),\n display_name: String(row.display_name || ''),\n description: row.description ? String(row.description) : undefined,\n created_at: Number(row.created_at || 0),\n formattedDate: row.created_at ? new Date(Number(row.created_at)).toLocaleDateString() : 'Unknown',\n field_count: fieldCount,\n managed: row.managed === 1\n }\n })\n\n const pageData: CollectionsListPageData = {\n collections,\n search,\n user: user ? {\n name: user.email,\n email: user.email,\n role: user.role\n } : undefined,\n version: c.get('appVersion')\n }\n\n return c.html(renderCollectionsListPage(pageData))\n } catch (error) {\n console.error('Error fetching collections:', error)\n const errorMessage = error instanceof Error ? error.message : String(error)\n return c.html(html`Error loading collections: ${errorMessage}
`)\n }\n})\n\n// New collection form\nadminCollectionsRoutes.get('/new', async (c) => {\n const user = c.get('user')\n const db = c.env.DB\n\n // Check which editor plugins are active\n const [tinymceActive, quillActive, mdxeditorActive] = await Promise.all([\n isPluginActive(db, 'tinymce-plugin'),\n isPluginActive(db, 'quill-editor'),\n isPluginActive(db, 'easy-mdx')\n ])\n\n console.log('[Collections /new] Editor plugins status:', {\n tinymce: tinymceActive,\n quill: quillActive,\n easyMdx: mdxeditorActive\n })\n\n const formData: CollectionFormData = {\n isEdit: false,\n user: user ? {\n name: user.email,\n email: user.email,\n role: user.role\n } : undefined,\n version: c.get('appVersion'),\n editorPlugins: {\n tinymce: tinymceActive,\n quill: quillActive,\n easyMdx: mdxeditorActive\n }\n }\n\n return c.html(renderCollectionFormPage(formData))\n})\n\n// Create collection\nadminCollectionsRoutes.post('/', async (c) => {\n try {\n const formData = await c.req.formData()\n const name = formData.get('name') as string\n const displayName = formData.get('displayName') as string\n const description = formData.get('description') as string\n\n // Check if this is an HTMX request\n const isHtmx = c.req.header('HX-Request') === 'true'\n\n // Basic validation\n if (!name || !displayName) {\n const errorMsg = 'Name and display name are required.'\n if (isHtmx) {\n return c.html(html`\n \n ${errorMsg}\n
\n `)\n } else {\n // For regular form submission, redirect back with error\n return c.redirect('/admin/collections/new')\n }\n }\n\n // Validate name format\n if (!/^[a-z0-9_]+$/.test(name)) {\n const errorMsg = 'Collection name must contain only lowercase letters, numbers, and underscores.'\n if (isHtmx) {\n return c.html(html`\n \n ${errorMsg}\n
\n `)\n } else {\n return c.redirect('/admin/collections/new')\n }\n }\n\n const db = c.env.DB\n\n // Check if collection already exists\n const existingStmt = db.prepare('SELECT id FROM collections WHERE name = ?')\n const existing = await existingStmt.bind(name).first()\n\n if (existing) {\n const errorMsg = 'A collection with this name already exists.'\n if (isHtmx) {\n return c.html(html`\n \n ${errorMsg}\n
\n `)\n } else {\n return c.redirect('/admin/collections/new')\n }\n }\n\n // Create basic schema for the collection\n const basicSchema = {\n type: \"object\",\n properties: {\n title: {\n type: \"string\",\n title: \"Title\",\n required: true\n },\n content: {\n type: \"string\",\n title: \"Content\",\n format: \"richtext\"\n },\n status: {\n type: \"string\",\n title: \"Status\",\n enum: [\"draft\", \"published\", \"archived\"],\n default: \"draft\"\n }\n },\n required: [\"title\"]\n }\n\n // Create collection\n const collectionId = crypto.randomUUID()\n const now = Date.now()\n\n const insertStmt = db.prepare(`\n INSERT INTO collections (id, name, display_name, description, schema, is_active, created_at, updated_at)\n VALUES (?, ?, ?, ?, ?, ?, ?, ?)\n `)\n\n await insertStmt.bind(\n collectionId,\n name,\n displayName,\n description || null,\n JSON.stringify(basicSchema),\n 1, // is_active\n now,\n now\n ).run()\n\n // Clear cache (only if CACHE_KV is available)\n if (c.env.CACHE_KV) {\n try {\n await c.env.CACHE_KV.delete('cache:collections:all')\n await c.env.CACHE_KV.delete(`cache:collection:${name}`)\n } catch (e) {\n console.error('Error clearing cache:', e)\n }\n }\n\n if (isHtmx) {\n return c.html(html`\n \n Collection created successfully! Redirecting to edit mode...\n \n
\n `)\n } else {\n // For regular form submission, redirect to edit page\n return c.redirect(`/admin/collections/${collectionId}`)\n }\n } catch (error) {\n console.error('Error creating collection:', error)\n const isHtmx = c.req.header('HX-Request') === 'true'\n\n if (isHtmx) {\n return c.html(html`\n \n Failed to create collection. Please try again.\n
\n `)\n } else {\n return c.redirect('/admin/collections/new')\n }\n }\n})\n\n// Edit collection form\nadminCollectionsRoutes.get('/:id', async (c) => {\n const db = c.env.DB\n try {\n const id = c.req.param('id')\n const user = c.get('user')\n\n const stmt = db.prepare('SELECT * FROM collections WHERE id = ?')\n const collection = await stmt.bind(id).first() as any\n\n if (!collection) {\n // Check which editor plugins are active\n const [tinymceActive, quillActive, mdxeditorActive] = await Promise.all([\n isPluginActive(db, 'tinymce-plugin'),\n isPluginActive(db, 'quill-editor'),\n isPluginActive(db, 'easy-mdx')\n ])\n\n const formData: CollectionFormData = {\n isEdit: true,\n error: 'Collection not found.',\n user: user ? {\n name: user.email,\n email: user.email,\n role: user.role\n } : undefined,\n version: c.get('appVersion'),\n editorPlugins: {\n tinymce: tinymceActive,\n quill: quillActive,\n easyMdx: mdxeditorActive\n }\n }\n return c.html(renderCollectionFormPage(formData))\n }\n\n // Get collection fields - try schema first, then content_fields table\n let fields: CollectionField[] = []\n\n // If collection has a schema, parse it\n if (collection.schema) {\n try {\n const schema = typeof collection.schema === 'string' ? JSON.parse(collection.schema) : collection.schema\n if (schema && schema.properties) {\n // Convert schema properties to field format\n let fieldOrder = 0\n fields = Object.entries(schema.properties).map(([fieldName, fieldConfig]: [string, any]) => {\n // Normalize schema formats to UI field types\n // Check explicit editor types first (quill, mdxeditor) before format-based detection\n let fieldType = fieldConfig.type || 'string'\n if (fieldConfig.type === 'quill' || fieldConfig.type === 'mdxeditor') {\n fieldType = fieldConfig.type\n } else if (fieldConfig.enum) {\n fieldType = 'select'\n } else if (fieldConfig.format === 'richtext') {\n fieldType = 'richtext'\n } else if (fieldConfig.format === 'media') {\n fieldType = 'media'\n } else if (fieldConfig.format === 'date-time') {\n fieldType = 'date'\n } else if (fieldConfig.type === 'slug' || fieldConfig.format === 'slug') {\n fieldType = 'slug'\n }\n \n return {\n id: `schema-${fieldName}`,\n field_name: fieldName,\n field_type: fieldType,\n field_label: fieldConfig.title || fieldName,\n field_options: fieldConfig,\n field_order: fieldOrder++,\n is_required: fieldConfig.required === true || (schema.required && schema.required.includes(fieldName)),\n is_searchable: fieldConfig.searchable === true || false\n }\n })\n }\n } catch (e) {\n console.error('Error parsing collection schema:', e)\n }\n }\n\n // Fall back to content_fields table if no schema or parsing failed\n if (fields.length === 0) {\n const fieldsStmt = db.prepare(`\n SELECT * FROM content_fields\n WHERE collection_id = ?\n ORDER BY field_order ASC\n `)\n const { results: fieldsResults } = await fieldsStmt.bind(id).all()\n fields = (fieldsResults || []).map((row: any) => {\n let fieldOptions = {}\n if (row.field_options) {\n try {\n fieldOptions = typeof row.field_options === 'string' ? JSON.parse(row.field_options) : row.field_options\n } catch (e) {\n console.error('Error parsing field_options for field:', row.field_name, e)\n fieldOptions = {}\n }\n }\n return {\n id: row.id,\n field_name: row.field_name,\n field_type: row.field_type,\n field_label: row.field_label,\n field_options: fieldOptions,\n field_order: row.field_order,\n is_required: row.is_required === 1,\n is_searchable: row.is_searchable === 1\n }\n })\n }\n\n // Check which editor plugins are active\n const [tinymceActive, quillActive, mdxeditorActive] = await Promise.all([\n isPluginActive(db, 'tinymce-plugin'),\n isPluginActive(db, 'quill-editor'),\n isPluginActive(db, 'easy-mdx')\n ])\n\n console.log('[Collections /:id] Editor plugins status:', {\n tinymce: tinymceActive,\n quill: quillActive,\n easyMdx: mdxeditorActive\n })\n\n const formData: CollectionFormData = {\n id: collection.id,\n name: collection.name,\n display_name: collection.display_name,\n description: collection.description,\n fields: fields,\n managed: collection.managed === 1,\n isEdit: true,\n user: user ? {\n name: user.email,\n email: user.email,\n role: user.role\n } : undefined,\n version: c.get('appVersion'),\n editorPlugins: {\n tinymce: tinymceActive,\n quill: quillActive,\n easyMdx: mdxeditorActive\n }\n }\n\n return c.html(renderCollectionFormPage(formData))\n } catch (error) {\n console.error('Error fetching collection:', error)\n const user = c.get('user')\n\n // Check which editor plugins are active (even in error state)\n const [tinymceActive, quillActive, mdxeditorActive] = await Promise.all([\n isPluginActive(db, 'tinymce-plugin'),\n isPluginActive(db, 'quill-editor'),\n isPluginActive(db, 'easy-mdx')\n ])\n\n const formData: CollectionFormData = {\n isEdit: true,\n error: 'Failed to load collection.',\n user: user ? {\n name: user.email,\n email: user.email,\n role: user.role\n } : undefined,\n version: c.get('appVersion'),\n editorPlugins: {\n tinymce: tinymceActive,\n quill: quillActive,\n easyMdx: mdxeditorActive\n }\n }\n return c.html(renderCollectionFormPage(formData))\n }\n})\n\n// Update collection\nadminCollectionsRoutes.put('/:id', async (c) => {\n try {\n const id = c.req.param('id')\n const formData = await c.req.formData()\n const displayName = formData.get('displayName') as string\n const description = formData.get('description') as string\n\n if (!displayName) {\n return c.html(html`\n \n Display name is required.\n
\n `)\n }\n\n const db = c.env.DB\n\n const updateStmt = db.prepare(`\n UPDATE collections\n SET display_name = ?, description = ?, updated_at = ?\n WHERE id = ?\n `)\n\n await updateStmt.bind(displayName, description || null, Date.now(), id).run()\n\n return c.html(html`\n \n Collection updated successfully!\n
\n `)\n } catch (error) {\n console.error('Error updating collection:', error)\n return c.html(html`\n \n Failed to update collection. Please try again.\n
\n `)\n }\n})\n\n// Delete collection\nadminCollectionsRoutes.delete('/:id', async (c) => {\n try {\n const id = c.req.param('id')\n const db = c.env.DB\n\n // Check if collection has content\n const contentStmt = db.prepare('SELECT COUNT(*) as count FROM content WHERE collection_id = ?')\n const contentResult = await contentStmt.bind(id).first() as any\n\n if (contentResult && contentResult.count > 0) {\n return c.html(html`\n \n Cannot delete collection: it contains ${contentResult.count} content item(s). Delete all content first.\n
\n `)\n }\n\n // Delete collection fields first\n const deleteFieldsStmt = db.prepare('DELETE FROM content_fields WHERE collection_id = ?')\n await deleteFieldsStmt.bind(id).run()\n\n // Delete collection\n const deleteStmt = db.prepare('DELETE FROM collections WHERE id = ?')\n await deleteStmt.bind(id).run()\n\n return c.html(html`\n \n `)\n } catch (error) {\n console.error('Error deleting collection:', error)\n return c.html(html`\n \n Failed to delete collection. Please try again.\n
\n `)\n }\n})\n\n// Add field to collection\nadminCollectionsRoutes.post('/:id/fields', async (c) => {\n try {\n const collectionId = c.req.param('id')\n const formData = await c.req.formData()\n const fieldName = formData.get('field_name') as string\n const fieldType = formData.get('field_type') as string\n const fieldLabel = formData.get('field_label') as string\n const isRequired = formData.get('is_required') === '1'\n const isSearchable = formData.get('is_searchable') === '1'\n const fieldOptions = formData.get('field_options') as string || '{}'\n\n if (!fieldName || !fieldType || !fieldLabel) {\n return c.json({ success: false, error: 'Field name, type, and label are required.' })\n }\n\n // Validate field name format\n if (!/^[a-z0-9_]+$/.test(fieldName)) {\n return c.json({ success: false, error: 'Field name must contain only lowercase letters, numbers, and underscores.' })\n }\n\n const db = c.env.DB\n\n // Get current collection to check its schema\n const getCollectionStmt = db.prepare('SELECT * FROM collections WHERE id = ?')\n const collection = await getCollectionStmt.bind(collectionId).first() as any\n\n if (!collection) {\n return c.json({ success: false, error: 'Collection not found.' })\n }\n\n // Check if field already exists in schema\n let schema = collection.schema ? (typeof collection.schema === 'string' ? JSON.parse(collection.schema) : collection.schema) : null\n\n if (schema && schema.properties && schema.properties[fieldName]) {\n return c.json({ success: false, error: 'A field with this name already exists.' })\n }\n\n // Also check content_fields table for legacy support\n const existingStmt = db.prepare('SELECT id FROM content_fields WHERE collection_id = ? AND field_name = ?')\n const existing = await existingStmt.bind(collectionId, fieldName).first()\n\n if (existing) {\n return c.json({ success: false, error: 'A field with this name already exists.' })\n }\n\n // Parse field options\n let parsedOptions = {}\n try {\n parsedOptions = fieldOptions ? JSON.parse(fieldOptions) : {}\n } catch (e) {\n console.error('Error parsing field options:', e)\n }\n\n // Add field to schema (primary storage method)\n if (schema) {\n if (!schema.properties) {\n schema.properties = {}\n }\n if (!schema.required) {\n schema.required = []\n }\n\n // Build field config based on type\n const fieldConfig: any = {\n type: fieldType === 'number' ? 'number' : fieldType === 'boolean' ? 'boolean' : 'string',\n title: fieldLabel,\n searchable: isSearchable,\n ...parsedOptions\n }\n\n // Handle special field types\n if (fieldType === 'richtext') {\n fieldConfig.format = 'richtext'\n } else if (fieldType === 'date') {\n fieldConfig.format = 'date-time'\n } else if (fieldType === 'select') {\n fieldConfig.enum = (parsedOptions as any).options || []\n } else if (fieldType === 'media') {\n fieldConfig.format = 'media'\n } else if (fieldType === 'slug') {\n fieldConfig.type = 'slug'\n fieldConfig.format = 'slug'\n } else if (fieldType === 'quill') {\n fieldConfig.type = 'quill'\n } else if (fieldType === 'mdxeditor') {\n fieldConfig.type = 'mdxeditor'\n } else if (fieldType === 'reference') {\n fieldConfig.type = 'reference'\n }\n\n schema.properties[fieldName] = fieldConfig\n\n // Add to required array if needed\n if (isRequired && !schema.required.includes(fieldName)) {\n schema.required.push(fieldName)\n }\n\n // Update collection schema in database\n const updateSchemaStmt = db.prepare(`\n UPDATE collections\n SET schema = ?, updated_at = ?\n WHERE id = ?\n `)\n\n await updateSchemaStmt.bind(JSON.stringify(schema), Date.now(), collectionId).run()\n\n console.log('[Add Field] Added field to schema:', fieldName, fieldConfig)\n\n return c.json({ success: true, fieldId: `schema-${fieldName}` })\n }\n\n // Fallback: If no schema exists, use content_fields table\n // Get next field order\n const orderStmt = db.prepare('SELECT MAX(field_order) as max_order FROM content_fields WHERE collection_id = ?')\n const orderResult = await orderStmt.bind(collectionId).first() as any\n const nextOrder = (orderResult?.max_order || 0) + 1\n\n // Create field in content_fields table\n const fieldId = crypto.randomUUID()\n const now = Date.now()\n\n const insertStmt = db.prepare(`\n INSERT INTO content_fields (\n id, collection_id, field_name, field_type, field_label,\n field_options, field_order, is_required, is_searchable,\n created_at, updated_at\n ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\n `)\n\n await insertStmt.bind(\n fieldId,\n collectionId,\n fieldName,\n fieldType,\n fieldLabel,\n fieldOptions,\n nextOrder,\n isRequired ? 1 : 0,\n isSearchable ? 1 : 0,\n now,\n now\n ).run()\n\n return c.json({ success: true, fieldId })\n } catch (error) {\n console.error('Error adding field:', error)\n return c.json({ success: false, error: 'Failed to add field.' })\n }\n})\n\n// Update field\nadminCollectionsRoutes.put('/:collectionId/fields/:fieldId', async (c) => {\n try {\n const fieldId = c.req.param('fieldId')\n const collectionId = c.req.param('collectionId')\n const formData = await c.req.formData()\n const fieldLabel = formData.get('field_label') as string\n const fieldType = formData.get('field_type') as string\n // Use getAll() to handle hidden input + checkbox pattern (get last value)\n const isRequiredValues = formData.getAll('is_required')\n const isSearchableValues = formData.getAll('is_searchable')\n const isRequired = isRequiredValues[isRequiredValues.length - 1] === '1'\n const isSearchable = isSearchableValues[isSearchableValues.length - 1] === '1'\n const fieldOptions = formData.get('field_options') as string || '{}'\n\n // Log all form data for debugging\n console.log('[Field Update] Field ID:', fieldId)\n console.log('[Field Update] Form data received:', {\n field_label: fieldLabel,\n field_type: fieldType,\n is_required: formData.get('is_required'),\n is_searchable: formData.get('is_searchable'),\n field_options: fieldOptions\n })\n\n if (!fieldLabel) {\n return c.json({ success: false, error: 'Field label is required.' })\n }\n\n const db = c.env.DB\n\n // Check if this is a schema field (starts with \"schema-\")\n if (fieldId.startsWith('schema-')) {\n // Schema fields are part of the collection's JSON schema\n // We need to update the collection's schema in the database\n const fieldName = fieldId.replace('schema-', '')\n\n console.log('[Field Update] Updating schema field:', fieldName)\n\n // Get the current collection\n const getCollectionStmt = db.prepare('SELECT * FROM collections WHERE id = ?')\n const collection = await getCollectionStmt.bind(collectionId).first()\n\n if (!collection) {\n return c.json({ success: false, error: 'Collection not found.' })\n }\n\n // Parse the current schema\n let schema = typeof collection.schema === 'string' ? JSON.parse(collection.schema) : collection.schema\n if (!schema) {\n schema = { type: 'object', properties: {}, required: [] }\n }\n if (!schema.properties) {\n schema.properties = {}\n }\n if (!schema.required) {\n schema.required = []\n }\n\n // Update the field in the schema\n if (schema.properties[fieldName]) {\n // Parse field options from form\n let parsedFieldOptions: Record = {}\n try {\n parsedFieldOptions = JSON.parse(fieldOptions)\n } catch (e) {\n console.error('[Field Update] Error parsing field options:', e)\n }\n\n // Build the updated field config - merge in field options\n const updatedFieldConfig: any = {\n ...schema.properties[fieldName],\n ...parsedFieldOptions,\n type: fieldType,\n title: fieldLabel,\n searchable: isSearchable\n }\n\n // Clean up format when switching editor types\n // e.g., switching from TinyMCE (format: 'richtext') to Quill (type: 'quill')\n if (fieldType === 'quill' || fieldType === 'mdxeditor') {\n delete updatedFieldConfig.format\n } else if (fieldType === 'richtext') {\n // TinyMCE uses type: 'string' + format: 'richtext'\n updatedFieldConfig.type = 'string'\n updatedFieldConfig.format = 'richtext'\n }\n\n // Also set/remove the individual required property on the field\n // This ensures consistency regardless of which format is checked in GET\n if (isRequired) {\n updatedFieldConfig.required = true\n } else {\n delete updatedFieldConfig.required\n }\n\n schema.properties[fieldName] = updatedFieldConfig\n\n // Handle required field in the schema's required array (proper JSON Schema way)\n const requiredIndex = schema.required.indexOf(fieldName)\n console.log('[Field Update] Required field handling:', {\n fieldName,\n isRequired,\n currentRequiredArray: schema.required,\n requiredIndex\n })\n\n if (isRequired && requiredIndex === -1) {\n // Add to required array if checked and not already there\n schema.required.push(fieldName)\n console.log('[Field Update] Added field to required array')\n } else if (!isRequired && requiredIndex !== -1) {\n // Remove from required array if unchecked and currently there\n schema.required.splice(requiredIndex, 1)\n console.log('[Field Update] Removed field from required array')\n }\n\n console.log('[Field Update] Final required array:', schema.required)\n console.log('[Field Update] Final field config:', schema.properties[fieldName])\n }\n\n // Update the collection in the database\n const updateCollectionStmt = db.prepare(`\n UPDATE collections\n SET schema = ?, updated_at = ?\n WHERE id = ?\n `)\n\n const result = await updateCollectionStmt.bind(JSON.stringify(schema), Date.now(), collectionId).run()\n\n console.log('[Field Update] Schema update result:', {\n success: result.success,\n changes: result.meta?.changes\n })\n\n return c.json({ success: true })\n }\n\n // For regular database fields\n const updateStmt = db.prepare(`\n UPDATE content_fields\n SET field_label = ?, field_type = ?, field_options = ?, is_required = ?, is_searchable = ?, updated_at = ?\n WHERE id = ?\n `)\n\n const result = await updateStmt.bind(fieldLabel, fieldType, fieldOptions, isRequired ? 1 : 0, isSearchable ? 1 : 0, Date.now(), fieldId).run()\n\n console.log('[Field Update] Update result:', {\n success: result.success,\n meta: result.meta,\n changes: result.meta?.changes,\n last_row_id: result.meta?.last_row_id\n })\n\n // Verify the update by reading back the field\n const verifyStmt = db.prepare('SELECT * FROM content_fields WHERE id = ?')\n const verifyResult = await verifyStmt.bind(fieldId).first()\n console.log('[Field Update] Verification - field after update:', verifyResult)\n\n console.log('[Field Update] Successfully updated field with type:', fieldType)\n\n return c.json({ success: true })\n } catch (error) {\n console.error('Error updating field:', error)\n return c.json({ success: false, error: 'Failed to update field.' })\n }\n})\n\n// Delete field\nadminCollectionsRoutes.delete('/:collectionId/fields/:fieldId', async (c) => {\n try {\n const fieldId = c.req.param('fieldId')\n const collectionId = c.req.param('collectionId')\n const db = c.env.DB\n\n // Check if this is a schema field (starts with \"schema-\")\n if (fieldId.startsWith('schema-')) {\n const fieldName = fieldId.replace('schema-', '')\n\n // Get the current collection\n const getCollectionStmt = db.prepare('SELECT * FROM collections WHERE id = ?')\n const collection = await getCollectionStmt.bind(collectionId).first() as any\n\n if (!collection) {\n return c.json({ success: false, error: 'Collection not found.' })\n }\n\n // Parse the current schema\n let schema = typeof collection.schema === 'string' ? JSON.parse(collection.schema) : collection.schema\n if (!schema || !schema.properties) {\n return c.json({ success: false, error: 'Field not found in schema.' })\n }\n\n // Remove field from schema\n if (schema.properties[fieldName]) {\n delete schema.properties[fieldName]\n\n // Also remove from required array if present\n if (schema.required && Array.isArray(schema.required)) {\n const requiredIndex = schema.required.indexOf(fieldName)\n if (requiredIndex !== -1) {\n schema.required.splice(requiredIndex, 1)\n }\n }\n\n // Update the collection in the database\n const updateCollectionStmt = db.prepare(`\n UPDATE collections\n SET schema = ?, updated_at = ?\n WHERE id = ?\n `)\n\n await updateCollectionStmt.bind(JSON.stringify(schema), Date.now(), collectionId).run()\n\n console.log('[Delete Field] Removed field from schema:', fieldName)\n\n return c.json({ success: true })\n } else {\n return c.json({ success: false, error: 'Field not found in schema.' })\n }\n }\n\n // For regular database fields\n const deleteStmt = db.prepare('DELETE FROM content_fields WHERE id = ?')\n await deleteStmt.bind(fieldId).run()\n\n return c.json({ success: true })\n } catch (error) {\n console.error('Error deleting field:', error)\n return c.json({ success: false, error: 'Failed to delete field.' })\n }\n})\n\n// Update field order\nadminCollectionsRoutes.post('/:collectionId/fields/reorder', async (c) => {\n try {\n const body = await c.req.json()\n const fieldIds = body.fieldIds as string[]\n\n if (!Array.isArray(fieldIds)) {\n return c.json({ success: false, error: 'Invalid field order data.' })\n }\n\n const db = c.env.DB\n\n // Update field order\n for (let i = 0; i < fieldIds.length; i++) {\n const updateStmt = db.prepare('UPDATE content_fields SET field_order = ?, updated_at = ? WHERE id = ?')\n await updateStmt.bind(i + 1, Date.now(), fieldIds[i]).run()\n }\n\n return c.json({ success: true })\n } catch (error) {\n console.error('Error reordering fields:', error)\n return c.json({ success: false, error: 'Failed to reorder fields.' })\n }\n})\n","import { renderAdminLayoutCatalyst, AdminLayoutCatalystData } from '../layouts/admin-layout-catalyst.template'\nimport { renderConfirmationDialog, getConfirmationDialogScript } from '../components/confirmation-dialog.template'\n\nexport interface SettingsPageData {\n user?: {\n name: string\n email: string\n role: string\n }\n settings?: {\n general?: GeneralSettings\n appearance?: AppearanceSettings\n security?: SecuritySettings\n notifications?: NotificationSettings\n storage?: StorageSettings\n migrations?: MigrationSettings\n databaseTools?: DatabaseToolsSettings\n }\n activeTab?: string\n version?: string\n}\n\nexport interface GeneralSettings {\n siteName: string\n siteDescription: string\n adminEmail: string\n timezone: string\n language: string\n maintenanceMode: boolean\n}\n\nexport interface AppearanceSettings {\n theme: 'light' | 'dark' | 'auto'\n primaryColor: string\n logoUrl: string\n favicon: string\n customCSS: string\n}\n\nexport interface SecuritySettings {\n twoFactorEnabled: boolean\n sessionTimeout: number\n passwordRequirements: {\n minLength: number\n requireUppercase: boolean\n requireNumbers: boolean\n requireSymbols: boolean\n }\n ipWhitelist: string[]\n}\n\nexport interface NotificationSettings {\n emailNotifications: boolean\n contentUpdates: boolean\n systemAlerts: boolean\n userRegistrations: boolean\n emailFrequency: 'immediate' | 'daily' | 'weekly'\n}\n\nexport interface StorageSettings {\n maxFileSize: number\n allowedFileTypes: string[]\n storageProvider: 'local' | 'cloudflare' | 's3'\n backupFrequency: 'daily' | 'weekly' | 'monthly'\n retentionPeriod: number\n}\n\nexport interface MigrationSettings {\n totalMigrations: number\n appliedMigrations: number\n pendingMigrations: number\n lastApplied?: string\n migrations: Array<{\n id: string\n name: string\n filename: string\n description?: string\n applied: boolean\n appliedAt?: string\n size?: number\n }>\n}\n\nexport interface DatabaseToolsSettings {\n totalTables: number\n totalRows: number\n lastBackup?: string\n databaseSize?: string\n tables: Array<{\n name: string\n rowCount: number\n }>\n}\n\nexport function renderSettingsPage(data: SettingsPageData): string {\n const activeTab = data.activeTab || 'general'\n \n const pageContent = `\n \n \n
\n
\n
Settings \n
Manage your application settings and preferences
\n
\n
\n\n \n
\n
\n \n ${renderTabButton('general', 'General', 'M10.325 4.317c.426-1.756 2.924-1.756 3.35 0a1.724 1.724 0 002.573 1.066c1.543-.94 3.31.826 2.37 2.37a1.724 1.724 0 001.065 2.572c1.756.426 1.756 2.924 0 3.35a1.724 1.724 0 00-1.066 2.573c.94 1.543-.826 3.31-2.37 2.37a1.724 1.724 0 00-2.572 1.065c-.426 1.756-2.924 1.756-3.35 0a1.724 1.724 0 00-2.573-1.066c-1.543.94-3.31-.826-2.37-2.37a1.724 1.724 0 00-1.065-2.572c-1.756-.426-1.756-2.924 0-3.35a1.724 1.724 0 001.066-2.573c-.94-1.543.826-3.31 2.37-2.37.996.608 2.296.07 2.572-1.065z M15 12a3 3 0 11-6 0 3 3 0 016 0z', activeTab)}\n ${renderTabButton('appearance', 'Appearance', 'M7 21a4 4 0 01-4-4V5a2 2 0 012-2h4a2 2 0 012 2v12a4 4 0 01-4 4zM21 5a2 2 0 00-2-2h-4a2 2 0 00-2 2v12a4 4 0 004 4h4a2 2 0 002-2V5z', activeTab)}\n ${renderTabButton('security', 'Security', 'M12 15v2m-6 4h12a2 2 0 002-2v-6a2 2 0 00-2-2H6a2 2 0 00-2 2v6a2 2 0 002 2zm10-10V7a4 4 0 00-8 0v4h8z', activeTab)}\n ${renderTabButton('notifications', 'Notifications', 'M15 17h5l-1.405-1.405A2.032 2.032 0 0118 14.158V11a6.002 6.002 0 00-4-5.659V5a2 2 0 10-4 0v.341C7.67 6.165 6 8.388 6 11v3.159c0 .538-.214 1.055-.595 1.436L4 17h5m6 0v1a3 3 0 11-6 0v-1m6 0H9', activeTab)}\n ${renderTabButton('storage', 'Storage', 'M7 16a4 4 0 01-.88-7.903A5 5 0 1115.9 6L16 6a5 5 0 011 9.9M15 13l-3-3m0 0l-3 3m3-3v12', activeTab)}\n ${renderTabButton('migrations', 'Migrations', 'M4 7v10c0 2.21 3.582 4 8 4s8-1.79 8-4V7M4 7c0 2.21 3.582 4 8 4s8-1.79 8-4M4 7c0-2.21 3.582-4 8-4s8 1.79 8 4m0 5c0 2.21-3.582 4-8 4s-8-1.79-8-4', activeTab)}\n ${renderTabButton('database-tools', 'Database Tools', 'M5 12h14M5 12a2 2 0 01-2-2V6a2 2 0 012-2h14a2 2 0 012 2v4a2 2 0 01-2 2M5 12a2 2 0 00-2 2v4a2 2 0 002 2h14a2 2 0 002-2v-4a2 2 0 00-2-2m-2-4h.01M17 16h.01', activeTab)}\n \n
\n
\n\n \n
\n
\n ${renderTabContent(activeTab, data.settings)}\n
\n
\n
\n\n \n\n \n ${renderConfirmationDialog({\n id: 'run-migrations-confirm',\n title: 'Run Migrations',\n message: 'Are you sure you want to run pending migrations? This action cannot be undone.',\n confirmText: 'Run Migrations',\n cancelText: 'Cancel',\n iconColor: 'blue',\n confirmClass: 'bg-blue-500 hover:bg-blue-400',\n onConfirm: 'performRunMigrations()'\n })}\n\n ${getConfirmationDialogScript()}\n `\n\n const layoutData: AdminLayoutCatalystData = {\n title: 'Settings',\n pageTitle: 'Settings',\n currentPath: '/admin/settings',\n user: data.user,\n version: data.version,\n content: pageContent\n }\n\n return renderAdminLayoutCatalyst(layoutData)\n}\n\nfunction renderTabButton(tabId: string, label: string, iconPath: string, activeTab: string): string {\n const isActive = activeTab === tabId\n const baseClasses = 'flex items-center space-x-2 px-4 py-3 text-sm font-medium transition-colors border-b-2 whitespace-nowrap no-underline'\n const activeClasses = isActive\n ? 'border-zinc-950 dark:border-white text-zinc-950 dark:text-white'\n : 'border-transparent text-zinc-500 dark:text-zinc-400 hover:text-zinc-700 dark:hover:text-zinc-300 hover:border-zinc-300 dark:hover:border-zinc-700'\n\n return `\n \n \n \n \n ${label} \n \n `\n}\n\nfunction renderTabContent(activeTab: string, settings?: SettingsPageData['settings']): string {\n switch (activeTab) {\n case 'general':\n return renderGeneralSettings(settings?.general)\n case 'appearance':\n return renderAppearanceSettings(settings?.appearance)\n case 'security':\n return renderSecuritySettings(settings?.security)\n case 'notifications':\n return renderNotificationSettings(settings?.notifications)\n case 'storage':\n return renderStorageSettings(settings?.storage)\n case 'migrations':\n return renderMigrationSettings(settings?.migrations)\n case 'database-tools':\n return renderDatabaseToolsSettings(settings?.databaseTools)\n default:\n return renderGeneralSettings(settings?.general)\n }\n}\n\nfunction renderGeneralSettings(settings?: GeneralSettings): string {\n return `\n \n
\n
General Settings \n
Configure basic application settings and preferences.
\n
\n \n
\n
\n
\n Site Name \n \n
\n\n
\n Admin Email \n \n
\n\n
\n Timezone \n \n UTC \n Eastern Time \n Central Time \n Mountain Time \n Pacific Time \n \n
\n
\n\n
\n
\n Site Description \n ${settings?.siteDescription || ''} \n
\n\n
\n Language \n \n English \n Spanish \n French \n German \n \n
\n \n
\n
\n
\n \n Enable maintenance mode\n \n
\n
\n
\n
\n\n \n
\n
\n \n \n \n Save Changes\n \n
\n
\n `\n}\n\nfunction renderAppearanceSettings(settings?: AppearanceSettings): string {\n return `\n \n \n
\n
\n
\n \n \n
\n
Work in Progress \n
\n This settings section is currently under development and provided for reference and design feedback only. Changes made here will not be saved.\n
\n
\n
\n
\n\n
\n
Appearance Settings \n
Customize the look and feel of your application.
\n
\n \n
\n
\n
\n \n
\n \n
\n Logo URL \n \n
\n
\n \n
\n
\n Favicon URL \n \n
\n \n
\n Custom CSS \n ${settings?.customCSS || ''} \n
\n
\n
\n\n \n
\n
\n \n \n \n Save Changes\n \n
\n
\n `\n}\n\nfunction renderSecuritySettings(settings?: SecuritySettings): string {\n return `\n \n \n
\n
\n
\n \n \n
\n
Work in Progress \n
\n This settings section is currently under development and provided for reference and design feedback only. Changes made here will not be saved.\n
\n
\n
\n
\n\n
\n
Security Settings \n
Configure security and authentication settings.
\n
\n \n
\n
\n
\n
\n
\n \n Enable Two-Factor Authentication\n \n
\n
\n \n
\n Session Timeout (minutes) \n \n
\n \n
\n
Password Requirements \n
\n
\n
\n
\n Require uppercase letters \n
\n
\n
\n
\n
\n Require numbers \n
\n
\n
\n
\n
\n Require symbols \n
\n
\n
\n
\n
\n \n
\n
\n Minimum Password Length \n \n
\n \n
\n
IP Whitelist \n
${settings?.ipWhitelist?.join('\\n') || ''} \n
Leave empty to allow all IPs
\n
\n
\n
\n\n \n
\n
\n \n \n \n Save Changes\n \n
\n
\n `\n}\n\nfunction renderNotificationSettings(settings?: NotificationSettings): string {\n return `\n \n \n
\n
\n
\n \n \n
\n
Work in Progress \n
\n This settings section is currently under development and provided for reference and design feedback only. Changes made here will not be saved.\n
\n
\n
\n
\n\n
\n
Notification Settings \n
Configure how and when you receive notifications.
\n
\n \n
\n
\n
\n
Email Notifications \n
\n
\n
\n
\n Enable email notifications \n
\n
\n\n
\n
\n
\n Content updates \n
\n
\n\n
\n
\n
\n System alerts \n
\n
\n\n
\n
\n
\n New user registrations \n
\n
\n
\n
\n
\n \n
\n
\n Email Frequency \n \n Immediate \n Daily Digest \n Weekly Digest \n \n
\n \n
\n
\n
\n \n \n
\n
Notification Preferences \n
\n Critical system alerts will always be sent immediately regardless of your frequency setting.\n
\n
\n
\n
\n
\n
\n\n \n
\n
\n \n \n \n Save Changes\n \n
\n
\n `\n}\n\nfunction renderStorageSettings(settings?: StorageSettings): string {\n return `\n \n \n
\n
\n
\n \n \n
\n
Work in Progress \n
\n This settings section is currently under development and provided for reference and design feedback only. Changes made here will not be saved.\n
\n
\n
\n
\n\n
\n
Storage Settings \n
Configure file storage and backup settings.
\n
\n \n
\n
\n
\n Max File Size (MB) \n \n
\n \n
\n Storage Provider \n \n Local Storage \n Cloudflare R2 \n Amazon S3 \n \n
\n \n
\n Backup Frequency \n \n Daily \n Weekly \n Monthly \n \n
\n
\n \n
\n
\n Allowed File Types \n ${settings?.allowedFileTypes?.join(', ') || 'jpg, jpeg, png, gif, pdf, docx'} \n
\n \n
\n Backup Retention (days) \n \n
\n \n
\n
\n
\n \n \n
\n
Storage Status \n
\n Current usage: 2.4 GB / 10 GB available\n
\n
\n
\n
\n
\n
\n\n \n
\n
\n \n \n \n Save Changes\n \n
\n
\n `\n}\n\nfunction renderMigrationSettings(settings?: MigrationSettings): string {\n return `\n \n
\n
Database Migrations \n
View and manage database migrations to keep your schema up to date.
\n
\n \n \n
\n
\n
\n
\n
Total Migrations
\n
${settings?.totalMigrations || '0'}
\n
\n
\n \n \n
\n
\n \n
\n
\n
\n
Applied
\n
${settings?.appliedMigrations || '0'}
\n
\n
\n \n \n
\n
\n \n
\n
\n
\n
Pending
\n
${settings?.pendingMigrations || '0'}
\n
\n
\n \n \n
\n
\n
\n\n \n
\n
\n \n \n \n Refresh Status\n \n \n
\n \n \n \n Run Pending\n \n\n
\n \n \n \n Validate Schema\n \n
\n\n \n
\n
\n
Migration History \n
List of all available database migrations
\n
\n \n
\n
\n
\n \n \n
Loading migration status...
\n
\n
\n
\n
\n\n \n `\n}\n\nfunction renderDatabaseToolsSettings(settings?: DatabaseToolsSettings): string {\n return `\n \n
\n
Database Tools \n
Manage database operations including backup, restore, and maintenance.
\n
\n\n \n
\n
\n
\n
\n
Total Tables
\n
${settings?.totalTables || '0'}
\n
\n
\n
\n
\n\n
\n
\n
\n
Total Rows
\n
${settings?.totalRows?.toLocaleString() || '0'}
\n
\n
\n
\n
\n
\n\n \n
\n \n
\n
Safe Operations \n
\n
\n \n \n \n Refresh Stats\n \n\n
\n \n \n \n Create Backup\n \n\n
\n \n \n \n Validate Database\n \n
\n
\n
\n\n \n
\n
\n
Database Tables \n
Click on a table to view its data
\n
\n\n
\n
\n
\n \n \n
Loading database statistics...
\n
\n
\n
\n\n \n
\n
\n
\n \n \n
\n
Danger Zone \n
\n These operations are destructive and cannot be undone.\n Your admin account will be preserved , but all other data will be permanently deleted.\n
\n
\n
\n \n \n \n Truncate All Data\n \n
\n
\n
\n
\n
\n `\n}","import { Hono } from 'hono'\n// import { html } from 'hono/html'\nimport { requireAuth } from '../middleware'\nimport { renderSettingsPage, SettingsPageData } from '../templates/pages/admin-settings.template'\nimport { MigrationService } from '../services/migrations'\nimport { SettingsService } from '../services/settings'\n\ntype Bindings = {\n DB: D1Database\n CACHE_KV: KVNamespace\n MEDIA_BUCKET: R2Bucket\n ASSETS: Fetcher\n EMAIL_QUEUE?: Queue\n SENDGRID_API_KEY?: string\n DEFAULT_FROM_EMAIL?: string\n IMAGES_ACCOUNT_ID?: string\n IMAGES_API_TOKEN?: string\n ENVIRONMENT?: string\n}\n\ntype Variables = {\n user?: {\n userId: string\n email: string\n role: string\n exp: number\n iat: number\n }\n requestId?: string\n startTime?: number\n appVersion?: string\n}\n\nexport const adminSettingsRoutes = new Hono<{ Bindings: Bindings; Variables: Variables }>()\n\n// Apply authentication middleware\nadminSettingsRoutes.use('*', requireAuth())\n\n// Helper function to get mock settings data\nfunction getMockSettings(user: any) {\n return {\n general: {\n siteName: 'SonicJS AI',\n siteDescription: 'A modern headless CMS powered by AI',\n adminEmail: user?.email || 'admin@example.com',\n timezone: 'UTC',\n language: 'en',\n maintenanceMode: false\n },\n appearance: {\n theme: 'dark' as const,\n primaryColor: '#465FFF',\n logoUrl: '',\n favicon: '',\n customCSS: ''\n },\n security: {\n twoFactorEnabled: false,\n sessionTimeout: 30,\n passwordRequirements: {\n minLength: 8,\n requireUppercase: true,\n requireNumbers: true,\n requireSymbols: false\n },\n ipWhitelist: []\n },\n notifications: {\n emailNotifications: true,\n contentUpdates: true,\n systemAlerts: true,\n userRegistrations: false,\n emailFrequency: 'immediate' as const\n },\n storage: {\n maxFileSize: 10,\n allowedFileTypes: ['jpg', 'jpeg', 'png', 'gif', 'pdf', 'docx'],\n storageProvider: 'cloudflare' as const,\n backupFrequency: 'daily' as const,\n retentionPeriod: 30\n },\n migrations: {\n totalMigrations: 0,\n appliedMigrations: 0,\n pendingMigrations: 0,\n lastApplied: undefined,\n migrations: []\n },\n databaseTools: {\n totalTables: 0,\n totalRows: 0,\n lastBackup: undefined,\n databaseSize: '0 MB',\n tables: []\n }\n }\n}\n\n// Settings page (redirects to general settings)\nadminSettingsRoutes.get('/', (c) => {\n return c.redirect('/admin/settings/general')\n})\n\n// General settings\nadminSettingsRoutes.get('/general', async (c) => {\n const user = c.get('user')\n const db = c.env.DB\n const settingsService = new SettingsService(db)\n\n // Get real general settings from database\n const generalSettings = await settingsService.getGeneralSettings(user?.email)\n\n const mockSettings = getMockSettings(user)\n mockSettings.general = generalSettings\n\n const pageData: SettingsPageData = {\n user: user ? {\n name: user.email,\n email: user.email,\n role: user.role\n } : undefined,\n settings: mockSettings,\n activeTab: 'general',\n version: c.get('appVersion')\n }\n return c.html(renderSettingsPage(pageData))\n})\n\n// Appearance settings\nadminSettingsRoutes.get('/appearance', (c) => {\n const user = c.get('user')\n const pageData: SettingsPageData = {\n user: user ? {\n name: user.email,\n email: user.email,\n role: user.role\n } : undefined,\n settings: getMockSettings(user),\n activeTab: 'appearance',\n version: c.get('appVersion')\n }\n return c.html(renderSettingsPage(pageData))\n})\n\n// Security settings\nadminSettingsRoutes.get('/security', (c) => {\n const user = c.get('user')\n const pageData: SettingsPageData = {\n user: user ? {\n name: user.email,\n email: user.email,\n role: user.role\n } : undefined,\n settings: getMockSettings(user),\n activeTab: 'security',\n version: c.get('appVersion')\n }\n return c.html(renderSettingsPage(pageData))\n})\n\n// Notifications settings\nadminSettingsRoutes.get('/notifications', (c) => {\n const user = c.get('user')\n const pageData: SettingsPageData = {\n user: user ? {\n name: user.email,\n email: user.email,\n role: user.role\n } : undefined,\n settings: getMockSettings(user),\n activeTab: 'notifications',\n version: c.get('appVersion')\n }\n return c.html(renderSettingsPage(pageData))\n})\n\n// Storage settings\nadminSettingsRoutes.get('/storage', (c) => {\n const user = c.get('user')\n const pageData: SettingsPageData = {\n user: user ? {\n name: user.email,\n email: user.email,\n role: user.role\n } : undefined,\n settings: getMockSettings(user),\n activeTab: 'storage',\n version: c.get('appVersion')\n }\n return c.html(renderSettingsPage(pageData))\n})\n\n// Migrations settings\nadminSettingsRoutes.get('/migrations', (c) => {\n const user = c.get('user')\n const pageData: SettingsPageData = {\n user: user ? {\n name: user.email,\n email: user.email,\n role: user.role\n } : undefined,\n settings: getMockSettings(user),\n activeTab: 'migrations',\n version: c.get('appVersion')\n }\n return c.html(renderSettingsPage(pageData))\n})\n\n// Database tools settings\nadminSettingsRoutes.get('/database-tools', (c) => {\n const user = c.get('user')\n const pageData: SettingsPageData = {\n user: user ? {\n name: user.email,\n email: user.email,\n role: user.role\n } : undefined,\n settings: getMockSettings(user),\n activeTab: 'database-tools',\n version: c.get('appVersion')\n }\n return c.html(renderSettingsPage(pageData))\n})\n\n// Get migration status\nadminSettingsRoutes.get('/api/migrations/status', async (c) => {\n try {\n const db = c.env.DB\n const migrationService = new MigrationService(db)\n const status = await migrationService.getMigrationStatus()\n\n return c.json({\n success: true,\n data: status\n })\n } catch (error) {\n console.error('Error fetching migration status:', error)\n return c.json({\n success: false,\n error: 'Failed to fetch migration status'\n }, 500)\n }\n})\n\n// Run pending migrations\nadminSettingsRoutes.post('/api/migrations/run', async (c) => {\n try {\n const user = c.get('user')\n\n // Only allow admin users to run migrations\n if (!user || user.role !== 'admin') {\n return c.json({\n success: false,\n error: 'Unauthorized. Admin access required.'\n }, 403)\n }\n\n const db = c.env.DB\n const migrationService = new MigrationService(db)\n const result = await migrationService.runPendingMigrations()\n\n return c.json({\n success: result.success,\n message: result.message,\n applied: result.applied\n })\n } catch (error) {\n console.error('Error running migrations:', error)\n return c.json({\n success: false,\n error: 'Failed to run migrations'\n }, 500)\n }\n})\n\n// Validate database schema\nadminSettingsRoutes.get('/api/migrations/validate', async (c) => {\n try {\n const db = c.env.DB\n const migrationService = new MigrationService(db)\n const validation = await migrationService.validateSchema()\n\n return c.json({\n success: true,\n data: validation\n })\n } catch (error) {\n console.error('Error validating schema:', error)\n return c.json({\n success: false,\n error: 'Failed to validate schema'\n }, 500)\n }\n})\n\n// Get database tools stats\nadminSettingsRoutes.get('/api/database-tools/stats', async (c) => {\n try {\n const db = c.env.DB\n\n // Get list of all tables\n const tablesQuery = await db.prepare(`\n SELECT name FROM sqlite_master\n WHERE type='table'\n AND name NOT LIKE 'sqlite_%'\n AND name NOT LIKE '_cf_%'\n ORDER BY name\n `).all()\n\n const tables = tablesQuery.results || []\n let totalRows = 0\n\n // Get row count for each table\n const tableStats = await Promise.all(\n tables.map(async (table: any) => {\n try {\n const countResult = await db.prepare(`SELECT COUNT(*) as count FROM ${table.name}`).first()\n const rowCount = (countResult as any)?.count || 0\n totalRows += rowCount\n return {\n name: table.name,\n rowCount\n }\n } catch (error) {\n console.error(`Error counting rows in ${table.name}:`, error)\n return {\n name: table.name,\n rowCount: 0\n }\n }\n })\n )\n\n // D1 doesn't expose database size directly, so we'll estimate based on row counts\n // Average row size estimate: 1KB per row (rough approximation)\n const estimatedSizeBytes = totalRows * 1024\n const databaseSizeMB = (estimatedSizeBytes / (1024 * 1024)).toFixed(2)\n\n return c.json({\n success: true,\n data: {\n totalTables: tables.length,\n totalRows,\n databaseSize: `${databaseSizeMB} MB (estimated)`,\n tables: tableStats\n }\n })\n } catch (error) {\n console.error('Error fetching database stats:', error)\n return c.json({\n success: false,\n error: 'Failed to fetch database statistics'\n }, 500)\n }\n})\n\n// Validate database\nadminSettingsRoutes.get('/api/database-tools/validate', async (c) => {\n try {\n const db = c.env.DB\n\n // Run PRAGMA integrity_check\n const integrityResult = await db.prepare('PRAGMA integrity_check').first()\n const isValid = (integrityResult as any)?.integrity_check === 'ok'\n\n return c.json({\n success: true,\n data: {\n valid: isValid,\n message: isValid ? 'Database integrity check passed' : 'Database integrity check failed'\n }\n })\n } catch (error) {\n console.error('Error validating database:', error)\n return c.json({\n success: false,\n error: 'Failed to validate database'\n }, 500)\n }\n})\n\n// Backup database\nadminSettingsRoutes.post('/api/database-tools/backup', async (c) => {\n try {\n const user = c.get('user')\n\n // Only allow admin users\n if (!user || user.role !== 'admin') {\n return c.json({\n success: false,\n error: 'Unauthorized. Admin access required.'\n }, 403)\n }\n\n // TODO: Implement actual backup functionality\n // For now, return success message\n return c.json({\n success: true,\n message: 'Database backup feature coming soon. Use Cloudflare Dashboard for backups.'\n })\n } catch (error) {\n console.error('Error creating backup:', error)\n return c.json({\n success: false,\n error: 'Failed to create backup'\n }, 500)\n }\n})\n\n// Truncate tables\nadminSettingsRoutes.post('/api/database-tools/truncate', async (c) => {\n try {\n const user = c.get('user')\n\n // Only allow admin users\n if (!user || user.role !== 'admin') {\n return c.json({\n success: false,\n error: 'Unauthorized. Admin access required.'\n }, 403)\n }\n\n const body = await c.req.json()\n const tablesToTruncate = body.tables || []\n\n if (!Array.isArray(tablesToTruncate) || tablesToTruncate.length === 0) {\n return c.json({\n success: false,\n error: 'No tables specified for truncation'\n }, 400)\n }\n\n const db = c.env.DB\n const results = []\n\n for (const tableName of tablesToTruncate) {\n try {\n await db.prepare(`DELETE FROM ${tableName}`).run()\n results.push({ table: tableName, success: true })\n } catch (error) {\n console.error(`Error truncating ${tableName}:`, error)\n results.push({ table: tableName, success: false, error: String(error) })\n }\n }\n\n return c.json({\n success: true,\n message: `Truncated ${results.filter(r => r.success).length} of ${tablesToTruncate.length} tables`,\n results\n })\n } catch (error) {\n console.error('Error truncating tables:', error)\n return c.json({\n success: false,\n error: 'Failed to truncate tables'\n }, 500)\n }\n})\n\n// Save general settings\nadminSettingsRoutes.post('/general', async (c) => {\n try {\n const user = c.get('user')\n\n if (!user || user.role !== 'admin') {\n return c.json({\n success: false,\n error: 'Unauthorized. Admin access required.'\n }, 403)\n }\n\n const formData = await c.req.formData()\n const db = c.env.DB\n const settingsService = new SettingsService(db)\n\n // Extract general settings from form data\n const settings = {\n siteName: formData.get('siteName') as string,\n siteDescription: formData.get('siteDescription') as string,\n adminEmail: formData.get('adminEmail') as string,\n timezone: formData.get('timezone') as string,\n language: formData.get('language') as string,\n maintenanceMode: formData.get('maintenanceMode') === 'true'\n }\n\n // Validate required fields\n if (!settings.siteName || !settings.siteDescription) {\n return c.json({\n success: false,\n error: 'Site name and description are required'\n }, 400)\n }\n\n // Save settings to database\n const success = await settingsService.saveGeneralSettings(settings)\n\n if (success) {\n return c.json({\n success: true,\n message: 'General settings saved successfully!'\n })\n } else {\n return c.json({\n success: false,\n error: 'Failed to save settings'\n }, 500)\n }\n } catch (error) {\n console.error('Error saving general settings:', error)\n return c.json({\n success: false,\n error: 'Failed to save settings. Please try again.'\n }, 500)\n }\n})\n\n// Save settings (legacy endpoint - redirect to general)\nadminSettingsRoutes.post('/', async (c) => {\n return c.redirect('/admin/settings/general')\n})\n","import { renderAdminLayoutCatalyst, AdminLayoutCatalystData } from '../layouts/admin-layout-catalyst.template'\nimport { renderTable } from '../components/table.template'\n\nexport interface Form {\n id: string\n name: string\n display_name: string\n description?: string\n category: string\n submission_count: number\n is_active: boolean\n is_public: boolean\n created_at: number\n formattedDate: string\n}\n\nexport interface FormsListPageData {\n forms: Form[]\n search?: string\n category?: string\n user?: {\n name: string\n email: string\n role: string\n }\n version?: string\n}\n\nexport function renderFormsListPage(data: FormsListPageData): string {\n const tableData: any = {\n tableId: 'forms-table',\n rowClickable: true,\n rowClickUrl: (form: Form) => `/admin/forms/${form.id}/builder`,\n columns: [\n {\n key: 'name',\n label: 'Name',\n sortable: true,\n sortType: 'string',\n render: (_value: any, form: any) => `\n \n \n ${form.name}\n \n
\n `\n },\n {\n key: 'display_name',\n label: 'Display Name',\n sortable: true,\n sortType: 'string'\n },\n {\n key: 'category',\n label: 'Category',\n sortable: true,\n sortType: 'string',\n render: (_value: any, form: any) => {\n const categoryColors: Record = {\n 'contact': 'bg-blue-50 dark:bg-blue-500/10 text-blue-700 dark:text-blue-300 ring-blue-700/10 dark:ring-blue-400/20',\n 'survey': 'bg-purple-50 dark:bg-purple-500/10 text-purple-700 dark:text-purple-300 ring-purple-700/10 dark:ring-purple-400/20',\n 'registration': 'bg-green-50 dark:bg-green-500/10 text-green-700 dark:text-green-300 ring-green-700/10 dark:ring-green-400/20',\n 'feedback': 'bg-orange-50 dark:bg-orange-500/10 text-orange-700 dark:text-orange-300 ring-orange-700/10 dark:ring-orange-400/20',\n 'general': 'bg-gray-50 dark:bg-gray-500/10 text-gray-700 dark:text-gray-300 ring-gray-700/10 dark:ring-gray-400/20'\n }\n const colorClass = categoryColors[form.category] || categoryColors['general']\n return `\n \n ${form.category || 'general'}\n \n `\n }\n },\n {\n key: 'submission_count',\n label: 'Submissions',\n sortable: true,\n sortType: 'number',\n render: (_value: any, form: any) => {\n const count = form.submission_count || 0\n return `\n \n \n ${count}\n \n
\n `\n }\n },\n {\n key: 'is_active',\n label: 'Status',\n sortable: true,\n sortType: 'string',\n render: (_value: any, form: any) => {\n if (form.is_active) {\n return `\n \n Active\n \n `\n } else {\n return `\n \n Inactive\n \n `\n }\n }\n },\n {\n key: 'formattedDate',\n label: 'Created',\n sortable: true,\n sortType: 'date'\n },\n {\n key: 'actions',\n label: 'Actions',\n sortable: false,\n render: (_value: any, form: any) => {\n if (!form || !form.id) return '- '\n return `\n \n `\n }\n }\n ],\n rows: data.forms,\n emptyMessage: 'No forms found. Create your first form to get started!'\n }\n\n const pageContent = `\n \n \n
\n
\n
Forms \n
Create and manage forms with the visual form builder
\n
\n
\n
\n\n \n
\n
\n
\n
\n
\n
\n Total Forms \n ${data.forms.length} \n \n
\n
\n
\n\n
\n
\n
\n
\n
\n Active Forms \n ${data.forms.filter(f => f.is_active).length} \n \n
\n
\n
\n\n
\n
\n
\n
\n
\n Total Submissions \n ${data.forms.reduce((sum, f) => sum + (f.submission_count || 0), 0)} \n \n
\n
\n
\n
\n\n \n
\n
\n \n \n
\n \n \n All Categories \n Contact \n Survey \n Registration \n Feedback \n General \n \n
\n \n \n \n \n Filter\n \n ${data.search || data.category ? `\n \n Clear\n \n ` : ''}\n \n
\n\n \n
\n ${renderTable(tableData)}\n
\n
\n `\n\n const layoutData: AdminLayoutCatalystData = {\n title: 'Forms',\n content: pageContent,\n user: data.user,\n version: data.version\n }\n\n return renderAdminLayoutCatalyst(layoutData)\n}\n","import { renderAdminLayoutCatalyst, AdminLayoutCatalystData } from '../layouts/admin-layout-catalyst.template'\n\nexport interface FormBuilderPageData {\n id: string\n name: string\n display_name: string\n description?: string\n category?: string\n formio_schema: any\n settings?: any\n is_active?: boolean\n is_public?: boolean\n google_maps_api_key?: string\n turnstile_site_key?: string\n user?: {\n name: string\n email: string\n role: string\n }\n version?: string\n}\n\n// Inline Turnstile component for Form.io builder\nfunction getTurnstileComponentScript(): string {\n return `\n (function() {\n 'use strict';\n\n if (!window.Formio || !window.Formio.Components) {\n console.error('Form.io library not loaded');\n return;\n }\n\n const FieldComponent = Formio.Components.components.field;\n\n class TurnstileComponent extends FieldComponent {\n static schema(...extend) {\n return FieldComponent.schema({\n type: 'turnstile',\n label: 'Turnstile Verification',\n key: 'turnstile',\n input: true,\n persistent: false,\n protected: true,\n unique: false,\n hidden: false,\n clearOnHide: true,\n tableView: false,\n validate: {\n required: false\n },\n siteKey: '',\n theme: 'auto',\n size: 'normal',\n action: '',\n appearance: 'always',\n errorMessage: 'Please complete the security verification'\n }, ...extend);\n }\n\n static get builderInfo() {\n return {\n title: 'Turnstile',\n group: 'premium',\n icon: 'fa fa-shield-alt',\n weight: 120,\n documentation: '/admin/forms/docs#turnstile',\n schema: TurnstileComponent.schema()\n };\n }\n\n constructor(component, options, data) {\n super(component, options, data);\n this.widgetId = null;\n this.scriptLoaded = false;\n }\n\n init() {\n super.init();\n // Only load script if NOT in builder/edit mode\n if (!this.options.editMode && !this.options.builder && !this.builderMode) {\n this.loadTurnstileScript();\n }\n }\n\n loadTurnstileScript() {\n // Extra safety: never load in builder\n if (this.options.editMode || this.options.builder || this.builderMode) {\n console.log('Turnstile: Skipping script load in builder mode');\n return Promise.resolve();\n }\n\n if (window.turnstile) {\n this.scriptLoaded = true;\n return Promise.resolve();\n }\n\n if (this.scriptPromise) {\n return this.scriptPromise;\n }\n\n console.log('Turnstile: Loading script for form mode');\n this.scriptPromise = new Promise((resolve, reject) => {\n const script = document.createElement('script');\n script.src = 'https://challenges.cloudflare.com/turnstile/v0/api.js';\n script.async = true;\n script.defer = true;\n script.onload = () => {\n this.scriptLoaded = true;\n resolve();\n };\n script.onerror = () => reject(new Error('Failed to load Turnstile'));\n document.head.appendChild(script);\n });\n\n return this.scriptPromise;\n }\n\n render() {\n return super.render(\\`\n \n \\`);\n }\n\n attach(element) {\n this.loadRefs(element, {\n turnstileContainer: 'single',\n turnstileWidget: 'single'\n });\n\n const superAttach = super.attach(element);\n\n // Check if we're in builder mode or form mode\n if (this.options.editMode || this.options.builder) {\n // Builder mode - show placeholder only\n this.renderPlaceholder();\n } else {\n // Form mode - render actual widget\n this.loadTurnstileScript()\n .then(() => this.renderWidget())\n .catch(err => {\n console.error('Failed to load Turnstile:', err);\n if (this.refs.turnstileWidget) {\n this.refs.turnstileWidget.innerHTML = \\`\n \n Error: Failed to load security verification\n
\n \\`;\n }\n });\n }\n\n return superAttach;\n }\n\n renderPlaceholder() {\n if (!this.refs.turnstileWidget) {\n return;\n }\n \n this.refs.turnstileWidget.innerHTML = \\`\n \n
š”ļø
\n
Turnstile Verification
\n
CAPTCHA-free bot protection by Cloudflare
\n
Widget will appear here on the live form
\n
\n \\`;\n }\n\n renderWidget() {\n if (!this.refs.turnstileWidget || !window.turnstile) {\n return;\n }\n\n this.refs.turnstileWidget.innerHTML = '';\n\n const siteKey = this.component.siteKey || \n (this.root && this.root.options && this.root.options.turnstileSiteKey) || \n '';\n \n if (!siteKey) {\n this.refs.turnstileWidget.innerHTML = \\`\n \n ā ļø Configuration Required: Turnstile site key not configured. \n Please enable the Turnstile plugin in Settings ā Plugins.\n
\n \\`;\n return;\n }\n\n try {\n const self = this;\n this.widgetId = window.turnstile.render(this.refs.turnstileWidget, {\n sitekey: siteKey,\n theme: this.component.theme || 'auto',\n size: this.component.size || 'normal',\n action: this.component.action || '',\n appearance: this.component.appearance || 'always',\n callback: function(token) {\n self.updateValue(token);\n self.triggerChange();\n },\n 'error-callback': function() {\n self.updateValue(null);\n self.setCustomValidity(self.component.errorMessage || 'Security verification failed');\n },\n 'expired-callback': function() {\n self.updateValue(null);\n self.setCustomValidity('Security verification expired. Please verify again.');\n },\n 'timeout-callback': function() {\n self.updateValue(null);\n self.setCustomValidity('Security verification timed out. Please try again.');\n }\n });\n } catch (err) {\n console.error('Failed to render Turnstile widget:', err);\n this.refs.turnstileWidget.innerHTML = \\`\n \n Error: Failed to render security verification\n
\n \\`;\n }\n }\n\n detach() {\n if (this.widgetId !== null && window.turnstile) {\n try {\n window.turnstile.remove(this.widgetId);\n this.widgetId = null;\n } catch (err) {\n console.error('Failed to remove Turnstile widget:', err);\n }\n }\n return super.detach();\n }\n\n getValue() {\n if (this.widgetId !== null && window.turnstile) {\n return window.turnstile.getResponse(this.widgetId);\n }\n return this.dataValue;\n }\n\n setValue(value, flags) {\n const changed = super.setValue(value, flags);\n return changed;\n }\n\n getValueAsString(value) {\n return value ? 'ā
Verified' : 'ā Not Verified';\n }\n\n isEmpty(value) {\n return !value;\n }\n\n updateValue(value, flags) {\n const changed = super.updateValue(value, flags);\n \n if (value) {\n this.setCustomValidity('');\n }\n \n return changed;\n }\n\n checkValidity(data, dirty, row) {\n const result = super.checkValidity(data, dirty, row);\n \n if (this.component.validate && this.component.validate.required) {\n const value = this.getValue();\n if (!value) {\n this.setCustomValidity(this.component.errorMessage || 'Please complete the security verification');\n return false;\n }\n }\n \n return result;\n }\n }\n\n Formio.Components.addComponent('turnstile', TurnstileComponent);\n console.log('ā
Turnstile component registered with Form.io');\n window.TurnstileComponent = TurnstileComponent;\n })();\n `;\n}\n\nexport function renderFormBuilderPage(data: FormBuilderPageData): string {\n const formioSchema = data.formio_schema || { components: [] }\n const settings = data.settings || {}\n const googleMapsApiKey = data.google_maps_api_key || ''\n const turnstileSiteKey = data.turnstile_site_key || ''\n\n const pageContent = `\n \n\n \n \n
\n
\n
\n
\n \n \n \n \n
\n
\n Form Builder: ${data.display_name}\n \n
\n \n ${data.name}\n \n
\n
\n
\n\n \n
\n
\n
\n\n \n
\n
Display Type: \n
\n
\n \n \n \n Single Page\n \n
\n \n \n \n Multi-Page Wizard\n \n
\n
\n š” Use Panel components (Layout tab) for each page\n \n
\n\n \n
\n\n \n
\n
\n
\n \n \n \n
Loading Form Builder...
\n
\n
\n\n \n
\n\n \n
\n
\n
\n
Form Preview \n
\n \n \n \n \n
\n
\n
\n
\n
\n\n \n \n\n \n\n \n \n \n \n \n\n \n \n `\n\n const layoutData: AdminLayoutCatalystData = {\n title: `Form Builder: ${data.display_name}`,\n content: pageContent,\n user: data.user,\n version: data.version\n }\n\n return renderAdminLayoutCatalyst(layoutData)\n}\n","import { renderAdminLayoutCatalyst, AdminLayoutCatalystData } from '../layouts/admin-layout-catalyst.template'\nimport { renderForm } from '../components/form.template'\n\nexport interface FormCreatePageData {\n error?: string\n success?: string\n user?: {\n name: string\n email: string\n role: string\n }\n version?: string\n}\n\nexport function renderFormCreatePage(data: FormCreatePageData): string {\n const pageContent = `\n \n \n
\n
\n
\n \n \n \n \n
\n
Create New Form \n
Enter basic information to create your form. You'll be able to add fields in the builder.
\n
\n
\n
\n\n \n ${data.error ? `\n
\n
\n
\n \n \n
${data.error}
\n
\n
\n ` : ''}\n\n ${data.success ? `\n
\n
\n
\n \n \n
${data.success}
\n
\n
\n ` : ''}\n\n \n
\n
\n \n \n \n
\n
\n Form Name\n * \n \n
\n
\n Lowercase letters, numbers, and underscores only. Used in URLs and API.\n
\n
\n\n \n
\n
\n Display Name\n * \n \n
\n
\n Human-readable name shown in the admin interface.\n
\n
\n\n \n
\n \n Description\n \n \n
\n\n \n
\n
\n Category\n \n
\n General \n Contact \n Survey \n Registration \n Feedback \n \n
\n Helps organize forms in the admin panel.\n
\n
\n
\n\n \n \n
\n Cancel\n \n
\n \n \n \n Create & Open Builder\n \n
\n \n
\n\n \n
\n
\n
\n \n \n
\n
What happens next? \n
\n
After creating your form, you'll be taken to the Form Builder where you can:
\n
\n Drag and drop fields onto your form \n Configure field properties and validation \n Add conditional logic \n Preview your form in real-time \n Publish when ready \n \n
\n
\n
\n
\n
\n\n \n `\n\n const layoutData: AdminLayoutCatalystData = {\n title: 'Create Form',\n content: pageContent,\n user: data.user,\n version: data.version\n }\n\n return renderAdminLayoutCatalyst(layoutData)\n}\n","import { Hono } from 'hono'\nimport { requireAuth } from '../middleware'\nimport { renderFormsListPage } from '../templates/pages/admin-forms-list.template'\nimport { renderFormBuilderPage, type FormBuilderPageData } from '../templates/pages/admin-forms-builder.template'\nimport { renderFormCreatePage } from '../templates/pages/admin-forms-create.template'\nimport { TurnstileService } from '../plugins/core-plugins/turnstile-plugin/services/turnstile'\n\n// Type definitions for forms\ninterface Form {\n id: string\n name: string\n display_name: string\n description?: string\n category: string\n submission_count: number\n is_active: boolean\n is_public: boolean\n created_at: number\n updated_at: number\n formattedDate: string\n}\n\ninterface FormData {\n id?: string\n name?: string\n display_name?: string\n description?: string\n category?: string\n formio_schema?: any\n settings?: any\n is_active?: boolean\n is_public?: boolean\n google_maps_api_key?: string\n turnstile_site_key?: string\n error?: string\n success?: string\n user?: {\n name: string\n email: string\n role: string\n }\n version?: string\n}\n\ninterface FormsListPageData {\n forms: Form[]\n search?: string\n category?: string\n user?: {\n name: string\n email: string\n role: string\n }\n version?: string\n}\n\ntype Bindings = {\n DB: D1Database\n CACHE_KV: KVNamespace\n MEDIA_BUCKET: R2Bucket\n ASSETS: Fetcher\n EMAIL_QUEUE?: Queue\n SENDGRID_API_KEY?: string\n DEFAULT_FROM_EMAIL?: string\n ENVIRONMENT?: string\n GOOGLE_MAPS_API_KEY?: string\n}\n\ntype Variables = {\n user?: {\n userId: string\n email: string\n role: string\n exp: number\n iat: number\n }\n requestId?: string\n startTime?: number\n appVersion?: string\n}\n\nexport const adminFormsRoutes = new Hono<{ Bindings: Bindings; Variables: Variables }>()\n\n// Apply authentication middleware\nadminFormsRoutes.use('*', requireAuth())\n\n// Forms management - List all forms\nadminFormsRoutes.get('/', async (c) => {\n try {\n const user = c.get('user')\n const db = c.env.DB\n const search = c.req.query('search') || ''\n const category = c.req.query('category') || ''\n\n // Build query\n let query = 'SELECT * FROM forms WHERE 1=1'\n const params: string[] = []\n\n if (search) {\n query += ' AND (name LIKE ? OR display_name LIKE ?)'\n params.push(`%${search}%`, `%${search}%`)\n }\n\n if (category) {\n query += ' AND category = ?'\n params.push(category)\n }\n\n query += ' ORDER BY created_at DESC'\n\n const result = await db.prepare(query).bind(...params).all()\n\n // Format dates\n const forms = result.results.map((form: any) => ({\n ...form,\n formattedDate: new Date(form.created_at).toLocaleDateString('en-US', {\n year: 'numeric',\n month: 'short',\n day: 'numeric'\n })\n }))\n\n const pageData: FormsListPageData = {\n forms,\n search,\n category,\n user: user ? {\n name: user.email,\n email: user.email,\n role: user.role\n } : undefined,\n version: c.get('appVersion')\n }\n\n return c.html(renderFormsListPage(pageData))\n } catch (error: any) {\n console.error('Error listing forms:', error)\n return c.html('Error loading forms
', 500)\n }\n})\n\n// Show create form page\nadminFormsRoutes.get('/new', async (c) => {\n try {\n const user = c.get('user')\n\n const pageData: FormData = {\n user: user ? {\n name: user.email,\n email: user.email,\n role: user.role\n } : undefined,\n version: c.get('appVersion')\n }\n\n return c.html(renderFormCreatePage(pageData))\n } catch (error: any) {\n console.error('Error showing create form page:', error)\n return c.html('Error loading form
', 500)\n }\n})\n\n// Show docs page\nadminFormsRoutes.get('/docs', async (c) => {\n try {\n const user = c.get('user')\n const { renderFormsDocsPage } = await import('../templates/index.js')\n\n const pageData = {\n user: user ? {\n name: user.email,\n email: user.email,\n role: user.role\n } : undefined,\n version: c.get('appVersion')\n }\n\n return c.html(renderFormsDocsPage(pageData))\n } catch (error: any) {\n console.error('Error showing forms docs page:', error)\n return c.html('Error loading documentation
', 500)\n }\n})\n\n// Show examples page\nadminFormsRoutes.get('/examples', async (c) => {\n try {\n const user = c.get('user')\n const { renderFormsExamplesPage } = await import('../templates/index.js')\n\n const pageData = {\n user: user ? {\n name: user.email,\n email: user.email,\n role: user.role\n } : undefined,\n version: c.get('appVersion')\n }\n\n return c.html(renderFormsExamplesPage(pageData))\n } catch (error: any) {\n console.error('Error showing forms examples page:', error)\n return c.html('Error loading examples
', 500)\n }\n})\n\n// Create new form\nadminFormsRoutes.post('/', async (c) => {\n try {\n const user = c.get('user')\n const db = c.env.DB\n const body = await c.req.parseBody()\n\n const name = body.name as string\n const displayName = body.displayName as string\n const description = (body.description as string) || ''\n const category = (body.category as string) || 'general'\n\n // Validate required fields\n if (!name || !displayName) {\n return c.json({ error: 'Name and display name are required' }, 400)\n }\n\n // Validate name format (lowercase, numbers, underscores only)\n if (!/^[a-z0-9_]+$/.test(name)) {\n return c.json({ \n error: 'Form name must contain only lowercase letters, numbers, and underscores' \n }, 400)\n }\n\n // Check for duplicate name\n const existing = await db.prepare('SELECT id FROM forms WHERE name = ?')\n .bind(name)\n .first()\n\n if (existing) {\n return c.json({ error: 'A form with this name already exists' }, 400)\n }\n\n // Create form with empty schema\n const formId = crypto.randomUUID()\n const now = Date.now()\n const emptySchema = { components: [] } // Empty Form.io schema\n\n await db.prepare(`\n INSERT INTO forms (\n id, name, display_name, description, category,\n formio_schema, settings, is_active, is_public,\n created_by, created_at, updated_at\n ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)\n `).bind(\n formId,\n name,\n displayName,\n description,\n category,\n JSON.stringify(emptySchema),\n JSON.stringify({\n submitButtonText: 'Submit',\n successMessage: 'Thank you for your submission!',\n requireAuth: false,\n emailNotifications: false\n }),\n 1, // is_active\n 1, // is_public\n user?.userId || null,\n now,\n now\n ).run()\n\n // Redirect to builder\n return c.redirect(`/admin/forms/${formId}/builder`)\n } catch (error: any) {\n console.error('Error creating form:', error)\n return c.json({ error: 'Failed to create form' }, 500)\n }\n})\n\n// Show form builder\nadminFormsRoutes.get('/:id/builder', async (c) => {\n try {\n const user = c.get('user')\n const db = c.env.DB\n const formId = c.req.param('id')\n const googleMapsApiKey = c.env.GOOGLE_MAPS_API_KEY || ''\n\n // Get form\n const form = await db.prepare('SELECT * FROM forms WHERE id = ?')\n .bind(formId)\n .first()\n\n if (!form) {\n return c.html('Form not found
', 404)\n }\n\n // Get Turnstile configuration\n const turnstileService = new TurnstileService(db)\n const turnstileSettings = await turnstileService.getSettings()\n\n const pageData: FormData = {\n id: form.id as string,\n name: form.name as string,\n display_name: form.display_name as string,\n description: form.description as string | undefined,\n category: form.category as string,\n formio_schema: form.formio_schema ? JSON.parse(form.formio_schema as string) : { components: [] },\n settings: form.settings ? JSON.parse(form.settings as string) : {},\n is_active: Boolean(form.is_active),\n is_public: Boolean(form.is_public),\n google_maps_api_key: googleMapsApiKey,\n turnstile_site_key: turnstileSettings?.siteKey || '',\n user: user ? {\n name: user.email,\n email: user.email,\n role: user.role\n } : undefined,\n version: c.get('appVersion')\n }\n\n return c.html(renderFormBuilderPage(pageData as FormBuilderPageData))\n } catch (error: any) {\n console.error('Error showing form builder:', error)\n return c.html('Error loading form builder
', 500)\n }\n})\n\n// Update form (save schema)\nadminFormsRoutes.put('/:id', async (c) => {\n try {\n const user = c.get('user')\n const db = c.env.DB\n const formId = c.req.param('id')\n const body = await c.req.json()\n\n // Check if form exists\n const form = await db.prepare('SELECT id FROM forms WHERE id = ?')\n .bind(formId)\n .first()\n\n if (!form) {\n return c.json({ error: 'Form not found' }, 404)\n }\n\n const now = Date.now()\n\n // Update form\n await db.prepare(`\n UPDATE forms \n SET formio_schema = ?, \n updated_by = ?, \n updated_at = ?\n WHERE id = ?\n `).bind(\n JSON.stringify(body.formio_schema),\n user?.userId || null,\n now,\n formId\n ).run()\n\n return c.json({ success: true, message: 'Form saved successfully' })\n } catch (error: any) {\n console.error('Error updating form:', error)\n return c.json({ error: 'Failed to save form' }, 500)\n }\n})\n\n// Delete form\nadminFormsRoutes.delete('/:id', async (c) => {\n try {\n const db = c.env.DB\n const formId = c.req.param('id')\n\n // Check if form exists\n const form = await db.prepare('SELECT id, submission_count FROM forms WHERE id = ?')\n .bind(formId)\n .first()\n\n if (!form) {\n return c.json({ error: 'Form not found' }, 404)\n }\n\n // Warn if form has submissions\n const submissionCount = form.submission_count as number || 0\n if (submissionCount > 0) {\n return c.json({ \n error: `Cannot delete form with ${submissionCount} submissions. Archive it instead.` \n }, 400)\n }\n\n // Delete form (cascade will delete submissions and files)\n await db.prepare('DELETE FROM forms WHERE id = ?').bind(formId).run()\n\n return c.json({ success: true, message: 'Form deleted successfully' })\n } catch (error: any) {\n console.error('Error deleting form:', error)\n return c.json({ error: 'Failed to delete form' }, 500)\n }\n})\n\n// View form submissions\nadminFormsRoutes.get('/:id/submissions', async (c) => {\n try {\n const user = c.get('user')\n const db = c.env.DB\n const formId = c.req.param('id')\n\n // Get form\n const form = await db.prepare('SELECT * FROM forms WHERE id = ?')\n .bind(formId)\n .first()\n\n if (!form) {\n return c.html('Form not found
', 404)\n }\n\n // Get submissions\n const submissions = await db.prepare(\n 'SELECT * FROM form_submissions WHERE form_id = ? ORDER BY submitted_at DESC'\n ).bind(formId).all()\n\n // Simple submissions page for now\n const html = `\n \n \n \n Submissions - ${form.display_name} \n \n \n \n ā Back to Forms \n Submissions: ${form.display_name} \n Total submissions: ${submissions.results.length}
\n ${submissions.results.length > 0 ? `\n \n \n \n ID \n Submitted \n Data \n \n \n \n ${submissions.results.map((sub: any) => `\n \n ${sub.id.substring(0, 8)} \n ${new Date(sub.submitted_at).toLocaleString()} \n ${JSON.stringify(JSON.parse(sub.submission_data), null, 2)} \n \n `).join('')}\n \n
\n ` : 'No submissions yet.
'}\n \n \n `\n \n return c.html(html)\n } catch (error: any) {\n console.error('Error loading submissions:', error)\n return c.html('Error loading submissions
', 500)\n }\n})\n\nexport default adminFormsRoutes\n","import { Hono } from 'hono'\nimport { TurnstileService } from '../plugins/core-plugins/turnstile-plugin/services/turnstile'\n\ntype Bindings = {\n DB: D1Database\n CACHE_KV: KVNamespace\n MEDIA_BUCKET: R2Bucket\n ASSETS: Fetcher\n EMAIL_QUEUE?: Queue\n SENDGRID_API_KEY?: string\n DEFAULT_FROM_EMAIL?: string\n ENVIRONMENT?: string\n GOOGLE_MAPS_API_KEY?: string\n}\n\ntype Variables = {\n user?: {\n userId: string\n email: string\n role: string\n exp: number\n iat: number\n }\n requestId?: string\n startTime?: number\n appVersion?: string\n}\n\nexport const publicFormsRoutes = new Hono<{ Bindings: Bindings; Variables: Variables }>()\n\n// Get Turnstile configuration for a form (for headless frontends)\npublicFormsRoutes.get('/:identifier/turnstile-config', async (c) => {\n try {\n const db = c.env.DB\n const identifier = c.req.param('identifier')\n\n // Get form\n const form = await db.prepare(\n 'SELECT id, turnstile_enabled, turnstile_settings FROM forms WHERE (id = ? OR name = ?) AND is_active = 1'\n ).bind(identifier, identifier).first()\n\n if (!form) {\n return c.json({ error: 'Form not found' }, 404)\n }\n\n const turnstileService = new TurnstileService(db)\n const globalSettings = await turnstileService.getSettings()\n \n const formSettings = form.turnstile_settings \n ? JSON.parse(form.turnstile_settings as string)\n : { inherit: true }\n\n // Determine effective settings\n const enabled = form.turnstile_enabled === 1 || \n (formSettings.inherit && globalSettings?.enabled)\n\n if (!enabled || !globalSettings) {\n return c.json({ enabled: false })\n }\n\n return c.json({\n enabled: true,\n siteKey: formSettings.siteKey || globalSettings.siteKey,\n theme: formSettings.theme || globalSettings.theme || 'auto',\n size: formSettings.size || globalSettings.size || 'normal',\n mode: formSettings.mode || globalSettings.mode || 'managed',\n appearance: formSettings.appearance || globalSettings.appearance || 'always'\n })\n } catch (error: any) {\n console.error('Error fetching Turnstile config:', error)\n return c.json({ error: 'Failed to fetch config' }, 500)\n }\n})\n\n// Get form schema as JSON (for headless frontends)\npublicFormsRoutes.get('/:identifier/schema', async (c) => {\n try {\n const db = c.env.DB\n const identifier = c.req.param('identifier')\n\n // Get form by ID or name\n const form = await db.prepare(\n 'SELECT id, name, display_name, description, category, formio_schema, settings, is_active, is_public FROM forms WHERE (id = ? OR name = ?) AND is_active = 1 AND is_public = 1'\n ).bind(identifier, identifier).first()\n\n if (!form) {\n return c.json({ error: 'Form not found' }, 404)\n }\n\n const formioSchema = form.formio_schema ? JSON.parse(form.formio_schema as string) : { components: [] }\n const settings = form.settings ? JSON.parse(form.settings as string) : {}\n\n return c.json({\n id: form.id,\n name: form.name,\n displayName: form.display_name,\n description: form.description,\n category: form.category,\n schema: formioSchema,\n settings: settings,\n submitUrl: `/api/forms/${form.id}/submit`\n })\n } catch (error: any) {\n console.error('Error fetching form schema:', error)\n return c.json({ error: 'Failed to fetch form schema' }, 500)\n }\n})\n\n// Render public form by name\npublicFormsRoutes.get('/:name', async (c) => {\n try {\n const db = c.env.DB\n const formName = c.req.param('name')\n const googleMapsApiKey = c.env.GOOGLE_MAPS_API_KEY || ''\n\n // Get form by name\n const form = await db.prepare(\n 'SELECT * FROM forms WHERE name = ? AND is_active = 1 AND is_public = 1'\n ).bind(formName).first()\n\n if (!form) {\n return c.html('Form not found This form does not exist or is not publicly available.
', 404)\n }\n\n const formioSchema = form.formio_schema ? JSON.parse(form.formio_schema as string) : { components: [] }\n const settings = form.settings ? JSON.parse(form.settings as string) : {}\n\n const html = `\n \n \n \n \n \n ${form.display_name} \n \n \n \n \n \n \n \n \n
${form.display_name} \n ${form.description ? `
${form.description}
` : ''}\n \n
\n \n
\n
\n
\n\n \n \n \n \n \n \n \n \n \n `\n\n return c.html(html)\n } catch (error: any) {\n console.error('Error rendering form:', error)\n return c.html('Error loading form
', 500)\n }\n})\n\n// Handle form submission (accepts either name or ID)\npublicFormsRoutes.post('/:identifier/submit', async (c) => {\n try {\n const db = c.env.DB\n const identifier = c.req.param('identifier')\n const body = await c.req.json()\n\n // Get form by ID or name\n const form = await db.prepare(\n 'SELECT * FROM forms WHERE (id = ? OR name = ?) AND is_active = 1'\n ).bind(identifier, identifier).first()\n\n if (!form) {\n return c.json({ error: 'Form not found' }, 404)\n }\n\n // Check if Turnstile is enabled for this form\n const turnstileEnabled = form.turnstile_enabled === 1\n const turnstileSettings = form.turnstile_settings \n ? JSON.parse(form.turnstile_settings as string) \n : { inherit: true }\n\n // Validate Turnstile if enabled (or inheriting global settings)\n if (turnstileEnabled || turnstileSettings.inherit) {\n const turnstileService = new TurnstileService(db)\n \n // Check if Turnstile is globally enabled\n const globalEnabled = await turnstileService.isEnabled()\n \n if (globalEnabled || turnstileEnabled) {\n // Extract Turnstile token from submission data\n const turnstileToken = body.data?.turnstile || body.turnstile\n \n if (!turnstileToken) {\n return c.json({ \n error: 'Turnstile verification required. Please complete the security check.',\n code: 'TURNSTILE_MISSING'\n }, 400)\n }\n\n // Verify the token\n const clientIp = c.req.header('cf-connecting-ip')\n const verification = await turnstileService.verifyToken(turnstileToken, clientIp)\n \n if (!verification.success) {\n return c.json({ \n error: verification.error || 'Security verification failed. Please try again.',\n code: 'TURNSTILE_INVALID'\n }, 403)\n }\n\n // Remove Turnstile token from submission data before storing\n if (body.data?.turnstile) {\n delete body.data.turnstile\n }\n }\n }\n\n // Create submission\n const submissionId = crypto.randomUUID()\n const now = Date.now()\n\n await db.prepare(`\n INSERT INTO form_submissions (\n id, form_id, submission_data, user_id, ip_address, user_agent,\n submitted_at, updated_at\n ) VALUES (?, ?, ?, ?, ?, ?, ?, ?)\n `).bind(\n submissionId,\n form.id,\n JSON.stringify(body.data),\n null, // user_id (for authenticated users)\n c.req.header('cf-connecting-ip') || null,\n c.req.header('user-agent') || null,\n now,\n now\n ).run()\n\n // Update submission count\n await db.prepare(`\n UPDATE forms \n SET submission_count = submission_count + 1,\n updated_at = ?\n WHERE id = ?\n `).bind(now, form.id).run()\n\n return c.json({ \n success: true, \n submissionId,\n message: 'Form submitted successfully' \n })\n } catch (error: any) {\n console.error('Error submitting form:', error)\n return c.json({ error: 'Failed to submit form' }, 500)\n }\n})\n\nexport default publicFormsRoutes\n","import { renderAdminLayoutCatalyst, AdminLayoutCatalystData } from '../layouts/admin-layout-catalyst.template'\n\nexport interface APIEndpoint {\n method: string\n path: string\n description: string\n authentication: boolean\n category: string\n}\n\nexport interface APIReferencePageData {\n endpoints: APIEndpoint[]\n user?: {\n name: string\n email: string\n role: string\n }\n version?: string\n}\n\nexport function renderAPIReferencePage(data: APIReferencePageData): string {\n // Group endpoints by category\n const endpointsByCategory = data.endpoints.reduce((acc, endpoint) => {\n if (!acc[endpoint.category]) {\n acc[endpoint.category] = []\n }\n acc[endpoint.category]!.push(endpoint)\n return acc\n }, {} as Record)\n\n // Category order and descriptions\n const categoryInfo = {\n 'Auth': {\n title: 'Authentication',\n description: 'User authentication and authorization endpoints',\n icon: 'š'\n },\n 'Content': {\n title: 'Content Management',\n description: 'Content creation, retrieval, and management',\n icon: 'š'\n },\n 'Media': {\n title: 'Media Management',\n description: 'File upload, storage, and media operations',\n icon: 'š¼ļø'\n },\n 'Admin': {\n title: 'Admin Interface',\n description: 'Administrative panel and management features',\n icon: 'āļø'\n },\n 'System': {\n title: 'System',\n description: 'Health checks and system information',\n icon: 'š§'\n }\n }\n\n const pageContent = `\n \n \n
\n
\n
API Reference \n
Complete documentation of all available API endpoints
\n
\n
\n
\n\n \n
\n \n
Total Endpoints \n \n ${data.endpoints.length} \n \n \n \n
Public Endpoints \n \n ${data.endpoints.filter(e => !e.authentication).length} \n \n \n \n
Protected Endpoints \n \n ${data.endpoints.filter(e => e.authentication).length} \n \n \n \n
Categories \n \n ${Object.keys(endpointsByCategory).length} \n \n \n \n\n \n
\n
\n
\n
\n
\n
Method \n
\n
\n All Methods \n GET \n POST \n PUT \n PATCH \n DELETE \n \n
\n \n \n
\n
\n
\n
Category \n
\n
\n All Categories \n ${Object.keys(categoryInfo).map(category => `\n ${(categoryInfo as any)[category].title} \n `).join('')}\n \n
\n \n \n
\n
\n
\n
\n
\n\n \n
\n ${Object.entries(endpointsByCategory).map(([category, endpoints]) => {\n const info = (categoryInfo as any)[category] || { title: category, description: '', icon: 'š' }\n return `\n
\n
\n \n
\n
\n
${info.icon} \n
\n
${info.title} \n
${info.description}
\n
\n
\n \n ${endpoints.length} endpoint${endpoints.length !== 1 ? 's' : ''}\n \n
\n
\n
\n\n \n
\n ${endpoints.map(endpoint => `\n
\n
\n
\n ${endpoint.method}\n \n
\n
\n
${endpoint.path}\n ${endpoint.authentication ? `\n
\n \n \n \n Auth\n \n ` : `\n
\n \n \n \n Public\n \n `}\n
\n
${endpoint.description}
\n
\n
\n
\n `).join('')}\n
\n
\n
\n `\n }).join('')}\n
\n\n \n
\n
\n \n \n
No endpoints found \n
Try adjusting your search or filter criteria
\n
\n
\n\n \n\n \n `\n\n const layoutData: AdminLayoutCatalystData = {\n title: 'API Reference',\n pageTitle: 'API Reference',\n currentPath: '/admin/api-reference',\n user: data.user,\n version: data.version,\n content: pageContent\n }\n\n return renderAdminLayoutCatalyst(layoutData)\n}","/**\n * Admin API Reference Routes\n *\n * Provides the API Reference page for the admin dashboard\n */\n\nimport { Hono } from 'hono'\nimport type { D1Database, KVNamespace, R2Bucket } from '@cloudflare/workers-types'\nimport { requireAuth } from '../middleware'\nimport {\n renderAPIReferencePage,\n type APIEndpoint,\n type APIReferencePageData\n} from '../templates/pages/admin-api-reference.template'\nimport { getCoreVersion } from '../utils/version'\n\nconst VERSION = getCoreVersion()\n\ntype Bindings = {\n DB: D1Database\n CACHE_KV: KVNamespace\n MEDIA_BUCKET: R2Bucket\n}\n\ntype Variables = {\n user?: {\n userId: string\n email: string\n role: string\n }\n}\n\nconst router = new Hono<{ Bindings: Bindings; Variables: Variables }>()\n\n// Apply authentication middleware\nrouter.use('*', requireAuth())\n\n/**\n * Define all API endpoints for documentation\n */\nconst apiEndpoints: APIEndpoint[] = [\n // Auth endpoints\n {\n method: 'POST',\n path: '/auth/login',\n description: 'Authenticate user with email and password',\n authentication: false,\n category: 'Auth'\n },\n {\n method: 'POST',\n path: '/auth/register',\n description: 'Register a new user account',\n authentication: false,\n category: 'Auth'\n },\n {\n method: 'POST',\n path: '/auth/logout',\n description: 'Log out the current user and invalidate session',\n authentication: true,\n category: 'Auth'\n },\n {\n method: 'GET',\n path: '/auth/me',\n description: 'Get current authenticated user information',\n authentication: true,\n category: 'Auth'\n },\n {\n method: 'POST',\n path: '/auth/refresh',\n description: 'Refresh authentication token',\n authentication: true,\n category: 'Auth'\n },\n\n // Content endpoints\n {\n method: 'GET',\n path: '/api/collections',\n description: 'List all available collections',\n authentication: false,\n category: 'Content'\n },\n {\n method: 'GET',\n path: '/api/collections/:collection/content',\n description: 'Get all content items from a specific collection',\n authentication: false,\n category: 'Content'\n },\n {\n method: 'GET',\n path: '/api/content/:id',\n description: 'Get a specific content item by ID',\n authentication: false,\n category: 'Content'\n },\n {\n method: 'POST',\n path: '/api/content',\n description: 'Create a new content item',\n authentication: true,\n category: 'Content'\n },\n {\n method: 'PUT',\n path: '/api/content/:id',\n description: 'Update an existing content item',\n authentication: true,\n category: 'Content'\n },\n {\n method: 'DELETE',\n path: '/api/content/:id',\n description: 'Delete a content item',\n authentication: true,\n category: 'Content'\n },\n\n // Media endpoints\n {\n method: 'GET',\n path: '/api/media',\n description: 'List all media files with pagination',\n authentication: false,\n category: 'Media'\n },\n {\n method: 'GET',\n path: '/api/media/:id',\n description: 'Get a specific media file by ID',\n authentication: false,\n category: 'Media'\n },\n {\n method: 'POST',\n path: '/api/media/upload',\n description: 'Upload a new media file to R2 storage',\n authentication: true,\n category: 'Media'\n },\n {\n method: 'DELETE',\n path: '/api/media/:id',\n description: 'Delete a media file from storage',\n authentication: true,\n category: 'Media'\n },\n\n // Admin endpoints\n {\n method: 'GET',\n path: '/admin/api/stats',\n description: 'Get dashboard statistics (collections, content, media, users)',\n authentication: true,\n category: 'Admin'\n },\n {\n method: 'GET',\n path: '/admin/api/storage',\n description: 'Get storage usage information',\n authentication: true,\n category: 'Admin'\n },\n {\n method: 'GET',\n path: '/admin/api/activity',\n description: 'Get recent activity logs',\n authentication: true,\n category: 'Admin'\n },\n {\n method: 'GET',\n path: '/admin/api/collections',\n description: 'List all collections with field counts',\n authentication: true,\n category: 'Admin'\n },\n {\n method: 'POST',\n path: '/admin/api/collections',\n description: 'Create a new collection',\n authentication: true,\n category: 'Admin'\n },\n {\n method: 'PATCH',\n path: '/admin/api/collections/:id',\n description: 'Update an existing collection',\n authentication: true,\n category: 'Admin'\n },\n {\n method: 'DELETE',\n path: '/admin/api/collections/:id',\n description: 'Delete a collection (must be empty)',\n authentication: true,\n category: 'Admin'\n },\n {\n method: 'GET',\n path: '/admin/api/migrations/status',\n description: 'Get database migration status',\n authentication: true,\n category: 'Admin'\n },\n {\n method: 'POST',\n path: '/admin/api/migrations/run',\n description: 'Run pending database migrations',\n authentication: true,\n category: 'Admin'\n },\n\n // System endpoints\n {\n method: 'GET',\n path: '/health',\n description: 'Health check endpoint for monitoring',\n authentication: false,\n category: 'System'\n },\n {\n method: 'GET',\n path: '/api/health',\n description: 'API health check with schema information',\n authentication: false,\n category: 'System'\n },\n {\n method: 'GET',\n path: '/api',\n description: 'API root - returns API information and OpenAPI spec',\n authentication: false,\n category: 'System'\n }\n]\n\n/**\n * GET /admin/api-reference - API Reference Page\n */\nrouter.get('/', async (c) => {\n const user = c.get('user')\n\n try {\n const pageData: APIReferencePageData = {\n endpoints: apiEndpoints,\n user: user ? {\n name: user.email.split('@')[0] || user.email,\n email: user.email,\n role: user.role\n } : undefined,\n version: VERSION\n }\n\n return c.html(renderAPIReferencePage(pageData))\n } catch (error) {\n console.error('API Reference page error:', error)\n\n // Return page with empty endpoints on error\n const pageData: APIReferencePageData = {\n endpoints: [],\n user: user ? {\n name: user.email,\n email: user.email,\n role: user.role\n } : undefined,\n version: VERSION\n }\n\n return c.html(renderAPIReferencePage(pageData))\n }\n})\n\nexport { router as adminApiReferenceRoutes }\n","/**\n * Embedding Service\n * Generates embeddings using Cloudflare Workers AI\n */\n\nexport class EmbeddingService {\n constructor(private ai: any) {}\n\n /**\n * Generate embedding for a single text\n * \n * ā Enhanced with Cloudflare Similarity-Based Caching\n * - Automatically caches embeddings for 30 days\n * - Similar queries share the same cache (semantic matching)\n * - 90%+ speedup for repeated/similar queries (200ms ā 5ms)\n * - Zero infrastructure cost (included with Workers AI)\n * \n * Example: \"cloudflare workers\" and \"cloudflare worker\" share cache\n */\n async generateEmbedding(text: string): Promise {\n try {\n // Use Cloudflare Workers AI embedding model\n // @cf/baai/bge-base-en-v1.5 produces 768-dimensional vectors\n const response = await this.ai.run('@cf/baai/bge-base-en-v1.5', {\n text: this.preprocessText(text)\n }, {\n // ā Enable Cloudflare's Similarity-Based Caching\n // This provides semantic cache matching across similar queries\n cf: {\n cacheTtl: 2592000, // 30 days (maximum allowed)\n cacheEverything: true, // Cache all AI responses\n }\n })\n\n // Extract embedding vector\n if (response.data && response.data.length > 0) {\n return response.data[0]\n }\n\n throw new Error('No embedding data returned')\n } catch (error) {\n console.error('[EmbeddingService] Error generating embedding:', error)\n throw error\n }\n }\n\n /**\n * Generate embeddings for multiple texts using native batch API.\n * Workers AI supports up to 100 texts per call for bge-base-en-v1.5.\n */\n async generateBatch(\n texts: string[],\n onProgress?: (completed: number, total: number) => Promise\n ): Promise {\n try {\n const batchSize = 50 // Workers AI batch limit; 50 is safe for large texts\n const allEmbeddings: number[][] = []\n\n for (let i = 0; i < texts.length; i += batchSize) {\n const batch = texts.slice(i, i + batchSize)\n const preprocessed = batch.map(t => this.preprocessText(t))\n\n // Use native batch API ā single call for all texts in batch\n const response = await this.ai.run('@cf/baai/bge-base-en-v1.5', {\n text: preprocessed\n })\n\n if (response.data && Array.isArray(response.data)) {\n allEmbeddings.push(...response.data)\n } else {\n throw new Error(`Unexpected embedding response at batch offset ${i}`)\n }\n\n if (onProgress) {\n await onProgress(allEmbeddings.length, texts.length)\n }\n }\n\n return allEmbeddings\n } catch (error) {\n console.error('[EmbeddingService] Error generating batch embeddings:', error)\n throw error\n }\n }\n\n /**\n * Preprocess text before generating embedding\n * - Trim whitespace\n * - Limit length to avoid token limits\n * - Remove special characters that might cause issues\n */\n private preprocessText(text: string): string {\n if (!text) return ''\n\n // Trim and normalize whitespace\n let processed = text.trim().replace(/\\s+/g, ' ')\n\n // Limit to ~8000 characters (rough token limit)\n if (processed.length > 8000) {\n processed = processed.substring(0, 8000)\n }\n\n return processed\n }\n\n /**\n * Calculate cosine similarity between two embeddings\n */\n cosineSimilarity(a: number[], b: number[]): number {\n if (a.length !== b.length) {\n throw new Error('Embeddings must have same dimensions')\n }\n\n let dotProduct = 0\n let normA = 0\n let normB = 0\n\n for (let i = 0; i < a.length; i++) {\n const aVal = a[i] ?? 0\n const bVal = b[i] ?? 0\n dotProduct += aVal * bVal\n normA += aVal * aVal\n normB += bVal * bVal\n }\n\n return dotProduct / (Math.sqrt(normA) * Math.sqrt(normB))\n }\n}\n","/**\n * Chunking Service\n * Splits content into optimal chunks for embedding and search\n */\n\nexport interface ContentChunk {\n id: string\n content_id: string\n collection_id: string\n title: string\n text: string\n chunk_index: number\n metadata: Record\n}\n\nexport class ChunkingService {\n // Default chunk size (in approximate tokens)\n private readonly CHUNK_SIZE = 500\n private readonly CHUNK_OVERLAP = 50\n\n /**\n * Chunk a single content item\n */\n chunkContent(\n contentId: string,\n collectionId: string,\n title: string,\n data: any,\n metadata: Record = {}\n ): ContentChunk[] {\n // Extract all text from content\n const text = this.extractText(data)\n \n if (!text || text.trim().length === 0) {\n console.warn(`[ChunkingService] No text found for content ${contentId}`)\n return []\n }\n\n // Split into chunks\n const textChunks = this.splitIntoChunks(text)\n\n // Create chunk objects\n return textChunks.map((chunkText, index) => ({\n id: `${contentId}_chunk_${index}`,\n content_id: contentId,\n collection_id: collectionId,\n title: title,\n text: chunkText,\n chunk_index: index,\n metadata: {\n ...metadata,\n total_chunks: textChunks.length\n }\n }))\n }\n\n /**\n * Chunk multiple content items\n */\n chunkContentBatch(items: Array<{\n id: string\n collection_id: string\n title: string\n data: any\n metadata?: Record\n }>): ContentChunk[] {\n const allChunks: ContentChunk[] = []\n\n for (const item of items) {\n const chunks = this.chunkContent(\n item.id,\n item.collection_id,\n item.title,\n item.data,\n item.metadata\n )\n allChunks.push(...chunks)\n }\n\n return allChunks\n }\n\n /**\n * Extract all text from content data\n */\n private extractText(data: any): string {\n const parts: string[] = []\n\n // Common text fields\n if (data.title) parts.push(String(data.title))\n if (data.name) parts.push(String(data.name))\n if (data.description) parts.push(String(data.description))\n if (data.content) parts.push(String(data.content))\n if (data.body) parts.push(String(data.body))\n if (data.text) parts.push(String(data.text))\n if (data.summary) parts.push(String(data.summary))\n\n // Recursively extract from nested objects\n const extractRecursive = (obj: any): void => {\n if (typeof obj === 'string') {\n // Skip very short strings and URLs\n if (obj.length > 10 && !obj.startsWith('http')) {\n parts.push(obj)\n }\n } else if (Array.isArray(obj)) {\n obj.forEach(extractRecursive)\n } else if (obj && typeof obj === 'object') {\n // Skip certain keys\n const skipKeys = ['id', 'slug', 'url', 'image', 'thumbnail', 'metadata']\n \n Object.entries(obj).forEach(([key, value]) => {\n if (!skipKeys.includes(key.toLowerCase())) {\n extractRecursive(value)\n }\n })\n }\n }\n\n extractRecursive(data)\n\n return parts.join('\\n\\n').trim()\n }\n\n /**\n * Split text into overlapping chunks\n */\n private splitIntoChunks(text: string): string[] {\n // Split by words\n const words = text.split(/\\s+/)\n \n if (words.length <= this.CHUNK_SIZE) {\n return [text]\n }\n\n const chunks: string[] = []\n let startIndex = 0\n\n while (startIndex < words.length) {\n // Get chunk with overlap\n const endIndex = Math.min(startIndex + this.CHUNK_SIZE, words.length)\n const chunk = words.slice(startIndex, endIndex).join(' ')\n chunks.push(chunk)\n\n // Move forward by chunk size minus overlap\n startIndex += this.CHUNK_SIZE - this.CHUNK_OVERLAP\n\n // Ensure we don't create a tiny last chunk\n if (startIndex >= words.length - this.CHUNK_OVERLAP) {\n break\n }\n }\n\n return chunks\n }\n\n /**\n * Get optimal chunk size based on content type\n */\n getOptimalChunkSize(contentType: string): number {\n switch (contentType) {\n case 'blog_posts':\n case 'articles':\n return 600 // Larger chunks for long-form content\n case 'products':\n case 'pages':\n return 400 // Medium chunks for structured content\n case 'messages':\n case 'comments':\n return 200 // Small chunks for short content\n default:\n return this.CHUNK_SIZE\n }\n }\n}\n","/**\n * Custom RAG Service\n * Implements full RAG pipeline using Cloudflare Vectorize\n * \n * Fulfills GitHub Issue #362: Advanced search with Cloudflare Search\n */\n\nimport type { D1Database } from '@cloudflare/workers-types'\nimport { EmbeddingService } from './embedding.service'\nimport { ChunkingService, type ContentChunk } from './chunking.service'\nimport type { SearchQuery, SearchResponse, SearchResult, AISearchSettings } from '../types'\n\nexport class CustomRAGService {\n private embeddingService: EmbeddingService\n private chunkingService: ChunkingService\n\n constructor(\n private db: D1Database,\n private ai: any,\n private vectorize: any\n ) {\n this.embeddingService = new EmbeddingService(ai)\n this.chunkingService = new ChunkingService()\n }\n\n /**\n * Index all content from a collection.\n * onProgress reports (phase, processedItems, totalItems) so callers can update UI.\n * Phases: 'chunking' ā 'embedding' ā 'storing'\n */\n async indexCollection(\n collectionId: string,\n onProgress?: (phase: string, processed: number, total: number) => Promise\n ): Promise<{\n total_items: number\n total_chunks: number\n indexed_chunks: number\n errors: number\n }> {\n console.log(`[CustomRAG] Starting indexing for collection: ${collectionId}`)\n\n try {\n // Get all published content from collection\n const { results: contentItems } = await this.db\n .prepare(`\n SELECT c.id, c.title, c.data, c.collection_id, c.status,\n c.created_at, c.updated_at, c.author_id,\n col.name as collection_name, col.display_name as collection_display_name\n FROM content c\n JOIN collections col ON c.collection_id = col.id\n WHERE c.collection_id = ? AND c.status != 'deleted'\n `)\n .bind(collectionId)\n .all<{\n id: string\n title: string\n data: string\n collection_id: string\n status: string\n created_at: number\n updated_at: number\n author_id?: string\n collection_name: string\n collection_display_name: string\n }>()\n\n const totalItems = contentItems?.length || 0\n\n if (totalItems === 0) {\n console.log(`[CustomRAG] No content found in collection ${collectionId}`)\n return { total_items: 0, total_chunks: 0, indexed_chunks: 0, errors: 0 }\n }\n\n // Chunk all content\n if (onProgress) await onProgress('chunking', 0, totalItems)\n\n const items = (contentItems || []).map(item => ({\n id: item.id,\n collection_id: item.collection_id,\n title: item.title || 'Untitled',\n data: typeof item.data === 'string' ? JSON.parse(item.data) : item.data,\n metadata: {\n status: item.status,\n created_at: item.created_at,\n updated_at: item.updated_at,\n author_id: item.author_id,\n collection_name: item.collection_name,\n collection_display_name: item.collection_display_name\n }\n }))\n\n const chunks = this.chunkingService.chunkContentBatch(items)\n const totalChunks = chunks.length\n\n console.log(`[CustomRAG] Generated ${totalChunks} chunks from ${totalItems} items`)\n\n // Generate embeddings with progress callback\n if (onProgress) await onProgress('embedding', 0, totalChunks)\n\n const embeddings = await this.embeddingService.generateBatch(\n chunks.map(c => `${c.title}\\n\\n${c.text}`),\n onProgress ? async (completed, total) => {\n await onProgress('embedding', completed, total)\n } : undefined\n )\n\n console.log(`[CustomRAG] Generated ${embeddings.length} embeddings`)\n\n // Store in Vectorize\n if (onProgress) await onProgress('storing', 0, totalChunks)\n\n let indexedChunks = 0\n let errors = 0\n const batchSize = 100\n\n for (let i = 0; i < chunks.length; i += batchSize) {\n const chunkBatch = chunks.slice(i, i + batchSize)\n const embeddingBatch = embeddings.slice(i, i + batchSize)\n\n try {\n await this.vectorize.upsert(\n chunkBatch.map((chunk, idx) => ({\n id: chunk.id,\n values: embeddingBatch[idx],\n metadata: {\n content_id: chunk.content_id,\n collection_id: chunk.collection_id,\n title: chunk.title,\n text: chunk.text.substring(0, 500),\n chunk_index: chunk.chunk_index,\n ...chunk.metadata\n }\n }))\n )\n\n indexedChunks += chunkBatch.length\n if (onProgress) await onProgress('storing', indexedChunks, totalChunks)\n } catch (error) {\n console.error(`[CustomRAG] Error indexing batch ${i / batchSize + 1}:`, error)\n errors += chunkBatch.length\n }\n }\n\n console.log(`[CustomRAG] Indexing complete: ${indexedChunks}/${totalChunks} chunks indexed`)\n\n return {\n total_items: totalItems,\n total_chunks: totalChunks,\n indexed_chunks: indexedChunks,\n errors\n }\n } catch (error) {\n console.error(`[CustomRAG] Error indexing collection ${collectionId}:`, error)\n throw error\n }\n }\n\n /**\n * Auto-index content in selected collections that hasn't been indexed into Vectorize yet.\n * Mirrors FTS5's ensureCollectionsIndexed() self-healing pattern.\n */\n private async ensureCollectionsIndexed(collections: string[]): Promise {\n if (collections.length === 0) return\n\n try {\n // Check which collections have been indexed via ai_search_index_meta\n // Require both 'completed' status AND indexed_items > 0 to avoid\n // false positives from IndexManager marking empty indexes as completed\n const placeholders = collections.map(() => '?').join(', ')\n const { results: indexedCollections } = await this.db\n .prepare(`\n SELECT collection_id, status, indexed_items FROM ai_search_index_meta\n WHERE collection_id IN (${placeholders}) AND status = 'completed' AND indexed_items > 0\n `)\n .bind(...collections)\n .all<{ collection_id: string; status: string; indexed_items: number }>()\n\n const completedIds = new Set((indexedCollections || []).map(r => r.collection_id))\n const unindexedCollections = collections.filter(id => !completedIds.has(id))\n\n if (unindexedCollections.length === 0) return\n\n console.log(`[CustomRAG] Auto-indexing ${unindexedCollections.length} collection(s) into Vectorize...`)\n\n for (const collectionId of unindexedCollections) {\n try {\n // Mark as indexing\n await this.db\n .prepare(`\n INSERT OR REPLACE INTO ai_search_index_meta(collection_id, collection_name, status, total_items, indexed_items)\n VALUES (?, ?, 'indexing', 0, 0)\n `)\n .bind(collectionId, collectionId)\n .run()\n\n const result = await this.indexCollection(collectionId)\n\n // Mark as completed\n await this.db\n .prepare(`\n UPDATE ai_search_index_meta\n SET status = 'completed', total_items = ?, indexed_items = ?, last_sync_at = ?\n WHERE collection_id = ?\n `)\n .bind(result.total_items, result.indexed_chunks, Date.now(), collectionId)\n .run()\n\n console.log(`[CustomRAG] Auto-indexed collection ${collectionId}: ${result.indexed_chunks} chunks from ${result.total_items} items`)\n } catch (error) {\n console.error(`[CustomRAG] Error auto-indexing collection ${collectionId}:`, error)\n // Mark as error but don't fail the search\n await this.db\n .prepare(`\n UPDATE ai_search_index_meta SET status = 'error', error_message = ?\n WHERE collection_id = ?\n `)\n .bind(String(error), collectionId)\n .run().catch(() => {})\n }\n }\n } catch (error) {\n // Don't fail the search if auto-indexing fails\n console.error('[CustomRAG] Error during auto-indexing check:', error)\n }\n }\n\n /**\n * Search using RAG (semantic search with Vectorize)\n */\n async search(query: SearchQuery, settings: AISearchSettings): Promise {\n const startTime = Date.now()\n\n try {\n // Auto-index selected collections that haven't been indexed yet\n const collections = query.filters?.collections?.length\n ? query.filters.collections\n : settings.selected_collections\n await this.ensureCollectionsIndexed(collections)\n\n // Generate query embedding\n const queryEmbedding = await this.embeddingService.generateEmbedding(query.query)\n\n // Build Vectorize query filters\n const filter: any = {}\n \n if (query.filters?.collections && query.filters.collections.length > 0) {\n filter.collection_id = { $in: query.filters.collections }\n } else if (settings.selected_collections.length > 0) {\n filter.collection_id = { $in: settings.selected_collections }\n }\n\n if (query.filters?.status && query.filters.status.length > 0) {\n filter.status = { $in: query.filters.status }\n }\n\n // Vectorize filters have issues, so we query without filter and manually filter results\n const vectorResults = await this.vectorize.query(queryEmbedding, {\n topK: 50, // Max allowed with returnMetadata: true\n returnMetadata: 'all'\n })\n\n // Manually filter results by collection_id if filter exists\n let filteredMatches = vectorResults.matches || []\n if (filter.collection_id?.$in && Array.isArray(filter.collection_id.$in)) {\n const allowedCollections = filter.collection_id.$in\n const beforeCount = filteredMatches.length\n filteredMatches = filteredMatches.filter((match: any) =>\n allowedCollections.includes(match.metadata?.collection_id)\n )\n }\n\n // Apply status filter if exists\n if (filter.status?.$in && Array.isArray(filter.status.$in)) {\n const allowedStatuses = filter.status.$in\n filteredMatches = filteredMatches.filter((match: any) =>\n allowedStatuses.includes(match.metadata?.status)\n )\n }\n\n // Limit to requested topK\n const topK = query.limit || settings.results_limit || 20\n filteredMatches = filteredMatches.slice(0, topK)\n\n // Replace matches with filtered results\n vectorResults.matches = filteredMatches\n\n if (!vectorResults.matches || vectorResults.matches.length === 0) {\n return {\n results: [],\n total: 0,\n query_time_ms: Date.now() - startTime,\n mode: 'ai'\n }\n }\n\n // Get unique content IDs from Vectorize matches\n const contentIds = [...new Set(\n vectorResults.matches.map((m: any) => m.metadata.content_id)\n )]\n\n\n // Fetch full content from D1\n const placeholders = contentIds.map(() => '?').join(',')\n const { results: contentItems } = await this.db\n .prepare(`\n SELECT c.id, c.title, c.slug, c.collection_id, c.status,\n c.created_at, c.updated_at, c.author_id,\n col.display_name as collection_name\n FROM content c\n JOIN collections col ON c.collection_id = col.id\n WHERE c.id IN (${placeholders})\n `)\n .bind(...contentIds)\n .all<{\n id: string\n title: string\n slug: string\n collection_id: string\n collection_name: string\n status: string\n created_at: number\n updated_at: number\n author_id?: string\n }>()\n\n // Only include results that exist in D1 (skip stale Vectorize entries)\n const d1Map = new Map((contentItems || []).map(item => [item.id, item]))\n\n // Deduplicate by content_id, keeping the best score per content item\n const bestByContent = new Map()\n for (const match of vectorResults.matches) {\n const cid = match.metadata?.content_id\n if (!cid || !d1Map.has(cid)) continue // Skip stale entries\n const existing = bestByContent.get(cid)\n if (!existing || match.score > existing.score) {\n bestByContent.set(cid, match)\n }\n }\n\n // Sort by score descending and apply score filtering.\n // Skip filtering in hybrid mode ā RRF handles ranking and needs the full candidate set.\n const sortedEntries = [...bestByContent.entries()]\n .sort((a, b) => b[1].score - a[1].score)\n\n if (query.mode !== 'hybrid') {\n const MIN_RELEVANCE_SCORE = 0.45\n const SCORE_GAP_THRESHOLD = 0.15\n const filteredEntries: [string, any][] = []\n for (let i = 0; i < sortedEntries.length; i++) {\n const entry = sortedEntries[i]!\n const score = entry[1].score\n if (score < MIN_RELEVANCE_SCORE) break\n\n if (i > 0) {\n const prevScore = sortedEntries[i - 1]![1].score\n const gap = prevScore - score\n if (gap > SCORE_GAP_THRESHOLD) {\n break\n }\n }\n\n filteredEntries.push(entry)\n }\n\n bestByContent.clear()\n for (const [key, value] of filteredEntries) {\n bestByContent.set(key, value)\n }\n }\n\n const searchResults: SearchResult[] = []\n for (const [contentId, bestMatch] of bestByContent) {\n const d1Item = d1Map.get(contentId)!\n searchResults.push({\n id: d1Item.id,\n title: d1Item.title || 'Untitled',\n slug: d1Item.slug || '',\n collection_id: d1Item.collection_id,\n collection_name: d1Item.collection_name,\n snippet: bestMatch.metadata?.text || '',\n relevance_score: bestMatch.score || 0,\n status: d1Item.status,\n created_at: d1Item.created_at,\n updated_at: d1Item.updated_at\n })\n }\n\n // Sort by relevance score\n searchResults.sort((a, b) => (b.relevance_score || 0) - (a.relevance_score || 0))\n\n const queryTime = Date.now() - startTime\n console.log(`[CustomRAG] Search completed in ${queryTime}ms, ${searchResults.length} results`)\n\n return {\n results: searchResults,\n total: searchResults.length,\n query_time_ms: queryTime,\n mode: 'ai'\n }\n } catch (error) {\n console.error('[CustomRAG] Search error:', error)\n throw error\n }\n }\n\n /**\n * Update index for a single content item\n */\n async updateContentIndex(contentId: string): Promise {\n try {\n // Get content item\n const content = await this.db\n .prepare(`\n SELECT c.id, c.title, c.data, c.collection_id, c.status,\n c.created_at, c.updated_at, c.author_id,\n col.name as collection_name, col.display_name as collection_display_name\n FROM content c\n JOIN collections col ON c.collection_id = col.id\n WHERE c.id = ?\n `)\n .bind(contentId)\n .first<{\n id: string\n title: string\n data: string\n collection_id: string\n status: string\n created_at: number\n updated_at: number\n author_id?: string\n collection_name: string\n collection_display_name: string\n }>()\n\n if (!content) {\n console.warn(`[CustomRAG] Content ${contentId} not found`)\n return\n }\n\n // If content is not published, remove from index\n if (content.status !== 'published') {\n await this.removeContentFromIndex(contentId)\n return\n }\n\n // Chunk content\n const chunks = this.chunkingService.chunkContent(\n content.id,\n content.collection_id,\n content.title || 'Untitled',\n typeof content.data === 'string' ? JSON.parse(content.data) : content.data,\n {\n status: content.status,\n created_at: content.created_at,\n updated_at: content.updated_at,\n author_id: content.author_id,\n collection_name: content.collection_name,\n collection_display_name: content.collection_display_name\n }\n )\n\n // Generate embeddings\n const embeddings = await this.embeddingService.generateBatch(\n chunks.map(c => `${c.title}\\n\\n${c.text}`)\n )\n\n // Update in Vectorize\n await this.vectorize.upsert(\n chunks.map((chunk, idx) => ({\n id: chunk.id,\n values: embeddings[idx],\n metadata: {\n content_id: chunk.content_id,\n collection_id: chunk.collection_id,\n title: chunk.title,\n text: chunk.text.substring(0, 500),\n chunk_index: chunk.chunk_index,\n ...chunk.metadata\n }\n }))\n )\n\n console.log(`[CustomRAG] Updated index for content ${contentId}: ${chunks.length} chunks`)\n } catch (error) {\n console.error(`[CustomRAG] Error updating index for ${contentId}:`, error)\n throw error\n }\n }\n\n /**\n * Remove content from index\n */\n async removeContentFromIndex(contentId: string): Promise {\n try {\n // Note: Vectorize doesn't have a bulk delete by metadata filter\n // We need to delete each chunk individually\n // In practice, we would track chunk IDs or use a different approach\n \n console.log(`[CustomRAG] Removing content ${contentId} from index`)\n \n // For now, we'll let stale chunks age out\n // A better approach would be to maintain a mapping in D1\n // TODO: Implement proper chunk tracking\n \n } catch (error) {\n console.error(`[CustomRAG] Error removing content ${contentId}:`, error)\n throw error\n }\n }\n\n /**\n * Get search suggestions based on query\n */\n async getSuggestions(partialQuery: string, limit: number = 5): Promise {\n try {\n // Generate embedding for partial query\n const queryEmbedding = await this.embeddingService.generateEmbedding(partialQuery)\n\n // Search for similar content titles\n const results = await this.vectorize.query(queryEmbedding, {\n topK: limit * 2, // Get more to filter\n returnMetadata: true\n })\n\n // Extract unique titles\n const suggestions = [...new Set(\n results.matches?.map((m: any) => m.metadata.title).filter(Boolean) || []\n )].slice(0, limit)\n\n return suggestions as string[]\n } catch (error) {\n console.error('[CustomRAG] Error getting suggestions:', error)\n return []\n }\n }\n\n /**\n * Check if Vectorize is available and configured\n */\n isAvailable(): boolean {\n return !!this.vectorize && !!this.ai\n }\n}\n","/**\n * Hybrid Search Service\n *\n * Combines FTS5 (BM25) and AI (Vectorize) search results using\n * Reciprocal Rank Fusion (RRF):\n * 1. Retrieve candidates from both FTS5 and AI in parallel\n * 2. Score each doc: RRF(d) = Ī£ 1/(k + rank_in_system)\n * 3. Docs found by BOTH systems get boosted (two rank contributions)\n * 4. Sort by combined RRF score, slice to limit\n *\n * RRF is the industry standard for multi-source fusion ā it properly\n * balances contributions without requiring score normalization.\n *\n * When Vectorize is unavailable (local dev), falls back to FTS5-only\n * while still returning mode: 'hybrid'.\n */\n\nimport type { SearchQuery, SearchResponse, SearchResult, AISearchSettings } from '../types'\nimport type { FTS5Service } from './fts5.service'\nimport type { CustomRAGService } from './custom-rag.service'\n\n/** RRF constant ā standard value from the original paper (Cormack et al. 2009) */\nconst RRF_K = 60\n\nexport class HybridSearchService {\n constructor(\n private fts5Service: FTS5Service,\n private customRAG?: CustomRAGService\n ) {}\n\n /**\n * Run FTS5 + AI searches in parallel, merge with RRF\n * Uses Promise.allSettled for partial failure tolerance\n *\n * Each sub-search retrieves 3x the final limit to give RRF a larger\n * candidate pool. This prevents relevant docs from one system being\n * displaced by irrelevant docs from the other when results are sliced.\n */\n async search(query: SearchQuery, settings: AISearchSettings): Promise {\n const startTime = Date.now()\n\n // Expand candidate pool: retrieve 3x limit from each sub-search\n const finalLimit = query.limit || settings.results_limit || 20\n const candidateLimit = finalLimit * 3\n const expandedQuery: SearchQuery = { ...query, limit: candidateLimit }\n\n // Build search promises: FTS5 always, AI only if available\n const fts5Weights = {\n titleBoost: settings.fts5_title_boost,\n slugBoost: settings.fts5_slug_boost,\n bodyBoost: settings.fts5_body_boost,\n }\n const searches: Promise[] = [\n this.fts5Service.search(expandedQuery, settings, fts5Weights)\n ]\n if (this.customRAG?.isAvailable()) {\n searches.push(this.customRAG.search(expandedQuery, settings))\n }\n\n const settled = await Promise.allSettled(searches)\n\n // Extract fulfilled results, log any rejections\n const fulfilled: SearchResponse[] = []\n for (const result of settled) {\n if (result.status === 'fulfilled') {\n fulfilled.push(result.value)\n } else {\n console.error('[HybridSearch] One search leg failed:', result.reason)\n }\n }\n\n // If ALL legs failed, return empty results\n if (fulfilled.length === 0) {\n return {\n results: [],\n total: 0,\n query_time_ms: Date.now() - startTime,\n mode: 'hybrid'\n }\n }\n\n // Single leg (FTS5 only) ā no fusion needed\n if (fulfilled.length === 1) {\n const single = fulfilled[0]!\n return {\n results: single.results,\n total: single.total,\n suggestions: single.suggestions,\n mode: 'hybrid' as const,\n query_time_ms: Date.now() - startTime\n }\n }\n\n // Two legs: Reciprocal Rank Fusion\n return this.mergeWithRRF(fulfilled[0]!, fulfilled[1]!, query, settings, startTime)\n }\n\n /**\n * Reciprocal Rank Fusion (RRF)\n *\n * For each document d, compute:\n * RRF_score(d) = Ī£ 1/(k + rank_i(d))\n * where rank_i(d) is the 1-based rank of d in system i.\n *\n * Docs found by both systems get two contributions (higher score).\n * k=60 smooths out rank differences (standard value).\n */\n private mergeWithRRF(\n fts5Response: SearchResponse,\n aiResponse: SearchResponse,\n query: SearchQuery,\n settings: AISearchSettings,\n startTime: number\n ): SearchResponse {\n // RRF score accumulator and doc data store\n const rrfScores = new Map()\n const docData = new Map()\n\n // Score AI results (1-based rank)\n aiResponse.results.forEach((doc, i) => {\n const rank = i + 1\n const score = 1.0 / (RRF_K + rank)\n rrfScores.set(doc.id, (rrfScores.get(doc.id) || 0) + score)\n docData.set(doc.id, { ...doc })\n })\n\n // Score FTS5 results (1-based rank)\n fts5Response.results.forEach((doc, i) => {\n const rank = i + 1\n const score = 1.0 / (RRF_K + rank)\n rrfScores.set(doc.id, (rrfScores.get(doc.id) || 0) + score)\n\n // Merge: keep AI data if exists, add FTS5 highlights/bm25\n const existing = docData.get(doc.id)\n if (existing) {\n if (doc.highlights) existing.highlights = doc.highlights\n if (doc.bm25_score) existing.bm25_score = doc.bm25_score\n } else {\n docData.set(doc.id, { ...doc })\n }\n })\n\n // Sort by RRF score descending\n const sorted = [...rrfScores.entries()].sort((a, b) => b[1] - a[1])\n\n const limit = query.limit || settings.results_limit || 20\n const results: SearchResult[] = sorted.slice(0, limit).map(([id, score]) => ({\n ...docData.get(id)!,\n relevance_score: score,\n }))\n\n return {\n mode: 'hybrid',\n results,\n total: rrfScores.size,\n query_time_ms: Date.now() - startTime,\n }\n }\n}\n","/**\n * Query Rewriter Service\n *\n * Uses Workers AI LLM to expand vague or short queries with\n * relevant search terms before dispatching to the search pipeline.\n *\n * Off by default (query_rewriting_enabled setting). Only activates when:\n * - AI binding is available\n * - Setting is enabled\n * - Query is at least 15 characters\n * - Mode is 'hybrid'\n */\n\nconst REWRITE_SYSTEM_PROMPT = `You are a search query optimizer. Given a user's search query, rewrite it to improve search results by:\n- Adding relevant synonyms or related terms\n- Expanding abbreviations\n- Keeping the core intent intact\n\nRules:\n- Return ONLY the rewritten query, nothing else\n- Keep it concise (under 100 characters)\n- Do not add explanations or formatting\n- Do not wrap in quotes\n- If the query is already precise, return it unchanged`\n\nexport class QueryRewriterService {\n constructor(private ai: any) {}\n\n /**\n * Rewrite a query using LLM expansion\n * Returns original query on any failure\n */\n async rewrite(originalQuery: string): Promise {\n try {\n const response = await this.ai.run(\n '@cf/meta/llama-3.1-8b-instruct-fp8-fast',\n {\n messages: [\n { role: 'system', content: REWRITE_SYSTEM_PROMPT },\n { role: 'user', content: originalQuery }\n ],\n max_tokens: 100\n }\n )\n\n const rewritten = response.response?.trim()\n\n // Validation: reject if empty\n if (!rewritten) return originalQuery\n\n // Reject if too long (>3x original or >200 chars)\n if (rewritten.length > originalQuery.length * 3) return originalQuery\n if (rewritten.length > 200) return originalQuery\n\n // Reject multi-line responses (likely explanations, not queries)\n if (rewritten.includes('\\n')) return originalQuery\n\n return rewritten\n } catch (error) {\n console.error('[QueryRewriter] LLM call failed, using original query:', error)\n return originalQuery\n }\n }\n\n /**\n * Check if a query should be rewritten\n * Short/precise queries don't benefit from rewriting\n */\n static shouldRewrite(query: string): boolean {\n return query.length >= 15\n }\n}\n","import type { D1Database } from '@cloudflare/workers-types'\nimport type { QueryRule } from '../types'\n\n/**\n * Query Rules Service\n *\n * Deterministic pre-dispatch query substitution: \"if user searches X, replace with Y\".\n * Rules are checked priority DESC, first match wins, before any search mode dispatch.\n */\nexport class QueryRulesService {\n constructor(private db: D1Database) {}\n\n // === CRUD ===\n\n async getAll(): Promise {\n try {\n const { results } = await this.db\n .prepare('SELECT id, match_pattern, match_type, substitute_query, enabled, priority, created_at, updated_at FROM ai_search_query_rules ORDER BY priority DESC, created_at DESC')\n .all<{ id: string; match_pattern: string; match_type: string; substitute_query: string; enabled: number; priority: number; created_at: number; updated_at: number }>()\n\n return (results || []).map(row => ({\n id: row.id,\n match_pattern: row.match_pattern,\n match_type: row.match_type as 'exact' | 'prefix',\n substitute_query: row.substitute_query,\n enabled: row.enabled === 1,\n priority: row.priority,\n created_at: row.created_at,\n updated_at: row.updated_at,\n }))\n } catch {\n return []\n }\n }\n\n async getById(id: string): Promise {\n try {\n const row = await this.db\n .prepare('SELECT id, match_pattern, match_type, substitute_query, enabled, priority, created_at, updated_at FROM ai_search_query_rules WHERE id = ?')\n .bind(id)\n .first<{ id: string; match_pattern: string; match_type: string; substitute_query: string; enabled: number; priority: number; created_at: number; updated_at: number }>()\n\n if (!row) return null\n\n return {\n id: row.id,\n match_pattern: row.match_pattern,\n match_type: row.match_type as 'exact' | 'prefix',\n substitute_query: row.substitute_query,\n enabled: row.enabled === 1,\n priority: row.priority,\n created_at: row.created_at,\n updated_at: row.updated_at,\n }\n } catch {\n return null\n }\n }\n\n async create(data: {\n match_pattern: string\n match_type?: 'exact' | 'prefix'\n substitute_query: string\n enabled?: boolean\n priority?: number\n }): Promise {\n const pattern = data.match_pattern.trim()\n const substitute = data.substitute_query.trim()\n if (!pattern) throw new Error('match_pattern is required')\n if (!substitute) throw new Error('substitute_query is required')\n\n const id = crypto.randomUUID().replace(/-/g, '')\n const matchType = data.match_type || 'exact'\n const enabled = data.enabled !== false\n const priority = data.priority ?? 0\n\n await this.db\n .prepare('INSERT INTO ai_search_query_rules (id, match_pattern, match_type, substitute_query, enabled, priority) VALUES (?, ?, ?, ?, ?, ?)')\n .bind(id, pattern, matchType, substitute, enabled ? 1 : 0, priority)\n .run()\n\n const created = await this.getById(id)\n if (!created) throw new Error('Failed to create query rule')\n return created\n }\n\n async update(id: string, data: {\n match_pattern?: string\n match_type?: 'exact' | 'prefix'\n substitute_query?: string\n enabled?: boolean\n priority?: number\n }): Promise {\n const existing = await this.getById(id)\n if (!existing) return null\n\n const pattern = data.match_pattern !== undefined ? data.match_pattern.trim() : existing.match_pattern\n const matchType = data.match_type !== undefined ? data.match_type : existing.match_type\n const substitute = data.substitute_query !== undefined ? data.substitute_query.trim() : existing.substitute_query\n const enabled = data.enabled !== undefined ? data.enabled : existing.enabled\n const priority = data.priority !== undefined ? data.priority : existing.priority\n\n if (!pattern) throw new Error('match_pattern cannot be empty')\n if (!substitute) throw new Error('substitute_query cannot be empty')\n\n await this.db\n .prepare('UPDATE ai_search_query_rules SET match_pattern = ?, match_type = ?, substitute_query = ?, enabled = ?, priority = ?, updated_at = unixepoch() WHERE id = ?')\n .bind(pattern, matchType, substitute, enabled ? 1 : 0, priority, id)\n .run()\n\n return this.getById(id)\n }\n\n async delete(id: string): Promise {\n const result = await this.db\n .prepare('DELETE FROM ai_search_query_rules WHERE id = ?')\n .bind(id)\n .run()\n\n return (result.meta?.changes ?? 0) > 0\n }\n\n // === Query Substitution ===\n\n /**\n * Apply substitution rules to a query string.\n * Loads enabled rules (priority DESC), first match wins.\n * - Exact: LOWER(query) === LOWER(pattern)\n * - Prefix: LOWER(query).startsWith(LOWER(pattern)) ā preserves suffix\n * Returns the (possibly modified) query plus metadata.\n */\n async applyRules(query: string): Promise<{ query: string; ruleId?: string; originalQuery?: string }> {\n try {\n const rules = await this.getEnabled()\n if (rules.length === 0) return { query }\n\n const queryLower = query.toLowerCase().trim()\n\n for (const rule of rules) {\n const patternLower = rule.match_pattern.toLowerCase().trim()\n\n if (rule.match_type === 'exact') {\n if (queryLower === patternLower) {\n return {\n query: rule.substitute_query,\n ruleId: rule.id,\n originalQuery: query,\n }\n }\n } else if (rule.match_type === 'prefix') {\n if (queryLower.startsWith(patternLower)) {\n // Preserve suffix: \"docs api\" + rule \"docs\"ā\"documentation\" = \"documentation api\"\n const suffix = query.substring(rule.match_pattern.trim().length)\n return {\n query: rule.substitute_query + suffix,\n ruleId: rule.id,\n originalQuery: query,\n }\n }\n }\n }\n\n return { query }\n } catch (error) {\n console.warn('[QueryRulesService] applyRules error (returning original query):', error)\n return { query }\n }\n }\n\n // === Helpers ===\n\n private async getEnabled(): Promise {\n try {\n const { results } = await this.db\n .prepare('SELECT id, match_pattern, match_type, substitute_query, enabled, priority, created_at, updated_at FROM ai_search_query_rules WHERE enabled = 1 ORDER BY priority DESC')\n .all<{ id: string; match_pattern: string; match_type: string; substitute_query: string; enabled: number; priority: number; created_at: number; updated_at: number }>()\n\n return (results || []).map(row => ({\n id: row.id,\n match_pattern: row.match_pattern,\n match_type: row.match_type as 'exact' | 'prefix',\n substitute_query: row.substitute_query,\n enabled: row.enabled === 1,\n priority: row.priority,\n created_at: row.created_at,\n updated_at: row.updated_at,\n }))\n } catch {\n return []\n }\n }\n}\n","/**\n * AI Search Plugin Types\n */\n\nexport interface AISearchSettings {\n id?: number\n enabled: boolean\n ai_mode_enabled: boolean\n selected_collections: string[] // Collection IDs to index (TEXT/UUID)\n dismissed_collections: string[] // Collection IDs user dismissed (TEXT/UUID)\n autocomplete_enabled: boolean\n cache_duration: number // hours\n results_limit: number\n index_media: boolean\n index_status?: Record // Collection ID -> status\n last_indexed_at?: number\n created_at?: number\n updated_at?: number\n // Phase 2: Hybrid search settings\n query_rewriting_enabled?: boolean // Off by default, adds ~100-300ms latency\n reranking_enabled?: boolean // On by default, adds ~50-150ms latency\n // Phase 2: FTS5 field weight tuning (BM25 boosting)\n fts5_title_boost?: number // Default: 5.0\n fts5_slug_boost?: number // Default: 2.0\n fts5_body_boost?: number // Default: 1.0\n // Phase 2C: Query Synonyms\n query_synonyms_enabled?: boolean // Default: true\n // Faceted Search\n facets_enabled?: boolean // Master toggle (default: false)\n facet_config?: FacetDefinition[] // Ordered list of configured facets\n facet_max_values?: number // Global max values per facet (default: 20)\n // Related Searches\n related_searches_enabled?: boolean // Master toggle (default: true)\n}\n\nexport interface IndexStatus {\n collection_id: string // Collection ID (TEXT/UUID)\n collection_name: string\n total_items: number\n indexed_items: number\n last_sync_at?: number\n status: 'pending' | 'indexing' | 'completed' | 'error'\n error_message?: string\n}\n\nexport interface SearchQuery {\n query: string\n mode: 'ai' | 'keyword' | 'fts5' | 'hybrid'\n filters?: SearchFilters\n limit?: number\n offset?: number\n facets?: boolean // Request facet computation alongside results\n cache?: boolean // Set to false to bypass KV result cache (default: true)\n}\n\nexport interface SearchFilters {\n collections?: string[] // Collection IDs to search (TEXT/UUID)\n dateRange?: {\n start: Date\n end: Date\n field?: 'created_at' | 'updated_at'\n }\n status?: string[] // draft, published, archived, etc.\n tags?: string[]\n author?: string // author_id (TEXT/UUID)\n custom?: Record // Custom metadata filters\n}\n\nexport interface SearchResult {\n id: string\n title: string\n slug: string\n collection_id: string // Collection ID (TEXT/UUID)\n collection_name: string\n snippet?: string\n relevance_score?: number // For AI and FTS5 search\n status: string\n created_at: number\n updated_at: number\n author_name?: string\n url?: string\n // FTS5-specific fields\n highlights?: {\n title?: string // Full title with tags around matches\n body?: string // Body snippet with tags around matches\n }\n bm25_score?: number // Raw BM25 score (positive, higher = better match)\n // Phase 2: Hybrid search fields\n rrf_score?: number // Reciprocal Rank Fusion score (internal sorting)\n rerank_score?: number // Cross-encoder reranking score\n pipeline_score?: number // Composite ranking pipeline score [0, 1]\n}\n\nexport interface SearchResponse {\n results: SearchResult[]\n total: number\n query_time_ms: number\n mode: 'ai' | 'keyword' | 'fts5' | 'hybrid'\n search_id?: string // ID linking to ai_search_history row for click tracking\n suggestions?: string[] // Autocomplete suggestions\n facets?: FacetResult[] // Facet counts from full result set\n original_query?: string // Set when a query substitution rule was applied\n applied_rule_id?: string // ID of the substitution rule that matched\n cached?: boolean // True when result was served from KV cache\n related_searches?: RelatedSearchResult[] // Related search suggestions\n}\n\nexport interface SearchHistory {\n id: number\n query: string\n mode: 'ai' | 'keyword' | 'fts5' | 'hybrid'\n results_count: number\n user_id?: number\n created_at: number\n}\n\nexport interface CollectionInfo {\n id: string // Collection ID (TEXT/UUID)\n name: string\n display_name: string\n description?: string\n item_count?: number\n is_indexed: boolean\n is_dismissed: boolean\n is_new?: boolean\n}\n\nexport interface NewCollectionNotification {\n collection: CollectionInfo\n message: string\n}\n\n/** Configuration for a single ranking pipeline stage */\nexport interface RankingStage {\n type: 'exactMatch' | 'bm25' | 'semantic' | 'recency' | 'popularity' | 'custom'\n weight: number // 0-10, step 0.1\n enabled: boolean\n config?: Record // Stage-specific (e.g. recency half_life_days)\n}\n\n/** A bidirectional synonym group ā searching any term expands to all terms */\nexport interface SynonymGroup {\n id: string\n terms: string[]\n enabled: boolean\n created_at: number\n updated_at: number\n}\n\n/** A deterministic query substitution rule ā \"if user searches X, replace with Y\" */\nexport interface QueryRule {\n id: string\n match_pattern: string\n match_type: 'exact' | 'prefix'\n substitute_query: string\n enabled: boolean\n priority: number\n created_at: number\n updated_at: number\n}\n\n/** Default pipeline ā used when no config exists in DB */\nexport const DEFAULT_RANKING_PIPELINE: RankingStage[] = [\n { type: 'exactMatch', weight: 10, enabled: true },\n { type: 'bm25', weight: 5, enabled: true },\n { type: 'semantic', weight: 3, enabled: true },\n { type: 'recency', weight: 1, enabled: true, config: { half_life_days: 30 } },\n { type: 'popularity', weight: 0, enabled: false },\n { type: 'custom', weight: 0, enabled: false },\n]\n\n// ==========================================\n// Faceted Search Types\n// ==========================================\n\n/** Persisted facet configuration ā stored in AISearchSettings.facet_config */\nexport interface FacetDefinition {\n name: string // Display name (\"Tags\", \"Category\", \"Status\")\n field: string // \"collection_name\" | \"status\" | \"author\" | \"$.tags\" | \"$.category\"\n type: 'builtin' | 'json_scalar' | 'json_array'\n collections?: string[] // Collection IDs that have this field (empty = all)\n maxValues?: number // Per-facet limit override (default: 20)\n sortBy?: 'count' | 'alpha' // Default: 'count'\n enabled: boolean\n source: 'auto' | 'manual' | 'agent' // Who created this config entry\n position: number // Display order (Phase 6 agent can optimize)\n}\n\n/** Facet counts returned in search response */\nexport interface FacetResult {\n name: string // Display name\n field: string // Field identifier\n values: FacetValue[]\n}\n\nexport interface FacetValue {\n value: string\n count: number\n}\n\n/** Field discovered from collection schemas ā returned by discover endpoint */\nexport interface DiscoveredField {\n field: string // JSON path or built-in name (\"$.tags\", \"collection_name\")\n title: string // Human label from schema or built-in\n type: 'builtin' | 'json_scalar' | 'json_array'\n recommended: boolean // true for enum, array, boolean fields\n collections: Array<{ id: string; name: string }> // Which collections have this field\n enumValues?: string[] // Known values for enum-type fields\n}\n\n// ==========================================\n// InstantSearch.js Protocol Types (Algolia-compatible)\n// ==========================================\n\nexport interface InstantSearchRequest {\n indexName: string\n params?: InstantSearchParams\n}\n\nexport interface InstantSearchParams {\n query?: string\n page?: number\n hitsPerPage?: number\n facets?: string[]\n facetFilters?: string[] | string[][] // Algolia facet filter format\n filters?: string\n highlightPreTag?: string\n highlightPostTag?: string\n attributesToRetrieve?: string[]\n attributesToHighlight?: string[]\n attributesToSnippet?: string[]\n}\n\nexport interface InstantSearchHit {\n objectID: string\n [key: string]: any\n // eslint-disable-next-line @typescript-eslint/naming-convention -- Algolia protocol field name\n _highlightResult?: Record\n // eslint-disable-next-line @typescript-eslint/naming-convention -- Algolia protocol field name\n _snippetResult?: Record\n}\n\nexport interface InstantSearchResult {\n hits: InstantSearchHit[]\n nbHits: number\n page: number\n nbPages: number\n hitsPerPage: number\n processingTimeMS: number\n query: string\n params: string\n exhaustiveNbHits?: boolean\n facets?: Record>\n index?: string\n}\n\nexport interface InstantSearchMultiResponse {\n results: InstantSearchResult[]\n}\n\n// ==========================================\n// AI Search Quality Agent Types\n// ==========================================\n\nexport type RecommendationCategory = 'synonym' | 'query_rule' | 'low_ctr' | 'unused_facet' | 'content_gap' | 'related_search'\nexport type RecommendationStatus = 'pending' | 'applied' | 'dismissed'\n\nexport interface Recommendation {\n id: string\n category: RecommendationCategory\n title: string\n description: string\n supporting_data: Record\n action_payload: Record | null\n status: RecommendationStatus\n fingerprint: string\n run_id: string\n applied_at: number | null\n created_at: number\n updated_at: number\n}\n\nexport interface AgentRun {\n id: string\n status: 'running' | 'completed' | 'failed'\n recommendations_count: number\n duration_ms: number | null\n error_message: string | null\n created_at: number\n completed_at: number | null\n}\n\n// ==========================================\n// Trending Searches Types\n// ==========================================\n\nexport interface TrendingSearch {\n query: string\n trend_score: number\n search_count: number\n}\n\nexport interface TrendingSearchResult {\n items: TrendingSearch[]\n cached: boolean\n}\n\n// ==========================================\n// Related Searches Types\n// ==========================================\n\nexport interface RelatedSearch {\n id: string\n source_query: string\n related_query: string\n source: 'manual' | 'agent'\n position: number\n bidirectional: boolean\n enabled: boolean\n created_at: number\n updated_at: number\n}\n\nexport interface RelatedSearchResult {\n query: string\n source: 'manual' | 'agent' | 'auto'\n}\n\n// ==========================================\n// A/B Testing / Experiments Types\n// ==========================================\n\nexport type ExperimentStatus = 'draft' | 'running' | 'paused' | 'completed' | 'archived'\nexport type ExperimentMode = 'ab' | 'interleave' | 'bandit'\n\nexport interface Experiment {\n id: string\n name: string\n description: string | null\n status: ExperimentStatus\n mode: ExperimentMode\n traffic_pct: number\n split_ratio: number\n variants: {\n control: Partial\n treatment: Partial\n }\n metrics: ExperimentMetrics | null\n winner: string | null\n confidence: number | null\n min_searches: number\n started_at: number | null\n ended_at: number | null\n created_at: number\n updated_at: number\n}\n\nexport interface ExperimentMetrics {\n control: VariantMetrics\n treatment: VariantMetrics\n confidence: number\n significant: boolean\n}\n\nexport interface VariantMetrics {\n searches: number\n clicks: number\n ctr: number\n zero_result_rate: number\n avg_click_position: number\n avg_response_time_ms: number\n}\n\nexport interface InterleavedResult {\n contentId: string\n origin: 'control' | 'treatment'\n}\n\nexport interface InterleaveOutput {\n results: SearchResult[]\n origins: Record\n}\n","import type { D1Database } from '@cloudflare/workers-types'\nimport type { RankingStage, SearchResult, SearchResponse } from '../types'\nimport { DEFAULT_RANKING_PIPELINE } from '../types'\n\n/** Clamp a weight value to [0, 10] with 1 decimal place */\nfunction clampWeight(val: any, fallback: number): number {\n const n = Number(val)\n return (isNaN(n) || !isFinite(n)) ? fallback : Math.round(Math.min(10, Math.max(0, n)) * 10) / 10\n}\n\nconst VALID_STAGE_TYPES = new Set(['exactMatch', 'bm25', 'semantic', 'recency', 'popularity', 'custom'])\n\n/**\n * Ranking Pipeline Service\n *\n * Manages a composable scoring pipeline that post-processes search results.\n * Each stage produces a [0, 1] score, combined via weighted sum into pipeline_score.\n */\nexport class RankingPipelineService {\n constructor(private db: D1Database) {}\n\n // === Config CRUD ===\n\n async getConfig(): Promise {\n try {\n const row = await this.db\n .prepare(\"SELECT pipeline_json FROM ai_search_ranking_config WHERE id = 'default' LIMIT 1\")\n .first<{ pipeline_json: string }>()\n\n if (!row?.pipeline_json) {\n return structuredClone(DEFAULT_RANKING_PIPELINE)\n }\n\n return this.validateStages(JSON.parse(row.pipeline_json))\n } catch {\n // Table may not exist yet (migration not run)\n return structuredClone(DEFAULT_RANKING_PIPELINE)\n }\n }\n\n async saveConfig(stages: RankingStage[]): Promise {\n const validated = this.validateStages(stages)\n await this.db\n .prepare(`\n INSERT INTO ai_search_ranking_config (id, pipeline_json, updated_at)\n VALUES ('default', ?, unixepoch())\n ON CONFLICT(id) DO UPDATE SET pipeline_json = excluded.pipeline_json, updated_at = excluded.updated_at\n `)\n .bind(JSON.stringify(validated))\n .run()\n }\n\n private validateStages(stages: RankingStage[]): RankingStage[] {\n if (!Array.isArray(stages)) return structuredClone(DEFAULT_RANKING_PIPELINE)\n return stages\n .filter(s => VALID_STAGE_TYPES.has(s.type))\n .map(s => ({\n type: s.type,\n weight: clampWeight(s.weight, 0),\n enabled: Boolean(s.enabled),\n config: s.config || undefined,\n }))\n }\n\n // === Pipeline Execution ===\n\n async apply(response: SearchResponse, query: string): Promise {\n const results = response.results\n if (results.length === 0) return response\n\n const stages = await this.getConfig()\n const activeStages = stages.filter(s => s.enabled && s.weight > 0)\n if (activeStages.length === 0) return response\n\n const totalWeight = activeStages.reduce((sum, s) => sum + s.weight, 0)\n if (totalWeight === 0) return response\n\n // Pre-compute BM25 min/max for normalization\n let minBM25 = Infinity\n let maxBM25 = -Infinity\n const hasBM25 = activeStages.some(s => s.type === 'bm25')\n if (hasBM25) {\n for (const r of results) {\n if (r.bm25_score != null) {\n if (r.bm25_score < minBM25) minBM25 = r.bm25_score\n if (r.bm25_score > maxBM25) maxBM25 = r.bm25_score\n }\n }\n if (minBM25 === Infinity) { minBM25 = 0; maxBM25 = 0 }\n }\n\n // Batch-load content scores if needed\n const contentIds = results.map(r => r.id)\n let popularityScores = new Map()\n let customScores = new Map()\n\n const needsPopularity = activeStages.some(s => s.type === 'popularity')\n const needsCustom = activeStages.some(s => s.type === 'custom')\n\n if (needsPopularity) {\n popularityScores = await this.getContentScores(contentIds, 'popularity')\n this.normalizeScoresMinMax(popularityScores)\n }\n if (needsCustom) {\n customScores = await this.getContentScores(contentIds, 'custom')\n }\n\n // Compute pipeline_score for each result\n for (const result of results) {\n let weightedSum = 0\n\n for (const stage of activeStages) {\n let score = 0\n\n switch (stage.type) {\n case 'exactMatch':\n score = this.scoreExactMatch(result, query)\n break\n case 'bm25':\n score = this.scoreBM25(result, minBM25, maxBM25)\n break\n case 'semantic':\n score = this.scoreSemantic(result)\n break\n case 'recency':\n score = this.scoreRecency(result, stage.config?.half_life_days ?? 30)\n break\n case 'popularity':\n score = popularityScores.get(result.id) ?? 0\n break\n case 'custom':\n score = Math.max(0, Math.min(1, customScores.get(result.id) ?? 0))\n break\n }\n\n weightedSum += stage.weight * score\n }\n\n result.pipeline_score = weightedSum / totalWeight\n }\n\n // Re-sort by pipeline_score descending\n results.sort((a, b) => (b.pipeline_score ?? 0) - (a.pipeline_score ?? 0))\n\n return { ...response, results }\n }\n\n // === Content Scores CRUD ===\n\n async getContentScores(contentIds: string[], scoreType: string): Promise> {\n if (contentIds.length === 0) return new Map()\n\n try {\n const placeholders = contentIds.map(() => '?').join(',')\n const { results } = await this.db\n .prepare(`SELECT content_id, score FROM ai_search_content_scores WHERE content_id IN (${placeholders}) AND score_type = ?`)\n .bind(...contentIds, scoreType)\n .all<{ content_id: string; score: number }>()\n\n const map = new Map()\n for (const row of results || []) {\n map.set(row.content_id, row.score)\n }\n return map\n } catch {\n return new Map()\n }\n }\n\n async setContentScore(contentId: string, scoreType: string, score: number): Promise {\n const clamped = Math.max(0, Math.min(1, score))\n await this.db\n .prepare(`\n INSERT INTO ai_search_content_scores (content_id, score_type, score, updated_at)\n VALUES (?, ?, ?, unixepoch())\n ON CONFLICT(content_id, score_type) DO UPDATE SET score = excluded.score, updated_at = excluded.updated_at\n `)\n .bind(contentId, scoreType, clamped)\n .run()\n }\n\n async deleteContentScore(contentId: string, scoreType: string): Promise {\n await this.db\n .prepare('DELETE FROM ai_search_content_scores WHERE content_id = ? AND score_type = ?')\n .bind(contentId, scoreType)\n .run()\n }\n\n // === Scoring Functions ===\n\n private scoreExactMatch(result: SearchResult, query: string): number {\n if (!query || !result.title) return 0\n return result.title.toLowerCase().includes(query.toLowerCase()) ? 1.0 : 0.0\n }\n\n private scoreBM25(result: SearchResult, minBM25: number, maxBM25: number): number {\n if (result.bm25_score == null) return 0\n if (maxBM25 === minBM25) return 1.0\n return (result.bm25_score - minBM25) / (maxBM25 - minBM25)\n }\n\n private scoreSemantic(result: SearchResult): number {\n return result.relevance_score ?? 0\n }\n\n private scoreRecency(result: SearchResult, halfLifeDays: number): number {\n if (!result.created_at) return 0\n const nowMs = Date.now()\n // Handle both Unix seconds and milliseconds\n const createdMs = result.created_at > 1e12 ? result.created_at : result.created_at * 1000\n const ageDays = (nowMs - createdMs) / (1000 * 60 * 60 * 24)\n if (ageDays <= 0) return 1.0\n if (halfLifeDays <= 0) return 0\n return Math.exp(-Math.LN2 * ageDays / halfLifeDays)\n }\n\n /** Min-max normalize a map of scores in-place */\n private normalizeScoresMinMax(scores: Map): void {\n if (scores.size === 0) return\n let min = Infinity\n let max = -Infinity\n for (const v of scores.values()) {\n if (v < min) min = v\n if (v > max) max = v\n }\n if (max === min) {\n for (const k of scores.keys()) scores.set(k, scores.size > 0 ? 1.0 : 0)\n return\n }\n for (const [k, v] of scores) {\n scores.set(k, (v - min) / (max - min))\n }\n }\n}\n","import type { D1Database } from '@cloudflare/workers-types'\nimport type { SynonymGroup } from '../types'\n\n/**\n * Synonym Service\n *\n * Manages bidirectional synonym groups and provides query expansion.\n * All terms in a group are equivalent ā searching any one expands to all.\n */\nexport class SynonymService {\n constructor(private db: D1Database) {}\n\n // === CRUD ===\n\n async getAll(): Promise {\n try {\n const { results } = await this.db\n .prepare('SELECT id, terms, enabled, created_at, updated_at FROM ai_search_synonyms ORDER BY created_at DESC')\n .all<{ id: string; terms: string; enabled: number; created_at: number; updated_at: number }>()\n\n return (results || []).map(row => ({\n id: row.id,\n terms: JSON.parse(row.terms),\n enabled: row.enabled === 1,\n created_at: row.created_at,\n updated_at: row.updated_at,\n }))\n } catch {\n return []\n }\n }\n\n async getById(id: string): Promise {\n try {\n const row = await this.db\n .prepare('SELECT id, terms, enabled, created_at, updated_at FROM ai_search_synonyms WHERE id = ?')\n .bind(id)\n .first<{ id: string; terms: string; enabled: number; created_at: number; updated_at: number }>()\n\n if (!row) return null\n\n return {\n id: row.id,\n terms: JSON.parse(row.terms),\n enabled: row.enabled === 1,\n created_at: row.created_at,\n updated_at: row.updated_at,\n }\n } catch {\n return null\n }\n }\n\n async create(terms: string[], enabled: boolean = true): Promise {\n const sanitized = this.sanitizeTerms(terms)\n if (sanitized.length < 2) {\n throw new Error('A synonym group must have at least 2 terms')\n }\n\n const id = crypto.randomUUID().replace(/-/g, '')\n\n await this.db\n .prepare('INSERT INTO ai_search_synonyms (id, terms, enabled) VALUES (?, ?, ?)')\n .bind(id, JSON.stringify(sanitized), enabled ? 1 : 0)\n .run()\n\n const created = await this.getById(id)\n if (!created) throw new Error('Failed to create synonym group')\n return created\n }\n\n async update(id: string, data: { terms?: string[]; enabled?: boolean }): Promise {\n const existing = await this.getById(id)\n if (!existing) return null\n\n const terms = data.terms !== undefined ? this.sanitizeTerms(data.terms) : existing.terms\n if (terms.length < 2) {\n throw new Error('A synonym group must have at least 2 terms')\n }\n const enabled = data.enabled !== undefined ? data.enabled : existing.enabled\n\n await this.db\n .prepare('UPDATE ai_search_synonyms SET terms = ?, enabled = ?, updated_at = unixepoch() WHERE id = ?')\n .bind(JSON.stringify(terms), enabled ? 1 : 0, id)\n .run()\n\n return this.getById(id)\n }\n\n async delete(id: string): Promise {\n const result = await this.db\n .prepare('DELETE FROM ai_search_synonyms WHERE id = ?')\n .bind(id)\n .run()\n\n return (result.meta?.changes ?? 0) > 0\n }\n\n // === Query Expansion ===\n\n /**\n * Expand an array of sanitized search terms using enabled synonym groups.\n * For each input term, if it appears in a group, all other terms from\n * that group are added. Returns deduplicated expanded term list.\n */\n async expandQuery(terms: string[]): Promise {\n const groups = await this.getEnabled()\n if (groups.length === 0) return terms\n\n // Build lookup: lowercase term ā Set of all synonym terms in its groups\n const synonymMap = new Map>()\n for (const group of groups) {\n const lowerTerms = group.terms.map(t => t.toLowerCase())\n for (const term of lowerTerms) {\n if (!synonymMap.has(term)) {\n synonymMap.set(term, new Set())\n }\n for (const synonym of lowerTerms) {\n synonymMap.get(term)!.add(synonym)\n }\n }\n }\n\n // Expand each input term\n const expanded = new Set()\n for (const term of terms) {\n expanded.add(term.toLowerCase())\n const synonyms = synonymMap.get(term.toLowerCase())\n if (synonyms) {\n for (const syn of synonyms) {\n expanded.add(syn)\n }\n }\n }\n\n return Array.from(expanded)\n }\n\n // === Helpers ===\n\n private async getEnabled(): Promise {\n try {\n const { results } = await this.db\n .prepare('SELECT id, terms, enabled, created_at, updated_at FROM ai_search_synonyms WHERE enabled = 1')\n .all<{ id: string; terms: string; enabled: number; created_at: number; updated_at: number }>()\n\n return (results || []).map(row => ({\n id: row.id,\n terms: JSON.parse(row.terms),\n enabled: row.enabled === 1,\n created_at: row.created_at,\n updated_at: row.updated_at,\n }))\n } catch {\n return []\n }\n }\n\n /** Sanitize terms: trim, lowercase, deduplicate, remove empties */\n private sanitizeTerms(terms: string[]): string[] {\n const seen = new Set()\n const result: string[] = []\n for (const raw of terms) {\n const term = raw.trim().toLowerCase()\n if (term && !seen.has(term)) {\n seen.add(term)\n result.push(term)\n }\n }\n return result\n }\n}\n","/**\n * Reranker Service\n *\n * Uses @cf/baai/bge-reranker-base cross-encoder to rerank search results\n * by scoring each (query, passage) pair for semantic relevance.\n *\n * API shape (verified from Cloudflare Workers AI docs):\n * Request: { query: string, contexts: [{text: string}, ...], top_k?: number }\n * Response: [{id: number, score: number}, ...] where id = original index, score in [0,1]\n *\n * On by default (reranking_enabled setting). Gracefully falls back to\n * original order on any error.\n */\n\nimport type { SearchResult } from '../types'\n\nexport class RerankerService {\n constructor(private ai: any) {}\n\n /**\n * Rerank results using cross-encoder scoring\n * Returns results sorted by reranker score with rerank_score field added\n */\n async rerank(\n query: string,\n results: SearchResult[],\n topK?: number\n ): Promise {\n if (results.length <= 1) return results\n\n const limit = topK || results.length\n\n try {\n // Build contexts from result titles + snippets\n const contexts = results.map(r => ({\n text: `${r.title}. ${r.snippet || ''}`\n }))\n\n const response = await this.ai.run('@cf/baai/bge-reranker-base', {\n query,\n contexts,\n top_k: limit\n })\n\n // Response is an array of {id: number, score: number}\n // where id references the original index in contexts\n const scores = Array.isArray(response) ? response : response.response\n if (!Array.isArray(scores) || scores.length === 0) {\n console.warn('[Reranker] Unexpected response format, returning original order')\n return results.slice(0, limit)\n }\n\n // Map scores back to results by original index\n const reranked: SearchResult[] = scores\n .filter((s: any) => s.id >= 0 && s.id < results.length)\n .map((s: any) => {\n const result = results[s.id]!\n return { ...result, rerank_score: s.score }\n })\n\n return reranked.slice(0, limit)\n } catch (error) {\n console.error('[Reranker] Cross-encoder failed, returning original order:', error)\n return results.slice(0, limit)\n }\n }\n}\n","import type { D1Database, KVNamespace } from '@cloudflare/workers-types'\nimport type { TrendingSearch, TrendingSearchResult } from '../types'\n\n/**\n * Trending Search Service\n *\n * Computes trending search queries using time-decay bucket scoring.\n * Results are KV-cached with a 15-minute TTL.\n *\n * Scoring buckets (5-tier time decay):\n * Last 1h: 4x | Last 6h: 2x | Last 24h: 1x | Last 7d: 0.5x | Older: 0.25x\n */\nexport class TrendingSearchService {\n constructor(private db: D1Database, private kv?: KVNamespace) {}\n\n /**\n * Get trending searches ā returns from KV cache if available, otherwise computes.\n */\n async getTrending(limit = 10, periodDays = 7): Promise {\n const cacheKey = `trending:${periodDays}d:${limit}`\n\n // Try KV cache first\n if (this.kv) {\n try {\n const cached = await this.kv.get(cacheKey, 'json')\n if (cached) {\n return { items: cached as TrendingSearch[], cached: true }\n }\n } catch {\n // KV read failed ā compute fresh\n }\n }\n\n const items = await this.computeTrending(limit, periodDays)\n\n // Store in KV with 15-minute TTL\n if (this.kv) {\n try {\n await this.kv.put(cacheKey, JSON.stringify(items), { expirationTtl: 900 })\n } catch {\n // KV write failed ā still return results\n }\n }\n\n return { items, cached: false }\n }\n\n /**\n * Compute trending searches using time-decay bucket scoring.\n * Precomputes all thresholds in TypeScript for clean parameter binding.\n */\n private async computeTrending(limit: number, periodDays: number): Promise {\n const now = Date.now()\n const t1h = now - 3_600_000 // 1 hour ago\n const t6h = now - 21_600_000 // 6 hours ago\n const t24h = now - 86_400_000 // 24 hours ago\n const t7d = now - 604_800_000 // 7 days ago\n const lookback = now - (periodDays * 86_400_000) // period start\n\n try {\n const sql = `\n SELECT\n LOWER(query) as q,\n SUM(\n CASE\n WHEN created_at > ?1 THEN 4.0\n WHEN created_at > ?2 THEN 2.0\n WHEN created_at > ?3 THEN 1.0\n WHEN created_at > ?4 THEN 0.5\n ELSE 0.25\n END\n ) as trend_score,\n COUNT(*) as raw_count\n FROM ai_search_history\n WHERE created_at > ?5\n AND results_count > 0\n AND query IS NOT NULL\n AND LENGTH(TRIM(query)) >= 2\n GROUP BY LOWER(query)\n HAVING COUNT(*) >= 3\n ORDER BY trend_score DESC\n LIMIT ?6\n `\n // ?1=t1h, ?2=t6h, ?3=t24h, ?4=t7d, ?5=lookback, ?6=limit (fetch extra for post-filter)\n const fetchLimit = Math.min(limit * 2, 40)\n const { results } = await this.db\n .prepare(sql)\n .bind(t1h, t6h, t24h, t7d, lookback, fetchLimit)\n .all<{ q: string; trend_score: number; raw_count: number }>()\n\n if (!results || results.length === 0) return []\n\n // Post-filter garbage queries\n return results\n .filter((r) => this.isValidQuery(r.q))\n .slice(0, limit)\n .map((r) => ({\n query: r.q,\n trend_score: Math.round(r.trend_score * 100) / 100,\n search_count: r.raw_count,\n }))\n } catch (error) {\n console.log('[TrendingSearchService] Query failed:', error)\n return []\n }\n }\n\n /**\n * Post-filter: reject garbage queries that slip through SQL filters.\n */\n private isValidQuery(q: string): boolean {\n if (q.length < 3) return false\n if (q.length > 100) return false\n if (/^\\d+$/.test(q)) return false\n if (/^[0-9a-f-]{8,}$/i.test(q)) return false\n return true\n }\n\n /**\n * Invalidate all trending KV cache keys.\n */\n async invalidateCache(): Promise {\n if (!this.kv) return\n // KV doesn't support prefix deletion ā invalidate common combinations\n const periods = [1, 7, 14, 30]\n const limits = [5, 10, 15, 20]\n const deletes = periods.flatMap((p) =>\n limits.map((l) => this.kv!.delete(`trending:${p}d:${l}`))\n )\n await Promise.allSettled(deletes)\n }\n}\n","import type { D1Database, KVNamespace } from '@cloudflare/workers-types'\nimport type { RelatedSearch, RelatedSearchResult } from '../types'\n\n/**\n * Related Search Service\n *\n * Manages related search suggestions from three sources:\n * 1. Manual (admin-curated, highest priority)\n * 2. Agent (approved from Quality Agent recommendations)\n * 3. Auto (computed from click overlap + session co-occurrence, cached in KV)\n */\nexport class RelatedSearchService {\n constructor(private db: D1Database, private kv?: KVNamespace) {}\n\n // =============================================\n // Main Entry Point\n // =============================================\n\n /**\n * Get related searches for a query ā merges manual + agent (D1) + auto (KV/compute).\n * Returns deduplicated results with manual first, then agent, then auto, up to limit.\n */\n async getRelatedSearches(query: string, limit = 5): Promise {\n const normalized = this.normalize(query)\n if (!normalized) return []\n\n // 1. Get stored entries (manual + agent) from D1\n const stored = await this.getStoredRelated(normalized)\n const results: RelatedSearchResult[] = stored.map(r => ({\n query: r.related_query,\n source: r.source,\n }))\n\n // If we already have enough from stored entries, return early\n if (results.length >= limit) {\n return results.slice(0, limit)\n }\n\n // 2. Get auto-generated from KV cache or compute\n const remaining = limit - results.length\n const autoResults = await this.getAutoRelated(normalized, remaining, results)\n results.push(...autoResults)\n\n return results.slice(0, limit)\n }\n\n // =============================================\n // Stored Entries (Manual + Agent)\n // =============================================\n\n async getStoredRelated(normalizedQuery: string): Promise {\n try {\n const { results } = await this.db\n .prepare(`\n SELECT * FROM ai_search_related\n WHERE source_query = ? AND enabled = 1\n ORDER BY\n CASE source WHEN 'manual' THEN 0 WHEN 'agent' THEN 1 END,\n position ASC\n `)\n .bind(normalizedQuery)\n .all()\n\n return (results || []).map(row => this.mapRow(row))\n } catch {\n return []\n }\n }\n\n // =============================================\n // Auto-Generated (Click Overlap + Session Co-occurrence)\n // =============================================\n\n private async getAutoRelated(\n normalizedQuery: string,\n limit: number,\n existingResults: RelatedSearchResult[]\n ): Promise {\n if (!this.kv || limit <= 0) return []\n\n const cacheKey = `related:auto:${normalizedQuery}`\n\n // Check KV cache first\n try {\n const cached = await this.kv.get(cacheKey, 'json')\n if (cached) {\n const existingQueries = new Set(existingResults.map(r => r.query.toLowerCase()))\n return cached\n .filter(r => !existingQueries.has(r.query.toLowerCase()))\n .slice(0, limit)\n }\n } catch {\n // Cache miss or error ā compute fresh\n }\n\n // Check minimum data threshold\n const thirtyDaysAgo = Date.now() - (30 * 24 * 60 * 60 * 1000)\n try {\n const countRow = await this.db\n .prepare('SELECT COUNT(*) as cnt FROM ai_search_history WHERE created_at >= ?')\n .bind(thirtyDaysAgo)\n .first<{ cnt: number }>()\n\n if (!countRow || countRow.cnt < 100) return []\n } catch {\n return []\n }\n\n // Compute from click overlap and session co-occurrence\n const existingQueries = new Set(existingResults.map(r => r.query.toLowerCase()))\n const scoreMap = new Map()\n\n // Signal A: Click overlap ā queries that led to clicks on the same content\n try {\n const { results: clickRows } = await this.db\n .prepare(`\n WITH target_clicks AS (\n SELECT DISTINCT c.clicked_content_id\n FROM ai_search_clicks c\n JOIN ai_search_history h ON c.search_id = CAST(h.id AS TEXT)\n WHERE LOWER(h.query) = ?\n AND h.created_at >= ?\n ),\n related AS (\n SELECT LOWER(h.query) as related_query,\n COUNT(DISTINCT c.clicked_content_id) as shared_clicks\n FROM ai_search_clicks c\n JOIN ai_search_history h ON c.search_id = CAST(h.id AS TEXT)\n JOIN target_clicks t ON c.clicked_content_id = t.clicked_content_id\n WHERE LOWER(h.query) != ?\n AND LENGTH(TRIM(h.query)) >= 2\n AND h.results_count > 0\n GROUP BY LOWER(h.query)\n HAVING shared_clicks >= 2\n )\n SELECT related_query, shared_clicks\n FROM related\n ORDER BY shared_clicks DESC\n LIMIT 20\n `)\n .bind(normalizedQuery, thirtyDaysAgo, normalizedQuery)\n .all<{ related_query: string; shared_clicks: number }>()\n\n for (const row of clickRows || []) {\n if (!existingQueries.has(row.related_query)) {\n scoreMap.set(row.related_query, (scoreMap.get(row.related_query) || 0) + row.shared_clicks)\n }\n }\n } catch (error) {\n console.warn('[RelatedSearchService] Click overlap query failed:', error)\n }\n\n // Signal B: Session co-occurrence (authenticated users only)\n try {\n const { results: sessionRows } = await this.db\n .prepare(`\n WITH target_searches AS (\n SELECT user_id, created_at\n FROM ai_search_history\n WHERE LOWER(query) = ?\n AND created_at >= ?\n AND results_count > 0\n AND user_id IS NOT NULL\n ),\n co_occurring AS (\n SELECT LOWER(h.query) as related_query, COUNT(*) as co_count\n FROM ai_search_history h\n JOIN target_searches t ON h.user_id = t.user_id\n AND ABS(h.created_at - t.created_at) <= 1800000\n WHERE LOWER(h.query) != ?\n AND h.results_count > 0\n AND h.user_id IS NOT NULL\n AND LENGTH(TRIM(h.query)) >= 2\n GROUP BY LOWER(h.query)\n HAVING co_count >= 2\n )\n SELECT related_query, co_count\n FROM co_occurring\n ORDER BY co_count DESC\n LIMIT 20\n `)\n .bind(normalizedQuery, thirtyDaysAgo, normalizedQuery)\n .all<{ related_query: string; co_count: number }>()\n\n for (const row of sessionRows || []) {\n if (!existingQueries.has(row.related_query)) {\n scoreMap.set(row.related_query, (scoreMap.get(row.related_query) || 0) + row.co_count)\n }\n }\n } catch (error) {\n console.warn('[RelatedSearchService] Session co-occurrence query failed:', error)\n }\n\n // Sort by combined score and build results\n const autoResults: RelatedSearchResult[] = Array.from(scoreMap.entries())\n .sort((a, b) => b[1] - a[1])\n .slice(0, limit + 5) // Fetch extra in case of dedup\n .map(([query]) => ({ query, source: 'auto' as const }))\n\n // Cache in KV with 1-hour TTL\n try {\n await this.kv.put(cacheKey, JSON.stringify(autoResults), { expirationTtl: 3600 })\n } catch {\n // Non-critical cache write failure\n }\n\n return autoResults.slice(0, limit)\n }\n\n // =============================================\n // CRUD\n // =============================================\n\n async create(\n sourceQuery: string,\n relatedQuery: string,\n opts?: { source?: 'manual' | 'agent'; position?: number; bidirectional?: boolean }\n ): Promise {\n const source = opts?.source || 'manual'\n const position = opts?.position ?? 0\n const bidirectional = opts?.bidirectional ? 1 : 0\n const normalizedSource = this.normalize(sourceQuery)\n const normalizedRelated = this.normalize(relatedQuery)\n\n const id = crypto.randomUUID().replace(/-/g, '')\n await this.db\n .prepare(`\n INSERT INTO ai_search_related (id, source_query, related_query, source, position, bidirectional, enabled)\n VALUES (?, ?, ?, ?, ?, ?, 1)\n `)\n .bind(id, normalizedSource, normalizedRelated, source, position, bidirectional)\n .run()\n\n // If bidirectional, create the reverse pair\n if (opts?.bidirectional) {\n const reverseId = crypto.randomUUID().replace(/-/g, '')\n try {\n await this.db\n .prepare(`\n INSERT INTO ai_search_related (id, source_query, related_query, source, position, bidirectional, enabled)\n VALUES (?, ?, ?, ?, ?, ?, 1)\n `)\n .bind(reverseId, normalizedRelated, normalizedSource, source, position, bidirectional)\n .run()\n } catch {\n // Reverse pair may already exist (UNIQUE constraint) ā that's fine\n }\n }\n\n return {\n id,\n source_query: normalizedSource,\n related_query: normalizedRelated,\n source,\n position,\n bidirectional: !!opts?.bidirectional,\n enabled: true,\n created_at: Math.floor(Date.now() / 1000),\n updated_at: Math.floor(Date.now() / 1000),\n }\n }\n\n async update(id: string, fields: Partial>): Promise {\n const setClauses: string[] = ['updated_at = unixepoch()']\n const params: any[] = []\n\n if (fields.related_query !== undefined) {\n setClauses.push('related_query = ?')\n params.push(this.normalize(fields.related_query))\n }\n if (fields.position !== undefined) {\n setClauses.push('position = ?')\n params.push(fields.position)\n }\n if (fields.enabled !== undefined) {\n setClauses.push('enabled = ?')\n params.push(fields.enabled ? 1 : 0)\n }\n\n params.push(id)\n await this.db\n .prepare(`UPDATE ai_search_related SET ${setClauses.join(', ')} WHERE id = ?`)\n .bind(...params)\n .run()\n\n return this.getById(id)\n }\n\n async delete(id: string): Promise {\n const result = await this.db\n .prepare('DELETE FROM ai_search_related WHERE id = ?')\n .bind(id)\n .run()\n\n return (result?.meta?.changes ?? 0) > 0\n }\n\n async getById(id: string): Promise {\n try {\n const row = await this.db\n .prepare('SELECT * FROM ai_search_related WHERE id = ?')\n .bind(id)\n .first()\n\n return row ? this.mapRow(row) : null\n } catch {\n return null\n }\n }\n\n async getAll(opts?: {\n source_query?: string\n source?: 'manual' | 'agent'\n enabled?: boolean\n limit?: number\n offset?: number\n }): Promise {\n const conditions: string[] = []\n const params: any[] = []\n\n if (opts?.source_query) {\n conditions.push('source_query = ?')\n params.push(this.normalize(opts.source_query))\n }\n if (opts?.source) {\n conditions.push('source = ?')\n params.push(opts.source)\n }\n if (opts?.enabled !== undefined) {\n conditions.push('enabled = ?')\n params.push(opts.enabled ? 1 : 0)\n }\n\n const where = conditions.length > 0 ? `WHERE ${conditions.join(' AND ')}` : ''\n const limit = opts?.limit || 100\n const offset = opts?.offset || 0\n\n try {\n const { results } = await this.db\n .prepare(`SELECT * FROM ai_search_related ${where} ORDER BY source_query ASC, position ASC LIMIT ? OFFSET ?`)\n .bind(...params, limit, offset)\n .all()\n\n return (results || []).map(row => this.mapRow(row))\n } catch {\n return []\n }\n }\n\n async bulkCreate(\n entries: Array<{ source_query: string; related_query: string; source?: 'manual' | 'agent'; position?: number; bidirectional?: boolean }>\n ): Promise {\n let count = 0\n for (const entry of entries) {\n try {\n await this.create(entry.source_query, entry.related_query, {\n source: entry.source,\n position: entry.position,\n bidirectional: entry.bidirectional,\n })\n count++\n } catch {\n // Skip duplicates (UNIQUE constraint)\n }\n }\n return count\n }\n\n async invalidateCache(query?: string): Promise {\n if (!this.kv) return\n\n if (query) {\n await this.kv.delete(`related:auto:${this.normalize(query)}`)\n } else {\n // KV doesn't support prefix deletion ā list and delete\n try {\n const list = await this.kv.list({ prefix: 'related:auto:' })\n for (const key of list.keys) {\n await this.kv.delete(key.name)\n }\n } catch {\n // Best-effort cache clear\n }\n }\n }\n\n // =============================================\n // Helpers\n // =============================================\n\n private normalize(query: string): string {\n return query.toLowerCase().trim()\n }\n\n private mapRow(row: Record): RelatedSearch {\n return {\n id: row.id as string,\n source_query: row.source_query as string,\n related_query: row.related_query as string,\n source: row.source as 'manual' | 'agent',\n position: row.position as number,\n bidirectional: (row.bidirectional as number) === 1,\n enabled: (row.enabled as number) === 1,\n created_at: row.created_at as number,\n updated_at: row.updated_at as number,\n }\n }\n}\n","import type { D1Database } from '@cloudflare/workers-types'\nimport type {\n AISearchSettings,\n CollectionInfo,\n FacetResult,\n NewCollectionNotification,\n SearchQuery,\n SearchResponse,\n SearchResult,\n} from '../types'\nimport { CustomRAGService } from './custom-rag.service'\nimport { FacetService } from './facet.service'\nimport { FTS5Service } from './fts5.service'\nimport { HybridSearchService } from './hybrid-search.service'\nimport { QueryRewriterService } from './query-rewriter.service'\nimport { QueryRulesService } from './query-rules.service'\nimport { RankingPipelineService } from './ranking-pipeline.service'\nimport { SynonymService } from './synonym.service'\nimport { RerankerService } from './reranker.service'\nimport { SearchCacheService } from './search-cache.service'\nimport { TrendingSearchService } from './trending-search.service'\nimport { RelatedSearchService } from './related-search.service'\n\n/**\n * AI Search Service\n * Handles search operations, settings management, and collection detection\n * Now uses Custom RAG with Vectorize for semantic search\n */\nexport class AISearchService {\n private customRAG?: CustomRAGService\n private fts5Service?: FTS5Service\n private hybridService?: HybridSearchService\n private queryRewriter?: QueryRewriterService\n private reranker?: RerankerService\n private rankingPipeline: RankingPipelineService\n private synonymService: SynonymService\n private queryRulesService: QueryRulesService\n private searchCache?: SearchCacheService\n\n constructor(\n private db: D1Database,\n private ai?: any, // Workers AI for embeddings\n private vectorize?: any, // Vectorize for vector search\n private kv?: any // KVNamespace for search result caching\n ) {\n // Initialize Custom RAG if bindings are available\n if (this.ai && this.vectorize) {\n this.customRAG = new CustomRAGService(db, ai, vectorize)\n console.log('[AISearchService] Custom RAG initialized')\n } else {\n console.log('[AISearchService] Custom RAG not available, using keyword search only')\n }\n\n // Initialize FTS5 service (always available, degrades gracefully if table doesn't exist)\n this.fts5Service = new FTS5Service(db)\n console.log('[AISearchService] FTS5 service initialized')\n\n // Initialize hybrid search (FTS5 always, AI when available)\n this.hybridService = new HybridSearchService(this.fts5Service, this.customRAG)\n console.log('[AISearchService] Hybrid search service initialized')\n\n // Initialize AI-dependent services\n if (this.ai) {\n this.queryRewriter = new QueryRewriterService(this.ai)\n this.reranker = new RerankerService(this.ai)\n console.log('[AISearchService] Query rewriter and reranker initialized')\n }\n\n // Synonym service (always available, degrades gracefully if table doesn't exist)\n this.synonymService = new SynonymService(db)\n if (this.fts5Service) {\n this.fts5Service.setSynonymService(this.synonymService)\n }\n\n // Query substitution rules (always available, degrades gracefully if table doesn't exist)\n this.queryRulesService = new QueryRulesService(db)\n\n // Ranking pipeline (always available, zero cost when no stages active)\n this.rankingPipeline = new RankingPipelineService(db)\n\n // Search result cache (available when KV binding is present)\n if (this.kv) {\n this.searchCache = new SearchCacheService(this.kv)\n }\n }\n\n /**\n * Get plugin settings\n */\n async getSettings(): Promise {\n try {\n const plugin = await this.db\n .prepare(`SELECT settings FROM plugins WHERE id = ? LIMIT 1`)\n .bind('ai-search')\n .first<{ settings: string | null }>()\n\n if (!plugin || !plugin.settings) {\n return this.getDefaultSettings()\n }\n\n return JSON.parse(plugin.settings) as AISearchSettings\n } catch (error) {\n console.error('Error fetching AI Search settings:', error)\n return this.getDefaultSettings()\n }\n }\n\n /**\n * Get default settings\n */\n getDefaultSettings(): AISearchSettings {\n return {\n enabled: true,\n ai_mode_enabled: true,\n selected_collections: [],\n dismissed_collections: [],\n autocomplete_enabled: true,\n cache_duration: 1,\n results_limit: 20,\n index_media: false,\n query_rewriting_enabled: false,\n reranking_enabled: true,\n fts5_title_boost: 5.0,\n fts5_slug_boost: 2.0,\n fts5_body_boost: 1.0,\n }\n }\n\n /**\n * Update plugin settings\n */\n async updateSettings(settings: Partial): Promise {\n const existing = await this.getSettings()\n const updated: AISearchSettings = {\n ...existing!,\n ...settings,\n }\n\n try {\n // Update plugin settings in plugins table\n await this.db\n .prepare(`\n UPDATE plugins\n SET settings = ?,\n updated_at = unixepoch()\n WHERE id = 'ai-search'\n `)\n .bind(JSON.stringify(updated))\n .run()\n\n return updated\n } catch (error) {\n console.error('Error updating AI Search settings:', error)\n throw error\n }\n }\n\n /**\n * Detect new collections that aren't indexed or dismissed\n */\n async detectNewCollections(): Promise {\n try {\n // Get all collections (exclude test collections)\n // Note: D1 doesn't support parameterized LIKE, so we filter in JavaScript\n const collectionsStmt = this.db.prepare(\n 'SELECT id, name, display_name, description FROM collections WHERE is_active = 1'\n )\n const { results: allCollections } = await collectionsStmt.all<{\n id: number\n name: string\n display_name: string\n description?: string\n }>()\n\n // Filter out test collections (starts with test_, ends with _test, or is test_collection)\n const collections = (allCollections || []).filter(\n (col) => {\n if (!col.name) return false\n const name = col.name.toLowerCase()\n return !name.startsWith('test_') &&\n !name.endsWith('_test') &&\n name !== 'test_collection' &&\n !name.includes('_test_') &&\n name !== 'large_payload_test' &&\n name !== 'concurrent_test'\n }\n )\n\n // Get settings\n const settings = await this.getSettings()\n const selected = settings?.selected_collections || []\n const dismissed = settings?.dismissed_collections || []\n\n // Get item counts for each collection\n const notifications: NewCollectionNotification[] = []\n\n for (const collection of collections || []) {\n const collectionId = String(collection.id)\n\n // Skip if already selected or dismissed\n if (selected.includes(collectionId) || dismissed.includes(collectionId)) {\n continue\n }\n\n // Get item count\n const countStmt = this.db.prepare(\n 'SELECT COUNT(*) as count FROM content WHERE collection_id = ?'\n )\n const countResult = await countStmt.bind(collectionId).first<{ count: number }>()\n const itemCount = countResult?.count || 0\n\n notifications.push({\n collection: {\n id: collectionId,\n name: collection.name,\n display_name: collection.display_name,\n description: collection.description,\n item_count: itemCount,\n is_indexed: false,\n is_dismissed: false,\n is_new: true,\n },\n message: `New collection \"${collection.display_name}\" with ${itemCount} items available for indexing`,\n })\n }\n\n return notifications\n } catch (error) {\n console.error('Error detecting new collections:', error)\n return []\n }\n }\n\n /**\n * Get all collections with indexing status\n */\n async getAllCollections(): Promise {\n try {\n // Get all collections (same query as content page)\n const collectionsStmt = this.db.prepare(\n 'SELECT id, name, display_name, description FROM collections WHERE is_active = 1 ORDER BY display_name'\n )\n const { results: allCollections } = await collectionsStmt.all<{\n id: string\n name: string\n display_name: string\n description?: string\n }>()\n\n console.log('[AISearchService.getAllCollections] Raw collections from DB:', allCollections?.length || 0)\n const firstCollection = allCollections?.[0]\n if (firstCollection) {\n console.log('[AISearchService.getAllCollections] Sample collection:', {\n id: firstCollection.id,\n name: firstCollection.name,\n display_name: firstCollection.display_name\n })\n }\n\n // No filtering needed - test collections are now properly cleaned up by E2E tests\n const collections = (allCollections || []).filter(\n (col) => col.id && col.name\n )\n\n console.log('[AISearchService.getAllCollections] After filtering test collections:', collections.length)\n console.log('[AISearchService.getAllCollections] Remaining collections:', collections.map(c => c.name).join(', '))\n\n // Get settings\n const settings = await this.getSettings()\n const selected = settings?.selected_collections || []\n const dismissed = settings?.dismissed_collections || []\n\n console.log('[AISearchService.getAllCollections] Settings:', {\n selected_count: selected.length,\n dismissed_count: dismissed.length,\n selected: selected\n })\n\n // Get item counts and indexing status\n const collectionInfos: CollectionInfo[] = []\n\n for (const collection of collections) {\n if (!collection.id || !collection.name) continue\n const collectionId = String(collection.id)\n\n if (!collectionId) {\n console.warn('[AISearchService] Skipping invalid collection:', collection)\n continue\n }\n\n // Get item count\n const countStmt = this.db.prepare(\n 'SELECT COUNT(*) as count FROM content WHERE collection_id = ?'\n )\n const countResult = await countStmt.bind(collectionId).first<{ count: number }>()\n const itemCount = countResult?.count || 0\n\n collectionInfos.push({\n id: collectionId,\n name: collection.name,\n display_name: collection.display_name || collection.name,\n description: collection.description,\n item_count: itemCount,\n is_indexed: selected.includes(collectionId),\n is_dismissed: dismissed.includes(collectionId),\n is_new: !selected.includes(collectionId) && !dismissed.includes(collectionId),\n })\n }\n\n console.log('[AISearchService.getAllCollections] Returning collectionInfos:', collectionInfos.length)\n const firstInfo = collectionInfos[0]\n if (collectionInfos.length > 0 && firstInfo) {\n console.log('[AISearchService.getAllCollections] First collectionInfo:', {\n id: firstInfo.id,\n name: firstInfo.name,\n display_name: firstInfo.display_name,\n item_count: firstInfo.item_count\n })\n }\n return collectionInfos\n } catch (error) {\n console.error('[AISearchService] Error fetching collections:', error)\n return []\n }\n }\n\n /**\n * Execute search query\n * Supports three modes: 'ai' (semantic), 'fts5' (full-text), 'keyword' (basic)\n */\n async search(query: SearchQuery): Promise {\n const startTime = Date.now()\n const settings = await this.getSettings()\n\n if (!settings?.enabled) {\n return {\n results: [],\n total: 0,\n query_time_ms: 0,\n mode: query.mode,\n }\n }\n\n // Apply query substitution rules (pre-dispatch, affects all modes)\n let originalQuery: string | undefined\n let appliedRuleId: string | undefined\n const ruleResult = await this.queryRulesService.applyRules(query.query)\n if (ruleResult.originalQuery) {\n originalQuery = ruleResult.originalQuery\n appliedRuleId = ruleResult.ruleId\n query = { ...query, query: ruleResult.query }\n }\n\n // Cache check: after rule expansion so the key reflects the actual query\n if (this.searchCache) {\n const cacheKey = await this.searchCache.buildKey(query)\n if (cacheKey) {\n const cached = await this.searchCache.get(cacheKey)\n if (cached) {\n // Cache hit ā log search + related searches in parallel\n const elapsed = Date.now() - startTime\n const [searchId, relatedSearches] = await Promise.all([\n this.logSearch(query.query, query.mode, cached.results.length, elapsed, true),\n (settings.related_searches_enabled !== false)\n ? new RelatedSearchService(this.db, this.kv)\n .getRelatedSearches(query.query, 5)\n .catch(() => undefined)\n : Promise.resolve(undefined),\n ])\n return {\n ...cached,\n query_time_ms: elapsed,\n search_id: searchId,\n cached: true,\n ...(relatedSearches ? { related_searches: relatedSearches } : {}),\n // Re-attach rule metadata (not cached)\n ...(originalQuery ? { original_query: originalQuery, applied_rule_id: appliedRuleId } : {}),\n }\n }\n }\n }\n\n // Determine if facets should be computed\n const shouldComputeFacets = query.facets && settings.facets_enabled\n\n // Auto-generate facet config on first enable (if none exists)\n if (shouldComputeFacets && (!settings.facet_config || settings.facet_config.length === 0)) {\n try {\n const facetService = new FacetService(this.db)\n const discovered = await facetService.discoverFields()\n const config = facetService.autoGenerateConfig(discovered)\n if (config.length > 0) {\n await this.updateSettings({ facet_config: config })\n settings.facet_config = config\n }\n } catch (error) {\n console.warn('[AISearchService] Auto-generate facet config failed:', error)\n }\n }\n\n // Build the search promise\n let searchPromise: Promise\n\n // Hybrid mode - FTS5 + AI combined with RRF, optional rewriting + reranking\n if (query.mode === 'hybrid') {\n searchPromise = this.searchHybrid(query, settings)\n }\n // FTS5 mode - full-text search with BM25 ranking and highlighting\n else if (query.mode === 'fts5') {\n searchPromise = this.searchFTS5(query, settings)\n }\n // AI mode - semantic search using Custom RAG with Vectorize\n else if (query.mode === 'ai' && settings.ai_mode_enabled && this.customRAG?.isAvailable()) {\n searchPromise = this.searchAI(query, settings)\n }\n // Fallback to keyword search\n else {\n searchPromise = this.searchKeyword(query, settings)\n }\n\n // Build the facet promise (runs in parallel with search)\n let facetPromise: Promise | null = null\n if (shouldComputeFacets && settings.facet_config && settings.facet_config.length > 0) {\n facetPromise = this.computeFacets(query, settings)\n }\n\n // Execute search + facets in parallel\n const [result, facets] = await Promise.all([\n searchPromise,\n facetPromise || Promise.resolve(null),\n ])\n\n // In-memory facet filtering for AI/hybrid modes (SQL-based modes filter at query level)\n if (query.filters?.custom && Object.keys(query.filters.custom).length > 0\n && (query.mode === 'ai' || query.mode === 'hybrid')) {\n result.results = this.filterResultsByFacets(result.results, query.filters.custom)\n result.total = result.results.length\n }\n\n // Attach facets to response\n if (facets && facets.length > 0) {\n result.facets = facets\n }\n\n // For AI mode, compute facets from result IDs (can't run in parallel)\n if (shouldComputeFacets && query.mode === 'ai' && result.results.length > 0 && settings.facet_config?.length) {\n try {\n const facetService = new FacetService(this.db)\n const contentIds = result.results.map(r => r.id).slice(0, 50)\n result.facets = await facetService.computeFacetsFromIds(\n settings.facet_config,\n contentIds,\n settings.facet_max_values || 20\n )\n } catch (error) {\n console.warn('[AISearchService] AI mode facet computation failed:', error)\n }\n }\n\n // Attach query substitution metadata\n if (originalQuery) {\n result.original_query = originalQuery\n result.applied_rule_id = appliedRuleId\n }\n\n // Apply ranking pipeline (post-processing: re-scores and re-sorts)\n // Zero-cost when no stages are enabled\n let finalResult: SearchResponse\n try {\n finalResult = await this.rankingPipeline.apply(result, query.query)\n } catch (error) {\n console.warn('[AISearchService] Ranking pipeline error (preserving original order):', error)\n finalResult = result\n }\n\n // Cache write + related searches in parallel\n // Related searches are NOT cached in the search cache ā they have their own KV TTL\n const cachePromise = (this.searchCache && settings.cache_duration > 0)\n ? this.searchCache.buildKey(query).then(async (cacheKey) => {\n if (cacheKey) {\n const ttlSeconds = settings.cache_duration * 3600\n await this.searchCache!.put(cacheKey, finalResult, ttlSeconds).catch(err => {\n console.warn('[AISearchService] Cache write failed:', err)\n })\n }\n })\n : Promise.resolve()\n\n const relatedPromise = (settings.related_searches_enabled !== false)\n ? new RelatedSearchService(this.db, this.kv)\n .getRelatedSearches(query.query, 5)\n .catch(() => undefined)\n : Promise.resolve(undefined)\n\n const [, relatedSearches] = await Promise.all([cachePromise, relatedPromise])\n\n if (relatedSearches) {\n finalResult.related_searches = relatedSearches\n }\n\n return finalResult\n }\n\n /**\n * Execute search with experiment variant overrides applied.\n * Phase 1: flat AISearchSettings merge only (no pipeline weight overrides).\n * Used by A/B testing to run control/treatment searches with different configs.\n */\n async searchWithOverrides(query: SearchQuery, overrides: Partial): Promise {\n const startTime = Date.now()\n const baseSettings = await this.getSettings()\n if (!baseSettings?.enabled) {\n return { results: [], total: 0, query_time_ms: 0, mode: query.mode }\n }\n\n // Shallow merge: overrides win for flat fields\n const settings: AISearchSettings = { ...baseSettings, ...overrides }\n\n // Skip cache for experiment searches (each variant needs fresh results)\n // Skip related searches (not relevant for experiment comparison)\n\n // Apply query substitution rules\n let originalQuery: string | undefined\n let appliedRuleId: string | undefined\n const ruleResult = await this.queryRulesService.applyRules(query.query)\n if (ruleResult.originalQuery) {\n originalQuery = ruleResult.originalQuery\n appliedRuleId = ruleResult.ruleId\n query = { ...query, query: ruleResult.query }\n }\n\n // Route to mode-specific search\n let searchPromise: Promise\n if (query.mode === 'hybrid') {\n searchPromise = this.searchHybrid(query, settings)\n } else if (query.mode === 'fts5') {\n searchPromise = this.searchFTS5(query, settings)\n } else if (query.mode === 'ai' && settings.ai_mode_enabled && this.customRAG?.isAvailable()) {\n searchPromise = this.searchAI(query, settings)\n } else {\n searchPromise = this.searchKeyword(query, settings)\n }\n\n const result = await searchPromise\n\n if (originalQuery) {\n result.original_query = originalQuery\n result.applied_rule_id = appliedRuleId\n }\n\n // Apply ranking pipeline (uses default weights ā pipeline overrides are Phase 2)\n try {\n const ranked = await this.rankingPipeline.apply(result, query.query)\n ranked.query_time_ms = Date.now() - startTime\n return ranked\n } catch {\n result.query_time_ms = Date.now() - startTime\n return result\n }\n }\n\n /**\n * Compute facets for the current search query.\n * Delegates to FacetService with mode-appropriate strategy.\n */\n private async computeFacets(\n query: SearchQuery,\n settings: AISearchSettings\n ): Promise {\n const facetService = new FacetService(this.db)\n const config = settings.facet_config!\n const maxValues = settings.facet_max_values || 20\n\n // Determine collection IDs for facet queries\n const collectionIds = query.filters?.collections?.length\n ? query.filters.collections\n : settings.selected_collections\n\n const activeFilters = query.filters?.custom\n\n try {\n // FTS5 and hybrid: SQL GROUP BY with FTS5 MATCH\n if (query.mode === 'fts5' || query.mode === 'hybrid') {\n const matchQuery = FacetService.sanitizeFTS5Query(query.query)\n return await facetService.computeFacetsFts(config, matchQuery, collectionIds, maxValues, activeFilters)\n }\n\n // Keyword: SQL GROUP BY with LIKE\n if (query.mode === 'keyword') {\n return await facetService.computeFacetsKeyword(config, query.query, collectionIds, maxValues, activeFilters)\n }\n\n // AI mode: compute from result IDs (limited to top 50)\n // For AI mode, we can't run SQL facets in parallel because we need\n // the result IDs first. Return empty and let the caller post-fill.\n return []\n } catch (error) {\n console.warn('[AISearchService] Facet computation failed:', error)\n return []\n }\n }\n\n /**\n * FTS5 full-text search with BM25 ranking, stemming, and highlighting\n */\n private async searchFTS5(query: SearchQuery, settings: AISearchSettings): Promise {\n const startTime = Date.now()\n\n try {\n if (!this.fts5Service) {\n console.warn('[AISearchService] FTS5 service not initialized, falling back to keyword search')\n return this.searchKeyword(query, settings)\n }\n\n // Check if FTS5 table is available\n if (!(await this.fts5Service.isAvailable())) {\n console.warn('[AISearchService] FTS5 table not available, falling back to keyword search')\n return this.searchKeyword(query, settings)\n }\n\n const result = await this.fts5Service.search(query, settings, {\n titleBoost: settings.fts5_title_boost,\n slugBoost: settings.fts5_slug_boost,\n bodyBoost: settings.fts5_body_boost,\n })\n\n // Log search to history\n const elapsed = Date.now() - startTime\n const searchId = await this.logSearch(query.query, 'fts5', result.results.length, elapsed)\n result.search_id = searchId\n\n return result\n } catch (error) {\n console.error('[AISearchService] FTS5 search error, falling back to keyword:', error)\n return this.searchKeyword(query, settings)\n }\n }\n\n /**\n * Hybrid search: FTS5 + AI combined with RRF, optional query rewriting + reranking\n */\n private async searchHybrid(query: SearchQuery, settings: AISearchSettings): Promise {\n const startTime = Date.now()\n\n try {\n if (!this.hybridService || !this.fts5Service) {\n console.warn('[AISearchService] Hybrid service not available, falling back to keyword search')\n return this.searchKeyword(query, settings)\n }\n\n // Check if FTS5 table is available (required for hybrid)\n if (!(await this.fts5Service.isAvailable())) {\n console.warn('[AISearchService] FTS5 not available for hybrid, falling back to keyword search')\n return this.searchKeyword(query, settings)\n }\n\n let searchQuery = query\n\n // Step 1: Query Rewriting (if enabled + AI available + query >= 15 chars)\n const rewritingEnabled = settings.query_rewriting_enabled ?? false\n if (\n rewritingEnabled &&\n this.queryRewriter &&\n QueryRewriterService.shouldRewrite(query.query)\n ) {\n const rewritten = await this.queryRewriter.rewrite(query.query)\n if (rewritten !== query.query) {\n console.log(`[AISearchService] Query rewritten: \"${query.query}\" ā \"${rewritten}\"`)\n searchQuery = { ...query, query: rewritten }\n }\n }\n\n // Step 2: Hybrid Search (FTS5 + AI in parallel, semantic-first ranking)\n let result = await this.hybridService.search(searchQuery, settings)\n\n // Note: AI reranking is intentionally SKIPPED for hybrid mode.\n // Hybrid already ranks by Vectorize semantic scores (bi-encoder cosine similarity),\n // which outperforms the bge-reranker-base cross-encoder. Applying the reranker\n // here degrades nDCG and MRR (confirmed via BEIR benchmark evaluation).\n\n // Log search to history\n const elapsed = Date.now() - startTime\n const searchId = await this.logSearch(query.query, 'hybrid', result.results.length, elapsed)\n result.search_id = searchId\n\n return result\n } catch (error) {\n console.error('[AISearchService] Hybrid search error, falling back to keyword:', error)\n return this.searchKeyword(query, settings)\n }\n }\n\n /**\n * AI-powered semantic search using Custom RAG\n */\n private async searchAI(query: SearchQuery, settings: AISearchSettings): Promise {\n const startTime = Date.now()\n\n try {\n if (!this.customRAG) {\n console.warn('[AISearchService] CustomRAG not available, falling back to keyword search')\n return this.searchKeyword(query, settings)\n }\n\n // Use Custom RAG for semantic search - pass the full query object and settings\n const result = await this.customRAG.search(query, settings)\n\n // Log search to history\n const elapsed = Date.now() - startTime\n const searchId = await this.logSearch(query.query, 'ai', result.results.length, elapsed)\n result.search_id = searchId\n\n return result\n } catch (error) {\n console.error('[AISearchService] AI search error, falling back to keyword:', error)\n // Fallback to keyword search\n return this.searchKeyword(query, settings)\n }\n }\n\n /**\n * Traditional keyword search\n */\n private async searchKeyword(\n query: SearchQuery,\n settings: AISearchSettings\n ): Promise {\n const startTime = Date.now()\n\n try {\n const conditions: string[] = []\n const params: any[] = []\n\n // Search query\n if (query.query) {\n conditions.push('(c.title LIKE ? OR c.slug LIKE ? OR c.data LIKE ?)')\n const searchTerm = `%${query.query}%`\n params.push(searchTerm, searchTerm, searchTerm)\n }\n\n // Collection filter\n if (query.filters?.collections && query.filters.collections.length > 0) {\n const placeholders = query.filters.collections.map(() => '?').join(',')\n conditions.push(`c.collection_id IN (${placeholders})`)\n params.push(...query.filters.collections)\n } else if (settings.selected_collections.length > 0) {\n // Only search indexed collections\n const placeholders = settings.selected_collections.map(() => '?').join(',')\n conditions.push(`c.collection_id IN (${placeholders})`)\n params.push(...settings.selected_collections)\n }\n\n // Status filter\n if (query.filters?.status && query.filters.status.length > 0) {\n const placeholders = query.filters.status.map(() => '?').join(',')\n conditions.push(`c.status IN (${placeholders})`)\n params.push(...query.filters.status)\n } else {\n // Exclude deleted by default\n conditions.push(\"c.status != 'deleted'\")\n }\n\n // Date range filter\n if (query.filters?.dateRange) {\n const field = query.filters.dateRange.field || 'created_at'\n if (query.filters.dateRange.start) {\n conditions.push(`c.${field} >= ?`)\n params.push(query.filters.dateRange.start.getTime())\n }\n if (query.filters.dateRange.end) {\n conditions.push(`c.${field} <= ?`)\n params.push(query.filters.dateRange.end.getTime())\n }\n }\n\n // Author filter\n if (query.filters?.author) {\n conditions.push('c.author_id = ?')\n params.push(query.filters.author)\n }\n\n // Facet filter conditions (from active facet selections)\n if (query.filters?.custom && settings.facet_config?.length) {\n const { conditions: filterConditions, params: filterParams } = FacetService.buildFacetFilterSQL(\n query.filters.custom,\n settings.facet_config\n )\n conditions.push(...filterConditions)\n params.push(...filterParams)\n }\n\n const whereClause = conditions.length > 0 ? `WHERE ${conditions.join(' AND ')}` : ''\n\n // Get total count\n const countStmt = this.db.prepare(`\n SELECT COUNT(*) as count \n FROM content c\n ${whereClause}\n `)\n const countResult = await countStmt.bind(...params).first<{ count: number }>()\n const total = countResult?.count || 0\n\n // Get results\n const limit = query.limit || settings.results_limit\n const offset = query.offset || 0\n\n const resultsStmt = this.db.prepare(`\n SELECT \n c.id, c.title, c.slug, c.collection_id, c.status,\n c.created_at, c.updated_at, c.author_id, c.data,\n col.name as collection_name, col.display_name as collection_display_name,\n u.email as author_email\n FROM content c\n JOIN collections col ON c.collection_id = col.id\n LEFT JOIN users u ON c.author_id = u.id\n ${whereClause}\n ORDER BY c.updated_at DESC\n LIMIT ? OFFSET ?\n `)\n\n const { results } = await resultsStmt.bind(...params, limit, offset).all<{\n id: string\n title: string\n slug: string\n collection_id: number\n collection_name: string\n collection_display_name: string\n status: string\n created_at: number\n updated_at: number\n author_id?: string\n author_email?: string\n data: string\n }>()\n\n const searchResults: SearchResult[] = (results || []).map((row) => {\n const snippet = this.extractSnippet(row.data, query.query)\n const titleHighlight = this.highlightText(row.title || 'Untitled', query.query)\n return {\n id: String(row.id),\n title: row.title || 'Untitled',\n slug: row.slug || '',\n collection_id: String(row.collection_id),\n collection_name: row.collection_display_name || row.collection_name,\n snippet,\n highlights: {\n title: titleHighlight,\n body: snippet\n },\n status: row.status,\n created_at: Number(row.created_at),\n updated_at: Number(row.updated_at),\n author_name: row.author_email,\n }\n })\n\n const queryTime = Date.now() - startTime\n\n // Log search history\n const searchId = await this.logSearch(query.query, query.mode, searchResults.length, queryTime)\n\n return {\n results: searchResults,\n total,\n query_time_ms: queryTime,\n mode: query.mode,\n search_id: searchId,\n }\n } catch (error) {\n console.error('Keyword search error:', error)\n return {\n results: [],\n total: 0,\n query_time_ms: Date.now() - startTime,\n mode: query.mode,\n }\n }\n }\n\n /**\n * Extract snippet from content data\n * Pulls human-readable text from JSON data fields instead of raw JSON\n */\n private extractSnippet(data: string, query: string): string {\n try {\n const parsed = typeof data === 'string' ? JSON.parse(data) : data\n\n // Extract readable text from common content fields\n const textParts: string[] = []\n const textFields = ['description', 'content', 'body', 'text', 'summary', 'excerpt']\n for (const field of textFields) {\n if (parsed[field] && typeof parsed[field] === 'string') {\n textParts.push(parsed[field])\n }\n }\n\n // Fallback: collect all string values\n if (textParts.length === 0) {\n for (const value of Object.values(parsed)) {\n if (typeof value === 'string' && value.length > 20) {\n textParts.push(value)\n }\n }\n }\n\n const text = textParts.join(' ').replace(/\\s+/g, ' ').trim()\n\n if (!text) {\n return 'No preview available'\n }\n\n // Try to find query match and show context around it with highlighting\n const queryLower = query.toLowerCase()\n const textLower = text.toLowerCase()\n const index = textLower.indexOf(queryLower)\n\n if (index === -1) {\n return text.substring(0, 200) + (text.length > 200 ? '...' : '')\n }\n\n const start = Math.max(0, index - 80)\n const end = Math.min(text.length, index + query.length + 120)\n const prefix = start > 0 ? '...' : ''\n const suffix = end < text.length ? '...' : ''\n const excerpt = text.substring(start, end)\n\n // Add highlighting around all query matches in the excerpt\n return prefix + this.highlightText(excerpt, query) + suffix\n } catch {\n return data.substring(0, 200) + '...'\n }\n }\n\n /**\n * Highlight query terms in text with tags\n * Case-insensitive, highlights all occurrences\n */\n private highlightText(text: string, query: string): string {\n if (!text || !query) return text\n try {\n // Split query into words and escape for regex\n const words = query.trim().split(/\\s+/).filter(w => w.length > 1)\n if (words.length === 0) return text\n\n const escaped = words.map(w => w.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&'))\n const pattern = new RegExp(`(${escaped.join('|')})`, 'gi')\n return text.replace(pattern, '$1 ')\n } catch {\n return text\n }\n }\n\n /**\n * Filter search results in-memory by active facet selections.\n * Used for AI/hybrid modes where SQL-level filtering isn't possible.\n */\n private filterResultsByFacets(\n results: SearchResult[],\n customFilters: Record\n ): SearchResult[] {\n if (!customFilters || Object.keys(customFilters).length === 0) return results\n\n return results.filter(result => {\n for (const [field, values] of Object.entries(customFilters)) {\n if (!values || (Array.isArray(values) && values.length === 0)) continue\n const valueArr = Array.isArray(values) ? values : [values]\n if (valueArr.length === 0) continue\n\n switch (field) {\n case 'collection_name':\n if (!valueArr.includes(result.collection_name)) return false\n break\n case 'status':\n if (!valueArr.includes(result.status)) return false\n break\n case 'author':\n if (!result.author_name || !valueArr.includes(result.author_name)) return false\n break\n // JSON fields not available on SearchResult ā filtered at SQL level for FTS5/keyword\n }\n }\n return true\n })\n }\n\n /**\n * Get search suggestions (autocomplete)\n * Routes to trending queries (empty/short input) or prefix suggestions (2+ chars)\n */\n async getSearchSuggestions(partial: string): Promise {\n try {\n const settings = await this.getSettings()\n if (!settings?.autocomplete_enabled) {\n return []\n }\n\n const trimmed = partial.trim()\n if (trimmed.length < 2) {\n return this.getTrendingQueries()\n }\n return this.getPrefixSuggestions(trimmed)\n } catch (error) {\n console.error('Error getting suggestions:', error)\n return []\n }\n }\n\n /**\n * Get trending queries using TrendingSearchService (time-decay scoring + KV cache).\n * Delegates to the dedicated service for consistent behavior across suggest and trending endpoints.\n */\n private async getTrendingQueries(): Promise {\n try {\n const service = new TrendingSearchService(this.db, this.kv)\n const result = await service.getTrending(10, 7)\n return result.items.map((r) => r.query)\n } catch (error) {\n console.log('[AISearchService] Trending queries unavailable:', error)\n return []\n }\n }\n\n /**\n * Get prefix suggestions by blending popular query prefixes (30d) + FTS5 content title prefixes.\n * Popular queries appear first (real user intent), content titles fill remaining slots.\n */\n private async getPrefixSuggestions(prefix: string): Promise {\n const [popularQueries, contentTitles] = await Promise.all([\n this.getPopularQueryPrefixes(prefix, 5),\n this.getContentTitlePrefixes(prefix, 5),\n ])\n\n // Dedup: popular queries first, then content titles that aren't already included\n const seen = new Set(popularQueries.map((q) => q.toLowerCase()))\n const merged = [...popularQueries]\n for (const title of contentTitles) {\n if (!seen.has(title.toLowerCase())) {\n merged.push(title)\n seen.add(title.toLowerCase())\n }\n if (merged.length >= 10) break\n }\n return merged\n }\n\n /**\n * Popular query prefixes from search history (last 30 days).\n * Ranked by frequency, excludes zero-result queries.\n */\n private async getPopularQueryPrefixes(prefix: string, limit: number): Promise {\n try {\n const thirtyDaysAgo = Date.now() - 30 * 24 * 60 * 60 * 1000\n const stmt = this.db.prepare(`\n SELECT query, COUNT(*) as cnt, AVG(results_count) as avg_res\n FROM ai_search_history\n WHERE created_at >= ? AND LOWER(query) LIKE ?\n GROUP BY LOWER(query)\n HAVING avg_res >= 0.5\n ORDER BY cnt DESC\n LIMIT ?\n `)\n const { results } = await stmt\n .bind(thirtyDaysAgo, `${prefix.toLowerCase()}%`, limit)\n .all<{ query: string; cnt: number; avg_res: number }>()\n return (results || []).map((r) => r.query).filter(Boolean)\n } catch (error) {\n console.log('[AISearchService] Popular query prefixes unavailable:', error)\n return []\n }\n }\n\n /**\n * Content title prefixes via FTS5 prefix matching.\n * Falls back to ai_search_index LIKE if FTS5 is unavailable.\n */\n private async getContentTitlePrefixes(prefix: string, limit: number): Promise {\n // Try FTS5 prefix match first (fast + ranked by BM25)\n try {\n // Sanitize prefix for FTS5: remove special chars, keep alphanumeric + spaces\n const sanitized = prefix.replace(/[^\\w\\s]/g, '').trim()\n if (!sanitized) return []\n\n const stmt = this.db.prepare(`\n SELECT DISTINCT title FROM content_fts\n WHERE content_fts MATCH ?\n ORDER BY bm25(content_fts, 5.0, 2.0, 1.0)\n LIMIT ?\n `)\n const { results } = await stmt.bind(`${sanitized}*`, limit).all<{ title: string }>()\n return (results || []).map((r) => r.title).filter(Boolean)\n } catch {\n // FTS5 table may not exist ā fall back to ai_search_index\n }\n\n // Fallback: simple LIKE prefix on ai_search_index\n try {\n const stmt = this.db.prepare(`\n SELECT DISTINCT title FROM ai_search_index\n WHERE LOWER(title) LIKE ?\n ORDER BY title\n LIMIT ?\n `)\n const { results } = await stmt.bind(`${prefix.toLowerCase()}%`, limit).all<{ title: string }>()\n return (results || []).map((r) => r.title).filter(Boolean)\n } catch {\n return []\n }\n }\n\n /**\n * Log search query to history, returns the generated search_id\n */\n private async logSearch(query: string, mode: 'ai' | 'keyword' | 'fts5' | 'hybrid', resultsCount: number, responseTimeMs?: number, cached?: boolean): Promise {\n try {\n const result = await this.db.prepare(`\n INSERT INTO ai_search_history (query, mode, results_count, response_time_ms, cached, created_at)\n VALUES (?, ?, ?, ?, ?, ?)\n `).bind(query, mode, resultsCount, responseTimeMs ?? null, cached ? 1 : 0, Date.now()).run()\n // D1 returns the auto-incremented rowid via meta.last_row_id\n const rowId = result?.meta?.last_row_id\n return rowId ? String(rowId) : undefined\n } catch (error) {\n console.error('Error logging search:', error)\n return undefined\n }\n }\n\n /**\n * Get search analytics\n */\n async getSearchAnalytics(): Promise<{\n total_queries: number\n ai_queries: number\n keyword_queries: number\n fts5_queries: number\n hybrid_queries: number\n popular_queries: Array<{ query: string; count: number }>\n average_query_time: number\n }> {\n try {\n // Total queries (last 30 days)\n const totalStmt = this.db.prepare(`\n SELECT COUNT(*) as count\n FROM ai_search_history\n WHERE created_at >= ?\n `)\n const thirtyDaysAgo = Date.now() - 30 * 24 * 60 * 60 * 1000\n const totalResult = await totalStmt.bind(thirtyDaysAgo).first<{ count: number }>()\n\n // AI vs Keyword vs FTS5 breakdown\n const modeStmt = this.db.prepare(`\n SELECT mode, COUNT(*) as count\n FROM ai_search_history\n WHERE created_at >= ?\n GROUP BY mode\n `)\n const { results: modeResults } = await modeStmt.bind(thirtyDaysAgo).all<{\n mode: string\n count: number\n }>()\n\n const aiCount = modeResults?.find((r) => r.mode === 'ai')?.count || 0\n const keywordCount = modeResults?.find((r) => r.mode === 'keyword')?.count || 0\n const fts5Count = modeResults?.find((r) => r.mode === 'fts5')?.count || 0\n const hybridCount = modeResults?.find((r) => r.mode === 'hybrid')?.count || 0\n\n // Popular queries\n const popularStmt = this.db.prepare(`\n SELECT query, COUNT(*) as count\n FROM ai_search_history\n WHERE created_at >= ?\n GROUP BY query\n ORDER BY count DESC\n LIMIT 10\n `)\n const { results: popularResults } = await popularStmt.bind(thirtyDaysAgo).all<{\n query: string\n count: number\n }>()\n\n return {\n total_queries: totalResult?.count || 0,\n ai_queries: aiCount,\n keyword_queries: keywordCount,\n fts5_queries: fts5Count,\n hybrid_queries: hybridCount,\n popular_queries: (popularResults || []).map((r) => ({\n query: r.query,\n count: r.count,\n })),\n average_query_time: 0, // TODO: Track query times\n }\n } catch (error) {\n console.error('Error getting analytics:', error)\n return {\n total_queries: 0,\n ai_queries: 0,\n keyword_queries: 0,\n fts5_queries: 0,\n hybrid_queries: 0,\n popular_queries: [],\n average_query_time: 0,\n }\n }\n }\n\n /**\n * Get extended analytics for the Analytics tab\n */\n async getAnalyticsExtended(): Promise<{\n total_queries: number\n queries_today: number\n ai_queries: number\n keyword_queries: number\n fts5_queries: number\n hybrid_queries: number\n avg_results_per_query: number\n zero_result_rate: number\n avg_response_time_ms: number\n popular_queries: Array<{ query: string; count: number }>\n zero_result_queries: Array<{ query: string; count: number }>\n recent_queries: Array<{ query: string; mode: string; results_count: number; response_time_ms: number | null; created_at: number }>\n daily_counts: Array<{ date: string; count: number }>\n // Click analytics\n total_clicks_30d: number\n ctr_30d: number\n avg_click_position_30d: number\n ctr_over_time: Array<{ date: string; searches: number; clicks: number; ctr: number }>\n most_clicked_content: Array<{ content_id: string; content_title: string; click_count: number }>\n no_click_searches: Array<{ query: string; search_count: number; results_count_avg: number }>\n // Facet analytics\n total_facet_clicks_30d: number\n top_facet_fields: Array<{ facet_field: string; click_count: number }>\n top_facet_values: Array<{ facet_field: string; facet_value: string; click_count: number }>\n facet_clicks_over_time: Array<{ date: string; count: number }>\n }> {\n const thirtyDaysAgo = Date.now() - 30 * 24 * 60 * 60 * 1000\n const todayStart = new Date()\n todayStart.setHours(0, 0, 0, 0)\n const todayStartMs = todayStart.getTime()\n\n try {\n // Run all queries in parallel\n const [\n totalResult,\n todayResult,\n modeResults,\n avgResults,\n zeroCountResult,\n avgTimeResult,\n popularResults,\n zeroResultResults,\n recentResults,\n dailyResults,\n // Click analytics\n clickCountResult,\n avgClickPosResult,\n ctrOverTimeResults,\n mostClickedResults,\n noClickResults,\n // Facet analytics\n facetClickCountResult,\n topFacetFieldsResult,\n topFacetValuesResult,\n facetClicksOverTimeResult,\n ] = await Promise.all([\n // Total queries (30 days)\n this.db.prepare('SELECT COUNT(*) as count FROM ai_search_history WHERE created_at >= ?')\n .bind(thirtyDaysAgo).first<{ count: number }>(),\n\n // Queries today\n this.db.prepare('SELECT COUNT(*) as count FROM ai_search_history WHERE created_at >= ?')\n .bind(todayStartMs).first<{ count: number }>(),\n\n // Mode breakdown\n this.db.prepare('SELECT mode, COUNT(*) as count FROM ai_search_history WHERE created_at >= ? GROUP BY mode')\n .bind(thirtyDaysAgo).all<{ mode: string; count: number }>(),\n\n // Average results per query\n this.db.prepare('SELECT AVG(results_count) as avg_results FROM ai_search_history WHERE created_at >= ?')\n .bind(thirtyDaysAgo).first<{ avg_results: number | null }>(),\n\n // Zero result count\n this.db.prepare('SELECT COUNT(*) as count FROM ai_search_history WHERE created_at >= ? AND results_count = 0')\n .bind(thirtyDaysAgo).first<{ count: number }>(),\n\n // Average response time\n this.db.prepare('SELECT AVG(response_time_ms) as avg_time FROM ai_search_history WHERE created_at >= ? AND response_time_ms IS NOT NULL')\n .bind(thirtyDaysAgo).first<{ avg_time: number | null }>(),\n\n // Popular queries (top 15)\n this.db.prepare('SELECT query, COUNT(*) as count FROM ai_search_history WHERE created_at >= ? GROUP BY query ORDER BY count DESC LIMIT 15')\n .bind(thirtyDaysAgo).all<{ query: string; count: number }>(),\n\n // Zero-result queries (top 20)\n this.db.prepare('SELECT query, COUNT(*) as count FROM ai_search_history WHERE created_at >= ? AND results_count = 0 GROUP BY query ORDER BY count DESC LIMIT 20')\n .bind(thirtyDaysAgo).all<{ query: string; count: number }>(),\n\n // Recent queries (last 25)\n this.db.prepare('SELECT query, mode, results_count, response_time_ms, created_at FROM ai_search_history ORDER BY created_at DESC LIMIT 25')\n .all<{ query: string; mode: string; results_count: number; response_time_ms: number | null; created_at: number }>(),\n\n // Daily counts for last 30 days\n this.db.prepare(`\n SELECT date(created_at / 1000, 'unixepoch') as date, COUNT(*) as count\n FROM ai_search_history\n WHERE created_at >= ?\n GROUP BY date(created_at / 1000, 'unixepoch')\n ORDER BY date ASC\n `).bind(thirtyDaysAgo).all<{ date: string; count: number }>(),\n\n // Click analytics: total clicks (30 days)\n this.db.prepare(\"SELECT COUNT(*) as count FROM ai_search_clicks WHERE created_at > datetime('now', '-30 days')\")\n .first<{ count: number }>().catch(() => ({ count: 0 })),\n\n // Click analytics: average click position (30 days)\n this.db.prepare(\"SELECT AVG(click_position) as avg_pos FROM ai_search_clicks WHERE created_at > datetime('now', '-30 days')\")\n .first<{ avg_pos: number | null }>().catch(() => ({ avg_pos: null })),\n\n // Click analytics: CTR over time (daily, 30 days)\n this.db.prepare(`\n SELECT\n date(h.created_at / 1000, 'unixepoch') as date,\n COUNT(DISTINCT h.id) as searches,\n COUNT(c.id) as clicks\n FROM ai_search_history h\n LEFT JOIN ai_search_clicks c ON c.search_id = h.id\n WHERE h.created_at >= ?\n GROUP BY date(h.created_at / 1000, 'unixepoch')\n ORDER BY date ASC\n `).bind(thirtyDaysAgo).all<{ date: string; searches: number; clicks: number }>().catch(() => ({ results: [] })),\n\n // Click analytics: most clicked content (top 20)\n this.db.prepare(`\n SELECT clicked_content_id as content_id, clicked_content_title as content_title, COUNT(*) as click_count\n FROM ai_search_clicks\n WHERE created_at > datetime('now', '-30 days')\n GROUP BY clicked_content_id\n ORDER BY click_count DESC\n LIMIT 20\n `).all<{ content_id: string; content_title: string; click_count: number }>().catch(() => ({ results: [] })),\n\n // Click analytics: searches with no clicks (top 20)\n this.db.prepare(`\n SELECT h.query, COUNT(DISTINCT h.id) as search_count, CAST(AVG(h.results_count) AS INTEGER) as results_count_avg\n FROM ai_search_history h\n LEFT JOIN ai_search_clicks c ON c.search_id = h.id\n WHERE h.created_at >= ?\n AND h.results_count > 0\n AND c.id IS NULL\n GROUP BY h.query\n ORDER BY search_count DESC\n LIMIT 20\n `).bind(thirtyDaysAgo).all<{ query: string; search_count: number; results_count_avg: number }>().catch(() => ({ results: [] })),\n\n // Facet analytics: total facet clicks (30 days)\n this.db.prepare(\"SELECT COUNT(*) as count FROM ai_search_facet_clicks WHERE created_at > datetime('now', '-30 days')\")\n .first<{ count: number }>().catch(() => ({ count: 0 })),\n\n // Facet analytics: top facet fields by click count (30 days)\n this.db.prepare(`\n SELECT facet_field, COUNT(*) as click_count\n FROM ai_search_facet_clicks\n WHERE created_at > datetime('now', '-30 days')\n GROUP BY facet_field\n ORDER BY click_count DESC\n LIMIT 10\n `).all<{ facet_field: string; click_count: number }>().catch(() => ({ results: [] })),\n\n // Facet analytics: top facet values by click count (30 days)\n this.db.prepare(`\n SELECT facet_field, facet_value, COUNT(*) as click_count\n FROM ai_search_facet_clicks\n WHERE created_at > datetime('now', '-30 days')\n GROUP BY facet_field, facet_value\n ORDER BY click_count DESC\n LIMIT 15\n `).all<{ facet_field: string; facet_value: string; click_count: number }>().catch(() => ({ results: [] })),\n\n // Facet analytics: facet clicks over time (daily, 30 days)\n this.db.prepare(`\n SELECT date(created_at) as date, COUNT(*) as count\n FROM ai_search_facet_clicks\n WHERE created_at > datetime('now', '-30 days')\n GROUP BY date(created_at)\n ORDER BY date ASC\n `).all<{ date: string; count: number }>().catch(() => ({ results: [] })),\n ])\n\n const totalQueries = totalResult?.count || 0\n const zeroCount = zeroCountResult?.count || 0\n const modes = modeResults?.results || []\n\n // Compute click analytics\n const totalClicks = (clickCountResult as any)?.count || 0\n const avgClickPos = (avgClickPosResult as any)?.avg_pos\n const ctrRaw = (ctrOverTimeResults as any)?.results || []\n const ctrOverTime = ctrRaw.map((r: any) => ({\n date: r.date,\n searches: r.searches,\n clicks: r.clicks,\n ctr: r.searches > 0 ? Math.round((r.clicks / r.searches) * 1000) / 10 : 0,\n }))\n\n return {\n total_queries: totalQueries,\n queries_today: todayResult?.count || 0,\n ai_queries: modes.find(r => r.mode === 'ai')?.count || 0,\n keyword_queries: modes.find(r => r.mode === 'keyword')?.count || 0,\n fts5_queries: modes.find(r => r.mode === 'fts5')?.count || 0,\n hybrid_queries: modes.find(r => r.mode === 'hybrid')?.count || 0,\n avg_results_per_query: Math.round((avgResults?.avg_results ?? 0) * 10) / 10,\n zero_result_rate: totalQueries > 0 ? Math.round((zeroCount / totalQueries) * 1000) / 10 : 0,\n avg_response_time_ms: Math.round(avgTimeResult?.avg_time ?? 0),\n popular_queries: (popularResults?.results || []).map(r => ({ query: r.query, count: r.count })),\n zero_result_queries: (zeroResultResults?.results || []).map(r => ({ query: r.query, count: r.count })),\n recent_queries: (recentResults?.results || []).map(r => ({\n query: r.query,\n mode: r.mode,\n results_count: r.results_count,\n response_time_ms: r.response_time_ms,\n created_at: r.created_at,\n })),\n daily_counts: (dailyResults?.results || []).map(r => ({ date: r.date, count: r.count })),\n // Click analytics\n total_clicks_30d: totalClicks,\n ctr_30d: totalQueries > 0 ? Math.round((totalClicks / totalQueries) * 1000) / 10 : 0,\n avg_click_position_30d: avgClickPos != null ? Math.round(avgClickPos * 10) / 10 : 0,\n ctr_over_time: ctrOverTime,\n most_clicked_content: ((mostClickedResults as any)?.results || []).map((r: any) => ({\n content_id: r.content_id,\n content_title: r.content_title || 'Untitled',\n click_count: r.click_count,\n })),\n no_click_searches: ((noClickResults as any)?.results || []).map((r: any) => ({\n query: r.query,\n search_count: r.search_count,\n results_count_avg: r.results_count_avg,\n })),\n // Facet analytics\n total_facet_clicks_30d: (facetClickCountResult as any)?.count || 0,\n top_facet_fields: ((topFacetFieldsResult as any)?.results || []).map((r: any) => ({\n facet_field: r.facet_field,\n click_count: r.click_count,\n })),\n top_facet_values: ((topFacetValuesResult as any)?.results || []).map((r: any) => ({\n facet_field: r.facet_field,\n facet_value: r.facet_value,\n click_count: r.click_count,\n })),\n facet_clicks_over_time: ((facetClicksOverTimeResult as any)?.results || []).map((r: any) => ({\n date: r.date,\n count: r.count,\n })),\n }\n } catch (error) {\n console.error('Error getting extended analytics:', error)\n return {\n total_queries: 0,\n queries_today: 0,\n ai_queries: 0,\n keyword_queries: 0,\n fts5_queries: 0,\n hybrid_queries: 0,\n avg_results_per_query: 0,\n zero_result_rate: 0,\n avg_response_time_ms: 0,\n popular_queries: [],\n zero_result_queries: [],\n recent_queries: [],\n daily_counts: [],\n total_clicks_30d: 0,\n ctr_30d: 0,\n avg_click_position_30d: 0,\n ctr_over_time: [],\n most_clicked_content: [],\n no_click_searches: [],\n total_facet_clicks_30d: 0,\n top_facet_fields: [],\n top_facet_values: [],\n facet_clicks_over_time: [],\n }\n }\n }\n\n /**\n * Verify Custom RAG is available\n */\n verifyBinding(): boolean {\n return this.customRAG?.isAvailable() ?? false\n }\n\n /**\n * Get Custom RAG service instance (for indexer)\n */\n getCustomRAG(): CustomRAGService | undefined {\n return this.customRAG\n }\n\n /**\n * Get FTS5 service instance (for content sync and admin operations)\n */\n getFTS5Service(): FTS5Service | undefined {\n return this.fts5Service\n }\n\n /**\n * Get ranking pipeline service instance (for admin routes)\n */\n getRankingPipeline(): RankingPipelineService {\n return this.rankingPipeline\n }\n\n /**\n * Get synonym service instance (for admin routes)\n */\n getSynonymService(): SynonymService {\n return this.synonymService\n }\n\n /**\n * Get query rules service instance (for admin routes)\n */\n getQueryRulesService(): QueryRulesService {\n return this.queryRulesService\n }\n\n /**\n * Get search cache service instance (for cache invalidation from content CRUD hooks)\n */\n getSearchCache(): SearchCacheService | undefined {\n return this.searchCache\n }\n}\n","import type { D1Database } from '@cloudflare/workers-types'\nimport type { AISearchSettings, IndexStatus } from '../types'\nimport { CustomRAGService } from './custom-rag.service'\nimport { FTS5Service } from './fts5.service'\n\n/**\n * Index Manager Service\n * Handles indexing of content items using Custom RAG with Vectorize\n * Falls back to FTS5 indexing when Vectorize is not available\n */\nexport class IndexManager {\n private customRAG?: CustomRAGService\n private fts5Service: FTS5Service\n\n constructor(\n private db: D1Database,\n private ai?: any, // Workers AI for embeddings\n private vectorize?: any // Vectorize for vector search\n ) {\n this.fts5Service = new FTS5Service(db)\n\n // Initialize Custom RAG if bindings are available\n if (this.ai && this.vectorize) {\n this.customRAG = new CustomRAGService(db, ai, vectorize)\n console.log('[IndexManager] Custom RAG initialized')\n }\n }\n\n /**\n * Index all content items within a collection using Custom RAG\n */\n async indexCollection(collectionId: string): Promise {\n try {\n // Get collection info\n const collectionStmt = this.db.prepare(\n 'SELECT id, name, display_name FROM collections WHERE id = ?'\n )\n const collection = await collectionStmt.bind(collectionId).first<{\n id: string\n name: string\n display_name: string\n }>()\n\n if (!collection) {\n throw new Error(`Collection ${collectionId} not found`)\n }\n\n // Count total items before setting status so progress bar shows correctly\n const countResult = await this.db.prepare(\n \"SELECT COUNT(*) as cnt FROM content WHERE collection_id = ? AND status != 'deleted'\"\n ).bind(collectionId).first<{ cnt: number }>()\n const totalItems = countResult?.cnt || 0\n\n // Update status to indexing with actual total\n await this.updateIndexStatus(collectionId, {\n collection_id: collectionId,\n collection_name: collection.display_name,\n total_items: totalItems,\n indexed_items: 0,\n status: 'indexing',\n })\n\n // Use Custom RAG for indexing if available\n if (this.customRAG?.isAvailable()) {\n console.log(`[IndexManager] Using Custom RAG to index collection ${collectionId}`)\n\n // Track highest progress to prevent UI from jumping backward between phases\n let highWaterMark = 0\n\n let result: { total_items: number; total_chunks: number; indexed_chunks: number; errors: number }\n try {\n result = await this.customRAG.indexCollection(\n collectionId,\n async (phase, processed, total) => {\n // Map chunk progress to approximate item progress for the UI\n // Embedding phase = 0-90%, storing phase = 90-100%\n let itemProgress: number\n if (phase === 'chunking') {\n itemProgress = 0\n } else if (phase === 'embedding') {\n // Embedding is the slow part ā map to 0-90% of total items\n itemProgress = Math.round((processed / Math.max(total, 1)) * totalItems * 0.9)\n } else {\n // Storing phase ā map to 90-100% of total items\n itemProgress = Math.round(totalItems * 0.9 + (processed / Math.max(total, 1)) * totalItems * 0.1)\n }\n itemProgress = Math.min(totalItems, itemProgress)\n // Never go backward\n if (itemProgress > highWaterMark) {\n highWaterMark = itemProgress\n }\n await this.updateIndexStatus(collectionId, {\n collection_id: collectionId,\n collection_name: collection.display_name,\n total_items: totalItems,\n indexed_items: highWaterMark,\n status: 'indexing',\n })\n }\n )\n } catch (ragError) {\n // Ensure we mark as error even if the Worker is about to die\n console.error(`[IndexManager] CustomRAG indexing failed for ${collectionId}:`, ragError)\n await this.updateIndexStatus(collectionId, {\n collection_id: collectionId,\n collection_name: collection.display_name,\n total_items: totalItems,\n indexed_items: highWaterMark,\n status: 'error',\n error_message: ragError instanceof Error ? ragError.message : String(ragError),\n })\n return {\n collection_id: collectionId,\n collection_name: collection.display_name,\n total_items: totalItems,\n indexed_items: highWaterMark,\n status: 'error' as const,\n error_message: ragError instanceof Error ? ragError.message : String(ragError),\n }\n }\n\n const finalStatus: IndexStatus = {\n collection_id: collectionId,\n collection_name: collection.display_name,\n total_items: result.total_items,\n indexed_items: result.total_items, // Use total_items, not chunks, for final display\n last_sync_at: Date.now(),\n status: result.errors > 0 ? 'error' : 'completed',\n error_message: result.errors > 0 ? `${result.errors} errors during indexing` : undefined\n }\n\n await this.updateIndexStatus(collectionId, finalStatus)\n return finalStatus\n }\n\n // Fallback: No Vectorize ā use FTS5 for indexing\n console.log(`[IndexManager] Using FTS5 to index collection ${collectionId}`)\n\n // Check if FTS5 is available\n const fts5Available = await this.fts5Service.isAvailable()\n\n if (fts5Available) {\n // Run FTS5 indexing with progress updates\n const fts5Result = await this.fts5Service.indexCollection(\n collectionId,\n async (indexed, total) => {\n // Update progress in the database so polling picks it up\n await this.updateIndexStatus(collectionId, {\n collection_id: collectionId,\n collection_name: collection.display_name,\n total_items: total,\n indexed_items: indexed,\n status: 'indexing',\n })\n }\n )\n\n const fallbackStatus: IndexStatus = {\n collection_id: collectionId,\n collection_name: collection.display_name,\n total_items: fts5Result.total_items,\n indexed_items: fts5Result.indexed_items,\n last_sync_at: Date.now(),\n status: fts5Result.errors > 0 ? 'error' : 'completed',\n error_message: fts5Result.errors > 0 ? `${fts5Result.errors} errors during FTS5 indexing` : undefined\n }\n\n await this.updateIndexStatus(collectionId, fallbackStatus)\n return fallbackStatus\n }\n\n // No FTS5 either ā just count content items for display\n console.warn(`[IndexManager] No FTS5 available, counting content items for ${collectionId}`)\n const fallbackCount = await this.db.prepare(\n 'SELECT COUNT(*) as cnt FROM content WHERE collection_id = ?'\n ).bind(collectionId).first<{ cnt: number }>()\n\n const fallbackStatus: IndexStatus = {\n collection_id: collectionId,\n collection_name: collection.display_name,\n total_items: fallbackCount?.cnt || 0,\n indexed_items: 0,\n last_sync_at: Date.now(),\n status: 'completed',\n error_message: 'No search index available (Vectorize and FTS5 both unavailable)'\n }\n\n await this.updateIndexStatus(collectionId, fallbackStatus)\n return fallbackStatus\n } catch (error) {\n console.error(`[IndexManager] Error indexing collection ${collectionId}:`, error)\n const errorStatus: IndexStatus = {\n collection_id: collectionId,\n collection_name: 'Unknown',\n total_items: 0,\n indexed_items: 0,\n status: 'error',\n error_message: error instanceof Error ? error.message : String(error),\n }\n await this.updateIndexStatus(collectionId, errorStatus)\n return errorStatus\n }\n }\n\n /**\n * Index a single content item\n */\n private async indexContentItem(\n item: {\n id: string\n title: string\n slug: string\n data: string\n status: string\n created_at: number\n updated_at: number\n author_id?: string\n collection_name: string\n collection_display_name: string\n },\n collectionId: string\n ): Promise {\n try {\n // Parse content data\n let parsedData: any = {}\n try {\n parsedData = typeof item.data === 'string' ? JSON.parse(item.data) : item.data\n } catch {\n parsedData = {}\n }\n\n // Prepare document for AI Search\n const document = {\n id: `content_${item.id}`,\n title: item.title || 'Untitled',\n slug: item.slug || '',\n content: this.extractSearchableText(parsedData),\n metadata: {\n collection_id: collectionId,\n collection_name: item.collection_name,\n collection_display_name: item.collection_display_name,\n status: item.status,\n created_at: item.created_at,\n updated_at: item.updated_at,\n author_id: item.author_id,\n },\n }\n\n // TODO: Call Cloudflare AI Search API to index document\n // await this.aiSearch.index(document)\n\n // For now, just log (actual implementation will use AI Search API)\n console.log(`Indexed content item: ${item.id}`)\n } catch (error) {\n console.error(`Error indexing content item ${item.id}:`, error)\n throw error\n }\n }\n\n /**\n * Extract searchable text from content data\n */\n private extractSearchableText(data: any): string {\n const parts: string[] = []\n\n // Add title if present\n if (data.title) parts.push(String(data.title))\n if (data.name) parts.push(String(data.name))\n\n // Add description/content fields\n if (data.description) parts.push(String(data.description))\n if (data.content) parts.push(String(data.content))\n if (data.body) parts.push(String(data.body))\n if (data.text) parts.push(String(data.text))\n\n // Add all string values from data\n const extractStrings = (obj: any): void => {\n if (typeof obj === 'string') {\n parts.push(obj)\n } else if (Array.isArray(obj)) {\n obj.forEach(extractStrings)\n } else if (obj && typeof obj === 'object') {\n Object.values(obj).forEach(extractStrings)\n }\n }\n\n extractStrings(data)\n\n return parts.join(' ')\n }\n\n /**\n * Update a single content item in the index\n */\n async updateIndex(collectionId: number, contentId: string): Promise {\n try {\n // Get content item\n const stmt = this.db.prepare(`\n SELECT \n c.id, c.title, c.slug, c.data, c.status,\n c.created_at, c.updated_at, c.author_id,\n col.name as collection_name, col.display_name as collection_display_name\n FROM content c\n JOIN collections col ON c.collection_id = col.id\n WHERE c.id = ? AND c.collection_id = ?\n `)\n const item = await stmt.bind(contentId, collectionId).first<{\n id: string\n title: string\n slug: string\n data: string\n status: string\n created_at: number\n updated_at: number\n author_id?: string\n collection_name: string\n collection_display_name: string\n }>()\n\n if (!item) {\n throw new Error(`Content item ${contentId} not found`)\n }\n\n // Re-index the item\n await this.indexContentItem(item, String(collectionId))\n\n // Update last sync time for collection\n const status = await this.getIndexStatus(String(collectionId))\n if (status) {\n await this.updateIndexStatus(String(collectionId), {\n ...status,\n last_sync_at: Date.now(),\n })\n }\n } catch (error) {\n console.error(`Error updating index for content ${contentId}:`, error)\n throw error\n }\n }\n\n /**\n * Remove a content item from the index using Custom RAG\n */\n async removeFromIndex(collectionId: string, contentId: string): Promise {\n try {\n if (this.customRAG?.isAvailable()) {\n console.log(`[IndexManager] Removing content ${contentId} from index`)\n await this.customRAG.removeContentFromIndex(contentId)\n } else {\n console.warn(`[IndexManager] Custom RAG not available, skipping removal for ${contentId}`)\n }\n } catch (error) {\n console.error(`[IndexManager] Error removing content ${contentId} from index:`, error)\n throw error\n }\n }\n\n /**\n * Get indexing status for a collection\n */\n async getIndexStatus(collectionId: string): Promise {\n try {\n const stmt = this.db.prepare(\n 'SELECT * FROM ai_search_index_meta WHERE collection_id = ?'\n )\n const result = await stmt.bind(collectionId).first<{\n id: number\n collection_id: string\n collection_name: string\n total_items: number\n indexed_items: number\n last_sync_at?: number\n status: string\n error_message?: string\n }>()\n\n if (!result) {\n return null\n }\n\n return {\n collection_id: String(result.collection_id),\n collection_name: result.collection_name,\n total_items: result.total_items,\n indexed_items: result.indexed_items,\n last_sync_at: result.last_sync_at,\n status: result.status as IndexStatus['status'],\n error_message: result.error_message,\n }\n } catch (error) {\n console.error(`Error getting index status for collection ${collectionId}:`, error)\n return null\n }\n }\n\n /**\n * Get indexing status for all collections\n */\n async getAllIndexStatus(): Promise> {\n try {\n const stmt = this.db.prepare('SELECT * FROM ai_search_index_meta')\n const { results } = await stmt.all<{\n id: number\n collection_id: number\n collection_name: string\n total_items: number\n indexed_items: number\n last_sync_at?: number\n status: string\n error_message?: string\n }>()\n\n const statusMap: Record = {}\n\n for (const row of results || []) {\n const collectionId = String(row.collection_id)\n statusMap[collectionId] = {\n collection_id: collectionId,\n collection_name: row.collection_name,\n total_items: row.total_items,\n indexed_items: row.indexed_items,\n last_sync_at: row.last_sync_at,\n status: row.status as IndexStatus['status'],\n error_message: row.error_message,\n }\n }\n\n return statusMap\n } catch (error) {\n console.error('Error getting all index status:', error)\n return {}\n }\n }\n\n /**\n * Update index status in database\n */\n private async updateIndexStatus(collectionId: string, status: IndexStatus): Promise {\n try {\n // Check if record exists\n const checkStmt = this.db.prepare(\n 'SELECT id FROM ai_search_index_meta WHERE collection_id = ?'\n )\n const existing = await checkStmt.bind(collectionId).first<{ id: number }>()\n\n if (existing) {\n // Update existing\n const stmt = this.db.prepare(`\n UPDATE ai_search_index_meta \n SET collection_name = ?,\n total_items = ?,\n indexed_items = ?,\n last_sync_at = ?,\n status = ?,\n error_message = ?\n WHERE collection_id = ?\n `)\n await stmt\n .bind(\n status.collection_name,\n status.total_items,\n status.indexed_items,\n status.last_sync_at || null,\n status.status,\n status.error_message || null,\n String(collectionId)\n )\n .run()\n } else {\n // Insert new\n const stmt = this.db.prepare(`\n INSERT INTO ai_search_index_meta (\n collection_id, collection_name, total_items, indexed_items,\n last_sync_at, status, error_message\n ) VALUES (?, ?, ?, ?, ?, ?, ?)\n `)\n await stmt\n .bind(\n String(status.collection_id),\n status.collection_name,\n status.total_items,\n status.indexed_items,\n status.last_sync_at || null,\n status.status,\n status.error_message || null\n )\n .run()\n }\n } catch (error) {\n console.error(`Error updating index status for collection ${collectionId}:`, error)\n throw error\n }\n }\n\n /**\n * Sync all selected collections\n */\n async syncAll(selectedCollections: string[]): Promise {\n for (const collectionId of selectedCollections) {\n try {\n await this.indexCollection(collectionId)\n } catch (error) {\n console.error(`Error syncing collection ${collectionId}:`, error)\n }\n }\n }\n}\n","/**\n * Benchmark Dataset Registry\n *\n * Lightweight metadata for all supported BEIR benchmark datasets.\n * Actual corpus/query/qrel data lives in KV (CACHE_KV), not in the Worker bundle.\n *\n * To add a new dataset:\n * 1. Add an entry here\n * 2. Run: npx tsx scripts/generate-benchmark-data.ts --dataset \n * 3. No rebuild needed ā the Worker fetches data from KV on demand\n */\n\nexport interface DatasetInfo {\n id: string\n name: string\n description: string\n corpus_size: number\n query_count: number\n avg_qrels_per_query: number\n license: string\n /** If true, the KV data is a subset of the full corpus (relevant docs + noise) */\n subset?: boolean\n}\n\nexport interface BenchmarkDocument {\n // eslint-disable-next-line @typescript-eslint/naming-convention -- BEIR dataset schema uses _id\n _id: string\n title: string\n text: string\n}\n\nexport interface BenchmarkQuery {\n // eslint-disable-next-line @typescript-eslint/naming-convention -- BEIR dataset schema uses _id\n _id: string\n text: string\n}\n\nexport interface BenchmarkQrel {\n query_id: string\n doc_id: string\n score: number\n}\n\nexport const BENCHMARK_DATASETS: DatasetInfo[] = [\n {\n id: 'scifact',\n name: 'BEIR SciFact',\n description: 'Scientific fact verification ā abstracts from S2ORC',\n corpus_size: 5183,\n query_count: 1109,\n avg_qrels_per_query: 1.1,\n license: 'CC BY-SA 4.0',\n },\n {\n id: 'nfcorpus',\n name: 'BEIR NFCorpus',\n description: 'Bio-medical IR ā NutritionFacts clinical documents',\n corpus_size: 3633,\n query_count: 323,\n avg_qrels_per_query: 38.2,\n license: 'Mixed (see dataset)',\n },\n {\n id: 'fiqa',\n name: 'BEIR FiQA-2018',\n description: 'Financial Q&A ā opinion-based questions from StackExchange/Reddit',\n corpus_size: 57638,\n query_count: 648,\n avg_qrels_per_query: 2.6,\n license: 'Mixed (see dataset)',\n },\n]\n","/**\n * Benchmark Service ā BEIR Evaluation (KV-Backed)\n *\n * Provides seeding, purging, and evaluation of BEIR benchmark datasets\n * against the AI Search plugin's search modes.\n *\n * Dataset data (corpus, queries, qrels) is stored in KV and loaded on demand.\n * Supports multiple datasets: SciFact, NFCorpus, FiQA-2018, etc.\n *\n * Metrics computed: nDCG@k, Precision@k, Recall@k, MRR\n */\n\nimport type { D1Database, KVNamespace } from '@cloudflare/workers-types'\nimport {\n BENCHMARK_DATASETS,\n type DatasetInfo,\n type BenchmarkDocument,\n type BenchmarkQuery,\n type BenchmarkQrel,\n} from '../data/benchmark-datasets'\n\n// --- Result Types ---\n\nexport interface BenchmarkResults {\n mode: string\n limit: number\n corpus_size: number\n queries_evaluated: number\n total_time_ms: number\n avg_query_time_ms: number\n metrics: {\n ndcg_at_k: number\n precision_at_k: number\n recall_at_k: number\n mrr: number\n }\n per_query: PerQueryResult[]\n}\n\nexport interface PerQueryResult {\n query_id: string\n query_text: string\n ndcg: number\n precision: number\n recall: number\n mrr: number\n hits: number\n expected: number\n returned: number\n query_time_ms: number\n}\n\nexport interface SeedResult {\n seeded: number\n skipped: boolean\n}\n\nexport interface SeedProgress {\n phase: 'inserting' | 'complete'\n inserted: number\n total: number\n}\n\ninterface BenchmarkData {\n corpus: BenchmarkDocument[]\n queries: BenchmarkQuery[]\n qrels: BenchmarkQrel[]\n}\n\nexport class BenchmarkService {\n private dataset: string\n private data: BenchmarkData | null = null\n private idPrefix: string\n private collectionId: string\n\n constructor(\n private db: D1Database,\n private kv: KVNamespace,\n private vectorize?: any,\n dataset: string = 'scifact'\n ) {\n this.dataset = dataset\n this.idPrefix = `beir-${dataset}-`\n this.collectionId = `benchmark-${dataset}-collection`\n if (!BENCHMARK_DATASETS.find((d) => d.id === dataset)) {\n throw new Error(`Unknown benchmark dataset: ${dataset}`)\n }\n }\n\n /**\n * Load dataset from KV on first access. Cached for lifetime of the service instance.\n *\n * Corpus data may be stored as a single key or chunked across multiple keys\n * (for datasets that exceed the 25 MiB KV value limit). Chunked data uses:\n * benchmark:{dataset}:corpus:meta ā { chunks: N, total: M }\n * benchmark:{dataset}:corpus:0 ā first slice\n * benchmark:{dataset}:corpus:1 ā second slice\n * ...\n */\n private async loadData(): Promise {\n if (this.data) return this.data\n\n const corpusKey = `benchmark:${this.dataset}:corpus`\n\n const [corpus, queries, qrels, corpusMeta] = await Promise.all([\n this.kv.get(corpusKey, 'json'),\n this.kv.get(\n `benchmark:${this.dataset}:queries`,\n 'json'\n ),\n this.kv.get(\n `benchmark:${this.dataset}:qrels`,\n 'json'\n ),\n this.kv.get<{ chunks: number; total: number }>(\n `${corpusKey}:meta`,\n 'json'\n ),\n ])\n\n // Reassemble chunked corpus if metadata exists\n let resolvedCorpus = corpus\n if (!resolvedCorpus && corpusMeta) {\n console.log(\n `[BenchmarkService] Loading chunked corpus: ${corpusMeta.chunks} chunks, ${corpusMeta.total} docs`\n )\n const chunkPromises: Promise[] = []\n for (let i = 0; i < corpusMeta.chunks; i++) {\n chunkPromises.push(\n this.kv.get(`${corpusKey}:${i}`, 'json')\n )\n }\n const chunks = await Promise.all(chunkPromises)\n resolvedCorpus = []\n for (const chunk of chunks) {\n if (!chunk) {\n throw new Error(\n `Missing corpus chunk for dataset \"${this.dataset}\". Re-upload with: npx tsx scripts/generate-benchmark-data.ts --dataset ${this.dataset}`\n )\n }\n resolvedCorpus.push(...chunk)\n }\n console.log(\n `[BenchmarkService] Reassembled ${resolvedCorpus.length} docs from ${corpusMeta.chunks} chunks`\n )\n }\n\n if (!resolvedCorpus || !queries || !qrels) {\n throw new Error(\n `Benchmark dataset \"${this.dataset}\" not found in KV. Run: npx tsx scripts/generate-benchmark-data.ts --dataset ${this.dataset}`\n )\n }\n\n this.data = { corpus: resolvedCorpus, queries, qrels }\n return this.data\n }\n\n /**\n * Get the subset of corpus documents: only those referenced in qrels + noise.\n * Deterministic selection (sorted by ID) so results are reproducible.\n */\n private async getSubsetCorpus(): Promise {\n const { corpus, qrels } = await this.loadData()\n const relevantDocIds = new Set(qrels.map((qr) => qr.doc_id))\n const relevantDocs = corpus.filter((doc) => relevantDocIds.has(doc._id))\n // Deterministic noise: sorted by ID, take first 200 non-relevant\n const noiseDocs = corpus\n .filter((doc) => !relevantDocIds.has(doc._id))\n .slice(0, 200)\n return [...relevantDocs, ...noiseDocs]\n }\n\n /**\n * Seed benchmark documents into the content table.\n * Uses a dedicated collection per dataset created on-the-fly.\n * Idempotent ā skips if data already exists.\n */\n async seed(\n authorId: string,\n useSubset: boolean = true,\n onProgress?: (progress: SeedProgress) => void\n ): Promise {\n // Check if already seeded\n const existing = await this.db\n .prepare(\n `SELECT COUNT(*) as count FROM content WHERE id LIKE '${this.idPrefix}%'`\n )\n .first<{ count: number }>()\n\n if (existing && existing.count > 0) {\n return { seeded: existing.count, skipped: true }\n }\n\n // Ensure a benchmark collection exists\n const collectionId = await this.ensureBenchmarkCollection()\n\n // Choose corpus based on subset flag\n const { corpus: fullCorpus } = await this.loadData()\n const corpus = useSubset ? await this.getSubsetCorpus() : fullCorpus\n\n const now = Date.now()\n const batchSize = 50\n let inserted = 0\n\n for (let i = 0; i < corpus.length; i += batchSize) {\n const batch = corpus.slice(i, i + batchSize)\n\n const batchOps = batch.map((doc) => {\n const id = `${this.idPrefix}${doc._id}`\n const slug = `${this.idPrefix}${doc._id}`\n // Wrap in tags for richtext editor compatibility, escape HTML entities\n const safeText = doc.text\n .replace(/&/g, '&')\n .replace(//g, '>')\n const data = JSON.stringify({\n content: `
${safeText}
`,\n excerpt: doc.text.substring(0, 200),\n tags: [`beir-${this.dataset}`, 'benchmark'],\n })\n\n return this.db\n .prepare(\n `INSERT OR IGNORE INTO content\n (id, collection_id, slug, title, data, status, author_id, created_at, updated_at)\n VALUES (?, ?, ?, ?, ?, 'published', ?, ?, ?)`\n )\n .bind(id, collectionId, slug, doc.title, data, authorId, now, now)\n })\n\n await this.db.batch(batchOps)\n inserted += batch.length\n\n if (onProgress) {\n onProgress({\n phase: 'inserting',\n inserted,\n total: corpus.length,\n })\n }\n }\n\n if (onProgress) {\n onProgress({\n phase: 'complete',\n inserted: corpus.length,\n total: corpus.length,\n })\n }\n\n return { seeded: corpus.length, skipped: false }\n }\n\n /**\n * Remove all benchmark documents and related index entries for this dataset.\n */\n async purge(): Promise {\n // Delete from content (also removes from FTS5 via sync tracking)\n const result = await this.db\n .prepare(\n `DELETE FROM content WHERE id LIKE '${this.idPrefix}%'`\n )\n .run()\n\n // Clean up FTS5 index entries\n try {\n await this.db.batch([\n this.db.prepare(\n `DELETE FROM content_fts WHERE content_id LIKE '${this.idPrefix}%'`\n ),\n this.db.prepare(\n `DELETE FROM content_fts_sync WHERE content_id LIKE '${this.idPrefix}%'`\n ),\n ])\n } catch (error) {\n // FTS5 tables might not exist yet\n console.warn('[BenchmarkService] FTS5 cleanup skipped:', error)\n }\n\n // Remove the benchmark collection itself\n try {\n await this.db\n .prepare('DELETE FROM collections WHERE id = ?')\n .bind(this.collectionId)\n .run()\n } catch (error) {\n console.warn('[BenchmarkService] Collection cleanup skipped:', error)\n }\n\n // Remove index meta\n try {\n await this.db\n .prepare(\n 'DELETE FROM ai_search_index_meta WHERE collection_id = ?'\n )\n .bind(this.collectionId)\n .run()\n } catch (error) {\n // Table might not exist\n }\n\n // Clean up Vectorize vectors for benchmark data\n if (this.vectorize) {\n try {\n const { corpus } = await this.loadData()\n const vectorIds: string[] = []\n for (const doc of corpus) {\n // Chunk IDs are {idPrefix}{docId}-chunk-{0..N}\n for (let i = 0; i < 5; i++) {\n vectorIds.push(`${this.idPrefix}${doc._id}-chunk-${i}`)\n }\n }\n\n // Vectorize deleteByIds accepts up to 1000 IDs per call\n const batchSize = 1000\n for (let i = 0; i < vectorIds.length; i += batchSize) {\n const batch = vectorIds.slice(i, i + batchSize)\n await this.vectorize.deleteByIds(batch)\n }\n console.log(\n `[BenchmarkService] Deleted up to ${vectorIds.length} vectors from Vectorize`\n )\n } catch (error) {\n console.warn(\n '[BenchmarkService] Vectorize cleanup error (non-fatal):',\n error\n )\n }\n }\n\n return result.meta?.changes || 0\n }\n\n /**\n * Run benchmark queries against a search function and compute IR metrics.\n */\n async evaluate(\n searchFn: (\n query: string,\n mode: string,\n limit: number\n ) => Promise<{ results: Array<{ id: string }> }>,\n mode: string = 'fts5',\n limit: number = 10,\n maxQueries: number = 0\n ): Promise {\n const { corpus, queries, qrels } = await this.loadData()\n const startTime = Date.now()\n const perQuery: PerQueryResult[] = []\n\n // Build qrels lookup: query_id -> Map\n const qrelsMap = new Map>()\n for (const qrel of qrels) {\n if (!qrelsMap.has(qrel.query_id))\n qrelsMap.set(qrel.query_id, new Map())\n qrelsMap.get(qrel.query_id)!.set(qrel.doc_id, qrel.score)\n }\n\n // Only evaluate queries that have relevance judgments\n const queriesWithJudgments = queries.filter(\n (q) => qrelsMap.has(q._id) && qrelsMap.get(q._id)!.size > 0\n )\n\n const queriesToRun =\n maxQueries > 0\n ? queriesWithJudgments.slice(0, maxQueries)\n : queriesWithJudgments\n\n let totalNDCG = 0\n let totalPrecision = 0\n let totalRecall = 0\n let totalMRR = 0\n\n for (const query of queriesToRun) {\n const relevantDocs = qrelsMap.get(query._id)!\n\n const queryStart = Date.now()\n let response: { results: Array<{ id: string }> }\n\n try {\n response = await searchFn(query.text, mode, limit)\n } catch (error) {\n console.error(\n `[BenchmarkService] Search error for query ${query._id}:`,\n error\n )\n perQuery.push({\n query_id: query._id,\n query_text: query.text,\n ndcg: 0,\n precision: 0,\n recall: 0,\n mrr: 0,\n hits: 0,\n expected: relevantDocs.size,\n returned: 0,\n query_time_ms: Date.now() - queryStart,\n })\n continue\n }\n\n const queryTime = Date.now() - queryStart\n\n // Extract BEIR doc IDs from content IDs (strip dataset prefix)\n const rankedDocIds = response.results.map((r) =>\n r.id.startsWith(this.idPrefix)\n ? r.id.slice(this.idPrefix.length)\n : r.id\n )\n\n const ndcg = computeNDCG(rankedDocIds, relevantDocs, limit)\n const precision = computePrecision(rankedDocIds, relevantDocs, limit)\n const recall = computeRecall(rankedDocIds, relevantDocs)\n const mrr = computeMRR(rankedDocIds, relevantDocs)\n\n totalNDCG += ndcg\n totalPrecision += precision\n totalRecall += recall\n totalMRR += mrr\n\n perQuery.push({\n query_id: query._id,\n query_text: query.text,\n ndcg,\n precision,\n recall,\n mrr,\n hits: rankedDocIds.filter((id) => relevantDocs.has(id)).length,\n expected: relevantDocs.size,\n returned: rankedDocIds.length,\n query_time_ms: queryTime,\n })\n }\n\n const totalTime = Date.now() - startTime\n const evaluated = queriesToRun.length\n\n return {\n mode,\n limit,\n corpus_size: corpus.length,\n queries_evaluated: evaluated,\n total_time_ms: totalTime,\n avg_query_time_ms:\n evaluated > 0 ? Math.round(totalTime / evaluated) : 0,\n metrics: {\n ndcg_at_k: evaluated > 0 ? totalNDCG / evaluated : 0,\n precision_at_k: evaluated > 0 ? totalPrecision / evaluated : 0,\n recall_at_k: evaluated > 0 ? totalRecall / evaluated : 0,\n mrr: evaluated > 0 ? totalMRR / evaluated : 0,\n },\n per_query: perQuery,\n }\n }\n\n /**\n * Get the list of query IDs that have relevance judgments, optionally limited.\n */\n async getEvaluableQueryIds(maxQueries: number = 0): Promise {\n const { queries, qrels } = await this.loadData()\n\n const qrelsMap = new Map>()\n for (const qrel of qrels) {\n if (!qrelsMap.has(qrel.query_id))\n qrelsMap.set(qrel.query_id, new Map())\n qrelsMap.get(qrel.query_id)!.set(qrel.doc_id, qrel.score)\n }\n\n const ids = queries\n .filter((q) => qrelsMap.has(q._id) && qrelsMap.get(q._id)!.size > 0)\n .map((q) => q._id)\n\n return maxQueries > 0 ? ids.slice(0, maxQueries) : ids\n }\n\n /**\n * Evaluate a batch of queries by their IDs.\n * Returns per-query results for the batch so the client can accumulate and compute aggregates.\n */\n async evaluateBatch(\n searchFn: (\n query: string,\n mode: string,\n limit: number\n ) => Promise<{ results: Array<{ id: string }> }>,\n mode: string,\n limit: number,\n queryIds: string[]\n ): Promise {\n const { queries, qrels } = await this.loadData()\n\n // Build qrels lookup\n const qrelsMap = new Map>()\n for (const qrel of qrels) {\n if (!qrelsMap.has(qrel.query_id))\n qrelsMap.set(qrel.query_id, new Map())\n qrelsMap.get(qrel.query_id)!.set(qrel.doc_id, qrel.score)\n }\n\n // Build query lookup\n const queryMap = new Map(queries.map((q) => [q._id, q]))\n\n const results: PerQueryResult[] = []\n\n for (const qid of queryIds) {\n const query = queryMap.get(qid)\n const relevantDocs = qrelsMap.get(qid)\n if (!query || !relevantDocs) continue\n\n const queryStart = Date.now()\n let response: { results: Array<{ id: string }> }\n\n try {\n response = await searchFn(query.text, mode, limit)\n } catch (error) {\n console.error(\n `[BenchmarkService] Search error for query ${qid}:`,\n error\n )\n results.push({\n query_id: qid,\n query_text: query.text,\n ndcg: 0,\n precision: 0,\n recall: 0,\n mrr: 0,\n hits: 0,\n expected: relevantDocs.size,\n returned: 0,\n query_time_ms: Date.now() - queryStart,\n })\n continue\n }\n\n const queryTime = Date.now() - queryStart\n const rankedDocIds = response.results.map((r) =>\n r.id.startsWith(this.idPrefix)\n ? r.id.slice(this.idPrefix.length)\n : r.id\n )\n\n const ndcg = computeNDCG(rankedDocIds, relevantDocs, limit)\n const precision = computePrecision(rankedDocIds, relevantDocs, limit)\n const recall = computeRecall(rankedDocIds, relevantDocs)\n const mrr = computeMRR(rankedDocIds, relevantDocs)\n\n results.push({\n query_id: qid,\n query_text: query.text,\n ndcg,\n precision,\n recall,\n mrr,\n hits: rankedDocIds.filter((id) => relevantDocs.has(id)).length,\n expected: relevantDocs.size,\n returned: rankedDocIds.length,\n query_time_ms: queryTime,\n })\n }\n\n return results\n }\n\n /**\n * Get dataset metadata from the compiled-in registry (no KV needed).\n */\n getMeta(): DatasetInfo {\n return BENCHMARK_DATASETS.find((d) => d.id === this.dataset)!\n }\n\n getCorpusSize(): number {\n return this.getMeta().corpus_size\n }\n\n getQueryCount(): number {\n return this.getMeta().query_count\n }\n\n getDatasetId(): string {\n return this.dataset\n }\n\n getIdPrefix(): string {\n return this.idPrefix\n }\n\n getCollectionId(): string {\n return this.collectionId\n }\n\n async getSubsetSize(): Promise {\n const subset = await this.getSubsetCorpus()\n return subset.length\n }\n\n /**\n * Check if benchmark data is currently seeded for this dataset.\n */\n async isSeeded(): Promise<{ seeded: boolean; count: number }> {\n const result = await this.db\n .prepare(\n `SELECT COUNT(*) as count FROM content WHERE id LIKE '${this.idPrefix}%'`\n )\n .first<{ count: number }>()\n const count = result?.count || 0\n return { seeded: count > 0, count }\n }\n\n /**\n * Check if dataset data exists in KV.\n */\n async isDataAvailable(): Promise {\n // Just check if the queries key exists (smallest key)\n const queries = await this.kv.get(\n `benchmark:${this.dataset}:queries`\n )\n return queries !== null\n }\n\n /**\n * Ensure a benchmark collection exists in the collections table.\n * Returns the collection ID.\n */\n private async ensureBenchmarkCollection(): Promise {\n const existing = await this.db\n .prepare('SELECT id FROM collections WHERE id = ?')\n .bind(this.collectionId)\n .first<{ id: string }>()\n\n if (existing) {\n return this.collectionId\n }\n\n const meta = this.getMeta()\n const schema = JSON.stringify({\n type: 'object',\n properties: {\n title: { type: 'string', title: 'Title', required: true },\n content: { type: 'string', title: 'Content', format: 'richtext' },\n excerpt: { type: 'string', title: 'Excerpt' },\n tags: { type: 'array', title: 'Tags', items: { type: 'string' } },\n },\n required: ['title'],\n })\n\n await this.db\n .prepare(\n `INSERT OR IGNORE INTO collections (id, name, display_name, description, schema, is_active, created_at, updated_at)\n VALUES (?, ?, ?, ?, ?, 1, unixepoch(), unixepoch())`\n )\n .bind(\n this.collectionId,\n `benchmark_${this.dataset}`,\n `${meta.name} Benchmark`,\n meta.description,\n schema\n )\n .run()\n\n return this.collectionId\n }\n}\n\n// --- IR Metric Functions ---\n\n/**\n * Normalized Discounted Cumulative Gain at k\n * Measures ranking quality ā are relevant docs ranked higher?\n */\nfunction computeNDCG(\n ranked: string[],\n qrels: Map,\n k: number\n): number {\n let dcg = 0\n for (let i = 0; i < Math.min(ranked.length, k); i++) {\n const rel = qrels.get(ranked[i]!) || 0\n dcg += rel / Math.log2(i + 2) // log2(rank + 1), rank is 1-indexed\n }\n\n // Ideal DCG: sort relevance scores descending\n const ideal = Array.from(qrels.values())\n .sort((a, b) => b - a)\n .slice(0, k)\n let idcg = 0\n for (let i = 0; i < ideal.length; i++) {\n idcg += ideal[i]! / Math.log2(i + 2)\n }\n\n return idcg === 0 ? 0 : dcg / idcg\n}\n\n/**\n * Precision at k\n * What fraction of top-k results are relevant?\n */\nfunction computePrecision(\n ranked: string[],\n qrels: Map,\n k: number\n): number {\n const topK = ranked.slice(0, k)\n const hits = topK.filter((id) => (qrels.get(id) || 0) > 0).length\n return hits / k\n}\n\n/**\n * Recall at k\n * What fraction of all relevant docs appear in the results?\n */\nfunction computeRecall(\n ranked: string[],\n qrels: Map\n): number {\n const totalRelevant = Array.from(qrels.values()).filter(\n (v) => v > 0\n ).length\n if (totalRelevant === 0) return 0\n const hits = ranked.filter((id) => (qrels.get(id) || 0) > 0).length\n return hits / totalRelevant\n}\n\n/**\n * Mean Reciprocal Rank\n * How early does the first relevant result appear?\n */\nfunction computeMRR(\n ranked: string[],\n qrels: Map\n): number {\n for (let i = 0; i < ranked.length; i++) {\n if ((qrels.get(ranked[i]!) || 0) > 0) return 1 / (i + 1)\n }\n return 0\n}\n","/**\n * Admin Search Dashboard Template\n *\n * Thin orchestrator that imports per-tab modules, computes shared\n * data props, assembles tab navigation + header + tab HTML, wraps\n * all tab scripts in one \n `\n\n const layoutData: AdminLayoutCatalystData = {\n title: 'Search',\n pageTitle: 'Search',\n currentPath: '/admin/search',\n user: data.user,\n version: data.version,\n content: pageContent\n }\n\n return renderAdminLayoutCatalyst(layoutData)\n}\n\n// ----- Exported helpers (used by tab modules) -----\n\nexport function renderStatCard(label: string, value: string, color: string, icon: string, colorOverride?: string): string {\n const finalColor = colorOverride || color\n const colorClasses: Record = {\n lime: 'bg-lime-50 dark:bg-lime-500/10 text-lime-600 dark:text-lime-400 ring-lime-600/20 dark:ring-lime-500/20',\n blue: 'bg-blue-50 dark:bg-blue-500/10 text-blue-600 dark:text-blue-400 ring-blue-600/20 dark:ring-blue-500/20',\n purple: 'bg-purple-50 dark:bg-purple-500/10 text-purple-600 dark:text-purple-400 ring-purple-600/20 dark:ring-purple-500/20',\n sky: 'bg-sky-50 dark:bg-sky-500/10 text-sky-600 dark:text-sky-400 ring-sky-600/20 dark:ring-sky-500/20',\n amber: 'bg-amber-50 dark:bg-amber-500/10 text-amber-600 dark:text-amber-400 ring-amber-600/20 dark:ring-amber-500/20',\n red: 'bg-red-50 dark:bg-red-500/10 text-red-600 dark:text-red-400 ring-red-600/20 dark:ring-red-500/20'\n }\n\n return `\n \n `\n}\n\nexport function renderFeatureToggle(name: string, isOn: boolean): string {\n const dotClass = isOn\n ? 'bg-lime-500'\n : 'bg-zinc-300 dark:bg-zinc-600'\n const labelClass = isOn\n ? 'text-lime-700 dark:text-lime-400'\n : 'text-zinc-500 dark:text-zinc-400'\n return `\n \n ${name} \n \n \n ${isOn ? 'On' : 'Off'}\n \n
\n `\n}\n\nexport function escapeHtml(str: string): string {\n return str.replace(/&/g, '&').replace(//g, '>').replace(/\"/g, '"')\n}\n","/**\n * Admin Search Dashboard ā Overview Tab\n *\n * Stat cards, Feature Status, Search Activity, and Index Health.\n * Pure HTML, no client-side JavaScript.\n */\n\nimport { renderStatCard, renderFeatureToggle, escapeHtml } from './admin-search.template'\nimport type { TabProps } from './admin-search.template'\n\nexport function renderOverviewTab(props: TabProps): string {\n const {\n fts5TotalIndexed, queriesToday, avgQueryTime, ctr,\n enabled, aiModeEnabled, facetsEnabled, settings,\n totalQueries, totalClicks30d, zeroResults30d,\n popularQueries,\n fts5Available, vectorizeIndexedItems,\n selectedCollections, collections\n } = props\n\n return `\n \n \n
\n ${renderStatCard('Indexed Documents', String(fts5TotalIndexed), 'lime', `\n
\n \n \n `)}\n\n ${renderStatCard('Queries Today', String(queriesToday), 'sky', `\n
\n \n \n `)}\n\n ${renderStatCard('Avg Response Time', avgQueryTime > 0 ? avgQueryTime + 'ms' : 'N/A', 'purple', `\n
\n \n \n `)}\n\n ${renderStatCard('Click-Through Rate', ctr !== null ? ctr + '%' : 'N/A', 'amber', `\n
\n \n \n `)}\n
\n\n \n
\n \n
\n
\n
Feature Status \n \n
\n
\n ${renderFeatureToggle('Search', enabled)}\n ${renderFeatureToggle('AI Mode', aiModeEnabled)}\n ${renderFeatureToggle('Faceted Search', facetsEnabled)}\n ${renderFeatureToggle('Query Rewriting', settings.query_rewriting_enabled === true)}\n ${renderFeatureToggle('Reranking', settings.reranking_enabled === true)}\n ${renderFeatureToggle('Synonyms', settings.query_synonyms_enabled !== false)}\n
\n
\n
\n\n \n
\n
\n
Search Activity \n \n
\n
\n \n
\n
Quick Stats \n