diff --git a/.eslintrc.js b/.eslintrc.js index a06aa4f..a565645 100644 --- a/.eslintrc.js +++ b/.eslintrc.js @@ -28,6 +28,7 @@ module.exports = { google: true, rome: true, bootstrap: true, + IcecastMetadataPlayer: true, }, rules: { 'ember/no-jquery': 'off', diff --git a/app/components/icecast-player.hbs b/app/components/icecast-player.hbs new file mode 100644 index 0000000..d8c7963 --- /dev/null +++ b/app/components/icecast-player.hbs @@ -0,0 +1,7 @@ +
+

+ +
+
diff --git a/app/components/icecast-player.js b/app/components/icecast-player.js new file mode 100644 index 0000000..32ae8fc --- /dev/null +++ b/app/components/icecast-player.js @@ -0,0 +1,25 @@ +import Component from '@glimmer/component'; +import { action } from '@ember/object'; + +export default class IcecastPlayerComponent extends Component { + @action + initializePlayer(stream) { + const audioElement = document.getElementById('icecast-audio'); + const metadataEl = document.getElementById('icecast-metadata'); + + const onMetadata = (metadata) => { + metadataEl.innerHTML = `Now Playing: ${metadata['StreamTitle']}`; + }; + + new IcecastMetadataPlayer(stream, { + audioElement, // audio element in HTML + onMetadata, // called when metadata is synced with the audio + metadataTypes: ['icy'], // detect ICY metadata + icyDetectionTimeout: 5000, // attempt to detect ICY metadata for 5 seconds + enableLogging: true, // enable error logs to the console + onError: (message) => { + metadataEl.innerHTML = message; + }, + }); + } +} diff --git a/app/components/incident-map.js b/app/components/incident-map.js index 24a5097..a2d850e 100644 --- a/app/components/incident-map.js +++ b/app/components/incident-map.js @@ -632,7 +632,7 @@ export default class IncidentMap extends Component { } }; - const debounce = {"onMouseMove": onMouseMove}; + const debounce = { onMouseMove: onMouseMove }; this.map.on('mousemove', (e) => { if (e.originalEvent.buttons === 0) { diff --git a/app/components/notification-subscription-form.js b/app/components/notification-subscription-form.js index 2638f1d..bd55ed3 100644 --- a/app/components/notification-subscription-form.js +++ b/app/components/notification-subscription-form.js @@ -81,12 +81,19 @@ export default class NotificationSubscriptionFormComponent extends Component { } let isJustNtfy = true; for (const channel of formdata.getAll('notification_channels')) { - if (await this.store.peekRecord('notification-channel', channel).service != 'ntfy') { + if ( + (await this.store.peekRecord('notification-channel', channel) + .service) != 'ntfy' + ) { isJustNtfy = false; break; } } - if (formdata.get('keywords').length == 0 && !formdata.get('address') && !isJustNtfy) { + if ( + formdata.get('keywords').length == 0 && + !formdata.get('address') && + !isJustNtfy + ) { alert('You must enter at least one keyword or address.'); return; } diff --git a/app/components/transcript-search.js b/app/components/transcript-search.js index e3450fe..4d7e989 100644 --- a/app/components/transcript-search.js +++ b/app/components/transcript-search.js @@ -85,7 +85,7 @@ export default class TranscriptSearchComponent extends Component { if (window.location.hash.startsWith('#hit-')) { this.selectedHit = window.location.hash.split('#hit-')[1]; } - const savedSearches = localStorage.getItem('savedSearches') + const savedSearches = localStorage.getItem('savedSearches'); if (savedSearches) { let savedSearchesArray = JSON.parse(savedSearches); if (!Array.isArray(savedSearchesArray)) { @@ -329,7 +329,7 @@ export default class TranscriptSearchComponent extends Component { this.search.setUiState(state); } - @action saveSearch(event) { + @action saveSearch() { let searchName = prompt('Enter a name for this search'); if (!searchName) { return; @@ -347,7 +347,7 @@ export default class TranscriptSearchComponent extends Component { } } - @action removeSavedSearch(index, event) { + @action removeSavedSearch(index) { this.savedSearches.removeAt(index); try { localStorage.setItem('savedSearches', JSON.stringify(this.savedSearches)); diff --git a/app/router.js b/app/router.js index 4d2f379..5932ca1 100644 --- a/app/router.js +++ b/app/router.js @@ -35,4 +35,5 @@ Router.map(function () { path: '/transcripts/notifications', }); this.route('settings'); + this.route('airshow'); }); diff --git a/app/routes/airshow.js b/app/routes/airshow.js new file mode 100644 index 0000000..8f76383 --- /dev/null +++ b/app/routes/airshow.js @@ -0,0 +1,3 @@ +import Route from '@ember/routing/route'; + +export default class AirshowRoute extends Route {} diff --git a/app/routes/audio.js b/app/routes/audio.js index bb63908..d6fa867 100644 --- a/app/routes/audio.js +++ b/app/routes/audio.js @@ -9,12 +9,16 @@ export default class AudioRoute extends Route { model.streams = await response.json(); try { - const ytResponse = await fetch('https://worker.erictendian.workers.dev/youtubelive/'); + const ytResponse = await fetch( + 'https://worker.erictendian.workers.dev/youtubelive/', + ); const ytResponseData = await ytResponse.text(); const parser = new DOMParser(); const doc = parser.parseFromString(ytResponseData, 'text/html'); - model.youtubeEmbedUrl = doc.querySelector('meta[property="og:video:secure_url"]').attributes.content.value; + model.youtubeEmbedUrl = doc.querySelector( + 'meta[property="og:video:secure_url"]', + ).attributes.content.value; } catch (e) { console.error('Error fetching YouTube data', e); } diff --git a/app/styles/_transcript_search.scss b/app/styles/_transcript_search.scss index 1458989..44d3d50 100644 --- a/app/styles/_transcript_search.scss +++ b/app/styles/_transcript_search.scss @@ -44,6 +44,10 @@ } } +#saved-h-menu .list-group-item { + padding-top: 0.75rem !important; +} + .ais-Hits-item, .ais-InfiniteHits-item { display: block; margin: 0 -0.5rem; diff --git a/app/templates/airshow.hbs b/app/templates/airshow.hbs new file mode 100644 index 0000000..f2a4731 --- /dev/null +++ b/app/templates/airshow.hbs @@ -0,0 +1,5 @@ +{{page-title "Airshow"}} +
+

Chicago Air and Water Show radio

+ +
diff --git a/app/templates/audio.hbs b/app/templates/audio.hbs index 6560051..d133ee7 100644 --- a/app/templates/audio.hbs +++ b/app/templates/audio.hbs @@ -2,22 +2,23 @@
-
- -
- -
-
-

General #ChicagoScanner feed

-

Scanner feed of ISP Dist. Chicago, Metra PD, CPD Citywides, various CFD incident channels, Marine 16, and aviation UNICOM. Scan list subject to change.

View on YouTube

- -
-
-
- -
+ +
+ +
+
+

General #ChicagoScanner feed

+

Scanner feed of ISP Dist. Chicago, Metra PD, CPD Citywides, various CFD incident channels, Marine 16, and aviation UNICOM. Scan list subject to change.

View on YouTube

+ + +

Chicago Air and Water Show radio

+ +
+
+
+
@@ -81,13 +82,16 @@

STARCOM21

  • -

    Chicago OEMC 800MHz (NEW)

    +

    Chicago OEMC 800MHz (includes CFD)

    +
  • +
  • +

    Chicago Fire Department (old system, not in use usually)

  • -

    Chicago Fire Department

    +

    Chicago Police Department (including delayed encrypted feeds)

  • -

    Chicago Police Department

    +

    Chicago Suburbs

  • Broadcastify Calls

    diff --git a/app/templates/components/transcript-search.hbs b/app/templates/components/transcript-search.hbs index 10dfc76..7f792cd 100644 --- a/app/templates/components/transcript-search.hbs +++ b/app/templates/components/transcript-search.hbs @@ -98,7 +98,7 @@ {{/unless}} {{#each this.savedSearches as |search index|}}
      - + {{search.name}}
    • @@ -336,7 +336,7 @@

      {{#if (get segment "0")}} {{!-- template-lint-disable no-triple-curlies --}} - {{{get segment "0.label"}}}{{#if segment.0.address}} {{/if}}: + {{{get segment "0.label"}}}{{#if (get segment "0.address")}} {{/if}}: {{/if}} {{!-- template-lint-disable no-triple-curlies --}} {{{get segment "1"}}} diff --git a/ember-cli-build.js b/ember-cli-build.js index 6e07c80..591d202 100644 --- a/ember-cli-build.js +++ b/ember-cli-build.js @@ -161,11 +161,22 @@ module.exports = function (defaults) { app.import('node_modules/ogv/dist/ogv.js'); app.import('vendor/videojs-ogvjs.js'); - app.import('node_modules/videojs-wavesurfer/node_modules/wavesurfer.js/dist/wavesurfer.js'); - app.import('node_modules/videojs-wavesurfer/node_modules/wavesurfer.js/dist/plugin/wavesurfer.timeline.js'); + app.import( + 'node_modules/videojs-wavesurfer/node_modules/wavesurfer.js/dist/wavesurfer.js', + ); + app.import( + 'node_modules/videojs-wavesurfer/node_modules/wavesurfer.js/dist/plugin/wavesurfer.timeline.js', + ); app.import('node_modules/videojs-wavesurfer/dist/videojs.wavesurfer.js'); app.import('node_modules/videojs-wavesurfer/dist/css/videojs.wavesurfer.css'); + app.import( + 'node_modules/icecast-metadata-player/build/icecast-metadata-player-1.17.3.main.min.js', + ); + app.import( + 'node_modules/icecast-metadata-player/build/icecast-metadata-player-1.17.3.mediasource.min.js', + ); + const ogvAssets = new Funnel('node_modules/ogv/dist', { srcDir: '/', include: ['**/*.*'], diff --git a/package-lock.json b/package-lock.json index 9f391e7..493b571 100644 --- a/package-lock.json +++ b/package-lock.json @@ -64,6 +64,7 @@ "eslint-plugin-n": "^17.3.1", "eslint-plugin-prettier": "^5.1.3", "eslint-plugin-qunit": "^8.1.1", + "icecast-metadata-player": "^1.17.3", "instantsearch.css": "^8.1.0", "instantsearch.js": "^4.67.0", "interactjs": "^1.10.27", @@ -6165,6 +6166,12 @@ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "dev": true }, + "node_modules/@eshaz/web-worker": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/@eshaz/web-worker/-/web-worker-1.2.2.tgz", + "integrity": "sha512-WxXiHFmD9u/owrzempiDlBB1ZYqiLnm9s6aPc8AlFQalq2tKmqdmMr9GXOupDgzXtqnBipj8Un0gkIm7Sjf8mw==", + "dev": true + }, "node_modules/@eslint-community/eslint-utils": { "version": "4.4.0", "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", @@ -12299,6 +12306,44 @@ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", "dev": true }, + "node_modules/@wasm-audio-decoders/common": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/@wasm-audio-decoders/common/-/common-9.0.5.tgz", + "integrity": "sha512-b9JNh9sPAvn8PVIizNh9D60WkfQong/u9ea873H47u7zvVDLctxYIp2aZw9CQqXaQdk7JB3MoU5UHiseO40swg==", + "dev": true, + "dependencies": { + "@eshaz/web-worker": "1.2.2", + "simple-yenc": "^1.0.4" + } + }, + "node_modules/@wasm-audio-decoders/flac": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/@wasm-audio-decoders/flac/-/flac-0.2.4.tgz", + "integrity": "sha512-bsUlwIjd5y+IAEyILCQdi8y0LocKEkZ0enA8ljDL+NVVwN+5Rv5Xkm/HcdUxnB7MtekxN2cNcTsv1zkb2aZyWg==", + "dev": true, + "dependencies": { + "@wasm-audio-decoders/common": "9.0.5", + "codec-parser": "2.4.3" + }, + "funding": { + "type": "individual", + "url": "https://github.com/sponsors/eshaz" + } + }, + "node_modules/@wasm-audio-decoders/ogg-vorbis": { + "version": "0.1.15", + "resolved": "https://registry.npmjs.org/@wasm-audio-decoders/ogg-vorbis/-/ogg-vorbis-0.1.15.tgz", + "integrity": "sha512-skAN3NIrRzMkVouyfyq3gYT/op/K9iutMZr7kr5/9fnIaCnpYdrdbv69X8PZ6y3K2J5zy5KuGno5kzH8yGLOOg==", + "dev": true, + "dependencies": { + "@wasm-audio-decoders/common": "9.0.5", + "codec-parser": "2.4.3" + }, + "funding": { + "type": "individual", + "url": "https://github.com/sponsors/eshaz" + } + }, "node_modules/@webassemblyjs/ast": { "version": "1.12.1", "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.12.1.tgz", @@ -16698,6 +16743,12 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/codec-parser": { + "version": "2.4.3", + "resolved": "https://registry.npmjs.org/codec-parser/-/codec-parser-2.4.3.tgz", + "integrity": "sha512-3dAvFtdpxn4YLstqsB2ZiJXXNg7n1j7R5ONeDuk+2kBkb39PwrCRytOFHlSWA8q5jCjW3PumeMv9q37bFHsijg==", + "dev": true + }, "node_modules/collection-visit": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", @@ -35034,6 +35085,39 @@ "ms": "^2.0.0" } }, + "node_modules/icecast-metadata-js": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/icecast-metadata-js/-/icecast-metadata-js-1.2.8.tgz", + "integrity": "sha512-de36uvcuEP7iSLvYMyAEs9sljq0LlOkO+PDqasT08xm9JhSPfNUrcRkuuSl4cV0Pwixr/KM8oC+sweBWnooYbw==", + "dev": true, + "dependencies": { + "codec-parser": "2.4.3" + }, + "funding": { + "type": "individual", + "url": "https://github.com/sponsors/eshaz" + } + }, + "node_modules/icecast-metadata-player": { + "version": "1.17.3", + "resolved": "https://registry.npmjs.org/icecast-metadata-player/-/icecast-metadata-player-1.17.3.tgz", + "integrity": "sha512-RWeasTRMpokJsT+hh9nyBLV6wyEXZBX5ExyvJeiROmog3oRy6XLjJSrXnBTP3r6RpNZn+4D9YBPv+KnwH+KN7A==", + "dev": true, + "dependencies": { + "@wasm-audio-decoders/flac": "0.2.4", + "@wasm-audio-decoders/ogg-vorbis": "0.1.15", + "codec-parser": "2.4.3", + "icecast-metadata-js": "1.2.8", + "mpg123-decoder": "1.0.0", + "mse-audio-wrapper": "1.4.14", + "opus-decoder": "0.7.6", + "synaudio": "0.3.5" + }, + "funding": { + "type": "individual", + "url": "https://github.com/sponsors/eshaz" + } + }, "node_modules/iconv-lite": { "version": "0.4.24", "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", @@ -37479,12 +37563,38 @@ "mpd-to-m3u8-json": "bin/parse.js" } }, + "node_modules/mpg123-decoder": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/mpg123-decoder/-/mpg123-decoder-1.0.0.tgz", + "integrity": "sha512-WV+pyuMUhRqv7s8S6p/Ii4KQHdBD1pb3yaABxcKJRsNp+HQ/Y6z2iIBIaOZu0JMHPTOoICYt0REDZ7XfLu+n/g==", + "dev": true, + "dependencies": { + "@wasm-audio-decoders/common": "9.0.5" + }, + "funding": { + "type": "individual", + "url": "https://github.com/sponsors/eshaz" + } + }, "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==", "dev": true }, + "node_modules/mse-audio-wrapper": { + "version": "1.4.14", + "resolved": "https://registry.npmjs.org/mse-audio-wrapper/-/mse-audio-wrapper-1.4.14.tgz", + "integrity": "sha512-qdy5ezIS5JwA21DUJIYypGU2WtLzqJXCK9hgFoHu3ydjL/xrEt7XjsKuKPxYAiWZVOaBXjZluxfeNF+zRz5jrw==", + "dev": true, + "dependencies": { + "codec-parser": "2.4.3" + }, + "funding": { + "type": "individual", + "url": "https://github.com/sponsors/eshaz" + } + }, "node_modules/mustache": { "version": "4.2.0", "resolved": "https://registry.npmjs.org/mustache/-/mustache-4.2.0.tgz", @@ -43692,6 +43802,19 @@ "node": ">= 0.8.0" } }, + "node_modules/opus-decoder": { + "version": "0.7.6", + "resolved": "https://registry.npmjs.org/opus-decoder/-/opus-decoder-0.7.6.tgz", + "integrity": "sha512-5QYSl1YQYbSzWL7vM4dJoyrLC804xIvBFjfKTZZ6/z/EgmdFouOTT+8PDM2V18vzgnhRNPDuyB2aTfl/2hvMRA==", + "dev": true, + "dependencies": { + "@wasm-audio-decoders/common": "9.0.5" + }, + "funding": { + "type": "individual", + "url": "https://github.com/sponsors/eshaz" + } + }, "node_modules/ora": { "version": "3.4.0", "resolved": "https://registry.npmjs.org/ora/-/ora-3.4.0.tgz", @@ -46375,6 +46498,16 @@ "integrity": "sha512-C2WEK/Z3HoSFbYq8tI7ni3eOo/NneSPRoPpcM7WdLjFOArFuyXEjAoCdOC3DgMfRyziZQ1hCNR4mrNdWEvD0og==", "dev": true }, + "node_modules/simple-yenc": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/simple-yenc/-/simple-yenc-1.0.4.tgz", + "integrity": "sha512-5gvxpSd79e9a3V4QDYUqnqxeD4HGlhCakVpb6gMnDD7lexJggSBJRBO5h52y/iJrdXRilX9UCuDaIJhSWm5OWw==", + "dev": true, + "funding": { + "type": "individual", + "url": "https://github.com/sponsors/eshaz" + } + }, "node_modules/slash": { "version": "3.0.0", "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", @@ -47574,6 +47707,26 @@ "integrity": "sha512-0K91MEXFpBUaywiwSSkmKjnGcasG/rVBXFLJz5DrgGabpYD6N+3yZrfD6uUIfpuTu65DZLHi7N8CizHc07BPZA==", "dev": true }, + "node_modules/synaudio": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/synaudio/-/synaudio-0.3.5.tgz", + "integrity": "sha512-WBrjnWN3fCj2aESk/lzvD7PdfFqe6Sg0u4P0J4ZR9jxFq7cljEEql0YsyH53xtBT3bksCTG46AhhXVvCkzCXOw==", + "dev": true, + "dependencies": { + "@eshaz/web-worker": "1.2.1", + "simple-yenc": "^1.0.2" + }, + "funding": { + "type": "individual", + "url": "https://github.com/sponsors/eshaz" + } + }, + "node_modules/synaudio/node_modules/@eshaz/web-worker": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@eshaz/web-worker/-/web-worker-1.2.1.tgz", + "integrity": "sha512-v5AKAVtM0toVD2rDCGjzhySWlXG/sG5HVialdzrxFKTAnFZNCjQelX0n2tPK0tE86jf4s3hpWlpRtOh8OObktg==", + "dev": true + }, "node_modules/sync-disk-cache": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/sync-disk-cache/-/sync-disk-cache-2.1.0.tgz", diff --git a/package.json b/package.json index e0dc72f..a7923d5 100644 --- a/package.json +++ b/package.json @@ -91,6 +91,7 @@ "eslint-plugin-n": "^17.3.1", "eslint-plugin-prettier": "^5.1.3", "eslint-plugin-qunit": "^8.1.1", + "icecast-metadata-player": "^1.17.3", "instantsearch.css": "^8.1.0", "instantsearch.js": "^4.67.0", "interactjs": "^1.10.27", diff --git a/tests/integration/components/icecast-player-test.js b/tests/integration/components/icecast-player-test.js new file mode 100644 index 0000000..8d0bcc7 --- /dev/null +++ b/tests/integration/components/icecast-player-test.js @@ -0,0 +1,26 @@ +import { module, test } from 'qunit'; +import { setupRenderingTest } from 'crimeisdown/tests/helpers'; +import { render } from '@ember/test-helpers'; +import { hbs } from 'ember-cli-htmlbars'; + +module('Integration | Component | icecast-player', function (hooks) { + setupRenderingTest(hooks); + + test('it renders', async function (assert) { + // Set any properties with this.set('myProperty', 'value'); + // Handle any actions with this.set('myAction', function(val) { ... }); + + await render(hbs``); + + assert.dom().hasText(''); + + // Template block usage: + await render(hbs` + + template block text + + `); + + assert.dom().hasText('template block text'); + }); +}); diff --git a/tests/unit/routes/airshow-test.js b/tests/unit/routes/airshow-test.js new file mode 100644 index 0000000..50370e8 --- /dev/null +++ b/tests/unit/routes/airshow-test.js @@ -0,0 +1,11 @@ +import { module, test } from 'qunit'; +import { setupTest } from 'crimeisdown/tests/helpers'; + +module('Unit | Route | airshow', function (hooks) { + setupTest(hooks); + + test('it exists', function (assert) { + let route = this.owner.lookup('route:airshow'); + assert.ok(route); + }); +}); diff --git a/worker/src/index.js b/worker/src/index.js index 2836f58..1c41120 100644 --- a/worker/src/index.js +++ b/worker/src/index.js @@ -1,86 +1,85 @@ export default { - async fetch(request) { - const corsHeaders = { - "Access-Control-Allow-Origin": "*", - "Access-Control-Allow-Methods": "GET,HEAD,POST,OPTIONS", - "Access-Control-Max-Age": "86400", - }; + async fetch(request) { + const corsHeaders = { + 'Access-Control-Allow-Origin': '*', + 'Access-Control-Allow-Methods': 'GET,HEAD,POST,OPTIONS', + 'Access-Control-Max-Age': '86400', + }; - // The URL for the remote third party API you want to fetch from - // but does not implement CORS - const API_URL = "https://www.youtube.com/@EricTendian/live"; + // The URL for the remote third party API you want to fetch from + // but does not implement CORS + const API_URL = 'https://www.youtube.com/@EricTendian/live'; - // The endpoint you want the CORS reverse proxy to be on - const PROXY_ENDPOINT = "/youtubelive/"; + // The endpoint you want the CORS reverse proxy to be on + const PROXY_ENDPOINT = '/youtubelive/'; - async function handleRequest(originalRequest) { - // Rewrite request to point to API URL. This also makes the request mutable - // so you can add the correct Origin header to make the API server think - // that this request is not cross-site. - request = new Request(API_URL, originalRequest); - request.headers.set("Origin", new URL(API_URL).origin); - let response = await fetch(request); - // Recreate the response so you can modify the headers + async function handleRequest(originalRequest) { + // Rewrite request to point to API URL. This also makes the request mutable + // so you can add the correct Origin header to make the API server think + // that this request is not cross-site. + request = new Request(API_URL, originalRequest); + request.headers.set('Origin', new URL(API_URL).origin); + let response = await fetch(request, { + cf: { + cacheTtl: 3600, + cacheEverything: true, + }, + }); + // Recreate the response so you can modify the headers - response = new Response(response.body, response); - // Set CORS headers + response = new Response(response.body, response); + // Set CORS headers - response.headers.set("Access-Control-Allow-Origin", originalRequest.headers.get("Origin")); + response.headers.set('Access-Control-Allow-Origin', originalRequest.headers.get('Origin')); - // Append to/Add Vary header so browser will cache response correctly - response.headers.append("Vary", "Origin"); + // Append to/Add Vary header so browser will cache response correctly + response.headers.append('Vary', 'Origin'); - return response; - } + return response; + } - async function handleOptions(request) { - if ( - request.headers.get("Origin") !== null && - request.headers.get("Access-Control-Request-Method") !== null && - request.headers.get("Access-Control-Request-Headers") !== null - ) { - // Handle CORS preflight requests. - return new Response(null, { - headers: { - ...corsHeaders, - "Access-Control-Allow-Headers": request.headers.get( - "Access-Control-Request-Headers" - ), - }, - }); - } else { - // Handle standard OPTIONS request. - return new Response(null, { - headers: { - Allow: "GET, HEAD, POST, OPTIONS", - }, - }); - } - } + async function handleOptions(request) { + if ( + request.headers.get('Origin') !== null && + request.headers.get('Access-Control-Request-Method') !== null && + request.headers.get('Access-Control-Request-Headers') !== null + ) { + // Handle CORS preflight requests. + return new Response(null, { + headers: { + ...corsHeaders, + 'Access-Control-Allow-Headers': request.headers.get('Access-Control-Request-Headers'), + }, + }); + } else { + // Handle standard OPTIONS request. + return new Response(null, { + headers: { + Allow: 'GET, HEAD, POST, OPTIONS', + }, + }); + } + } - const url = new URL(request.url); - if (url.pathname.startsWith(PROXY_ENDPOINT)) { - if (request.method === "OPTIONS") { - // Handle CORS preflight requests - return handleOptions(request); - } else if ( - request.method === "GET" || - request.method === "HEAD" || - request.method === "POST" - ) { - // Handle requests to the API server - return handleRequest(request); - } else { - return new Response(null, { - status: 405, - statusText: "Method Not Allowed", - }); - } - } else { - return new Response(null, { - status: 404, - statusText: "Page Not Found", - }); - } - }, + const url = new URL(request.url); + if (url.pathname.startsWith(PROXY_ENDPOINT)) { + if (request.method === 'OPTIONS') { + // Handle CORS preflight requests + return handleOptions(request); + } else if (request.method === 'GET' || request.method === 'HEAD' || request.method === 'POST') { + // Handle requests to the API server + return handleRequest(request); + } else { + return new Response(null, { + status: 405, + statusText: 'Method Not Allowed', + }); + } + } else { + return new Response(null, { + status: 404, + statusText: 'Page Not Found', + }); + } + }, }; diff --git a/worker/test/index.spec.js b/worker/test/index.spec.js index 3529146..1d8662c 100644 --- a/worker/test/index.spec.js +++ b/worker/test/index.spec.js @@ -1,4 +1,4 @@ -import { env, createExecutionContext, waitOnExecutionContext, SELF } from 'cloudflare:test'; +import { env, createExecutionContext, waitOnExecutionContext } from 'cloudflare:test'; import { describe, it, expect } from 'vitest'; import worker from '../src';