diff --git a/src/ms-ics-fix/Dockerfile b/src/ms-ics-fix/Dockerfile index 089d464..0945976 100644 --- a/src/ms-ics-fix/Dockerfile +++ b/src/ms-ics-fix/Dockerfile @@ -8,7 +8,7 @@ COPY index.js . COPY package.json . COPY pnpm-lock.yaml . -RUN pnpm i +RUN pnpm i --prod EXPOSE 3000 CMD ["node", "index.js"] diff --git a/src/ms-ics-fix/README.md b/src/ms-ics-fix/README.md index 046c884..f1932f0 100644 --- a/src/ms-ics-fix/README.md +++ b/src/ms-ics-fix/README.md @@ -15,20 +15,17 @@ BEGIN:VCALENDAR VERSION:2.0 PRODID:-//Microsoft Corporation//Outlook 16.0 MIMEDIR//EN METHOD:PUBLISH -# Definition of multiple VTIMEZONE components in one file can lead to conflicts BEGIN:VTIMEZONE -TZID:Romance Standard Time # Non-standard and ambiguous TZID -# ... +TZID:Romance Standard Time END:VTIMEZONE -# Another timezone definition which can confuse interpretation BEGIN:VTIMEZONE TZID:UTC # ... END:VTIMEZONE BEGIN:VEVENT # Event uses a different timezone, not properly linked to any defined VTIMEZONE -DTSTART;TZID=Romance Standard Time:20240425T113000 # Uses TZID without proper global reference, -DTEND;TZID=Romance Standard Time:20240425T120000 # likely to fail in non-Microsoft apps +DTSTART;TZID=Central Europe Standard Time:20240425T113000 # Uses TZID without proper global reference, +DTEND;TZID=Central Europe Standard Time:20240425T120000 # likely to fail in non-Microsoft apps # ... END:VEVENT END:VCALENDAR @@ -43,7 +40,7 @@ And this is not a one time issue, see: - [answers.microsoft.com/[...]/published-calendar-events-show-incorrect-time-when](https://answers.microsoft.com/en-us/outlook_com/forum/all/published-calendar-events-show-incorrect-time-when/c8e60444-1d02-45e1-a356-486f5a9370fc) - [answers.microsoft.com/[...]/incorrect-timezone-when-subscribed-to-calendar](https://answers.microsoft.com/en-us/outlook_com/forum/all/incorrect-timezone-when-subscribed-to-calendar/c20444c1-df78-471d-9524-702f448c7c63) -To fix this, this tool will work like an ICS proxy, which will fix the timezone issue. +To fix this, this tool will work like an ICS proxy, which will re- parse the ICS file. ## Environment Variables @@ -52,6 +49,8 @@ To fix this, this tool will work like an ICS proxy, which will fix the timezone | `ICS_ON_DEMAND` | boolean | `false` | Whether to enable the on demand mode. | | `ICS_{counter}_URL` | string | `null` | The URL of the ICS file to serve. | | `ICS_{counter}_PATH` | string? | `null` | The path to serve the ICS file. | +| `REPLACE_{counter}_FROM` | string | `null` | The string to replace in the ICS file. | +| `REPLACE_{counter}_TO` | string | `null` | The string to replace the string from with. | ## On Demand Mode @@ -79,6 +78,9 @@ services: ICS_0_PATH: "your-new-filename-which-will-be-served.ics" ICS_1_URL: "https://example.com/calendar2.ics" # ... + REPLACE_0_FROM: "Romance Standard Time" + REPLACE_0_TO: "Europe/Paris" + # ... ``` This will result in to paths being published: diff --git a/src/ms-ics-fix/index.js b/src/ms-ics-fix/index.js index ea63bc6..f664a2c 100644 --- a/src/ms-ics-fix/index.js +++ b/src/ms-ics-fix/index.js @@ -6,7 +6,8 @@ const port = 3000 // Base config object const config = { onDemand: process.env.ICS_ON_DEMAND === 'true', - ics: [] + ics: [], + replace: [], } // Parse ICS configurations from environment variables @@ -19,6 +20,15 @@ while (process.env[`ICS_${counter}_URL`]) { counter++ } +counter = 0 +while (process.env[`REPLACE_${counter}_FROM`]) { + config.replace.push({ + from: process.env[`REPLACE_${counter}_FROM`], + to: process.env[`REPLACE_${counter}_TO`], + }) + counter++ +} + // Validate and normalize ICS configurations config.ics = (() => { const n = [] @@ -55,12 +65,23 @@ async function cache(url, fun) { // The little magic, microsoft is too lazy to implement... async function doIcsFix(url) { return await cache(url, async () => { - const raw = await fetch(url).then(res => res.text()) + const raw = await (async () => { + let t = await fetch(url).then(res => res.text()) + for (const r of config.replace) { + t = t.replaceAll(r.from, r.to) + } + return t + })() const obj = await ical.async.parseICS(raw) const events = [] for (const key in obj) { const event = obj[key] - if (!event.uid) continue + if (event.type !== 'VEVENT') continue + if (!event.uid) { + console.warn('Event without UID:', event) + continue + } + console.log(event.summary) const getTime = (x, t) => { try { const d = new Date(t) @@ -74,15 +95,26 @@ async function doIcsFix(url) { } catch (ignored) {} return [] } + const getString = (x, t) => { + if (!t || t === '') return [] + return [`${x}:${t.toString().replaceAll('\r\n', ' ').replaceAll('\n', ' ')}`] + } events.push([ `BEGIN:VEVENT`, `UID:${event.uid}`, ...getTime('DTSTART', event.start), ...getTime('DTEND', event.end), ...getTime('DTSTAMP', event.start), - `STATUS:${(event.status || '').toString().replaceAll('\n', ' ')}`, - `LOCATION:${(event.location || '').toString().replaceAll('\n', ' ')}`, - `SUMMARY:${(event.summary || '').toString().replaceAll('\n', ' ')}`, + ...getString('STATUS', event.status), + ...getString('SUMMARY', event.summary), + ...getString('LOCATION', event.location), + ...getString('DESCRIPTION', event.description), + ...getString('URL', event.url), + ...getString('PRIORITY', event.priority), + ...getString('CLASS', event.class), + ...getString('SEQUENCE', event.sequence), + ...getString('TRANSP', event.transparency), + ...getString('RRULE', event.rrule), `END:VEVENT` ].join('\n')) } @@ -94,10 +126,16 @@ async function doIcsFix(url) { ( raw.split('\n').find(l => l.startsWith('X-WR-CALNAME:') ) || ':Missing Calendar Name!').split(':')[1] - ).replaceAll('\n', ' ')}`, - events.join('\n'), + ).replaceAll('\r\n', ' ').replaceAll('\n', ' ')}`, + ...events.filter(e => e), `END:VCALENDAR` - ].join('\n').replaceAll('\n', '\r\n') + ] + .join('\n') + .split('\n') + .map(x => x.length > 75 ? x.match(/.{1,75}/g).join('\n ') : x) + .join('\n') + .replaceAll('\r\n', '\n') + .replaceAll('\n', '\r\n') }) } @@ -106,7 +144,13 @@ app.get('*', (req, res) => { const path = req.path.substring(1) const sendICS = (string) => { - res.set('Content-Type', 'text/calendar') + // if req params contains as-text, send as text + if (req.query['as-text']) { + res.set('Content-Type', 'text/plain') + } else { + res.set('Content-Disposition', 'attachment; filename="calendar.ics"') + res.set('Content-Type', 'text/calendar') + } res.send(string) } diff --git a/src/ms-ics-fix/package.json b/src/ms-ics-fix/package.json index 137a46b..7b4c522 100644 --- a/src/ms-ics-fix/package.json +++ b/src/ms-ics-fix/package.json @@ -1,6 +1,12 @@ { + "scripts": { + "dev": "ICS_ON_DEMAND=true nodemon node index.js" + }, "dependencies": { "express": "^4.19.2", "node-ical": "^0.18.0" + }, + "devDependencies": { + "nodemon": "^3.1.0" } } diff --git a/src/ms-ics-fix/pnpm-lock.yaml b/src/ms-ics-fix/pnpm-lock.yaml index bc977f5..2eeb47b 100644 --- a/src/ms-ics-fix/pnpm-lock.yaml +++ b/src/ms-ics-fix/pnpm-lock.yaml @@ -14,13 +14,24 @@ importers: node-ical: specifier: ^0.18.0 version: 0.18.0 + devDependencies: + nodemon: + specifier: ^3.1.0 + version: 3.1.0 packages: + abbrev@1.1.1: + resolution: {integrity: sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==} + accepts@1.3.8: resolution: {integrity: sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==} engines: {node: '>= 0.6'} + anymatch@3.1.3: + resolution: {integrity: sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==} + engines: {node: '>= 8'} + array-flatten@1.1.1: resolution: {integrity: sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==} @@ -30,10 +41,24 @@ packages: axios@1.6.7: resolution: {integrity: sha512-/hDJGff6/c7u0hDkvkGxR/oy6CbCs8ziCsC7SqmhjfozqiJGc8Z11wrv9z9lYfY4K8l+H9TpjcMDX0xOZmx+RA==} + balanced-match@1.0.2: + resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} + + binary-extensions@2.3.0: + resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} + engines: {node: '>=8'} + body-parser@1.20.2: resolution: {integrity: sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==} engines: {node: '>= 0.8', npm: 1.2.8000 || >= 1.4.16} + brace-expansion@1.1.11: + resolution: {integrity: sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==} + + braces@3.0.2: + resolution: {integrity: sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==} + engines: {node: '>=8'} + bytes@3.1.2: resolution: {integrity: sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==} engines: {node: '>= 0.8'} @@ -42,10 +67,17 @@ packages: resolution: {integrity: sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==} engines: {node: '>= 0.4'} + chokidar@3.6.0: + resolution: {integrity: sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==} + engines: {node: '>= 8.10.0'} + combined-stream@1.0.8: resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==} engines: {node: '>= 0.8'} + concat-map@0.0.1: + resolution: {integrity: sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==} + content-disposition@0.5.4: resolution: {integrity: sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==} engines: {node: '>= 0.6'} @@ -69,6 +101,15 @@ packages: supports-color: optional: true + debug@4.3.4: + resolution: {integrity: sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==} + engines: {node: '>=6.0'} + peerDependencies: + supports-color: '*' + peerDependenciesMeta: + supports-color: + optional: true + define-data-property@1.1.4: resolution: {integrity: sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==} engines: {node: '>= 0.4'} @@ -111,6 +152,10 @@ packages: resolution: {integrity: sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==} engines: {node: '>= 0.10.0'} + fill-range@7.0.1: + resolution: {integrity: sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==} + engines: {node: '>=8'} + finalhandler@1.2.0: resolution: {integrity: sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==} engines: {node: '>= 0.8'} @@ -136,6 +181,11 @@ packages: resolution: {integrity: sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==} engines: {node: '>= 0.6'} + fsevents@2.3.3: + resolution: {integrity: sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==} + engines: {node: ^8.16.0 || ^10.6.0 || >=11.0.0} + os: [darwin] + function-bind@1.1.2: resolution: {integrity: sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==} @@ -143,9 +193,17 @@ packages: resolution: {integrity: sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==} engines: {node: '>= 0.4'} + glob-parent@5.1.2: + resolution: {integrity: sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==} + engines: {node: '>= 6'} + gopd@1.0.1: resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==} + has-flag@3.0.0: + resolution: {integrity: sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==} + engines: {node: '>=4'} + has-property-descriptors@1.0.2: resolution: {integrity: sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==} @@ -169,6 +227,9 @@ packages: resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==} engines: {node: '>=0.10.0'} + ignore-by-default@1.0.1: + resolution: {integrity: sha512-Ius2VYcGNk7T90CppJqcIkS5ooHUZyIQK+ClZfMfMNFEF9VSE73Fq+906u/CWu92x4gzZMWOwfFYckPObzdEbA==} + inherits@2.0.4: resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==} @@ -176,6 +237,26 @@ packages: resolution: {integrity: sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==} engines: {node: '>= 0.10'} + is-binary-path@2.1.0: + resolution: {integrity: sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==} + engines: {node: '>=8'} + + is-extglob@2.1.1: + resolution: {integrity: sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==} + engines: {node: '>=0.10.0'} + + is-glob@4.0.3: + resolution: {integrity: sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==} + engines: {node: '>=0.10.0'} + + is-number@7.0.0: + resolution: {integrity: sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==} + engines: {node: '>=0.12.0'} + + lru-cache@6.0.0: + resolution: {integrity: sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==} + engines: {node: '>=10'} + media-typer@0.3.0: resolution: {integrity: sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==} engines: {node: '>= 0.6'} @@ -200,6 +281,9 @@ packages: engines: {node: '>=4'} hasBin: true + minimatch@3.1.2: + resolution: {integrity: sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==} + moment-timezone@0.5.45: resolution: {integrity: sha512-HIWmqA86KcmCAhnMAN0wuDOARV/525R2+lOLotuGFzn4HO+FH+/645z2wx0Dt3iDv6/p61SIvKnDstISainhLQ==} @@ -209,6 +293,9 @@ packages: ms@2.0.0: resolution: {integrity: sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==} + ms@2.1.2: + resolution: {integrity: sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==} + ms@2.1.3: resolution: {integrity: sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==} @@ -219,6 +306,19 @@ packages: node-ical@0.18.0: resolution: {integrity: sha512-FrOUPztjw9OUgSB9o/ffhl86BiVClQTut97C2NqCwKIgOAcKPEw5UQMuSuNJO/Y4hqTyJdKZh2TCqNHQnE9YFg==} + nodemon@3.1.0: + resolution: {integrity: sha512-xqlktYlDMCepBJd43ZQhjWwMw2obW/JRvkrLxq5RCNcuDDX1DbcPT+qT1IlIIdf+DhnWs90JpTMe+Y5KxOchvA==} + engines: {node: '>=10'} + hasBin: true + + nopt@1.0.10: + resolution: {integrity: sha512-NWmpvLSqUrgrAC9HCuxEvb+PSloHpqVu+FqcO4eeF2h5qYRhA7ev6KvelyQAKtegUbC6RypJnlEOhd8vloNKYg==} + hasBin: true + + normalize-path@3.0.0: + resolution: {integrity: sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==} + engines: {node: '>=0.10.0'} + object-inspect@1.13.1: resolution: {integrity: sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==} @@ -233,6 +333,10 @@ packages: path-to-regexp@0.1.7: resolution: {integrity: sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==} + picomatch@2.3.1: + resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} + engines: {node: '>=8.6'} + proxy-addr@2.0.7: resolution: {integrity: sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==} engines: {node: '>= 0.10'} @@ -240,6 +344,9 @@ packages: proxy-from-env@1.1.0: resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} + pstree.remy@1.1.8: + resolution: {integrity: sha512-77DZwxQmxKnu3aR542U+X8FypNzbfJ+C5XQDk3uWjWxn6151aIMGthWYRXTqT1E5oJvg+ljaa2OJi+VfvCOQ8w==} + qs@6.11.0: resolution: {integrity: sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==} engines: {node: '>=0.6'} @@ -252,6 +359,10 @@ packages: resolution: {integrity: sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==} engines: {node: '>= 0.8'} + readdirp@3.6.0: + resolution: {integrity: sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==} + engines: {node: '>=8.10.0'} + rrule@2.8.1: resolution: {integrity: sha512-hM3dHSBMeaJ0Ktp7W38BJZ7O1zOgaFEsn41PDk+yHoEtfLV+PoJt9E9xAlZiWgf/iqEqionN0ebHFZIDAp+iGw==} @@ -261,6 +372,11 @@ packages: safer-buffer@2.1.2: resolution: {integrity: sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==} + semver@7.6.0: + resolution: {integrity: sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==} + engines: {node: '>=10'} + hasBin: true + send@0.18.0: resolution: {integrity: sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==} engines: {node: '>= 0.8.0'} @@ -280,14 +396,30 @@ packages: resolution: {integrity: sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==} engines: {node: '>= 0.4'} + simple-update-notifier@2.0.0: + resolution: {integrity: sha512-a2B9Y0KlNXl9u/vsW6sTIu9vGEpfKu2wRV6l1H3XEas/0gUIzGzBoP/IouTcUQbm9JWZLH3COxyn03TYlFax6w==} + engines: {node: '>=10'} + statuses@2.0.1: resolution: {integrity: sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==} engines: {node: '>= 0.8'} + supports-color@5.5.0: + resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==} + engines: {node: '>=4'} + + to-regex-range@5.0.1: + resolution: {integrity: sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==} + engines: {node: '>=8.0'} + toidentifier@1.0.1: resolution: {integrity: sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==} engines: {node: '>=0.6'} + touch@3.1.0: + resolution: {integrity: sha512-WBx8Uy5TLtOSRtIq+M03/sKDrXCLHxwDcquSP2c43Le03/9serjQBIztjRz6FkJez9D/hleyAXTBGLwwZUw9lA==} + hasBin: true + tslib@2.6.2: resolution: {integrity: sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==} @@ -295,6 +427,9 @@ packages: resolution: {integrity: sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==} engines: {node: '>= 0.6'} + undefsafe@2.0.5: + resolution: {integrity: sha512-WxONCrssBM8TSPRqN5EmsjVrsv4A8X12J4ArBiiayv3DyyG3ZlIg6yysuuSYdZsVz3TKcTg2fd//Ujd4CHV1iA==} + unpipe@1.0.0: resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} engines: {node: '>= 0.8'} @@ -311,13 +446,23 @@ packages: resolution: {integrity: sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==} engines: {node: '>= 0.8'} + yallist@4.0.0: + resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} + snapshots: + abbrev@1.1.1: {} + accepts@1.3.8: dependencies: mime-types: 2.1.35 negotiator: 0.6.3 + anymatch@3.1.3: + dependencies: + normalize-path: 3.0.0 + picomatch: 2.3.1 + array-flatten@1.1.1: {} asynckit@0.4.0: {} @@ -330,6 +475,10 @@ snapshots: transitivePeerDependencies: - debug + balanced-match@1.0.2: {} + + binary-extensions@2.3.0: {} + body-parser@1.20.2: dependencies: bytes: 3.1.2 @@ -347,6 +496,15 @@ snapshots: transitivePeerDependencies: - supports-color + brace-expansion@1.1.11: + dependencies: + balanced-match: 1.0.2 + concat-map: 0.0.1 + + braces@3.0.2: + dependencies: + fill-range: 7.0.1 + bytes@3.1.2: {} call-bind@1.0.7: @@ -357,10 +515,24 @@ snapshots: get-intrinsic: 1.2.4 set-function-length: 1.2.2 + chokidar@3.6.0: + dependencies: + anymatch: 3.1.3 + braces: 3.0.2 + glob-parent: 5.1.2 + is-binary-path: 2.1.0 + is-glob: 4.0.3 + normalize-path: 3.0.0 + readdirp: 3.6.0 + optionalDependencies: + fsevents: 2.3.3 + combined-stream@1.0.8: dependencies: delayed-stream: 1.0.0 + concat-map@0.0.1: {} + content-disposition@0.5.4: dependencies: safe-buffer: 5.2.1 @@ -375,6 +547,12 @@ snapshots: dependencies: ms: 2.0.0 + debug@4.3.4(supports-color@5.5.0): + dependencies: + ms: 2.1.2 + optionalDependencies: + supports-color: 5.5.0 + define-data-property@1.1.4: dependencies: es-define-property: 1.0.0 @@ -437,6 +615,10 @@ snapshots: transitivePeerDependencies: - supports-color + fill-range@7.0.1: + dependencies: + to-regex-range: 5.0.1 + finalhandler@1.2.0: dependencies: debug: 2.6.9 @@ -461,6 +643,9 @@ snapshots: fresh@0.5.2: {} + fsevents@2.3.3: + optional: true + function-bind@1.1.2: {} get-intrinsic@1.2.4: @@ -471,10 +656,16 @@ snapshots: has-symbols: 1.0.3 hasown: 2.0.2 + glob-parent@5.1.2: + dependencies: + is-glob: 4.0.3 + gopd@1.0.1: dependencies: get-intrinsic: 1.2.4 + has-flag@3.0.0: {} + has-property-descriptors@1.0.2: dependencies: es-define-property: 1.0.0 @@ -499,10 +690,28 @@ snapshots: dependencies: safer-buffer: 2.1.2 + ignore-by-default@1.0.1: {} + inherits@2.0.4: {} ipaddr.js@1.9.1: {} + is-binary-path@2.1.0: + dependencies: + binary-extensions: 2.3.0 + + is-extglob@2.1.1: {} + + is-glob@4.0.3: + dependencies: + is-extglob: 2.1.1 + + is-number@7.0.0: {} + + lru-cache@6.0.0: + dependencies: + yallist: 4.0.0 + media-typer@0.3.0: {} merge-descriptors@1.0.1: {} @@ -517,6 +726,10 @@ snapshots: mime@1.6.0: {} + minimatch@3.1.2: + dependencies: + brace-expansion: 1.1.11 + moment-timezone@0.5.45: dependencies: moment: 2.30.1 @@ -525,6 +738,8 @@ snapshots: ms@2.0.0: {} + ms@2.1.2: {} + ms@2.1.3: {} negotiator@0.6.3: {} @@ -538,6 +753,25 @@ snapshots: transitivePeerDependencies: - debug + nodemon@3.1.0: + dependencies: + chokidar: 3.6.0 + debug: 4.3.4(supports-color@5.5.0) + ignore-by-default: 1.0.1 + minimatch: 3.1.2 + pstree.remy: 1.1.8 + semver: 7.6.0 + simple-update-notifier: 2.0.0 + supports-color: 5.5.0 + touch: 3.1.0 + undefsafe: 2.0.5 + + nopt@1.0.10: + dependencies: + abbrev: 1.1.1 + + normalize-path@3.0.0: {} + object-inspect@1.13.1: {} on-finished@2.4.1: @@ -548,6 +782,8 @@ snapshots: path-to-regexp@0.1.7: {} + picomatch@2.3.1: {} + proxy-addr@2.0.7: dependencies: forwarded: 0.2.0 @@ -555,6 +791,8 @@ snapshots: proxy-from-env@1.1.0: {} + pstree.remy@1.1.8: {} + qs@6.11.0: dependencies: side-channel: 1.0.6 @@ -568,6 +806,10 @@ snapshots: iconv-lite: 0.4.24 unpipe: 1.0.0 + readdirp@3.6.0: + dependencies: + picomatch: 2.3.1 + rrule@2.8.1: dependencies: tslib: 2.6.2 @@ -576,6 +818,10 @@ snapshots: safer-buffer@2.1.2: {} + semver@7.6.0: + dependencies: + lru-cache: 6.0.0 + send@0.18.0: dependencies: debug: 2.6.9 @@ -621,10 +867,26 @@ snapshots: get-intrinsic: 1.2.4 object-inspect: 1.13.1 + simple-update-notifier@2.0.0: + dependencies: + semver: 7.6.0 + statuses@2.0.1: {} + supports-color@5.5.0: + dependencies: + has-flag: 3.0.0 + + to-regex-range@5.0.1: + dependencies: + is-number: 7.0.0 + toidentifier@1.0.1: {} + touch@3.1.0: + dependencies: + nopt: 1.0.10 + tslib@2.6.2: {} type-is@1.6.18: @@ -632,6 +894,8 @@ snapshots: media-typer: 0.3.0 mime-types: 2.1.35 + undefsafe@2.0.5: {} + unpipe@1.0.0: {} utils-merge@1.0.1: {} @@ -639,3 +903,5 @@ snapshots: uuid@9.0.1: {} vary@1.1.2: {} + + yallist@4.0.0: {}