Skip to content

Commit 6058432

Browse files
authored
Weird and kinda borked initial commit
1 parent c72099e commit 6058432

22 files changed

+1674
-7122
lines changed

Backend/.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
node_modules
2+
.env
3+
.dev.vars

Backend/package.json

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
{
2+
"name": "htmltrack-worker",
3+
"version": "1.0.0",
4+
"description": "HTMLTrack Cloudflare Workers backend",
5+
"main": "dist/index.js",
6+
"scripts": {
7+
"build": "wrangler publish",
8+
"dev": "wrangler dev",
9+
"deploy": "wrangler publish"
10+
},
11+
"dependencies": {
12+
"itty-router": "^4.0.0"
13+
},
14+
"devDependencies": {
15+
"@cloudflare/workers-types": "^4.0.0",
16+
"@types/node": "^20.0.0",
17+
"typescript": "^5.0.0",
18+
"wrangler": "^3.0.0"
19+
}
20+
}

Backend/src/index.ts

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
import { Router } from 'itty-router';
2+
import { trackingService } from './services/tracking';
3+
import { errorHandler } from './middleware/errorHandler';
4+
5+
interface Env {
6+
TRACK_API_KEY: string;
7+
}
8+
9+
const router = Router();
10+
11+
router.post('/api/track', async (req: Request, env: Env) => {
12+
try {
13+
if (!env.TRACK_API_KEY) {
14+
return new Response(
15+
JSON.stringify({ error: 'API key not configured' }),
16+
{ status: 500, headers: { 'Content-Type': 'application/json' } }
17+
);
18+
}
19+
20+
const { trackingNumber, carrier } = await req.json();
21+
22+
if (!trackingNumber || !carrier) {
23+
return new Response(
24+
JSON.stringify({ error: 'Missing required fields: trackingNumber, carrier' }),
25+
{ status: 400, headers: { 'Content-Type': 'application/json' } }
26+
);
27+
}
28+
29+
const result = await trackingService.trackPackage(
30+
trackingNumber,
31+
carrier,
32+
env.TRACK_API_KEY
33+
);
34+
35+
return new Response(JSON.stringify(result), {
36+
status: 200,
37+
headers: {
38+
'Content-Type': 'application/json',
39+
'Access-Control-Allow-Origin': '*'
40+
}
41+
});
42+
} catch (error) {
43+
return errorHandler(error);
44+
}
45+
});
46+
47+
router.options('*', () => new Response(null, {
48+
status: 200,
49+
headers: {
50+
'Access-Control-Allow-Origin': '*',
51+
'Access-Control-Allow-Methods': 'GET, POST, OPTIONS',
52+
'Access-Control-Allow-Headers': 'Content-Type'
53+
}
54+
}));
55+
56+
export default {
57+
fetch: (req: Request, env: Env) => router.handle(req, env)
58+
};
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
export function errorHandler(error: unknown): Response {
2+
console.error('[Error]', error);
3+
4+
const message = error instanceof Error ? error.message : 'An unexpected error occurred';
5+
const status = error instanceof Error && 'status' in error ? (error.status as number) : 500;
6+
7+
return new Response(
8+
JSON.stringify({
9+
error: message,
10+
status
11+
}),
12+
{
13+
status,
14+
headers: { 'Content-Type': 'application/json' }
15+
}
16+
);
17+
}

Backend/src/services/tracking.ts

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
interface TrackingResult {
2+
trackingNumber: string;
3+
carrier: string;
4+
status: 'pending' | 'in_transit' | 'delivered' | 'failed';
5+
lastUpdate: string;
6+
destination?: string;
7+
estimatedDelivery?: string;
8+
events?: Array<{
9+
timestamp: string;
10+
location: string;
11+
status: string;
12+
}>;
13+
}
14+
15+
interface TrackingService {
16+
trackPackage(trackingNumber: string, carrier: string, apiKey: string): Promise<TrackingResult>;
17+
}
18+
19+
export const trackingService: TrackingService = {
20+
async trackPackage(trackingNumber: string, carrier: string, apiKey: string): Promise<TrackingResult> {
21+
const normalized = trackingNumber.toUpperCase().trim();
22+
23+
try {
24+
const response = await fetch('https://api.17track.net/track/v2/trackinfo', {
25+
method: 'POST',
26+
headers: {
27+
'Content-Type': 'application/json',
28+
'Authorization': `Bearer ${apiKey}`
29+
},
30+
body: JSON.stringify({
31+
tracking_number: normalized,
32+
carrier_code: this.normalizeCarrier(carrier)
33+
})
34+
});
35+
36+
if (!response.ok) {
37+
throw new Error(`17Track API error: ${response.status}`);
38+
}
39+
40+
const data = await response.json();
41+
42+
return this.formatTrackingResult(data, normalized, carrier);
43+
} catch (error) {
44+
console.error('[17Track API Error]', error);
45+
throw new Error('Failed to fetch tracking information from 17Track');
46+
}
47+
},
48+
49+
normalizeCarrier(carrier: string): string {
50+
const carrierMap: Record<string, string> = {
51+
'UPS': 'ups',
52+
'FedEx': 'fedex',
53+
'USPS': 'usps',
54+
'DHL': 'dhl',
55+
'Amazon Logistics': 'amazoncn',
56+
'Other': 'other'
57+
};
58+
return carrierMap[carrier] || carrier.toLowerCase();
59+
},
60+
61+
formatTrackingResult(data: any, trackingNumber: string, carrier: string): TrackingResult {
62+
const trackInfo = data.data?.[0];
63+
64+
if (!trackInfo) {
65+
throw new Error('No tracking information found');
66+
}
67+
68+
const statusMap: Record<number, 'pending' | 'in_transit' | 'delivered' | 'failed'> = {
69+
0: 'pending',
70+
1: 'in_transit',
71+
2: 'delivered',
72+
3: 'failed',
73+
4: 'in_transit',
74+
5: 'failed'
75+
};
76+
77+
const events = (trackInfo.events || []).map((event: any) => ({
78+
timestamp: new Date(event.time * 1000).toISOString(),
79+
location: event.location || 'Unknown',
80+
status: event.status_text || event.status || 'Update'
81+
}));
82+
83+
const lastEvent = events[events.length - 1];
84+
85+
return {
86+
trackingNumber,
87+
carrier,
88+
status: statusMap[trackInfo.status] || 'pending',
89+
lastUpdate: lastEvent?.timestamp || new Date().toISOString(),
90+
destination: trackInfo.dest_city || undefined,
91+
estimatedDelivery: trackInfo.estimated_delivery
92+
? new Date(trackInfo.estimated_delivery * 1000).toISOString()
93+
: undefined,
94+
events
95+
};
96+
}
97+
};

Backend/wrangler.toml

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
name = "htmltrack-worker"
2+
main = "src/index.ts"
3+
4+
[build]
5+
command = "npm install && npm run build"
6+
cwd = "./Backend"
7+
watch_paths = ["src/**/*.ts"]
8+
9+
[vars]
10+
LOG_LEVEL = "info"
11+
12+
# Secrets are set via: wrangler secret put TRACK_API_KEY
13+
# Or in .dev.vars for local development

Build/index.html

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,16 +2,11 @@
22
<html>
33

44
<head>
5-
<title>My Page</title>
6-
<link rel="stylesheet" data-inline="true" href="./styles/styles.css" />
5+
<title>HTMLTrack</title>
76
</head>
87

98
<body>
10-
<script type="module" data-inline="true" src="./src/main.js"></script>
11-
<h1>Hello, world!</h1>
12-
<p>This is a demo page.</p>
13-
<button onclick="testFunction()">Click me!</button>
14-
<button onclick="outputToPage()">Show a square.</button>
9+
<script type="module" data-inline="true" src="./src/pages/main.tsx"></script>
1510
</body>
1611

1712
</html>

0 commit comments

Comments
 (0)