Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,5 @@ APPWRITE_DB_INIT_ID=
APPWRITE_COL_INIT_ID=
APPWRITE_API_KEY_INIT=
SENTRY_AUTH_TOKEN=
PROFOUND_API_URL=
PROFOUND_API_KEY=
6 changes: 6 additions & 0 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ jobs:
APPWRITE_COL_INIT_ID: ${{ secrets.APPWRITE_COL_INIT_ID }}
APPWRITE_API_KEY_INIT: ${{ secrets.APPWRITE_API_KEY_INIT }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
PROFOUND_API_URL: ${{ secrets.PROFOUND_API_URL }}
PROFOUND_API_KEY: ${{ secrets.PROFOUND_API_KEY }}
run: bun run check
format:
runs-on: ubuntu-latest
Expand Down Expand Up @@ -77,6 +79,8 @@ jobs:
APPWRITE_COL_INIT_ID: ${{ secrets.APPWRITE_COL_INIT_ID }}
APPWRITE_API_KEY_INIT: ${{ secrets.APPWRITE_API_KEY_INIT }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
PROFOUND_API_URL: ${{ secrets.PROFOUND_API_URL }}
PROFOUND_API_KEY: ${{ secrets.PROFOUND_API_KEY }}
run: bun run test
build:
runs-on: ubuntu-latest
Expand Down Expand Up @@ -107,6 +111,8 @@ jobs:
APPWRITE_COL_INIT_ID: ${{ secrets.APPWRITE_COL_INIT_ID }}
APPWRITE_API_KEY_INIT: ${{ secrets.APPWRITE_API_KEY_INIT }}
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
PROFOUND_API_URL: ${{ secrets.PROFOUND_API_URL }}
PROFOUND_API_KEY: ${{ secrets.PROFOUND_API_KEY }}
run: bun run build
assets:
runs-on: ubuntu-latest
Expand Down
1 change: 1 addition & 0 deletions .prettierignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ node_modules
.env.*
!.env.example
deploy
src/lib/generated

# Ignore files for Bun
bun.lock
Expand Down
3 changes: 0 additions & 3 deletions log-collector/.gitignore

This file was deleted.

15 changes: 0 additions & 15 deletions log-collector/package.json

This file was deleted.

49 changes: 0 additions & 49 deletions log-collector/src/index.ts

This file was deleted.

14 changes: 0 additions & 14 deletions log-collector/tsconfig.json

This file was deleted.

16 changes: 0 additions & 16 deletions log-collector/wrangler.json

This file was deleted.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@
"type": "module",
"scripts": {
"build": "bun ./scripts/build.js",
"fetch:stars": "node scripts/fetch-github-stars.js",
"fetch:stars": "bun scripts/fetch-github-stars.js",
"prebuild": "bun run fetch:stars",
"check": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json",
"check:watch": "svelte-kit sync && svelte-check --tsconfig ./tsconfig.json --watch",
"clean": "rm -rf node_modules && rm -rf .svelte_kit && bun install",
"clean": "rm -rf node_modules && rm -rf .svelte_kit",
"dev": "vite dev",
"format": "prettier --write --cache .",
"format:check": "prettier --check .",
Expand Down
4 changes: 3 additions & 1 deletion src/hooks.server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { getMarkdownContent, processMarkdownWithPartials } from '$lib/server/mar
import { type GithubUser } from '$routes/(init)/init/(utils)/auth';
import { createInitSessionClient } from '$routes/(init)/init/(utils)/appwrite';
import type { AppwriteUser } from '$lib/utils/console';
import { profoundAnalytics } from '$lib/server/profound-analytics';

const redirectMap = new Map(redirects.map(({ link, redirect }) => [link, redirect]));

Expand Down Expand Up @@ -262,6 +263,7 @@ export const handle = sequence(
wwwRedirecter,
securityheaders,
initSession,
seoOptimization
seoOptimization,
profoundAnalytics
);
export const handleError = Sentry.handleErrorWithSentry();
6 changes: 3 additions & 3 deletions src/lib/generated/github-stars.json
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
{
"stars": 55124,
"fetchedAt": "2026-03-10T14:12:30.207Z"
}
"stars": 55136,
"fetchedAt": "2026-03-18T12:04:09.106Z"
}
128 changes: 128 additions & 0 deletions src/lib/server/profound-analytics.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
import type { Handle } from '@sveltejs/kit';
import { env } from '$env/dynamic/private';
import { building } from '$app/environment';

const { PROFOUND_API_URL, PROFOUND_API_KEY } = env;

interface LogEntry {
timestamp: number;
host: string;
method: string;
pathname: string;
query_params: Record<string, string>;
ip: string | null;
userAgent: string | null;
referer: string | null;
bytes: number;
status: number;
}

class LogBatcher {
private queue: LogEntry[] = [];
private readonly MAX_SIZE = 10000;
private readonly FLUSH_INTERVAL_MS = 10000;
private flushTimer: ReturnType<typeof setInterval> | null = null;
private isRunning = false;

constructor() {
this.start();
}

start(): void {
if (this.isRunning) return;

this.isRunning = true;
this.flushTimer = setInterval(() => {
void this.flush();
}, this.FLUSH_INTERVAL_MS);
}

stop(): void {
if (this.flushTimer) {
clearInterval(this.flushTimer);
this.flushTimer = null;
}
this.isRunning = false;
}

add(log: LogEntry): void {
// Evict oldest entries if at capacity (FIFO)
while (this.queue.length >= this.MAX_SIZE) {
this.queue.shift();
}
this.queue.push(log);
}

async flush(): Promise<void> {
if (this.queue.length === 0) return;
if (!PROFOUND_API_URL || !PROFOUND_API_KEY) return;

// Take all logs from queue
const batch = this.queue.splice(0);

try {
const response = await fetch(PROFOUND_API_URL, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-API-Key': PROFOUND_API_KEY
},
body: JSON.stringify(batch)
});

if (!response.ok) {
console.error(`Analytics flush failed: ${response.status} ${response.statusText}`);
}
} catch (error) {
console.error('Analytics flush failed:', error);
}
}
}

// Singleton instance
const logBatcher = new LogBatcher();

export const profoundAnalytics: Handle = async ({ event, resolve }) => {
// Short circuit if analytics is not configured or during pre-render
if (building || !PROFOUND_API_URL || !PROFOUND_API_KEY) {
return resolve(event);
}

const response = await resolve(event);

// Only track HTML pages, not API responses or static assets
const contentType = response.headers.get('content-type');
if (!contentType?.includes('text/html')) {
return response;
}

// Calculate header size
const headerSize = Array.from(response.headers.entries()).reduce(
(total, [key, value]) => total + key.length + value.length + 4,
0
);

// Get body size
const contentLength = response.headers.get('content-length');
const bodySize = contentLength ? Number.parseInt(contentLength, 10) || 0 : 0;
const totalBytesSent = headerSize + bodySize;

// Build log data
const logData: LogEntry = {
timestamp: Date.now(),
host: event.url.hostname,
method: event.request.method,
pathname: event.url.pathname,
query_params: Object.fromEntries(event.url.searchParams),
ip: event.getClientAddress(),
userAgent: event.request.headers.get('user-agent'),
referer: event.request.headers.get('referer'),
bytes: totalBytesSent,
status: response.status
};

// Non-blocking: add to queue and return immediately
logBatcher.add(logData);

return response;
};
2 changes: 0 additions & 2 deletions src/routes/(init)/init/+page.server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@ import { redirect, type Actions } from '@sveltejs/kit';
import { getTicketByUser } from './(utils)/tickets';
import { loginGithub } from './(utils)/auth';

export const prerender = false;

export const load = async ({ locals }) => {
const ticket = await getTicketByUser(locals.initUser);

Expand Down
1 change: 0 additions & 1 deletion src/routes/(marketing)/+page.ts

This file was deleted.

2 changes: 2 additions & 0 deletions src/routes/+layout.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
import { changelogCount } from './changelog/utils';

export const prerender = false;

export const trailingSlash = 'never';

export const load = () => ({
Expand Down
2 changes: 0 additions & 2 deletions src/routes/blog/[[page]]/+page.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,6 @@ import { getBlogEntries, normalizeCategory } from '../content';
import { BLOG_POSTS_PER_PAGE } from '$lib/constants';
import { error, redirect } from '@sveltejs/kit';

export const prerender = false;

export const entries = () => {
const { posts } = getBlogEntries();
const totalPages = Math.ceil(posts.length / BLOG_POSTS_PER_PAGE);
Expand Down
2 changes: 0 additions & 2 deletions src/routes/integrations/+page.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,5 +87,3 @@ export const load = () => {
featured: featuredIntegrationsWithCategoryHeadings
};
};

export const prerender = false;
2 changes: 1 addition & 1 deletion src/routes/llms-full.txt/+server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ function sectionWeight(href: string): number {
}
}

export const GET: RequestHandler = ({ request }) => {
export const GET: RequestHandler = () => {
try {
const base = 'https://appwrite.io';
type Item = { href: string; title: string; block: string };
Expand Down
2 changes: 0 additions & 2 deletions src/routes/partners/catalog/+page.ts
Original file line number Diff line number Diff line change
Expand Up @@ -92,5 +92,3 @@ export const load = () => {
featured: featuredIntegrationsWithCategoryHeadings
};
};

export const prerender = false;
1 change: 0 additions & 1 deletion src/routes/threads/+layout.ts

This file was deleted.

Loading