1# geolocation
2
3A helper function to fetch geolocation data from [ip-api](https://ip-api.com/)
4based on a visitor's IP address
5
6```ts
7import { fetchGeolocation } from "https://esm.town/v/mattrossman/geolocation/main.ts";
8
9export default async function (req: Request) {
10 const geolocation = await fetchGeolocation(req);
11 return new Response(`You're visiting from ${geolocation.city}`);
12}
21};
22
23export async function fetchGeolocation(req: Request) {
24 const ip = await getIp(req);
25 if (ip === undefined) throw new Error(`Missing "x-forwarded-for" header`);
26
27 const json = await fetch(`http://ip-api.com/json/${ip}`).then(
28 (res) => res.json(),
29 ) as IpApiGeolocation;
33
34export default async function (req: Request): Promise<Response> {
35 const geolocation = await fetchGeolocation(req);
36 return Response.json(geolocation);
37}
1import { fetchGeolocation } from "https://esm.town/v/mattrossman/geolocation/main.ts";
2
3export default async function (req: Request) {
4 const geolocation = await fetchGeolocation(req);
5 return new Response(`Hello from ${geolocation.city}`);
6}
62formData.append('html', 'your HTML goes here...');
63
64fetch('https://ishbrzero--086bc172453a11f0896c76b3cceeab13.web.val.run', {
65 method: 'POST',
66 body: formData,
20 if (!xForwardedFor) throw new Error(`Missing "x-forwarded-for" header`);
21
22 const json = await fetch(`http://ip-api.com/json/${xForwardedFor}`).then(
23 (res) => res.json(),
24 ) as IpApiResponse;
3
4try {
5 // Fetch with browser-like headers to avoid basic bot detection
6 const response = await fetch(targetUrl, {
7 method: "GET",
8 headers: {
15 "Connection": "keep-alive",
16 "Upgrade-Insecure-Requests": "1",
17 "Sec-Fetch-Dest": "document",
18 "Sec-Fetch-Mode": "navigate",
19 "Sec-Fetch-Site": "none",
20 "Cache-Control": "max-age=0",
21 },
32 };
33
34 const fetchData = async url => {
35 const text = await fetch(url).then(r => r.text());
36 return d3.csvParse(text).map(d => ({ age: +d.Age, qx: +d.qx }));
37 };
38
39 const [male, female] = await Promise.all([fetchData(urls.M), fetchData(urls.F)]);
40 const data = { M: male, F: female };
41 const maxAge = 120;
8});
9
10export default app.fetch;
1import { fetchJSON } from "https://esm.town/v/stevekrouse/fetchJSON?v=41";
2
3export const slackReplyToMessage = async (req: Request) => {
33 if (body.event?.type === "app_mention") {
34 try {
35 // Use standard fetch instead of fetchJSON for more control
36 const result = await fetch("https://slack.com/api/chat.postMessage", {
37 method: "POST",
38 headers: {
30 ];
31
32 const response = await fetch(
33 `https://wcc.sc.egov.usda.gov/awdbRestApi/services/v1/stations?stationIds=${coStationIds.join(',')}`
34 );
59 return c.json(apiResponse);
60 } catch (error) {
61 console.error("Error fetching sites:", error);
62 const apiResponse: ApiResponse<SnotelSite[]> = {
63 success: false,
85 ];
86
87 // Fetch recent data for these stations
88 const dataResponse = await fetch(
89 `https://wcc.sc.egov.usda.gov/awdbRestApi/services/v1/data?stationIds=${coStationIds.join(',')}&elementCds=SNWD,WTEQ,TOBS&ordinal=1&duration=DAILY&getFlags=false&alwaysReturnDailyFeb29=false&format=json&beginDate=${formatDate(startDate)}&endDate=${formatDate(endDate)}`
90 );
143 return c.json(apiResponse);
144 } catch (error) {
145 console.error("Error fetching data:", error);
146 const apiResponse: ApiResponse<SnotelData[]> = {
147 success: false,
152});
153
154export default app.fetch;