Compare commits
No commits in common. "master" and "web-server" have entirely different histories.
master
...
web-server
20 changed files with 903 additions and 590 deletions
|
@ -1,3 +0,0 @@
|
|||
node_modules
|
||||
npm-debug.log
|
||||
tmp
|
|
@ -1,11 +1,9 @@
|
|||
# Google
|
||||
SERPAPI_KEY
|
||||
|
||||
# Google
|
||||
GOOGLE_CALENDAR_ID
|
||||
GOOGLE_PROJECT_NUMBER
|
||||
GOOGLE_CLIENT_EMAIL
|
||||
GOOGLE_PRIVATE_KEY
|
||||
GOOGLE_KEY_ID
|
||||
|
||||
GOOGLE_CLIENT_ID
|
||||
GOOGLE_CLIENT_SECRET
|
14
.gitignore
vendored
14
.gitignore
vendored
|
@ -2,8 +2,8 @@
|
|||
node_modules
|
||||
|
||||
#javascript build files #
|
||||
# public/**/*
|
||||
dist/**/*
|
||||
public
|
||||
dist
|
||||
|
||||
# Tmp files #
|
||||
tmp
|
||||
|
@ -13,11 +13,5 @@ tmp
|
|||
.env
|
||||
config/client_google_auth.json
|
||||
|
||||
## Docker ##
|
||||
build_image.sh
|
||||
push_dockerhub.sh
|
||||
|
||||
# keys #
|
||||
keys/**/*
|
||||
|
||||
cron.log
|
||||
## output ##
|
||||
dist
|
||||
|
|
16
Dockerfile
16
Dockerfile
|
@ -1,16 +0,0 @@
|
|||
FROM node:16
|
||||
|
||||
ENV TZ=Asia/Jerusalem
|
||||
|
||||
WORKDIR /usr/src/app
|
||||
|
||||
COPY package*.json ./
|
||||
RUN npm install
|
||||
RUN npm install -g typescript
|
||||
COPY . .
|
||||
|
||||
EXPOSE ${PORT}
|
||||
RUN tsc
|
||||
|
||||
CMD [ "npm", "start" ]
|
||||
|
95
dist/GameSource.js
vendored
95
dist/GameSource.js
vendored
|
@ -1,95 +0,0 @@
|
|||
"use strict";
|
||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
require("dotenv").config();
|
||||
const axios_1 = __importDefault(require("axios"));
|
||||
const moment_1 = __importDefault(require("moment"));
|
||||
class GameSource {
|
||||
async getGamesFromHaifa(logger) {
|
||||
console.log("Trying to get games from Haifa...");
|
||||
try {
|
||||
// Get the current date and time in the required format
|
||||
const currentDate = (0, moment_1.default)().format("DD/MM/YYYY HH:mm");
|
||||
// Construct the filters object with the current date
|
||||
const filters = {
|
||||
date: {
|
||||
startDate: currentDate,
|
||||
endDate: "",
|
||||
},
|
||||
league: "",
|
||||
session: "",
|
||||
gamesDirection: "1",
|
||||
};
|
||||
// Encode the filters for the URL
|
||||
const filtersParam = encodeURIComponent(JSON.stringify(filters));
|
||||
// Construct the API URL with the encoded filters
|
||||
const sourceUrl = `https://api.mhaifafc.com/api/content/games-lobby?filters=${filtersParam}&start=0&limit=20&sortDirection=ASC&app=web&lang=he`;
|
||||
// Get the authorization token from environment variables
|
||||
const authorizationToken = process.env.HAIFA_API_AUTH_TOKEN;
|
||||
// Set up the request headers
|
||||
const headers = {
|
||||
Accept: "*/*",
|
||||
"Accept-Language": "en-US,en;q=0.7",
|
||||
Authorization: `Bearer ${authorizationToken}`,
|
||||
"User-Agent": "Mozilla/5.0",
|
||||
Origin: "https://www.mhaifafc.com",
|
||||
Referer: "https://www.mhaifafc.com/",
|
||||
};
|
||||
// Make the API request
|
||||
const response = await axios_1.default.get(sourceUrl, {
|
||||
headers,
|
||||
responseType: "json",
|
||||
responseEncoding: "utf8", // Ensure UTF-8 encoding
|
||||
});
|
||||
// Extract the games data from the response
|
||||
const gamesData = response.data.games.items;
|
||||
const games = [];
|
||||
// Loop through each game and construct the GoogleCalendarEvent objects
|
||||
for (const game of gamesData) {
|
||||
const gameDetails = game.gameDetails;
|
||||
const gameTime = gameDetails.gameTime; // ISO string
|
||||
const isFinalGameDate = gameDetails.isFinalGameDate;
|
||||
const gameLocation = gameDetails.gameLocation;
|
||||
// Skip games without a game time
|
||||
if (!gameTime)
|
||||
continue;
|
||||
const hostTeam = game.hostTeam;
|
||||
const guestTeam = game.guestTeam;
|
||||
// Get team names
|
||||
const hostTeamName = hostTeam.teamName;
|
||||
const guestTeamName = guestTeam.teamName;
|
||||
const summary = `${hostTeamName} vs. ${guestTeamName}`;
|
||||
// Include a note if the game date is not final
|
||||
let description = `${hostTeamName} vs. ${guestTeamName}`;
|
||||
if (!isFinalGameDate) {
|
||||
description += " (Date and time are subject to change)";
|
||||
}
|
||||
// Calculate start and end times
|
||||
const startDateTime = (0, moment_1.default)(gameTime).toISOString();
|
||||
const endDateTime = (0, moment_1.default)(gameTime).add(2, "hours").toISOString();
|
||||
// Add the event to the games array
|
||||
games.push({
|
||||
summary: summary,
|
||||
location: gameLocation,
|
||||
description: description,
|
||||
start: {
|
||||
dateTime: startDateTime,
|
||||
timeZone: "Asia/Jerusalem",
|
||||
},
|
||||
end: {
|
||||
dateTime: endDateTime,
|
||||
timeZone: "Asia/Jerusalem",
|
||||
},
|
||||
});
|
||||
}
|
||||
return games;
|
||||
}
|
||||
catch (error) {
|
||||
console.error(error);
|
||||
return [];
|
||||
}
|
||||
}
|
||||
}
|
||||
exports.default = GameSource;
|
88
dist/GoogleCalendar.js
vendored
88
dist/GoogleCalendar.js
vendored
|
@ -1,88 +0,0 @@
|
|||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const google_auth_library_1 = require("google-auth-library");
|
||||
const googleapis_1 = require("googleapis");
|
||||
require("dotenv").config();
|
||||
const env = process.env;
|
||||
class GoogleCalendar {
|
||||
constructor() {
|
||||
this.gamesMap = {};
|
||||
this.clientSecret = env.GOOGLE_CLIENT_SECRET;
|
||||
this.clientId = env.GOOGLE_CLIENT_ID;
|
||||
this.calenderId = env.GOOGLE_CALENDAR_ID;
|
||||
this.clientEmail = env.GOOGLE_CLIENT_EMAIL;
|
||||
this.googlePrivateKey = env.GOOGLE_PRIVATE_KEY.replace(/\\n/g, "\n");
|
||||
}
|
||||
async init() {
|
||||
console.log("INIT GOOGLE CALENDAR");
|
||||
const jwtClient = await this.authorize();
|
||||
this.calendar = googleapis_1.google.calendar({ version: "v3", auth: jwtClient });
|
||||
}
|
||||
async authorize() {
|
||||
console.log("AUTHORIZE GOOGLE CALENDAR");
|
||||
this.JWT_client = new google_auth_library_1.JWT({
|
||||
email: this.clientEmail,
|
||||
key: this.googlePrivateKey,
|
||||
scopes: ["https://www.googleapis.com/auth/calendar"],
|
||||
});
|
||||
const { access_token } = await this.JWT_client.authorize();
|
||||
this.token = access_token;
|
||||
if (!this.token) {
|
||||
throw new Error("Failed to connect to google calendar");
|
||||
}
|
||||
console.log("GOOGLE CALENDAR AUTHORIZED SUCCESSFULLY");
|
||||
return this.JWT_client;
|
||||
}
|
||||
async updateNewEvent(upcomingEvents) {
|
||||
// console.log(upcomingEvents)
|
||||
setTimeout(async () => {
|
||||
upcomingEvents.forEach(async (event) => {
|
||||
console.log("UPDATE NEW EVENT", upcomingEvents);
|
||||
const options = {
|
||||
auth: this.JWT_client,
|
||||
calendarId: this.calenderId,
|
||||
resource: {
|
||||
summary: event.summary,
|
||||
location: event.location,
|
||||
description: event.description,
|
||||
start: {
|
||||
dateTime: event.start.dateTime,
|
||||
timeZone: "Asia/Jerusalem",
|
||||
},
|
||||
end: { dateTime: event.end.dateTime, timeZone: "Asia/Jerusalem" },
|
||||
sendNotifications: true,
|
||||
},
|
||||
};
|
||||
await this.calendar.events.insert(options, function (err, event) {
|
||||
if (err) {
|
||||
console.log("There was an error contacting the Calendar service: " + err);
|
||||
return;
|
||||
}
|
||||
console.log(event.description + " created");
|
||||
});
|
||||
});
|
||||
}, 3000);
|
||||
}
|
||||
async isDuplicateEvent(startTime, endTime, title) {
|
||||
if (this.gamesMap[startTime]) {
|
||||
console.log("duplicate event");
|
||||
return true;
|
||||
}
|
||||
this.gamesMap[startTime] = true;
|
||||
console.log("checking for duplicate event");
|
||||
try {
|
||||
const response = await this.calendar.events.list({
|
||||
calendarId: this.calenderId,
|
||||
timeMin: startTime,
|
||||
timeMax: endTime,
|
||||
q: title, // Search for events with the same title
|
||||
});
|
||||
return response.data.items.length > 0;
|
||||
}
|
||||
catch (error) {
|
||||
console.error(error.message);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
exports.default = GoogleCalendar;
|
68
dist/index.js
vendored
68
dist/index.js
vendored
|
@ -1,68 +0,0 @@
|
|||
"use strict";
|
||||
var __importDefault = (this && this.__importDefault) || function (mod) {
|
||||
return (mod && mod.__esModule) ? mod : { "default": mod };
|
||||
};
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
||||
const GameSource_1 = __importDefault(require("./GameSource"));
|
||||
const GoogleCalendar_1 = __importDefault(require("./GoogleCalendar"));
|
||||
const dotenv_1 = __importDefault(require("dotenv"));
|
||||
const node_cron_1 = __importDefault(require("node-cron"));
|
||||
const fs_1 = __importDefault(require("fs")); // Importing fs for logging
|
||||
dotenv_1.default.config();
|
||||
class App {
|
||||
constructor() {
|
||||
this.gameSource = new GameSource_1.default();
|
||||
this.googleCalendar = new GoogleCalendar_1.default();
|
||||
}
|
||||
async startCronJob() {
|
||||
this.writeLog('START Haifa Reminder'); // Log when the cron job starts
|
||||
const newGamesAdded = [];
|
||||
await this.googleCalendar.init();
|
||||
try {
|
||||
const games = await this.gameSource.getGamesFromHaifa(this.writeLog);
|
||||
for (const game of games) {
|
||||
const isDuplicateEvent = await this.googleCalendar.isDuplicateEvent(game.start.dateTime, game.end.dateTime, game.summary);
|
||||
console.log(game);
|
||||
if (!isDuplicateEvent) {
|
||||
newGamesAdded.push(game);
|
||||
console.log("Event does not exist");
|
||||
await this.googleCalendar.updateNewEvent([game]);
|
||||
}
|
||||
else {
|
||||
console.log("Event already exists");
|
||||
}
|
||||
}
|
||||
if (newGamesAdded.length > 0) {
|
||||
console.log("New games added:", newGamesAdded);
|
||||
}
|
||||
else {
|
||||
console.log("No new games were Added!");
|
||||
}
|
||||
this.writeLog('Successfully ran project');
|
||||
}
|
||||
catch (error) {
|
||||
this.writeLog("Error in cron job:" + error.message);
|
||||
}
|
||||
finally {
|
||||
this.writeLog('END CRON JOB'); // Log when the cron job ends
|
||||
}
|
||||
}
|
||||
writeLog(message) {
|
||||
const timestamp = new Date().toISOString();
|
||||
const logMessage = `${timestamp} - ${message}\n`;
|
||||
// Write to log file synchronously
|
||||
fs_1.default.appendFileSync('cron.log', logMessage);
|
||||
console.log(logMessage); // Optional: also log to console
|
||||
}
|
||||
}
|
||||
const app = new App();
|
||||
node_cron_1.default.schedule('* * * * *', () => {
|
||||
console.log('Running startCronJob at 10:00 AM Jerusalem time');
|
||||
app.startCronJob().catch((error) => {
|
||||
console.error("Error in scheduled cron job:", error.message);
|
||||
app.writeLog(`ERROR: ${error.message}`); // Log any errors
|
||||
});
|
||||
}, {
|
||||
scheduled: true,
|
||||
timezone: "Asia/Jerusalem"
|
||||
});
|
2
dist/types/index.js
vendored
2
dist/types/index.js
vendored
|
@ -1,2 +0,0 @@
|
|||
"use strict";
|
||||
Object.defineProperty(exports, "__esModule", { value: true });
|
77
maccabi-haifa-fc.ics
Normal file
77
maccabi-haifa-fc.ics
Normal file
|
@ -0,0 +1,77 @@
|
|||
BEGIN:VCALENDAR
|
||||
VERSION:2.0
|
||||
CALSCALE:GREGORIAN
|
||||
PRODID:https://mhaifafc.com/
|
||||
METHOD:PUBLISH
|
||||
X-PUBLISHED-TTL:PT1H
|
||||
BEGIN:VEVENT
|
||||
UID:d27oNU81CRFrJItoqCLnW
|
||||
SUMMARY:Maccabi Haifa F.C.
|
||||
DTSTAMP:20230402T081739Z
|
||||
DTSTART:20230404T173000Z
|
||||
DTEND:20230404T193000Z
|
||||
DESCRIPTION:Maccabi Tel aviv vs. Maccabi Haifa
|
||||
URL:https://mhaifafc.com/
|
||||
LOCATION:Sammy Ofer Stadium
|
||||
STATUS:CONFIRMED
|
||||
CATEGORIES:
|
||||
ORGANIZER;CN=Maccabi Haifa F.C.
|
||||
X-MICROSOFT-CDO-BUSYSTATUS:BUSY
|
||||
END:VEVENT
|
||||
BEGIN:VEVENT
|
||||
UID:EW8ndR1-XGchn9ERDCt06
|
||||
SUMMARY:Maccabi Haifa F.C.
|
||||
DTSTAMP:20230402T081739Z
|
||||
DTSTART:20230408T170000Z
|
||||
DTEND:20230408T190000Z
|
||||
DESCRIPTION:Maccabi Haifa vs. Maccabi Netanya
|
||||
URL:https://mhaifafc.com/
|
||||
LOCATION:Sammy Ofer Stadium
|
||||
STATUS:CONFIRMED
|
||||
CATEGORIES:
|
||||
ORGANIZER;CN=Maccabi Haifa F.C.
|
||||
X-MICROSOFT-CDO-BUSYSTATUS:BUSY
|
||||
END:VEVENT
|
||||
BEGIN:VEVENT
|
||||
UID:81viYkz6AgaGWhoWoQAAR
|
||||
SUMMARY:Maccabi Haifa F.C.
|
||||
DTSTAMP:20230402T081739Z
|
||||
DTSTART:20230415T153000Z
|
||||
DTEND:20230415T173000Z
|
||||
DESCRIPTION:Hapoel Jerusalem vs. Maccabi Haifa
|
||||
URL:https://mhaifafc.com/
|
||||
LOCATION:Sammy Ofer Stadium
|
||||
STATUS:CONFIRMED
|
||||
CATEGORIES:
|
||||
ORGANIZER;CN=Maccabi Haifa F.C.
|
||||
X-MICROSOFT-CDO-BUSYSTATUS:BUSY
|
||||
END:VEVENT
|
||||
BEGIN:VEVENT
|
||||
UID:x-lwY95Hy0F_VMZprfU6z
|
||||
SUMMARY:Maccabi Haifa F.C.
|
||||
DTSTAMP:20230402T081739Z
|
||||
DTSTART:20230423T173000Z
|
||||
DTEND:20230423T193000Z
|
||||
DESCRIPTION:F.C Ashdod vs. Maccabi Haifa
|
||||
URL:https://mhaifafc.com/
|
||||
LOCATION:Sammy Ofer Stadium
|
||||
STATUS:CONFIRMED
|
||||
CATEGORIES:
|
||||
ORGANIZER;CN=Maccabi Haifa F.C.
|
||||
X-MICROSOFT-CDO-BUSYSTATUS:BUSY
|
||||
END:VEVENT
|
||||
BEGIN:VEVENT
|
||||
UID:0aphCOxxwj7KQi0QdHpD8
|
||||
SUMMARY:Maccabi Haifa F.C.
|
||||
DTSTAMP:20230402T081739Z
|
||||
DTSTART:20230501T173000Z
|
||||
DTEND:20230501T193000Z
|
||||
DESCRIPTION:H Be'er Sheva vs. Maccabi Haifa
|
||||
URL:https://mhaifafc.com/
|
||||
LOCATION:Sammy Ofer Stadium
|
||||
STATUS:CONFIRMED
|
||||
CATEGORIES:
|
||||
ORGANIZER;CN=Maccabi Haifa F.C.
|
||||
X-MICROSOFT-CDO-BUSYSTATUS:BUSY
|
||||
END:VEVENT
|
||||
END:VCALENDAR
|
706
package-lock.json
generated
706
package-lock.json
generated
|
@ -6,19 +6,28 @@
|
|||
"": {
|
||||
"dependencies": {
|
||||
"axios": "^1.3.4",
|
||||
"cron": "^2.3.0",
|
||||
"dotenv": "^16.0.3",
|
||||
"googleapis": "^122.0.0",
|
||||
"express": "^4.18.2",
|
||||
"googleapis": "^113.0.0",
|
||||
"ics": "^3.1.0",
|
||||
"moment": "^2.29.4",
|
||||
"moment-timezone": "^0.5.43",
|
||||
"node-cron": "^3.0.3",
|
||||
"node-html-parser": "^6.1.5",
|
||||
"uuid": "^9.0.0"
|
||||
"node-html-parser": "^6.1.5"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/express": "^4.17.17",
|
||||
"@types/node": "^18.15.5",
|
||||
"@types/node-cron": "^3.0.11",
|
||||
"typescript": "^5.0.3"
|
||||
"@types/node": "^18.15.5"
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/runtime": {
|
||||
"version": "7.21.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.21.0.tgz",
|
||||
"integrity": "sha512-xwII0//EObnq89Ji5AKYQaRYiW/nZ3llSv29d49IuxPhKbtJoLP+9QUUZ4nVragQVtaVGeZrpB+ZtG/Pdy/POw==",
|
||||
"dependencies": {
|
||||
"regenerator-runtime": "^0.13.11"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/body-parser": {
|
||||
|
@ -63,6 +72,11 @@
|
|||
"@types/range-parser": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/lodash": {
|
||||
"version": "4.14.192",
|
||||
"resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.192.tgz",
|
||||
"integrity": "sha512-km+Vyn3BYm5ytMO13k9KTp27O75rbQ0NFw+U//g+PX7VZyjCioXaRFisqSIJRECljcTv73G3i6BpglNGHgUQ5A=="
|
||||
},
|
||||
"node_modules/@types/mime": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/mime/-/mime-3.0.1.tgz",
|
||||
|
@ -75,12 +89,6 @@
|
|||
"integrity": "sha512-Ark2WDjjZO7GmvsyFFf81MXuGTA/d6oP38anyxWOL6EREyBKAxKoFHwBhaZxCfLRLpO8JgVXwqOwSwa7jRcjew==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/node-cron": {
|
||||
"version": "3.0.11",
|
||||
"resolved": "https://registry.npmjs.org/@types/node-cron/-/node-cron-3.0.11.tgz",
|
||||
"integrity": "sha512-0ikrnug3/IyneSHqCBeslAhlK2aBfYek1fGo4bP4QnZPmiqSGRK+Oy7ZMisLWkesffJvQ1cqAcBnJC+8+nxIAg==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/qs": {
|
||||
"version": "6.9.7",
|
||||
"resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz",
|
||||
|
@ -103,6 +111,18 @@
|
|||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/accepts": {
|
||||
"version": "1.3.8",
|
||||
"resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz",
|
||||
"integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==",
|
||||
"dependencies": {
|
||||
"mime-types": "~2.1.34",
|
||||
"negotiator": "0.6.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/agent-base": {
|
||||
"version": "6.0.2",
|
||||
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz",
|
||||
|
@ -114,6 +134,11 @@
|
|||
"node": ">= 6.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/array-flatten": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz",
|
||||
"integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg=="
|
||||
},
|
||||
"node_modules/arrify": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/arrify/-/arrify-2.0.1.tgz",
|
||||
|
@ -164,6 +189,56 @@
|
|||
"node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/body-parser": {
|
||||
"version": "1.20.1",
|
||||
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.1.tgz",
|
||||
"integrity": "sha512-jWi7abTbYwajOytWCQc37VulmWiRae5RyTpaCyDcS5/lMdtwSz5lOpDE67srw/HYe35f1z3fDQw+3txg7gNtWw==",
|
||||
"dependencies": {
|
||||
"bytes": "3.1.2",
|
||||
"content-type": "~1.0.4",
|
||||
"debug": "2.6.9",
|
||||
"depd": "2.0.0",
|
||||
"destroy": "1.2.0",
|
||||
"http-errors": "2.0.0",
|
||||
"iconv-lite": "0.4.24",
|
||||
"on-finished": "2.4.1",
|
||||
"qs": "6.11.0",
|
||||
"raw-body": "2.5.1",
|
||||
"type-is": "~1.6.18",
|
||||
"unpipe": "1.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.8",
|
||||
"npm": "1.2.8000 || >= 1.4.16"
|
||||
}
|
||||
},
|
||||
"node_modules/body-parser/node_modules/debug": {
|
||||
"version": "2.6.9",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
|
||||
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
|
||||
"dependencies": {
|
||||
"ms": "2.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/body-parser/node_modules/ms": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
|
||||
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
|
||||
},
|
||||
"node_modules/body-parser/node_modules/qs": {
|
||||
"version": "6.11.0",
|
||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz",
|
||||
"integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==",
|
||||
"dependencies": {
|
||||
"side-channel": "^1.0.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.6"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/boolbase": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz",
|
||||
|
@ -174,6 +249,14 @@
|
|||
"resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz",
|
||||
"integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA=="
|
||||
},
|
||||
"node_modules/bytes": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
|
||||
"integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==",
|
||||
"engines": {
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/call-bind": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.2.tgz",
|
||||
|
@ -197,6 +280,46 @@
|
|||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/content-disposition": {
|
||||
"version": "0.5.4",
|
||||
"resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz",
|
||||
"integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==",
|
||||
"dependencies": {
|
||||
"safe-buffer": "5.2.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/content-type": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz",
|
||||
"integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==",
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/cookie": {
|
||||
"version": "0.5.0",
|
||||
"resolved": "https://registry.npmjs.org/cookie/-/cookie-0.5.0.tgz",
|
||||
"integrity": "sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==",
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/cookie-signature": {
|
||||
"version": "1.0.6",
|
||||
"resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz",
|
||||
"integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ=="
|
||||
},
|
||||
"node_modules/cron": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/cron/-/cron-2.3.0.tgz",
|
||||
"integrity": "sha512-ZN5HP8zDY41sJolMsbc+GksRATcbvkPKF5wR/qc8FrV4NBVi9ORQa1HmYa5GydaysUB80X9XpRlRkooa5uEtTA==",
|
||||
"dependencies": {
|
||||
"luxon": "^3.2.1"
|
||||
}
|
||||
},
|
||||
"node_modules/css-select": {
|
||||
"version": "5.1.0",
|
||||
"resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz",
|
||||
|
@ -247,6 +370,23 @@
|
|||
"node": ">=0.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/depd": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz",
|
||||
"integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==",
|
||||
"engines": {
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/destroy": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz",
|
||||
"integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==",
|
||||
"engines": {
|
||||
"node": ">= 0.8",
|
||||
"npm": "1.2.8000 || >= 1.4.16"
|
||||
}
|
||||
},
|
||||
"node_modules/dom-serializer": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz",
|
||||
|
@ -314,6 +454,19 @@
|
|||
"safe-buffer": "^5.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/ee-first": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
|
||||
"integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="
|
||||
},
|
||||
"node_modules/encodeurl": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz",
|
||||
"integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==",
|
||||
"engines": {
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/entities": {
|
||||
"version": "4.4.0",
|
||||
"resolved": "https://registry.npmjs.org/entities/-/entities-4.4.0.tgz",
|
||||
|
@ -325,6 +478,87 @@
|
|||
"url": "https://github.com/fb55/entities?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/escape-html": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
|
||||
"integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow=="
|
||||
},
|
||||
"node_modules/etag": {
|
||||
"version": "1.8.1",
|
||||
"resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz",
|
||||
"integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==",
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/express": {
|
||||
"version": "4.18.2",
|
||||
"resolved": "https://registry.npmjs.org/express/-/express-4.18.2.tgz",
|
||||
"integrity": "sha512-5/PsL6iGPdfQ/lKM1UuielYgv3BUoJfz1aUwU9vHZ+J7gyvwdQXFEBIEIaxeGf0GIcreATNyBExtalisDbuMqQ==",
|
||||
"dependencies": {
|
||||
"accepts": "~1.3.8",
|
||||
"array-flatten": "1.1.1",
|
||||
"body-parser": "1.20.1",
|
||||
"content-disposition": "0.5.4",
|
||||
"content-type": "~1.0.4",
|
||||
"cookie": "0.5.0",
|
||||
"cookie-signature": "1.0.6",
|
||||
"debug": "2.6.9",
|
||||
"depd": "2.0.0",
|
||||
"encodeurl": "~1.0.2",
|
||||
"escape-html": "~1.0.3",
|
||||
"etag": "~1.8.1",
|
||||
"finalhandler": "1.2.0",
|
||||
"fresh": "0.5.2",
|
||||
"http-errors": "2.0.0",
|
||||
"merge-descriptors": "1.0.1",
|
||||
"methods": "~1.1.2",
|
||||
"on-finished": "2.4.1",
|
||||
"parseurl": "~1.3.3",
|
||||
"path-to-regexp": "0.1.7",
|
||||
"proxy-addr": "~2.0.7",
|
||||
"qs": "6.11.0",
|
||||
"range-parser": "~1.2.1",
|
||||
"safe-buffer": "5.2.1",
|
||||
"send": "0.18.0",
|
||||
"serve-static": "1.15.0",
|
||||
"setprototypeof": "1.2.0",
|
||||
"statuses": "2.0.1",
|
||||
"type-is": "~1.6.18",
|
||||
"utils-merge": "1.0.1",
|
||||
"vary": "~1.1.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/express/node_modules/debug": {
|
||||
"version": "2.6.9",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
|
||||
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
|
||||
"dependencies": {
|
||||
"ms": "2.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/express/node_modules/ms": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
|
||||
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
|
||||
},
|
||||
"node_modules/express/node_modules/qs": {
|
||||
"version": "6.11.0",
|
||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz",
|
||||
"integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==",
|
||||
"dependencies": {
|
||||
"side-channel": "^1.0.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.6"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/extend": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
|
||||
|
@ -335,6 +569,36 @@
|
|||
"resolved": "https://registry.npmjs.org/fast-text-encoding/-/fast-text-encoding-1.0.6.tgz",
|
||||
"integrity": "sha512-VhXlQgj9ioXCqGstD37E/HBeqEGV/qOD/kmbVG8h5xKBYvM1L3lR1Zn4555cQ8GkYbJa8aJSipLPndE1k6zK2w=="
|
||||
},
|
||||
"node_modules/finalhandler": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz",
|
||||
"integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==",
|
||||
"dependencies": {
|
||||
"debug": "2.6.9",
|
||||
"encodeurl": "~1.0.2",
|
||||
"escape-html": "~1.0.3",
|
||||
"on-finished": "2.4.1",
|
||||
"parseurl": "~1.3.3",
|
||||
"statuses": "2.0.1",
|
||||
"unpipe": "~1.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/finalhandler/node_modules/debug": {
|
||||
"version": "2.6.9",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
|
||||
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
|
||||
"dependencies": {
|
||||
"ms": "2.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/finalhandler/node_modules/ms": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
|
||||
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
|
||||
},
|
||||
"node_modules/follow-redirects": {
|
||||
"version": "1.15.2",
|
||||
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz",
|
||||
|
@ -367,29 +631,45 @@
|
|||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/forwarded": {
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz",
|
||||
"integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==",
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/fresh": {
|
||||
"version": "0.5.2",
|
||||
"resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz",
|
||||
"integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==",
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/function-bind": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz",
|
||||
"integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A=="
|
||||
},
|
||||
"node_modules/gaxios": {
|
||||
"version": "5.1.3",
|
||||
"resolved": "https://registry.npmjs.org/gaxios/-/gaxios-5.1.3.tgz",
|
||||
"integrity": "sha512-95hVgBRgEIRQQQHIbnxBXeHbW4TqFk4ZDJW7wmVtvYar72FdhRIo1UGOLS2eRAKCPEdPBWu+M7+A33D9CdX9rA==",
|
||||
"version": "5.1.0",
|
||||
"resolved": "https://registry.npmjs.org/gaxios/-/gaxios-5.1.0.tgz",
|
||||
"integrity": "sha512-aezGIjb+/VfsJtIcHGcBSerNEDdfdHeMros+RbYbGpmonKWQCOVOes0LVZhn1lDtIgq55qq0HaxymIoae3Fl/A==",
|
||||
"dependencies": {
|
||||
"extend": "^3.0.2",
|
||||
"https-proxy-agent": "^5.0.0",
|
||||
"is-stream": "^2.0.0",
|
||||
"node-fetch": "^2.6.9"
|
||||
"node-fetch": "^2.6.7"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/gcp-metadata": {
|
||||
"version": "5.3.0",
|
||||
"resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-5.3.0.tgz",
|
||||
"integrity": "sha512-FNTkdNEnBdlqF2oatizolQqNANMrcqJt6AAYt99B3y1aLLC8Hc5IOBb+ZnnzllodEEf6xMBp6wRcBbc16fa65w==",
|
||||
"version": "5.2.0",
|
||||
"resolved": "https://registry.npmjs.org/gcp-metadata/-/gcp-metadata-5.2.0.tgz",
|
||||
"integrity": "sha512-aFhhvvNycky2QyhG+dcfEdHBF0FRbYcf39s6WNHUDysKSrbJ5vuFbjydxBcmewtXeV248GP8dWT3ByPNxsyHCw==",
|
||||
"dependencies": {
|
||||
"gaxios": "^5.0.0",
|
||||
"json-bigint": "^1.0.0"
|
||||
|
@ -412,16 +692,16 @@
|
|||
}
|
||||
},
|
||||
"node_modules/google-auth-library": {
|
||||
"version": "8.9.0",
|
||||
"resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-8.9.0.tgz",
|
||||
"integrity": "sha512-f7aQCJODJFmYWN6PeNKzgvy9LI2tYmXnzpNDHEjG5sDNPgGb2FXQyTBnXeSH+PAtpKESFD+LmHw3Ox3mN7e1Fg==",
|
||||
"version": "8.7.0",
|
||||
"resolved": "https://registry.npmjs.org/google-auth-library/-/google-auth-library-8.7.0.tgz",
|
||||
"integrity": "sha512-1M0NG5VDIvJZEnstHbRdckLZESoJwguinwN8Dhae0j2ZKIQFIV63zxm6Fo6nM4xkgqUr2bbMtV5Dgo+Hy6oo0Q==",
|
||||
"dependencies": {
|
||||
"arrify": "^2.0.0",
|
||||
"base64-js": "^1.3.0",
|
||||
"ecdsa-sig-formatter": "^1.0.11",
|
||||
"fast-text-encoding": "^1.0.0",
|
||||
"gaxios": "^5.0.0",
|
||||
"gcp-metadata": "^5.3.0",
|
||||
"gcp-metadata": "^5.0.0",
|
||||
"gtoken": "^6.1.0",
|
||||
"jws": "^4.0.0",
|
||||
"lru-cache": "^6.0.0"
|
||||
|
@ -445,9 +725,9 @@
|
|||
}
|
||||
},
|
||||
"node_modules/googleapis": {
|
||||
"version": "122.0.0",
|
||||
"resolved": "https://registry.npmjs.org/googleapis/-/googleapis-122.0.0.tgz",
|
||||
"integrity": "sha512-n8Gt7j9LzSkhQEGPOrcLBKxllTvW/0v6oILuwszL/zqgelNsGJYXVqPJllgJJ6RM7maJ6T35UBeYqI6GQ/IlJg==",
|
||||
"version": "113.0.0",
|
||||
"resolved": "https://registry.npmjs.org/googleapis/-/googleapis-113.0.0.tgz",
|
||||
"integrity": "sha512-gsknEobaFuS+ACraCL3w22pAqeg1HselNhiSjcF5p2d2t2HB3QchbRDrFCfZ0wc4gKLYUBdmGzulCmRRL5qNXw==",
|
||||
"dependencies": {
|
||||
"google-auth-library": "^8.0.2",
|
||||
"googleapis-common": "^6.0.0"
|
||||
|
@ -515,6 +795,21 @@
|
|||
"he": "bin/he"
|
||||
}
|
||||
},
|
||||
"node_modules/http-errors": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz",
|
||||
"integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==",
|
||||
"dependencies": {
|
||||
"depd": "2.0.0",
|
||||
"inherits": "2.0.4",
|
||||
"setprototypeof": "1.2.0",
|
||||
"statuses": "2.0.1",
|
||||
"toidentifier": "1.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/https-proxy-agent": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz",
|
||||
|
@ -527,6 +822,39 @@
|
|||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/iconv-lite": {
|
||||
"version": "0.4.24",
|
||||
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
|
||||
"integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
|
||||
"dependencies": {
|
||||
"safer-buffer": ">= 2.1.2 < 3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/ics": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/ics/-/ics-3.1.0.tgz",
|
||||
"integrity": "sha512-O48TZKyLYagLlXoZwDmjetXc6SoT54wFkTu2MEYe7zse8kL+C/dgSynYCjRG1OTAv3iHtGtG0PWKG81LbcrKFA==",
|
||||
"dependencies": {
|
||||
"nanoid": "^3.1.23",
|
||||
"yup": "^0.32.9"
|
||||
}
|
||||
},
|
||||
"node_modules/inherits": {
|
||||
"version": "2.0.4",
|
||||
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
|
||||
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
|
||||
},
|
||||
"node_modules/ipaddr.js": {
|
||||
"version": "1.9.1",
|
||||
"resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz",
|
||||
"integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==",
|
||||
"engines": {
|
||||
"node": ">= 0.10"
|
||||
}
|
||||
},
|
||||
"node_modules/is-stream": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz",
|
||||
|
@ -565,6 +893,16 @@
|
|||
"safe-buffer": "^5.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/lodash": {
|
||||
"version": "4.17.21",
|
||||
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
|
||||
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
|
||||
},
|
||||
"node_modules/lodash-es": {
|
||||
"version": "4.17.21",
|
||||
"resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz",
|
||||
"integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw=="
|
||||
},
|
||||
"node_modules/lru-cache": {
|
||||
"version": "6.0.0",
|
||||
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
|
||||
|
@ -576,6 +914,46 @@
|
|||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/luxon": {
|
||||
"version": "3.3.0",
|
||||
"resolved": "https://registry.npmjs.org/luxon/-/luxon-3.3.0.tgz",
|
||||
"integrity": "sha512-An0UCfG/rSiqtAIiBPO0Y9/zAnHUZxAMiCpTd5h2smgsj7GGmcenvrvww2cqNA8/4A5ZrD1gJpHN2mIHZQF+Mg==",
|
||||
"engines": {
|
||||
"node": ">=12"
|
||||
}
|
||||
},
|
||||
"node_modules/media-typer": {
|
||||
"version": "0.3.0",
|
||||
"resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz",
|
||||
"integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==",
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/merge-descriptors": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz",
|
||||
"integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w=="
|
||||
},
|
||||
"node_modules/methods": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz",
|
||||
"integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==",
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/mime": {
|
||||
"version": "1.6.0",
|
||||
"resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
|
||||
"integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==",
|
||||
"bin": {
|
||||
"mime": "cli.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/mime-db": {
|
||||
"version": "1.52.0",
|
||||
"resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz",
|
||||
|
@ -603,45 +981,45 @@
|
|||
"node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/moment-timezone": {
|
||||
"version": "0.5.43",
|
||||
"resolved": "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.5.43.tgz",
|
||||
"integrity": "sha512-72j3aNyuIsDxdF1i7CEgV2FfxM1r6aaqJyLB2vwb33mXYyoyLly+F1zbWqhA3/bVIoJ4szlUoMbUnVdid32NUQ==",
|
||||
"dependencies": {
|
||||
"moment": "^2.29.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/ms": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
||||
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
|
||||
},
|
||||
"node_modules/node-cron": {
|
||||
"version": "3.0.3",
|
||||
"resolved": "https://registry.npmjs.org/node-cron/-/node-cron-3.0.3.tgz",
|
||||
"integrity": "sha512-dOal67//nohNgYWb+nWmg5dkFdIwDm8EpeGYMekPMrngV3637lqnX0lbUcCtgibHTz6SEz7DAIjKvKDFYCnO1A==",
|
||||
"dependencies": {
|
||||
"uuid": "8.3.2"
|
||||
"node_modules/nanoclone": {
|
||||
"version": "0.2.1",
|
||||
"resolved": "https://registry.npmjs.org/nanoclone/-/nanoclone-0.2.1.tgz",
|
||||
"integrity": "sha512-wynEP02LmIbLpcYw8uBKpcfF6dmg2vcpKqxeH5UcoKEYdExslsdUA4ugFauuaeYdTB76ez6gJW8XAZ6CgkXYxA=="
|
||||
},
|
||||
"node_modules/nanoid": {
|
||||
"version": "3.3.6",
|
||||
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz",
|
||||
"integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/ai"
|
||||
}
|
||||
],
|
||||
"bin": {
|
||||
"nanoid": "bin/nanoid.cjs"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.0.0"
|
||||
"node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/node-cron/node_modules/uuid": {
|
||||
"version": "8.3.2",
|
||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
|
||||
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==",
|
||||
"bin": {
|
||||
"uuid": "dist/bin/uuid"
|
||||
"node_modules/negotiator": {
|
||||
"version": "0.6.3",
|
||||
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz",
|
||||
"integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==",
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/node-fetch": {
|
||||
"version": "2.6.12",
|
||||
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.12.tgz",
|
||||
"integrity": "sha512-C/fGU2E8ToujUivIO0H+tpQ6HWo4eEmchoPIoXtxCrVghxdKq+QOHqEZW7tuP3KlV3bC8FRMO5nMCC7Zm1VP6g==",
|
||||
"version": "2.6.9",
|
||||
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.9.tgz",
|
||||
"integrity": "sha512-DJm/CJkZkRjKKj4Zi4BsKVZh3ValV5IR5s7LVZnW+6YMh0W1BfNA8XSs6DLMGYlId5F3KnA70uu2qepcR08Qqg==",
|
||||
"dependencies": {
|
||||
"whatwg-url": "^5.0.0"
|
||||
},
|
||||
|
@ -693,15 +1071,56 @@
|
|||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/on-finished": {
|
||||
"version": "2.4.1",
|
||||
"resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz",
|
||||
"integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==",
|
||||
"dependencies": {
|
||||
"ee-first": "1.1.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/parseurl": {
|
||||
"version": "1.3.3",
|
||||
"resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz",
|
||||
"integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==",
|
||||
"engines": {
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/path-to-regexp": {
|
||||
"version": "0.1.7",
|
||||
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz",
|
||||
"integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ=="
|
||||
},
|
||||
"node_modules/property-expr": {
|
||||
"version": "2.0.5",
|
||||
"resolved": "https://registry.npmjs.org/property-expr/-/property-expr-2.0.5.tgz",
|
||||
"integrity": "sha512-IJUkICM5dP5znhCckHSv30Q4b5/JA5enCtkRHYaOVOAocnH/1BQEYTC5NMfT3AVl/iXKdr3aqQbQn9DxyWknwA=="
|
||||
},
|
||||
"node_modules/proxy-addr": {
|
||||
"version": "2.0.7",
|
||||
"resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz",
|
||||
"integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==",
|
||||
"dependencies": {
|
||||
"forwarded": "0.2.0",
|
||||
"ipaddr.js": "1.9.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.10"
|
||||
}
|
||||
},
|
||||
"node_modules/proxy-from-env": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
|
||||
"integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg=="
|
||||
},
|
||||
"node_modules/qs": {
|
||||
"version": "6.11.2",
|
||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.11.2.tgz",
|
||||
"integrity": "sha512-tDNIz22aBzCDxLtVH++VnTfzxlfeK5CbqohpSqpJgj1Wg/cQbStNAz3NuqCs5vV+pjBsK4x4pN9HlVh7rcYRiA==",
|
||||
"version": "6.11.1",
|
||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.11.1.tgz",
|
||||
"integrity": "sha512-0wsrzgTz/kAVIeuxSjnpGC56rzYtr6JT/2BwEvMaPhFIoYa1aGO8LbzuU1R0uUYQkLpWBTOj0l/CLAJB64J6nQ==",
|
||||
"dependencies": {
|
||||
"side-channel": "^1.0.4"
|
||||
},
|
||||
|
@ -712,6 +1131,33 @@
|
|||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/range-parser": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
|
||||
"integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==",
|
||||
"engines": {
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/raw-body": {
|
||||
"version": "2.5.1",
|
||||
"resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.1.tgz",
|
||||
"integrity": "sha512-qqJBtEyVgS0ZmPGdCFPWJ3FreoqvG4MVQln/kCgF7Olq95IbOp0/BWyMwbdtn4VTvkM8Y7khCQ2Xgk/tcrCXig==",
|
||||
"dependencies": {
|
||||
"bytes": "3.1.2",
|
||||
"http-errors": "2.0.0",
|
||||
"iconv-lite": "0.4.24",
|
||||
"unpipe": "1.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/regenerator-runtime": {
|
||||
"version": "0.13.11",
|
||||
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz",
|
||||
"integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg=="
|
||||
},
|
||||
"node_modules/safe-buffer": {
|
||||
"version": "5.2.1",
|
||||
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
|
||||
|
@ -731,6 +1177,71 @@
|
|||
}
|
||||
]
|
||||
},
|
||||
"node_modules/safer-buffer": {
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
|
||||
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
|
||||
},
|
||||
"node_modules/send": {
|
||||
"version": "0.18.0",
|
||||
"resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz",
|
||||
"integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==",
|
||||
"dependencies": {
|
||||
"debug": "2.6.9",
|
||||
"depd": "2.0.0",
|
||||
"destroy": "1.2.0",
|
||||
"encodeurl": "~1.0.2",
|
||||
"escape-html": "~1.0.3",
|
||||
"etag": "~1.8.1",
|
||||
"fresh": "0.5.2",
|
||||
"http-errors": "2.0.0",
|
||||
"mime": "1.6.0",
|
||||
"ms": "2.1.3",
|
||||
"on-finished": "2.4.1",
|
||||
"range-parser": "~1.2.1",
|
||||
"statuses": "2.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/send/node_modules/debug": {
|
||||
"version": "2.6.9",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
|
||||
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
|
||||
"dependencies": {
|
||||
"ms": "2.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/send/node_modules/debug/node_modules/ms": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
|
||||
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A=="
|
||||
},
|
||||
"node_modules/send/node_modules/ms": {
|
||||
"version": "2.1.3",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
|
||||
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
|
||||
},
|
||||
"node_modules/serve-static": {
|
||||
"version": "1.15.0",
|
||||
"resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz",
|
||||
"integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==",
|
||||
"dependencies": {
|
||||
"encodeurl": "~1.0.2",
|
||||
"escape-html": "~1.0.3",
|
||||
"parseurl": "~1.3.3",
|
||||
"send": "0.18.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/setprototypeof": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz",
|
||||
"integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw=="
|
||||
},
|
||||
"node_modules/side-channel": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz",
|
||||
|
@ -744,22 +1255,50 @@
|
|||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/statuses": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz",
|
||||
"integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==",
|
||||
"engines": {
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/toidentifier": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz",
|
||||
"integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==",
|
||||
"engines": {
|
||||
"node": ">=0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/toposort": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/toposort/-/toposort-2.0.2.tgz",
|
||||
"integrity": "sha512-0a5EOkAUp8D4moMi2W8ZF8jcga7BgZd91O/yabJCFY8az+XSzeGyTKs0Aoo897iV1Nj6guFq8orWDS96z91oGg=="
|
||||
},
|
||||
"node_modules/tr46": {
|
||||
"version": "0.0.3",
|
||||
"resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
|
||||
"integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="
|
||||
},
|
||||
"node_modules/typescript": {
|
||||
"version": "5.0.3",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.0.3.tgz",
|
||||
"integrity": "sha512-xv8mOEDnigb/tN9PSMTwSEqAnUvkoXMQlicOb0IUVDBSQCgBSaAAROUZYy2IcUy5qU6XajK5jjjO7TMWqBTKZA==",
|
||||
"dev": true,
|
||||
"bin": {
|
||||
"tsc": "bin/tsc",
|
||||
"tsserver": "bin/tsserver"
|
||||
"node_modules/type-is": {
|
||||
"version": "1.6.18",
|
||||
"resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz",
|
||||
"integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==",
|
||||
"dependencies": {
|
||||
"media-typer": "0.3.0",
|
||||
"mime-types": "~2.1.24"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=12.20"
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/unpipe": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
|
||||
"integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==",
|
||||
"engines": {
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/url-template": {
|
||||
|
@ -767,6 +1306,14 @@
|
|||
"resolved": "https://registry.npmjs.org/url-template/-/url-template-2.0.8.tgz",
|
||||
"integrity": "sha512-XdVKMF4SJ0nP/O7XIPB0JwAEuT9lDIYnNsK8yGVe43y0AWoKeJNdv3ZNWh7ksJ6KqQFjOO6ox/VEitLnaVNufw=="
|
||||
},
|
||||
"node_modules/utils-merge": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz",
|
||||
"integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==",
|
||||
"engines": {
|
||||
"node": ">= 0.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/uuid": {
|
||||
"version": "9.0.0",
|
||||
"resolved": "https://registry.npmjs.org/uuid/-/uuid-9.0.0.tgz",
|
||||
|
@ -775,6 +1322,14 @@
|
|||
"uuid": "dist/bin/uuid"
|
||||
}
|
||||
},
|
||||
"node_modules/vary": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
|
||||
"integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==",
|
||||
"engines": {
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/webidl-conversions": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
|
||||
|
@ -793,6 +1348,23 @@
|
|||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
|
||||
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A=="
|
||||
},
|
||||
"node_modules/yup": {
|
||||
"version": "0.32.11",
|
||||
"resolved": "https://registry.npmjs.org/yup/-/yup-0.32.11.tgz",
|
||||
"integrity": "sha512-Z2Fe1bn+eLstG8DRR6FTavGD+MeAwyfmouhHsIUgaADz8jvFKbO/fXc2trJKZg+5EBjh4gGm3iU/t3onKlXHIg==",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.15.4",
|
||||
"@types/lodash": "^4.14.175",
|
||||
"lodash": "^4.17.21",
|
||||
"lodash-es": "^4.17.21",
|
||||
"nanoclone": "^0.2.1",
|
||||
"property-expr": "^2.0.4",
|
||||
"toposort": "^2.0.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=10"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
18
package.json
18
package.json
|
@ -1,23 +1,19 @@
|
|||
{
|
||||
"dependencies": {
|
||||
"axios": "^1.3.4",
|
||||
"cron": "^2.3.0",
|
||||
"dotenv": "^16.0.3",
|
||||
"googleapis": "^122.0.0",
|
||||
"express": "^4.18.2",
|
||||
"googleapis": "^113.0.0",
|
||||
"ics": "^3.1.0",
|
||||
"moment": "^2.29.4",
|
||||
"moment-timezone": "^0.5.43",
|
||||
"node-cron": "^3.0.3",
|
||||
"node-html-parser": "^6.1.5",
|
||||
"uuid": "^9.0.0"
|
||||
"node-html-parser": "^6.1.5"
|
||||
},
|
||||
"scripts": {
|
||||
"dev": "nodemon dist/index.js",
|
||||
"build": "npx tsc",
|
||||
"start": "node dist/index.js"
|
||||
"dev": "nodemon dist/index.js"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/express": "^4.17.17",
|
||||
"@types/node": "^18.15.5",
|
||||
"@types/node-cron": "^3.0.11",
|
||||
"typescript": "^5.0.3"
|
||||
"@types/node": "^18.15.5"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +0,0 @@
|
|||
#!/bin/bash
|
||||
docker stop haifareminder
|
||||
docker rm haifareminder
|
||||
docker run -p 3000:3000 -d --restart=unless-stopped --name haifareminder docker.io/kfda89/haifareminder
|
|
@ -1,106 +1,63 @@
|
|||
require("dotenv").config();
|
||||
require('dotenv').config();
|
||||
import axios from "axios";
|
||||
import { GoogleCalendarEvent } from "./types";
|
||||
import moment from "moment";
|
||||
import { parse } from 'node-html-parser';
|
||||
import moment from 'moment'; // require
|
||||
|
||||
// This calss will be the game source.
|
||||
// search for upcomming games
|
||||
|
||||
export default class GameSource {
|
||||
async getGamesFromHaifa(logger: Function): Promise<GoogleCalendarEvent[]> {
|
||||
console.log("Trying to get games from Haifa...");
|
||||
|
||||
try {
|
||||
// Get the current date and time in the required format
|
||||
const currentDate = moment().format("DD/MM/YYYY HH:mm");
|
||||
|
||||
// Construct the filters object with the current date
|
||||
const filters = {
|
||||
date: {
|
||||
startDate: currentDate,
|
||||
endDate: "",
|
||||
},
|
||||
league: "",
|
||||
session: "",
|
||||
gamesDirection: "1",
|
||||
};
|
||||
|
||||
// Encode the filters for the URL
|
||||
const filtersParam = encodeURIComponent(JSON.stringify(filters));
|
||||
|
||||
// Construct the API URL with the encoded filters
|
||||
const sourceUrl = `https://api.mhaifafc.com/api/content/games-lobby?filters=${filtersParam}&start=0&limit=20&sortDirection=ASC&app=web&lang=he`;
|
||||
|
||||
// Get the authorization token from environment variables
|
||||
const authorizationToken = process.env.HAIFA_API_AUTH_TOKEN;
|
||||
|
||||
// Set up the request headers
|
||||
const headers = {
|
||||
Accept: "*/*",
|
||||
"Accept-Language": "en-US,en;q=0.7",
|
||||
Authorization: `Bearer ${authorizationToken}`,
|
||||
"User-Agent": "Mozilla/5.0",
|
||||
Origin: "https://www.mhaifafc.com",
|
||||
Referer: "https://www.mhaifafc.com/",
|
||||
};
|
||||
|
||||
// Make the API request
|
||||
const response = await axios.get(sourceUrl, {
|
||||
headers,
|
||||
responseType: "json", // Ensure the response is parsed as JSON
|
||||
responseEncoding: "utf8", // Ensure UTF-8 encoding
|
||||
});
|
||||
|
||||
// Extract the games data from the response
|
||||
const gamesData = response.data.games.items;
|
||||
async getGamesFromHaifa(): Promise<GoogleCalendarEvent[]> {
|
||||
const sourceUrl = `https://mhaifafc.com/games?lang=en`;
|
||||
const result = await axios.get(sourceUrl);
|
||||
const parsedResult = parse(result.data.toString())
|
||||
const gameBoxs = parsedResult.querySelectorAll(".game-box");
|
||||
|
||||
const games: GoogleCalendarEvent[] = [];
|
||||
|
||||
// Loop through each game and construct the GoogleCalendarEvent objects
|
||||
for (const game of gamesData) {
|
||||
const gameDetails = game.gameDetails;
|
||||
const gameTime = gameDetails.gameTime; // ISO string
|
||||
const isFinalGameDate = gameDetails.isFinalGameDate;
|
||||
const gameLocation = gameDetails.gameLocation;
|
||||
for (let gameBox of gameBoxs) {
|
||||
|
||||
// Skip games without a game time
|
||||
if (!gameTime) continue;
|
||||
const teamsPlaying = gameBox.querySelectorAll(".team-name").map((team: any) => team.text);
|
||||
const regex = /[\r\n\s]+/g;
|
||||
const gameHeader = gameBox.querySelector(".game-header").text.replace(regex, " ").trim();
|
||||
const headerSplit = gameHeader.split(",");
|
||||
// In data, if there is no time, it means it's the last game for the calender
|
||||
const lastGameForCalender = headerSplit.length < 4;
|
||||
if (lastGameForCalender) break;
|
||||
|
||||
const hostTeam = game.hostTeam;
|
||||
const guestTeam = game.guestTeam;
|
||||
const gameDate = headerSplit[2].trim();
|
||||
const gameTime = headerSplit[3].trim();
|
||||
|
||||
// Get team names
|
||||
const hostTeamName = hostTeam.teamName;
|
||||
const guestTeamName = guestTeam.teamName;
|
||||
const startOriginal = moment(gameDate + gameTime, "DD/MM/YYYYHH:mm").format("DD/MM/YYYY HH:mm");
|
||||
const endOriginal = moment(gameDate + gameTime, "DD/MM/YYYYHH:mm").add(2, "hours").format("DD/MM/YYYY HH:mm");
|
||||
|
||||
const summary = `${hostTeamName} vs. ${guestTeamName}`;
|
||||
const start = [moment(startOriginal, 'DD/MM/YYYYHH:mm').year(), moment(startOriginal, 'DD/MM/YYYYHH:mm').month() + 1, moment(startOriginal, 'DD/MM/YYYYHH:mm').date(), moment(startOriginal, 'DD/MM/YYYYHH:mm').hour(), moment(startOriginal, 'DD/MM/YYYYHH:mm').minute()];
|
||||
const end = [moment(endOriginal, 'DD/MM/YYYYHH:mm').year(), moment(endOriginal, 'DD/MM/YYYYHH:mm').month() + 1, moment(endOriginal, 'DD/MM/YYYYHH:mm').date(), moment(endOriginal, 'DD/MM/YYYYHH:mm').hour(), moment(endOriginal, 'DD/MM/YYYYHH:mm').minute()]
|
||||
|
||||
// Include a note if the game date is not final
|
||||
let description = `${hostTeamName} vs. ${guestTeamName}`;
|
||||
if (!isFinalGameDate) {
|
||||
description += " (Date and time are subject to change)";
|
||||
}
|
||||
|
||||
// Calculate start and end times
|
||||
const startDateTime = moment(gameTime).toISOString();
|
||||
const endDateTime = moment(gameTime).add(2, "hours").toISOString();
|
||||
|
||||
// Add the event to the games array
|
||||
games.push({
|
||||
summary: summary,
|
||||
location: gameLocation,
|
||||
description: description,
|
||||
summary: 'Maccabi Haifa F.C.',
|
||||
location: "Sammy Ofer Stadium",
|
||||
description: `${teamsPlaying[0]} vs. ${teamsPlaying[1]}`,
|
||||
start: {
|
||||
dateTime: startDateTime,
|
||||
timeZone: "Asia/Jerusalem",
|
||||
dateTime: start,
|
||||
timeZone: 'Asia/Jerusalem'
|
||||
},
|
||||
end: {
|
||||
dateTime: endDateTime,
|
||||
timeZone: "Asia/Jerusalem",
|
||||
},
|
||||
});
|
||||
dateTime: end,
|
||||
timeZone: 'Asia/Jerusalem'
|
||||
}
|
||||
})
|
||||
}
|
||||
return games;
|
||||
} catch (error) {
|
||||
console.error(error);
|
||||
return [];
|
||||
}
|
||||
|
||||
getOpponentIndexByStadium(stadium: string) {
|
||||
if (stadium === "Sammy Ofer Stadium") {
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,97 +1,65 @@
|
|||
import { JWT } from "google-auth-library";
|
||||
import { google } from "googleapis";
|
||||
import { GoogleCalendarEvent } from "./types/index";
|
||||
import { JWT } from 'google-auth-library';
|
||||
import { google } from 'googleapis';
|
||||
import { GoogleCalendarEvent } from './types/index';
|
||||
|
||||
require("dotenv").config();
|
||||
require('dotenv').config();
|
||||
const env = process.env;
|
||||
|
||||
|
||||
export default class GoogleCalendar {
|
||||
gamesMap: any = {};
|
||||
clientSecret: string = env.GOOGLE_CLIENT_SECRET;
|
||||
clientId: string = env.GOOGLE_CLIENT_ID;
|
||||
calenderId: string = env.GOOGLE_CALENDAR_ID;
|
||||
calendar: any;
|
||||
clientEmail: string = env.GOOGLE_CLIENT_EMAIL;
|
||||
googlePrivateKey: string = env.GOOGLE_PRIVATE_KEY.replace(/\\n/g, "\n");
|
||||
googlePrivateKey: string = env.GOOGLE_PRIVATE_KEY.replace(/\\n/g, '\n');
|
||||
token: any;
|
||||
JWT_client: JWT;
|
||||
|
||||
async init() {
|
||||
console.log("INIT GOOGLE CALENDAR");
|
||||
console.log("INIT GOOGLE CALENDAR")
|
||||
const jwtClient = await this.authorize();
|
||||
this.calendar = google.calendar({ version: "v3", auth: jwtClient });
|
||||
this.calendar = google.calendar({ version: 'v3', auth: jwtClient });
|
||||
console.log("DONE INIT GOOGLE CALENDAR")
|
||||
}
|
||||
|
||||
async authorize() {
|
||||
console.log("AUTHORIZE GOOGLE CALENDAR");
|
||||
console.log("AUTHORIZE GOOGLE CALENDAR")
|
||||
this.JWT_client = new JWT({
|
||||
email: this.clientEmail,
|
||||
key: this.googlePrivateKey,
|
||||
scopes: ["https://www.googleapis.com/auth/calendar"],
|
||||
scopes: [
|
||||
'https://www.googleapis.com/auth/calendar',
|
||||
]
|
||||
});
|
||||
const { access_token } = await this.JWT_client.authorize();
|
||||
this.token = access_token;
|
||||
if (!this.token) {
|
||||
throw new Error("Failed to connect to google calendar");
|
||||
throw new Error('Failed to connect to google calendar');
|
||||
}
|
||||
console.log("GOOGLE CALENDAR AUTHORIZED SUCCESSFULLY");
|
||||
console.log("GOOGLE CALENDAR AUTHORIZED SUCCESSFULLY")
|
||||
return this.JWT_client;
|
||||
}
|
||||
|
||||
async updateNewEvent(upcomingEvents: GoogleCalendarEvent[]) {
|
||||
// console.log(upcomingEvents)
|
||||
setTimeout(async () => {
|
||||
upcomingEvents.forEach(async (event: GoogleCalendarEvent) => {
|
||||
console.log("UPDATE NEW EVENT", upcomingEvents);
|
||||
upcomingEvents.forEach((event: GoogleCalendarEvent) => {
|
||||
console.log("UPDATE NEW EVENT", upcomingEvents)
|
||||
const options = {
|
||||
auth: this.JWT_client,
|
||||
calendarId: this.calenderId,
|
||||
resource: {
|
||||
summary: event.summary,
|
||||
location: event.location,
|
||||
description: event.description,
|
||||
start: {
|
||||
dateTime: event.start.dateTime,
|
||||
timeZone: "Asia/Jerusalem",
|
||||
},
|
||||
end: { dateTime: event.end.dateTime, timeZone: "Asia/Jerusalem" },
|
||||
sendNotifications: true,
|
||||
},
|
||||
};
|
||||
await this.calendar.events.insert(
|
||||
options,
|
||||
function (err: any, event: any) {
|
||||
resource: event,
|
||||
}
|
||||
this.calendar.events.insert(options, function (err: any, event: any) {
|
||||
if (err) {
|
||||
console.log(
|
||||
"There was an error contacting the Calendar service: " + err
|
||||
);
|
||||
console.log('There was an error contacting the Calendar service: ' + err);
|
||||
return;
|
||||
}
|
||||
console.log(event.description + " created");
|
||||
}
|
||||
);
|
||||
console.log(event.description + ' created');
|
||||
});
|
||||
}, 3000);
|
||||
}
|
||||
|
||||
async isDuplicateEvent(startTime: string, endTime: string, title: string) {
|
||||
if (this.gamesMap[startTime]) {
|
||||
console.log("duplicate event");
|
||||
return true;
|
||||
}
|
||||
this.gamesMap[startTime] = true;
|
||||
console.log("checking for duplicate event");
|
||||
try {
|
||||
const response = await this.calendar.events.list({
|
||||
calendarId: this.calenderId,
|
||||
timeMin: startTime,
|
||||
timeMax: endTime,
|
||||
q: title, // Search for events with the same title
|
||||
});
|
||||
return response.data.items.length > 0;
|
||||
} catch (error) {
|
||||
console.error(error.message);
|
||||
return false;
|
||||
}
|
||||
})
|
||||
}, 3000)
|
||||
|
||||
}
|
||||
}
|
||||
|
|
43
src/Ics.ts
Normal file
43
src/Ics.ts
Normal file
|
@ -0,0 +1,43 @@
|
|||
import { GoogleCalendarEvent } from "./types";
|
||||
import * as ics from 'ics';
|
||||
|
||||
const uuid = require('uuid').v4();
|
||||
|
||||
|
||||
export default class Ics {
|
||||
|
||||
generateIcsOutputFromGames = (games: GoogleCalendarEvent[]) => {
|
||||
let output = [];
|
||||
games.forEach((game) => {
|
||||
output.push(this.generateIcsOutputFromGame(game));
|
||||
});
|
||||
|
||||
const { error, value } = ics.createEvents(output);
|
||||
if (error) {
|
||||
console.log(error);
|
||||
return '';
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
generateIcsOutputFromGame = (game: GoogleCalendarEvent) => {
|
||||
const { summary, location, description, start, end } = game;
|
||||
const icsEvent: ics.EventAttributes = {
|
||||
title: summary,
|
||||
description,
|
||||
location,
|
||||
start: [start.dateTime[0], start.dateTime[1], start.dateTime[2], start.dateTime[3], start.dateTime[4]],
|
||||
end: [end.dateTime[0], end.dateTime[1], end.dateTime[2], end.dateTime[3], end.dateTime[4]],
|
||||
url: 'https://mhaifafc.com/',
|
||||
status: 'CONFIRMED',
|
||||
busyStatus: 'BUSY',
|
||||
productId: 'https://mhaifafc.com/',
|
||||
recurrenceRule: '',
|
||||
attendees: [],
|
||||
alarms: [],
|
||||
categories: [],
|
||||
organizer: { name: 'Maccabi Haifa F.C.', email: '' }
|
||||
};
|
||||
return icsEvent;
|
||||
}
|
||||
}
|
0
src/WebServer.ts
Normal file
0
src/WebServer.ts
Normal file
104
src/index.ts
104
src/index.ts
|
@ -1,74 +1,64 @@
|
|||
import GameSource from "./GameSource";
|
||||
import GoogleCalendar from "./GoogleCalendar";
|
||||
import env from "dotenv";
|
||||
import cron from 'node-cron';
|
||||
import fs from 'fs'; // Importing fs for logging
|
||||
import GoogleCalendar from './GoogleCalendar';
|
||||
import GameSource from './GameSource';
|
||||
import fs from 'fs';
|
||||
import Ics from './Ics';
|
||||
import express from 'express'
|
||||
|
||||
|
||||
const CronJob = require('cron').CronJob;
|
||||
|
||||
env.config();
|
||||
|
||||
class App {
|
||||
gameSource: GameSource;
|
||||
googleToken: string;
|
||||
googleCalendar: GoogleCalendar;
|
||||
gameSource: GameSource;
|
||||
ics: Ics;
|
||||
googleToken: string;
|
||||
|
||||
constructor() {
|
||||
this.gameSource = new GameSource();
|
||||
this.googleCalendar = new GoogleCalendar();
|
||||
this.gameSource = new GameSource();
|
||||
this.ics = new Ics();
|
||||
|
||||
}
|
||||
|
||||
async startCronJob() {
|
||||
this.writeLog('START Haifa Reminder'); // Log when the cron job starts
|
||||
const newGamesAdded = [];
|
||||
async init() {
|
||||
console.log("INIT APP")
|
||||
await this.googleCalendar.init();
|
||||
try {
|
||||
const games = await this.gameSource.getGamesFromHaifa(this.writeLog);
|
||||
for (const game of games) {
|
||||
const isDuplicateEvent = await this.googleCalendar.isDuplicateEvent(
|
||||
game.start.dateTime,
|
||||
game.end.dateTime,
|
||||
game.summary
|
||||
);
|
||||
console.log(game)
|
||||
if (!isDuplicateEvent) {
|
||||
newGamesAdded.push(game);
|
||||
console.log("Event does not exist");
|
||||
await this.googleCalendar.updateNewEvent([game]);
|
||||
} else {
|
||||
console.log("Event already exists");
|
||||
}
|
||||
}
|
||||
|
||||
if (newGamesAdded.length > 0) {
|
||||
console.log("New games added:", newGamesAdded);
|
||||
} else {
|
||||
console.log("No new games were Added!");
|
||||
}
|
||||
this.writeLog('Successfully ran project');
|
||||
} catch (error) {
|
||||
this.writeLog("Error in cron job:" + error.message);
|
||||
} finally {
|
||||
this.writeLog('END CRON JOB'); // Log when the cron job ends
|
||||
}
|
||||
}
|
||||
|
||||
writeLog(message) {
|
||||
const timestamp = new Date().toISOString();
|
||||
const logMessage = `${timestamp} - ${message}\n`;
|
||||
// Write to log file synchronously
|
||||
fs.appendFileSync('cron.log', logMessage);
|
||||
console.log(logMessage); // Optional: also log to console
|
||||
async getNewGamesAndUpdateCalendar() {
|
||||
console.log("GET NEW GAMES AND UPDATE CALENDAR")
|
||||
const games = await this.gameSource.getGamesFromHaifa();
|
||||
this.googleCalendar.updateNewEvent(games);
|
||||
}
|
||||
}
|
||||
|
||||
const app = new App();
|
||||
|
||||
cron.schedule('* * * * *', () => {
|
||||
console.log('Running startCronJob at 10:00 AM Jerusalem time');
|
||||
app.startCronJob().catch((error) => {
|
||||
console.error("Error in scheduled cron job:", error.message);
|
||||
app.writeLog(`ERROR: ${error.message}`); // Log any errors
|
||||
});
|
||||
}, {
|
||||
scheduled: true,
|
||||
timezone: "Asia/Jerusalem"
|
||||
});
|
||||
console.log("Declaring Cron Job")
|
||||
|
||||
const cron = "0 10 * * *" // every day at 10:00
|
||||
|
||||
const job = new CronJob(
|
||||
"* * * * *",
|
||||
async () => {
|
||||
console.log("START")
|
||||
const outputFileLocation = 'maccabi-haifa-fc.ics';
|
||||
const games = await app.gameSource.getGamesFromHaifa();
|
||||
const icsEvents = app.ics.generateIcsOutputFromGames(games);
|
||||
fs.writeFileSync(outputFileLocation, icsEvents);
|
||||
},
|
||||
null,
|
||||
true,
|
||||
'Asia/Jerusalem'
|
||||
);
|
||||
|
||||
|
||||
|
||||
|
||||
const webServer = express();
|
||||
webServer.use(express.static('public'))
|
||||
|
||||
webServer.listen(3000, () => {
|
||||
console.log('Example app listening on port 3000!')
|
||||
})
|
|
@ -3,11 +3,11 @@ export interface GoogleCalendarEvent {
|
|||
location: string;
|
||||
description: string;
|
||||
start: {
|
||||
dateTime: string;
|
||||
dateTime: number[];
|
||||
timeZone: string;
|
||||
};
|
||||
end: {
|
||||
dateTime: string;
|
||||
dateTime: number[];
|
||||
timeZone: string;
|
||||
};
|
||||
}
|
3
start.sh
3
start.sh
|
@ -1,3 +0,0 @@
|
|||
#!/bin/bash
|
||||
docker run -p 3000:3000 -d --restart=unless-stopped --name haifareminder docker.io/kfda89/haifareminder
|
||||
|
|
@ -7,8 +7,5 @@
|
|||
"moduleResolution": "node",
|
||||
"outDir": "./dist",
|
||||
"rootDir": "./src"
|
||||
},
|
||||
"include": [
|
||||
"src/**/*"
|
||||
]
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue