83 * @param page Page number
84 * @param pageSize Number of results per page
85 * @param fetchData Whether to fetch the full data for each result
86 */
87export async function searchDocs(
89 page: number = 1,
90 pageSize: number = 10,
91 fetchData: boolean = true
92): Promise<{
93 results: DocSearchResult[];
105
106 // If we don't need the full data, just return the count
107 if (!fetchData) {
108 return { results: [], totalResults: unfilteredResultCount };
109 }
112 const paginatedResults = results.slice(startIndex, endIndex);
113
114 // Fetch all result data in parallel
115 const dataPromises = paginatedResults.map(result => result.data());
116 const resultDataArray = await Promise.all(dataPromises);
35 "integrity": "sha512-OF8fFQSkbL7vJY9rfuegK1R7sPgQ6kFMkDamiEccNUvieQ+3urzfDFI616oPl8V7T9zRmnTkSjMOImYCAVRVuw==",
36 "dependencies": [
37 "@libsql/isomorphic-fetch",
38 "@libsql/isomorphic-ws",
39 "js-base64",
40 "node-fetch@3.3.2"
41 ]
42 },
43 "@libsql/isomorphic-fetch@0.3.1": {
44 "integrity": "sha512-6kK3SUK5Uu56zPq/Las620n5aS9xJq+jMBcNSOmjhNf/MUvdyji4vrMTqD7ptY7/4/CAVEAYDeotUz60LNQHtw=="
45 },
69 "integrity": "sha512-kTPhdZyTQxB+2wpiRcFWrDcejc4JI6tkPuS7UZCG4l6Zvc5kU/gGQ/ozvHTh1XR5tS+UlfAfGuPajjzQjCiHCw=="
70 },
71 "@types/node-fetch@2.6.12": {
72 "integrity": "sha512-8nneRWKCg3rMtF69nLQJnOYUcbafYeFSjqkw3jCRLsqkWFlHaoQrr5mXmofFGOx3DKn7UfmBMyov8ySvLRVldA==",
73 "dependencies": [
104 "dependencies": [
105 "@types/node@18.19.86",
106 "@types/node-fetch",
107 "abort-controller",
108 "agentkeepalive",
109 "form-data-encoder",
110 "formdata-node",
111 "node-fetch@2.7.0"
112 ]
113 },
184 "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ=="
185 },
186 "fetch-blob@3.2.0": {
187 "integrity": "sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==",
188 "dependencies": [
213 "integrity": "sha512-buewHzMvYL29jdeQTVILecSaZKnt/RJWjoZCF5OW60Z67/GmSLBkOFM7qh1PI3zFNtJbaZL5eQu1vLfazOwj4g==",
214 "dependencies": [
215 "fetch-blob"
216 ]
217 },
300 "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ=="
301 },
302 "node-fetch@2.7.0": {
303 "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==",
304 "dependencies": [
306 ]
307 },
308 "node-fetch@3.3.2": {
309 "integrity": "sha512-dRB78srN/l6gqWulah9SrxeYnxeddIG30+GOqK/9OlLVyLg3HPnr6SqOWTWOXKRwC2eGYCkZ59NNuSgvSrpgOA==",
310 "dependencies": [
311 "data-uri-to-buffer",
312 "fetch-blob",
313 "formdata-polyfill"
314 ]
1import { blob } from "https://esm.town/v/std/blob?v=12";
2import { fetchJSON } from "https://esm.town/v/stevekrouse/fetchJSON";
3import { msDay } from "https://esm.town/v/stevekrouse/msDay";
4import { msHour } from "https://esm.town/v/stevekrouse/msHour";
25 lon: number;
26}) => {
27 const { results } = await fetchJSON(
28 `${BASE_URL}/v3/locations?`
29 + new URLSearchParams({
50export async function openAqNowcastAQI(location) {
51 const sensorID = location.sensors.find(s => s.parameter.name === "pm25").id;
52 const data = await fetchJSON(
53 `${BASE_URL}/v3/sensors/${sensorID}/measurements?`
54 + new URLSearchParams({
1import { fetchTodaysMeetings } from "./googleCalendar.ts";
2import { createMeetingPage } from "./notion.ts";
3import { getUserInfo } from "./userInfo.ts";
21 try {
22 // Get today's meetings from Google Calendar
23 const meetings = await fetchTodaysMeetings();
24 console.log(`Found ${meetings.length} total meetings for today`);
25
3export default async function(req: Request): Promise<Response> {
4 const url = new URL(req.url);
5 return fetch(TARGET_URL + url.pathname + url.search, {
6 headers: {
7 "X-API-Key": Deno.env.get("OpenAQ_API_KEY") as string,
56## How It Works
571. The cron job runs every morning
582. It fetches your calendar events for the day
593. It identifies meetings with exactly one external participant (not from your team domain)
604. For each user meeting, it:
1/**
2 * Google Calendar integration to fetch meetings and identify user meetings
3 */
4
45 }
46
47 const tokenResponse = await fetch("https://oauth2.googleapis.com/token", {
48 method: "POST",
49 headers: {
67
68/**
69 * Fetch today's calendar events from Google Calendar
70 */
71async function fetchCalendarEvents(): Promise<GoogleCalendarEvent[]> {
72 const accessToken = await getAccessToken();
73
83 const url = `https://www.googleapis.com/calendar/v3/calendars/${encodeURIComponent(calendarId)}/events?timeMin=${encodeURIComponent(timeMin)}&timeMax=${encodeURIComponent(timeMax)}&singleEvents=true&orderBy=startTime`;
84
85 const response = await fetch(url, {
86 headers: {
87 Authorization: `Bearer ${accessToken}`,
90
91 if (!response.ok) {
92 throw new Error(`Failed to fetch calendar events: ${await response.text()}`);
93 }
94
127 * Process calendar events to identify user meetings
128 */
129export async function fetchTodaysMeetings(): Promise<Meeting[]> {
130 const events = await fetchCalendarEvents();
131 const teamDomain = Deno.env.get("TEAM_DOMAIN") || "val.town";
132 console.log(`Using team domain: ${teamDomain}`);
1import { fetchJSON } from "https://esm.town/v/stevekrouse/fetchJSON";
2
3export function nominatimSearch(params: Search): Promise<Place[]> {
4 return fetchJSON(
5 "https://nominatim.openstreetmap.org/search?"
6 + new URLSearchParams({
37 : searchName;
38
39 const response = await fetch(
40 `https://serpapi.com/search.json?engine=google&q=${encodeURIComponent(searchQuery)}&api_key=${serpApiKey}`
41 );
127 return null;
128 } catch (error) {
129 console.error("Error fetching data from SERP API:", error);
130 return null;
131 }
147
148 if (serpApiKey) {
149 const response = await fetch(
150 `https://serpapi.com/search.json?engine=google&q=${encodeURIComponent(domain)}&api_key=${serpApiKey}`
151 );
185 };
186 } catch (error) {
187 console.error("Error fetching company data:", error);
188 return null;
189 }
261
262 // Create the page in Notion
263 const response = await fetch("https://api.notion.com/v1/pages", {
264 method: "POST",
265 headers: {