···
9
9
title?: string;
10
10
}>();
11
11
12
12
-
const title = $derived(props.title ?? 'Debug Information');
12
12
+
const title = $derived(props.title ?? 'Raw Headers');
13
13
const data = $derived(props.data ?? {});
14
14
15
15
-
// Log received data on mount
15
15
+
// Enable this for additional debugging
16
16
onMount(() => {
17
17
-
console.log('[DEBUG BUTTON] Received data keys:', Object.keys(data));
18
18
-
if (data.headers) {
19
19
-
console.log('[DEBUG BUTTON] Headers available:', Object.keys(data.headers).length);
20
20
-
} else {
21
21
-
console.log('[DEBUG BUTTON] No headers object found in data');
22
22
-
}
23
23
-
});
24
24
-
25
25
-
// Determine which headers object to use (supporting both data.headers and data.allHeaders)
26
26
-
const headers = $derived(() => {
27
27
-
if (data.headers) return data.headers;
28
28
-
if (data.allHeaders) return data.allHeaders;
29
29
-
return null;
17
17
+
console.log('[DEBUG BUTTON] Received data:', data);
18
18
+
console.log('[DEBUG BUTTON] Data keys:', Object.keys(data));
19
19
+
console.log('[DEBUG BUTTON] Has allHeaders?', !!data.allHeaders);
30
20
});
31
21
32
32
-
// Add fallback debugging info if headers are missing
33
33
-
const debugInfo = $derived(() => {
34
34
-
return {
35
35
-
dataAvailable: Object.keys(data).length > 0,
36
36
-
headersAvailable: headers ? Object.keys(headers).length : 0,
37
37
-
timestamp: new Date().toISOString()
38
38
-
};
39
39
-
});
22
22
+
// Get headers from top-level allHeaders property
23
23
+
const allHeaders = $derived(data.allHeaders || {});
40
24
41
41
-
// Check if we have Cloudflare-specific headers
42
42
-
const hasCfHeaders = $derived(() => {
43
43
-
if (!headers) return false;
44
44
-
return Object.keys(headers).some(key => key.startsWith('cf-'));
45
45
-
});
25
25
+
// Count headers for display
26
26
+
const headerCount = $derived(Object.keys(allHeaders).length);
46
27
47
47
-
function formatValue(value) {
48
48
-
if (value === null) return 'null';
49
49
-
if (value === undefined) return 'undefined';
50
50
-
if (typeof value === 'object') {
51
51
-
return JSON.stringify(value, null, 2);
52
52
-
}
53
53
-
return String(value);
54
54
-
}
28
28
+
// Check for Cloudflare headers
29
29
+
const hasCfHeaders = $derived(Object.keys(allHeaders).some(key => key.startsWith('cf-')));
55
30
</script>
56
31
57
32
<DropdownMenu.Root>
···
59
34
<Button
60
35
variant="outline"
61
36
size="icon"
62
62
-
class="rounded-full shadow-lg hover:shadow-xl transition-all duration-200 bg-blue-100 hover:bg-blue-200 dark:bg-blue-900 dark:hover:bg-blue-800"
37
37
+
class="rounded-full bg-blue-100 hover:bg-blue-200"
63
38
builders={[builder]}
64
39
>
65
40
<Bug class="h-5 w-5" />
66
41
</Button>
67
42
</DropdownMenu.Trigger>
68
68
-
<DropdownMenu.Content class="w-80 max-h-[80vh] overflow-y-auto">
43
43
+
<DropdownMenu.Content class="w-[90vw] max-w-[800px] max-h-[80vh] overflow-y-auto">
69
44
<DropdownMenu.Label>{title}</DropdownMenu.Label>
70
45
71
46
<div class="p-2 font-mono text-xs">
72
72
-
<!-- Diagnostic Information -->
73
73
-
<div class="mb-3 bg-yellow-50 p-2 rounded border">
74
74
-
<div class="font-semibold text-sm text-yellow-700">Diagnostic Info</div>
75
75
-
<div class="mt-1">
76
76
-
<div>Data keys: {Object.keys(data).join(', ') || 'none'}</div>
77
77
-
<div>Headers: {headers ? Object.keys(headers).length : 'Not available'}</div>
78
78
-
<div>CF detected: {hasCfHeaders ? 'Yes' : 'No'}</div>
79
79
-
<div>Timestamp: {debugInfo.timestamp}</div>
80
80
-
</div>
47
47
+
<!-- Show debugging info -->
48
48
+
<div class="bg-yellow-50 p-2 rounded border mb-2">
49
49
+
<div>Data keys received: {Object.keys(data).join(', ')}</div>
50
50
+
<div>allHeaders present: {data.allHeaders ? 'Yes' : 'No'}</div>
81
51
</div>
82
82
-
83
83
-
{#if data && Object.keys(data).length > 0}
84
84
-
{#if data.ip_country}
85
85
-
<div class="mb-3 bg-blue-50 p-2 rounded border">
86
86
-
<div class="font-semibold text-sm text-blue-700">Cloudflare Country</div>
87
87
-
<div class="mt-1">
88
88
-
<div class="text-lg font-bold">{data.ip_country || 'Not available'}</div>
89
89
-
{#if data.country_phone}
90
90
-
<div class="text-sm">Phone Code: {data.country_phone}</div>
91
91
-
{/if}
92
92
-
</div>
93
93
-
</div>
94
94
-
{/if}
95
95
-
96
96
-
{#if headers}
97
97
-
<div class="mb-3">
98
98
-
<div class="font-semibold text-sm text-green-700">HTTP Headers {hasCfHeaders ? '✓ Cloudflare Detected' : ''}</div>
99
99
-
<div class="bg-gray-50 p-2 rounded border mt-1 max-h-80 overflow-y-auto">
100
100
-
<input
101
101
-
type="text"
102
102
-
placeholder="Filter headers..."
103
103
-
class="w-full p-1 mb-2 border rounded text-xs"
104
104
-
on:input={(e) => {
105
105
-
const value = e.target.value.toLowerCase();
106
106
-
const rows = document.querySelectorAll('tr.header-row');
107
107
-
rows.forEach(row => {
108
108
-
const text = row.textContent.toLowerCase();
109
109
-
row.style.display = text.includes(value) ? '' : 'none';
110
110
-
});
111
111
-
}}
112
112
-
/>
113
113
-
<table class="w-full text-left">
114
114
-
<thead>
115
115
-
<tr>
116
116
-
<th class="pb-1 border-b">Header</th>
117
117
-
<th class="pb-1 border-b">Value</th>
118
118
-
</tr>
119
119
-
</thead>
120
120
-
<tbody>
121
121
-
{#each Object.entries(headers) as [key, value]}
122
122
-
<tr class="border-b border-gray-100 header-row {key.startsWith('cf-') ? 'bg-blue-50' : ''}">
123
123
-
<td class="pr-2 py-1 font-medium">{key}</td>
124
124
-
<td class="py-1 break-all">{value}</td>
125
125
-
</tr>
126
126
-
{/each}
127
127
-
</tbody>
128
128
-
</table>
129
129
-
</div>
130
130
-
</div>
52
52
+
53
53
+
<!-- Show raw headers data -->
54
54
+
<div class="bg-gray-50 p-2 rounded border mt-1 overflow-auto">
55
55
+
<pre class="whitespace-pre-wrap break-all">{JSON.stringify(allHeaders, null, 2)}</pre>
56
56
+
</div>
57
57
+
58
58
+
<!-- Basic stats about the data -->
59
59
+
<div class="mt-2 text-xs text-gray-500">
60
60
+
Headers count: {headerCount}
61
61
+
{#if hasCfHeaders}
62
62
+
<span class="ml-2 text-green-600 font-bold">✓ Cloudflare headers present</span>
131
63
{/if}
132
132
-
133
133
-
{#each Object.entries(data) as [key, value]}
134
134
-
{#if key !== 'headers' && key !== 'allHeaders' && key !== 'ip_country' && key !== 'country_phone'}
135
135
-
<div class="mb-3">
136
136
-
<div class="font-semibold text-sm">{key}</div>
137
137
-
<div class="bg-gray-50 p-2 rounded border mt-1">
138
138
-
{#if typeof value === 'object' && value !== null}
139
139
-
{#each Object.entries(value) as [subKey, subValue]}
140
140
-
<div class="mb-1">
141
141
-
<span class="font-medium">{subKey}:</span>
142
142
-
{#if typeof subValue === 'object' && subValue !== null && Array.isArray(subValue)}
143
143
-
<div class="ml-2">
144
144
-
{#if subValue.length > 0}
145
145
-
<ul class="list-disc ml-4 mt-1">
146
146
-
{#each subValue as item}
147
147
-
<li class="mb-1">
148
148
-
{#if typeof item === 'object' && item !== null}
149
149
-
<pre class="whitespace-pre-wrap break-all text-xs">{formatValue(item)}</pre>
150
150
-
{:else}
151
151
-
{item}
152
152
-
{/if}
153
153
-
</li>
154
154
-
{/each}
155
155
-
</ul>
156
156
-
{:else}
157
157
-
<span class="text-gray-500">Empty array</span>
158
158
-
{/if}
159
159
-
</div>
160
160
-
{:else if typeof subValue === 'object' && subValue !== null}
161
161
-
<pre class="ml-2 whitespace-pre-wrap break-all text-xs">{formatValue(subValue)}</pre>
162
162
-
{:else}
163
163
-
<span class="ml-2">{formatValue(subValue)}</span>
164
164
-
{/if}
165
165
-
</div>
166
166
-
{/each}
167
167
-
{:else}
168
168
-
{formatValue(value)}
169
169
-
{/if}
170
170
-
</div>
171
171
-
</div>
172
172
-
{/if}
173
173
-
{/each}
174
174
-
{:else}
175
175
-
<div class="text-gray-400">No debug data available</div>
176
176
-
{/if}
64
64
+
</div>
177
65
</div>
178
66
179
67
<DropdownMenu.Separator />
180
180
-
<DropdownMenu.Item on:click={() => console.log('Debug data:', data)}>
181
181
-
Log to Console
68
68
+
<DropdownMenu.Item on:click={() => console.log('Raw Headers:', allHeaders)}>
69
69
+
Log Headers to Console
182
70
</DropdownMenu.Item>
183
71
</DropdownMenu.Content>
184
72
</DropdownMenu.Root>
···
8
8
export function getCloudflareData(request) {
9
9
const { headers } = request;
10
10
11
11
-
// Capture all headers as an object for debugging
11
11
+
// Capture all headers as a plain object for debugging
12
12
+
// Using a plain object ensures it can be properly serialized
12
13
const allHeaders = {};
13
14
headers.forEach((value, key) => {
14
15
allHeaders[key] = value;
···
24
25
const countryInfo = getCountryInfo(ip_country);
25
26
const country_phone = countryInfo ? countryInfo.phone : null;
26
27
28
28
+
// Make sure we return a serializable plain object with all data
27
29
return {
28
30
ip_country,
29
31
country_phone,
30
32
accept_language,
31
33
countryInfo,
32
32
-
// Include all headers for client-side debugging
33
33
-
headers: allHeaders
34
34
+
allHeaders // Renamed from headers to allHeaders for clarity
34
35
};
35
36
}
···
1
1
import { getCloudflareData } from '$lib/utils/cloudflare.js';
2
2
-
import { Database } from 'bun:sqlite';
3
2
import type { LayoutServerLoad } from './$types';
4
3
5
4
export const load: LayoutServerLoad = async ({ request, params = {} }) => {
6
5
// Get Cloudflare data
7
6
const cloudflareData = getCloudflareData(request);
8
7
9
9
-
console.log('[LAYOUT SERVER] Headers received:', cloudflareData.headers);
10
10
-
console.log('[LAYOUT SERVER] Cloudflare country:', cloudflareData.ip_country);
11
11
-
12
12
-
// Test the database connection and log the result
13
13
-
const db = new Database(process.env.DATABASE_URL || ':memory:');
14
14
-
const testQuery = db.query("SELECT 'banana' AS fruit");
15
15
-
const result = testQuery.get();
8
8
+
// Log what we're passing to the client
9
9
+
console.log('[LAYOUT SERVER] Headers being passed to client:',
10
10
+
Object.keys(cloudflareData.allHeaders).length, 'headers');
16
11
12
12
+
// Simple test data instead of SQLite database
13
13
+
const testQueryResult = { fruit: 'banana' };
14
14
+
15
15
+
// In SvelteKit, returned objects are serialized with devalue
16
16
+
// Make sure we return allHeaders directly at the top level for accessibility
17
17
return {
18
18
-
...cloudflareData,
19
19
-
testQueryResult: result,
20
20
-
// Include the slug like textme does (if available)
21
21
-
slug: params.slug,
22
22
-
// Keep the headers for debugging
23
23
-
headers: cloudflareData.headers
18
18
+
ip_country: cloudflareData.ip_country,
19
19
+
country_phone: cloudflareData.country_phone,
20
20
+
accept_language: cloudflareData.accept_language,
21
21
+
countryInfo: cloudflareData.countryInfo,
22
22
+
allHeaders: cloudflareData.allHeaders,
23
23
+
testQueryResult,
24
24
+
// Don't nest under cloudflareData as it makes access more complex
25
25
+
slug: params.slug
26
26
+
24
27
};
25
28
};
···
10
10
/** @type {{children?: import('svelte').Snippet}} */
11
11
let { children } = $props();
12
12
13
13
-
// Add derived data for debugging using Svelte 5 runes
14
14
-
const pageData = $derived(page.data || {});
13
13
+
// Create debug data object with direct access to the headers
15
14
const debugData = $derived({
16
16
-
...page.data,
17
17
-
// Fallback structure if headers are missing
15
15
+
// Direct access to headers from the data object
16
16
+
allHeaders: $page.data.allHeaders,
17
17
+
// Include other data for reference
18
18
+
ip_country: $page.data.ip_country,
18
19
clientInfo: {
19
20
browser: browser ? 'True' : 'False',
20
21
timestamp: new Date().toISOString(),
···
22
23
}
23
24
});
24
25
25
25
-
// Log Cloudflare data to console on client
26
26
+
// Log Cloudflare data to console on client for debugging
26
27
onMount(() => {
27
27
-
if (browser && page && page.data) {
28
28
-
console.log('[CLIENT] Page data available:', Object.keys(page.data));
29
29
-
console.log('[CLIENT] Headers available:', page.data.headers ? 'Yes' : 'No');
28
28
+
if (browser) {
29
29
+
console.log('[CLIENT] Full page data structure:', $page.data);
30
30
31
31
-
// Log entire page data for debugging
32
32
-
console.log('[CLIENT] Full page data:', page.data);
31
31
+
// Specifically check for allHeaders
32
32
+
if ($page.data.allHeaders) {
33
33
+
console.log('[CLIENT] Headers found! Count:', Object.keys($page.data.allHeaders).length);
34
34
+
console.log('[CLIENT] Some headers:', Object.keys($page.data.allHeaders).slice(0, 3));
35
35
+
} else {
36
36
+
console.log('[CLIENT] No headers found in page data');
37
37
+
console.log('[CLIENT] Available keys:', Object.keys($page.data));
38
38
+
}
33
39
}
34
40
});
35
41
···
48
54
{#if browser}
49
55
<div class="fixed bottom-4 right-4 flex gap-2 z-50 bg-white/50 p-2 rounded-lg">
50
56
<DebugButton
51
51
-
title="Cloudflare Data"
57
57
+
title="Cloudflare Headers ({debugData.allHeaders ? Object.keys(debugData.allHeaders).length : 0})"
52
58
data={debugData}
53
59
/>
54
60
<SettingsButton />