From 2520fe43312da6c7ea5d0372a3bf0dbee4cbefac Mon Sep 17 00:00:00 2001 From: Alexander Heimbuch Date: Sat, 30 Dec 2023 09:02:38 +0100 Subject: [PATCH 01/20] dev bump --- apps/page/README.md | 54 + apps/page/astro.config.mjs | 14 + apps/page/package.json | 40 + apps/page/public/favicon.svg | 9 + apps/page/src/app.ts | 17 + apps/page/src/components/Contributor.vue | 25 + apps/page/src/components/HeaderContainer.vue | 28 + apps/page/src/components/PlayButton.vue | 39 + apps/page/src/components/PlayerTile.vue | 134 + apps/page/src/components/Popover.vue | 148 + apps/page/src/components/Test.vue | 15 + apps/page/src/env.d.ts | 1 + apps/page/src/features/PageHeader.vue | 54 + apps/page/src/i18n/index.ts | 2 + apps/page/src/i18n/messages.ts | 70 + apps/page/src/i18n/utils.ts | 28 + apps/page/src/layouts/Layout.astro | 84 + apps/page/src/logic/data/feed-parser.ts | 70 + apps/page/src/logic/index.bak | 94 + apps/page/src/logic/index.ts | 9 + apps/page/src/logic/sagas/data.sagas.ts | 23 + apps/page/src/logic/sagas/episode.sagas.ts | 105 + apps/page/src/logic/sagas/index.ts | 9 + apps/page/src/logic/sagas/playbar.sagas.ts | 66 + apps/page/src/logic/sagas/router.sagas.ts | 95 + apps/page/src/logic/sagas/search.sagas.ts | 184 + apps/page/src/logic/store/actions.ts | 27 + apps/page/src/logic/store/helper.ts | 3 + apps/page/src/logic/store/index.ts | 27 + apps/page/src/logic/store/reducers.ts | 47 + apps/page/src/logic/store/selectors.ts | 273 + apps/page/src/logic/store/state.ts | 46 + .../src/logic/store/stores/action.store.ts | 10 + .../src/logic/store/stores/episodes.store.ts | 36 + .../src/logic/store/stores/playbar.store.ts | 75 + .../src/logic/store/stores/player.store.ts | 30 + .../src/logic/store/stores/podcast.store.ts | 43 + .../src/logic/store/stores/router.store.ts | 36 + .../src/logic/store/stores/runtime.store.ts | 38 + .../src/logic/store/stores/search.store.ts | 101 + .../store/stores/subscribe-button.store.ts | 25 + .../src/logic/store/stores/theme.store.ts | 16 + apps/page/src/middleware/index.ts | 4 + apps/page/src/middleware/store.ts | 31 + apps/page/src/pages/episodes/[id].astro | 84 + apps/page/src/pages/index.astro | 25 + apps/page/src/screens/archive/EpisodeItem.vue | 101 + apps/page/src/screens/archive/Hero.vue | 56 + apps/page/src/screens/episodes/Hero.vue | 96 + apps/page/src/screens/episodes/Navigation.vue | 140 + apps/page/src/types/feed.types.ts | 33 + apps/page/tailwind.config.cjs | 102 + apps/page/tsconfig.json | 6 + .../src/components/play-button/PlayButton.vue | 2 +- .../components/src/components/icons/User.vue | 25 + .../components/src/components/icons/index.ts | 2 + packages/components/src/components/main.ts | 2 + .../src/components/play-button/PlayButton.vue | 7 +- packages/player/sagas/package.json | 8 + packages/player/sagas/vite.config.ts | 3 +- packages/player/state/src/episode.ts | 4 +- packages/utils/package.json | 8 + packages/utils/src/promise.ts | 18 +- packages/utils/vite.config.ts | 3 +- pnpm-lock.yaml | 12891 +++++++--------- 65 files changed, 8917 insertions(+), 6984 deletions(-) create mode 100644 apps/page/README.md create mode 100644 apps/page/astro.config.mjs create mode 100644 apps/page/package.json create mode 100644 apps/page/public/favicon.svg create mode 100644 apps/page/src/app.ts create mode 100644 apps/page/src/components/Contributor.vue create mode 100644 apps/page/src/components/HeaderContainer.vue create mode 100644 apps/page/src/components/PlayButton.vue create mode 100644 apps/page/src/components/PlayerTile.vue create mode 100644 apps/page/src/components/Popover.vue create mode 100644 apps/page/src/components/Test.vue create mode 100644 apps/page/src/env.d.ts create mode 100644 apps/page/src/features/PageHeader.vue create mode 100644 apps/page/src/i18n/index.ts create mode 100644 apps/page/src/i18n/messages.ts create mode 100644 apps/page/src/i18n/utils.ts create mode 100644 apps/page/src/layouts/Layout.astro create mode 100644 apps/page/src/logic/data/feed-parser.ts create mode 100644 apps/page/src/logic/index.bak create mode 100644 apps/page/src/logic/index.ts create mode 100644 apps/page/src/logic/sagas/data.sagas.ts create mode 100644 apps/page/src/logic/sagas/episode.sagas.ts create mode 100644 apps/page/src/logic/sagas/index.ts create mode 100644 apps/page/src/logic/sagas/playbar.sagas.ts create mode 100644 apps/page/src/logic/sagas/router.sagas.ts create mode 100644 apps/page/src/logic/sagas/search.sagas.ts create mode 100644 apps/page/src/logic/store/actions.ts create mode 100644 apps/page/src/logic/store/helper.ts create mode 100644 apps/page/src/logic/store/index.ts create mode 100644 apps/page/src/logic/store/reducers.ts create mode 100644 apps/page/src/logic/store/selectors.ts create mode 100644 apps/page/src/logic/store/state.ts create mode 100644 apps/page/src/logic/store/stores/action.store.ts create mode 100644 apps/page/src/logic/store/stores/episodes.store.ts create mode 100644 apps/page/src/logic/store/stores/playbar.store.ts create mode 100644 apps/page/src/logic/store/stores/player.store.ts create mode 100644 apps/page/src/logic/store/stores/podcast.store.ts create mode 100644 apps/page/src/logic/store/stores/router.store.ts create mode 100644 apps/page/src/logic/store/stores/runtime.store.ts create mode 100644 apps/page/src/logic/store/stores/search.store.ts create mode 100644 apps/page/src/logic/store/stores/subscribe-button.store.ts create mode 100644 apps/page/src/logic/store/stores/theme.store.ts create mode 100644 apps/page/src/middleware/index.ts create mode 100644 apps/page/src/middleware/store.ts create mode 100644 apps/page/src/pages/episodes/[id].astro create mode 100644 apps/page/src/pages/index.astro create mode 100644 apps/page/src/screens/archive/EpisodeItem.vue create mode 100644 apps/page/src/screens/archive/Hero.vue create mode 100644 apps/page/src/screens/episodes/Hero.vue create mode 100644 apps/page/src/screens/episodes/Navigation.vue create mode 100644 apps/page/src/types/feed.types.ts create mode 100644 apps/page/tailwind.config.cjs create mode 100644 apps/page/tsconfig.json create mode 100644 packages/components/src/components/icons/User.vue diff --git a/apps/page/README.md b/apps/page/README.md new file mode 100644 index 000000000..1db3fb399 --- /dev/null +++ b/apps/page/README.md @@ -0,0 +1,54 @@ +# Astro Starter Kit: Basics + +```sh +npm create astro@latest -- --template basics +``` + +[![Open in StackBlitz](https://developer.stackblitz.com/img/open_in_stackblitz.svg)](https://stackblitz.com/github/withastro/astro/tree/latest/examples/basics) +[![Open with CodeSandbox](https://assets.codesandbox.io/github/button-edit-lime.svg)](https://codesandbox.io/p/sandbox/github/withastro/astro/tree/latest/examples/basics) +[![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://codespaces.new/withastro/astro?devcontainer_path=.devcontainer/basics/devcontainer.json) + +> πŸ§‘β€πŸš€ **Seasoned astronaut?** Delete this file. Have fun! + +![just-the-basics](https://github.com/withastro/astro/assets/2244813/a0a5533c-a856-4198-8470-2d67b1d7c554) + +## πŸš€ Project Structure + +Inside of your Astro project, you'll see the following folders and files: + +```text +/ +β”œβ”€β”€ public/ +β”‚ └── favicon.svg +β”œβ”€β”€ src/ +β”‚ β”œβ”€β”€ components/ +β”‚ β”‚ └── Card.astro +β”‚ β”œβ”€β”€ layouts/ +β”‚ β”‚ └── Layout.astro +β”‚ └── pages/ +β”‚ └── index.astro +└── package.json +``` + +Astro looks for `.astro` or `.md` files in the `src/pages/` directory. Each page is exposed as a route based on its file name. + +There's nothing special about `src/components/`, but that's where we like to put any Astro/React/Vue/Svelte/Preact components. + +Any static assets, like images, can be placed in the `public/` directory. + +## 🧞 Commands + +All commands are run from the root of the project, from a terminal: + +| Command | Action | +| :------------------------ | :----------------------------------------------- | +| `npm install` | Installs dependencies | +| `npm run dev` | Starts local dev server at `localhost:4321` | +| `npm run build` | Build your production site to `./dist/` | +| `npm run preview` | Preview your build locally, before deploying | +| `npm run astro ...` | Run CLI commands like `astro add`, `astro check` | +| `npm run astro -- --help` | Get help using the Astro CLI | + +## πŸ‘€ Want to learn more? + +Feel free to check [our documentation](https://docs.astro.build) or jump into our [Discord server](https://astro.build/chat). diff --git a/apps/page/astro.config.mjs b/apps/page/astro.config.mjs new file mode 100644 index 000000000..69f9478b2 --- /dev/null +++ b/apps/page/astro.config.mjs @@ -0,0 +1,14 @@ +import { defineConfig } from 'astro/config'; +import node from '@astrojs/node'; +import vue from "@astrojs/vue"; + +import tailwind from "@astrojs/tailwind"; + +// https://astro.build/config +export default defineConfig({ + output: 'server', + adapter: node({ + mode: 'standalone' + }), + integrations: [vue({ appEntrypoint: '/src/app' }), tailwind()] +}); diff --git a/apps/page/package.json b/apps/page/package.json new file mode 100644 index 000000000..d884f6419 --- /dev/null +++ b/apps/page/package.json @@ -0,0 +1,40 @@ +{ + "name": "@podlove/page", + "type": "module", + "version": "0.0.1", + "scripts": { + "serve": "astro dev", + "build": "astro check && astro build", + "preview": "astro preview", + "astro": "astro" + }, + "dependencies": { + "@astrojs/check": "0.3.1", + "@astrojs/node": "6.1.0", + "@astrojs/tailwind": "5.0.2", + "@astrojs/vue": "4.0.0", + "astro": "3.6.4", + "vue": "3.2.30", + "fast-xml-parser": "4.3.2", + "lodash-es": "4.17.21", + "@podlove/player-sagas": "workspace:*", + "@podlove/utils": "workspace:*", + "@podlove/player-actions": "workspace:*", + "@podlove/player-state": "workspace:*", + "@podlove/components": "workspace:*", + "@podlove/types": "workspace:*", + "redux": "4.2.1", + "redux-vuex": "3.0.2", + "redux-actions": "3.0.0", + "redux-saga": "1.2.3", + "reselect": "4.1.8", + "vue-i18n": "9.8.0", + "scroll-into-view-if-needed": "3.1.0" + }, + "devDependencies": { + "tailwindcss": "3.0.24", + "typescript": "5.3.2", + "@types/lodash-es": "4.17.12", + "@types/redux-actions": "2.6.5" + } +} diff --git a/apps/page/public/favicon.svg b/apps/page/public/favicon.svg new file mode 100644 index 000000000..f157bd1c5 --- /dev/null +++ b/apps/page/public/favicon.svg @@ -0,0 +1,9 @@ + + + + diff --git a/apps/page/src/app.ts b/apps/page/src/app.ts new file mode 100644 index 000000000..ee99c0ea3 --- /dev/null +++ b/apps/page/src/app.ts @@ -0,0 +1,17 @@ +import { provideStore } from 'redux-vuex'; +import { createI18n } from 'vue-i18n'; +import type { App } from 'vue'; +import { messages, defaultLang, getLanguage } from './i18n'; +import { store, actions } from './logic'; + +export default (app: App) => { + const i18n = createI18n({ + legacy: false, + locale: getLanguage(), // set locale + fallbackLocale: defaultLang, + messages + }); + + app.use(i18n); + provideStore({ app, store, actions }); +}; diff --git a/apps/page/src/components/Contributor.vue b/apps/page/src/components/Contributor.vue new file mode 100644 index 000000000..691eaeac8 --- /dev/null +++ b/apps/page/src/components/Contributor.vue @@ -0,0 +1,25 @@ + + + diff --git a/apps/page/src/components/HeaderContainer.vue b/apps/page/src/components/HeaderContainer.vue new file mode 100644 index 000000000..4172438ce --- /dev/null +++ b/apps/page/src/components/HeaderContainer.vue @@ -0,0 +1,28 @@ + + + diff --git a/apps/page/src/components/PlayButton.vue b/apps/page/src/components/PlayButton.vue new file mode 100644 index 000000000..04e7aaed1 --- /dev/null +++ b/apps/page/src/components/PlayButton.vue @@ -0,0 +1,39 @@ + + + + + diff --git a/apps/page/src/components/PlayerTile.vue b/apps/page/src/components/PlayerTile.vue new file mode 100644 index 000000000..6ff428acd --- /dev/null +++ b/apps/page/src/components/PlayerTile.vue @@ -0,0 +1,134 @@ + + + + + diff --git a/apps/page/src/components/Popover.vue b/apps/page/src/components/Popover.vue new file mode 100644 index 000000000..4467fbf18 --- /dev/null +++ b/apps/page/src/components/Popover.vue @@ -0,0 +1,148 @@ + + + + + diff --git a/apps/page/src/components/Test.vue b/apps/page/src/components/Test.vue new file mode 100644 index 000000000..cefd88fb9 --- /dev/null +++ b/apps/page/src/components/Test.vue @@ -0,0 +1,15 @@ + + + diff --git a/apps/page/src/env.d.ts b/apps/page/src/env.d.ts new file mode 100644 index 000000000..f964fe0cf --- /dev/null +++ b/apps/page/src/env.d.ts @@ -0,0 +1 @@ +/// diff --git a/apps/page/src/features/PageHeader.vue b/apps/page/src/features/PageHeader.vue new file mode 100644 index 000000000..b7ad0da8d --- /dev/null +++ b/apps/page/src/features/PageHeader.vue @@ -0,0 +1,54 @@ + + diff --git a/apps/page/src/i18n/index.ts b/apps/page/src/i18n/index.ts new file mode 100644 index 000000000..a16c8d1ed --- /dev/null +++ b/apps/page/src/i18n/index.ts @@ -0,0 +1,2 @@ +export { messages, defaultLang } from './messages'; +export { getLanguage, useTranslations } from './utils'; diff --git a/apps/page/src/i18n/messages.ts b/apps/page/src/i18n/messages.ts new file mode 100644 index 000000000..b7b820aab --- /dev/null +++ b/apps/page/src/i18n/messages.ts @@ -0,0 +1,70 @@ +export const defaultLang = 'de'; + +const de = { + HEADER: { + SUBSCRIBE: 'Subscribe', + EPISODES: 'Episoden', + CONTRIBUTORS: 'Kontributoren' + }, + EPISODE: { + SUMMARY: 'Info', + SHOWNOTES: 'Shownotes', + TIMELINE: 'Timeline', + DISCUSS: 'Kommentare' + }, + PLAYBAR: { + CHAPTERS: 'Kapitel' + }, + CONTRIBUTOR: { + SOCIAL: 'Social', + DONATION: 'Support', + SUMMARY: 'Zusammenfassung', + EPISODES: 'Episoden', + EPISODE: 'Episode', + TIMELINE: 'Verlauf', + WORDS_TOTAL: 'WΓΆrter', + WORDS_TOTAL_TOOLTIP: '{relative}% aller WΓΆrter in diesem Podcast ({total})', + TALK_TIME_TOTAL: 'Sprechzeit', + TALK_TIME_TOTAL_TOOLTIP: '{relative}% der gesamten Sprechzeit in diesem Podcast ({total})', + EPISODES_TOTAL: 'Episoden', + EPISODES_TOTAL_TOOLTIP: '{relative}% aller Episoden in diesem Podcast ({total})' + }, + CONTRIBUTOR_LIST: { + TITLE: 'Kontributoren', + EPISODES_COUNT: ({ count }: { count: number }) => (count <= 1 ? `${count} Episode` : `${count} Episoden`) + }, + SEARCH: { + PLACEHOLDER: 'Suchen', + NO_RESULTS: 'Es wurden keine Ergebnisse gefunden', + INDEXING: 'Suchindex wird erstellt', + CATEGORY: { + EPISODE: 'Episoden', + CONTRIBUTOR: 'Kontributoren', + TRANSCRIPT: 'Transkripte' + } + }, + SUBSCRIBE_BUTTON: { + CLIENTS: 'Podcast Clients', + FEED: 'RSS Feed' + }, + A11Y: { + PLAYER_CHAPTER_END: 'Zum Ende der Episode springen', + PLAYER_CHAPTER_NEXT: 'Zum nΓ€chsten Kapitel: {index} - {title}', + PLAYER_CHAPTER_START: 'Zum Start der Episode springen', + PLAYER_CHAPTER_PREVIOUS: 'Zum vorhergehenden Kapitel: {index} - {title}', + PLAYER_CHAPTER_CURRENT: 'Zum Anfang des aktiven Kapitels springen: {index} - {title}', + PLAYER_STEPPER_BACK: '{seconds} Sekunden zurΓΌckspringen', + PLAYER_STEPPER_FORWARD: '{seconds} Sekunden vorspringen', + PROGRESSBAR_INPUT: 'Spielzeit in Prozent Γ€ndern', + PLAYER_PLAY: 'Episode abspielen', + PLAYER_START: 'Starte Episode - Dauer: {hours} Stunden {minutes} Minuten {seconds} Sekunden', + PLAYER_RESTART: 'Episode neustarten', + PLAYER_ERROR: 'Nochmals versuchen Episode abzuspielen', + PLAYER_PAUSE: 'Episode pausieren', + PLAYER_LOADING: 'Episode lΓ€dt' + } +}; + +export const messages = { + de +}; diff --git a/apps/page/src/i18n/utils.ts b/apps/page/src/i18n/utils.ts new file mode 100644 index 000000000..0f5190b8f --- /dev/null +++ b/apps/page/src/i18n/utils.ts @@ -0,0 +1,28 @@ +import { get } from 'lodash-es'; +import { messages, defaultLang } from './messages'; +import { store, selectors } from '../logic' + +export function useTranslations() { + const lang = getLanguage(); + + return (key: string) => { + const message = get(messages, [lang, key].join('.')); + + if (message) { + return message + } + + const fallback = get(messages, [defaultLang, key].join('.')); + + if (fallback) { + return fallback; + } + + return key; + }; +} + +export function getLanguage() { + const locale = selectors.runtime.locale(store.getState()); + return get(locale.split('-'), 0, defaultLang); +} diff --git a/apps/page/src/layouts/Layout.astro b/apps/page/src/layouts/Layout.astro new file mode 100644 index 000000000..1f4d69425 --- /dev/null +++ b/apps/page/src/layouts/Layout.astro @@ -0,0 +1,84 @@ +--- +import { ViewTransitions } from "astro:transitions"; +import PageHeader from '../features/PageHeader.vue'; +const { title } = Astro.props; +import { selectors, store }from '../logic'; +const state = store.getState(); +const lang = getLanguage(); +import Test from '../components/Test.vue' +import { getLanguage } from "../i18n"; +--- + + + + + + + + + + {title} + + + + + + +
+ +
+ + + + + + diff --git a/apps/page/src/logic/data/feed-parser.ts b/apps/page/src/logic/data/feed-parser.ts new file mode 100644 index 000000000..52c82a871 --- /dev/null +++ b/apps/page/src/logic/data/feed-parser.ts @@ -0,0 +1,70 @@ +import { get, castArray } from 'lodash-es'; +import { XMLParser } from 'fast-xml-parser'; +import type { Episode, Person, Podcast, Show } from '../../types/feed.types'; +import { toPlayerTime } from '@podlove/utils/time'; + +let CACHE = new Map>(); + +const parser = new XMLParser({ + ignoreAttributes: false +}); + +const transformPerson = (input: any): Person => ({ + name: get(input, '#text', null), + role: get(input, '@_role', null), + image: get(input, '@_img', null) +}); + +const transformShow = (data: any): Show => ({ + title: get(data, ['channel', 'title'], null), + description: get(data, ['channel', 'description'], null), + link: get(data, ['channel', 'link'], null), + summary: get(data, ['channel', 'itunes:summary'], null), + image: get(data, ['channel', 'image', 'url'], null) +}); + +const transformEpisode = (data: any): Episode => { + return { + id: get(data, 'itunes:episode', null), + title: get(data, 'title', null), + description: get(data, 'description', null), + subtitle: get(data, 'itunes:subtitle', null), + publicationDate: get(data, 'pubDate', null), + duration: toPlayerTime(get(data, 'duration', 0)), + content: get(data, 'content:encoded', null), + poster: get(data, ['itunes:image', '@_href'], null), + contributors: castArray(get(data, ['podcast:person'], [])).map(transformPerson) + }; +}; + +const transform = (data: any): Podcast => ({ + show: transformShow(data), + episodes: castArray(get(data, ['channel', 'item'], [])).map(transformEpisode), + hosts: castArray(get(data, ['channel', 'podcast:person'], [])).map(transformPerson) +}); + +export default async (feedUrl: string | null): Promise => { + if (!feedUrl) { + return transform({}); + } + + // const existing = CACHE.get(feedUrl); + + // if (existing) { + // return existing; + // } + + const result = fetch(feedUrl) + .then((result) => result.text()) + .then((data) => parser.parse(data)) + .then((data) => get(data, 'rss', {})) + // .then((data) => { + // console.log(data); + // return data; + // }) + .then(transform); + + // CACHE.set(feedUrl, result); + + return await result; +}; diff --git a/apps/page/src/logic/index.bak b/apps/page/src/logic/index.bak new file mode 100644 index 000000000..281744099 --- /dev/null +++ b/apps/page/src/logic/index.bak @@ -0,0 +1,94 @@ +import type { App } from 'vue'; +import sagasEngine from '@podlove/player-sagas/middleware'; +import { createStore as createReduxStore, applyMiddleware, compose } from 'redux'; +import { provideStore } from 'redux-vuex'; +import { quantilesSaga } from '@podlove/player-sagas/quantiles'; +import { chaptersSaga } from '@podlove/player-sagas/chapters'; +import { stepperSaga } from '@podlove/player-sagas/stepper'; + +import episodeSaga from './sagas/episode.sagas'; +import playbarSaga from './sagas/playbar.sagas'; +import routerSaga from './sagas/router.sagas'; +import searchSaga from './sagas/search.sagas'; + +import { reducers, actions, selectors } from './store'; + +export function createStore(app: App, { isClient }: { isClient: boolean, router: { navigate: (path: string) => void }}) { + let composeEnhancers = compose; + + if (isClient) { + composeEnhancers = (window as any).__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose; + } + + const store = createReduxStore( + reducers, + composeEnhancers(applyMiddleware(sagasEngine.middleware)) + ); + + provideStore({ app, store, actions }); + + const sagas = [ + episodeSaga({ + selectEpisode: selectors.episode.data, + selectMuted: selectors.player.audio.muted, + selectRate: selectors.player.audio.rate, + selectVolume: selectors.player.audio.volume, + selectCurrentEpisode: selectors.current.episode, + selectPlaying: selectors.player.playing + }), + chaptersSaga({ + selectDuration: selectors.player.duration, + selectPlaytime: selectors.player.playtime, + selectCurrentChapter: selectors.player.chapters.current, + selectChapterList: selectors.player.chapters.list + }), + stepperSaga({ + selectDuration: selectors.player.duration, + selectPlaytime: selectors.player.playtime, + selectLivesync: selectors. + }), + quantilesSaga, + playbarSaga({ + selectRate: selectors.player.audio.rate, + selectMuted: selectors.player.audio.muted + }) + ]; + + if (isClient) { + const { playerSaga } = require('@podlove/player-sagas/player'); + + sagas.push( + playerSaga({ + selectMedia: selectors.player.media, + selectPlaytime: selectors.player.playtime, + selectPoster: selectors.player.image, + selectTitle: selectors.player.title + }) + ); + + sagas.push( + routerSaga({ + selectEpisode: selectors.current.episode, + selectCurrentId: selectors.router.id, + selectPlaybarActive: selectors.playbar.active, + selectFollowContent: selectors.playbar.followContent, + router + }) + ); + + sagas.push( + searchSaga({ + selectVisible: selectors.search.visible, + selectResults: selectors.search.results, + selectInitialized: selectors.search.initialized, + selectSelectedResult: selectors.search.selectedResult, + Vue, + router + }) + ); + } + + sagasEngine.run.apply(this, sagas); + + return store; +} diff --git a/apps/page/src/logic/index.ts b/apps/page/src/logic/index.ts new file mode 100644 index 000000000..a14bbce29 --- /dev/null +++ b/apps/page/src/logic/index.ts @@ -0,0 +1,9 @@ +import { type Store } from 'redux'; +import { createStore, actions, selectors, type State } from "./store"; +import { createSideEffects } from './sagas' + +const store: Store = createStore(); + +createSideEffects(); + +export { store, actions, selectors} diff --git a/apps/page/src/logic/sagas/data.sagas.ts b/apps/page/src/logic/sagas/data.sagas.ts new file mode 100644 index 000000000..115dac608 --- /dev/null +++ b/apps/page/src/logic/sagas/data.sagas.ts @@ -0,0 +1,23 @@ +import type { Action } from 'redux-actions'; +import { put, select, takeEvery } from 'redux-saga/effects'; +import { actions } from '../store'; +import parseFeed from '../data/feed-parser'; +import type { initializePayload } from '../store/stores/runtime.store'; +import type { Podcast } from '../../types/feed.types'; + +function* fetchData(input: Action) { + const feedData: Podcast = yield parseFeed(input.payload.feed); + yield put(actions.dataFetched(feedData)); +} + +export default ({ selectInitializedApp }: { selectInitializedApp: (input: any) => boolean }) => { + return function* () { + const initialized: boolean = yield select(selectInitializedApp); + + if (initialized) { + return; + } + + yield takeEvery(actions.initializeApp.toString(), fetchData); + }; +}; diff --git a/apps/page/src/logic/sagas/episode.sagas.ts b/apps/page/src/logic/sagas/episode.sagas.ts new file mode 100644 index 000000000..124d5714c --- /dev/null +++ b/apps/page/src/logic/sagas/episode.sagas.ts @@ -0,0 +1,105 @@ +import { fetch } from 'gridsome' +import { delay } from 'redux-saga/effects' +import { isEmpty, path, isNil } from 'ramda' +import { put, takeEvery, select } from 'redux-saga/effects' +import { READY, BACKEND_LOADING_START } from '@podlove/player-actions/types' +import { requestPlay, requestPause } from '@podlove/player-actions/play' +import { requestPlaytime } from '@podlove/player-actions/timepiece' +import { takeOnce } from '@podlove/player-sagas/helper' +import { setRate, setVolume, mute, unmute } from '@podlove/player-actions/audio' + +import * as player from '../reducers/player.store' +import * as episodes from '../reducers/episodes.store' + +export default ({ + selectEpisode, + selectRate, + selectVolume, + selectMuted, + selectCurrentEpisode, + selectPlaying +}) => { + function* resetMeta() { + const rate = yield select(selectRate) + const volume = yield select(selectVolume) + const muted = yield select(selectMuted) + + yield put(setRate(rate)) + yield put(setVolume(volume)) + + yield put(muted ? mute() : unmute()) + } + + function* loadEpisode(id) { + let episode = yield select(selectEpisode(id)) + + if (isEmpty(episode)) { + const result = yield fetch(`/episode/${id}`) + episode = path(['data', 'podcastEpisode'], result) + yield put(episodes.actions.addEpisode(episode)) + } + + return episode + } + + function* injectEpisode(episode) { + const playing = yield select(selectPlaying) + + if (playing) { + yield put(requestPause()) + } + + yield put({ type: READY, payload: episode }) + yield delay(100) + yield put(requestPlay()) + yield takeOnce(BACKEND_LOADING_START, resetMeta) + } + + function* playEpisode({ payload: { id, playtime } }) { + const currentEpisode = yield select(selectCurrentEpisode) + const playing = yield select(selectPlaying) + + if (currentEpisode === id && playing) { + if (!isNil(playtime)) { + yield put(requestPlaytime(playtime)) + } + + return + } + + yield put(player.actions.selectEpisode(id)) + + const episode = yield loadEpisode(id) + + if (currentEpisode !== id) { + yield injectEpisode(episode) + } else { + yield put(requestPlay()) + } + + if (playtime) { + yield put(requestPlaytime(playtime)) + } + } + + function* pauseEpisode() { + yield put(requestPause()) + } + + function* restoreEpisode({ payload: { id, playtime } }) { + yield put(requestPause()) + yield put(player.actions.selectEpisode(id)) + + const episode = yield loadEpisode(id) + yield put({ type: READY, payload: episode }) + yield delay(100) + yield put(requestPlaytime(playtime)) + yield takeOnce(BACKEND_LOADING_START, resetMeta) + } + + return function* () { + yield takeEvery(player.types.EPISODE_PLAY, playEpisode) + yield takeEvery(player.types.EPISODE_PAUSE, pauseEpisode) + yield takeEvery(player.types.EPISODE_RESTORE, restoreEpisode) + } +} diff --git a/apps/page/src/logic/sagas/index.ts b/apps/page/src/logic/sagas/index.ts new file mode 100644 index 000000000..a0926dc09 --- /dev/null +++ b/apps/page/src/logic/sagas/index.ts @@ -0,0 +1,9 @@ +import sagasEngine from '@podlove/player-sagas/middleware'; + +import { selectors } from '../store'; +import dataSagas from './data.sagas'; + +export function createSideEffects() { + const sagas = [dataSagas({ selectInitializedApp: selectors.runtime.initialized })]; + sagasEngine.run(...sagas); +} diff --git a/apps/page/src/logic/sagas/playbar.sagas.ts b/apps/page/src/logic/sagas/playbar.sagas.ts new file mode 100644 index 000000000..82f5b2adf --- /dev/null +++ b/apps/page/src/logic/sagas/playbar.sagas.ts @@ -0,0 +1,66 @@ +import { put, takeEvery, select } from 'redux-saga/effects' +import { + BACKEND_PLAY, + BACKEND_PAUSE, + BACKEND_LOADING_START, + BACKEND_LOADING_END, + BACKEND_END +} from '@podlove/player-actions/types' +import { setRate, mute, unmute } from '@podlove/player-actions/audio' + +import * as playbar from '~/store/reducers/playbar' + +export default ({ selectRate, selectMuted }) => { + function* play() { + yield put(playbar.actions.play()) + } + + function* pause() { + yield put(playbar.actions.pause()) + } + + function* loading() { + yield put(playbar.actions.loading()) + } + + function* restart() { + yield put(playbar.actions.restart()) + } + + function* loaded({ payload }) { + if (payload.paused) { + yield pause() + } else { + yield play() + } + } + + function* nextRate() { + const steps = [0.5, 0.75, 1, 1.25, 1.5, 1.75, 2.0] + const rate = yield select(selectRate) + + const next = steps.indexOf(rate) + 1 + + if (next < steps.length) { + yield put(setRate(steps[next])) + } else { + yield put(setRate(steps[0])) + } + } + + function* toggleMute() { + const muted = yield select(selectMuted) + + yield put(muted ? unmute() : mute()) + } + + return function* () { + yield takeEvery(BACKEND_PLAY, play) + yield takeEvery(BACKEND_PAUSE, pause) + yield takeEvery(BACKEND_LOADING_START, loading) + yield takeEvery(BACKEND_LOADING_END, loaded) + yield takeEvery(BACKEND_END, restart) + yield takeEvery(playbar.types.NEXT_RATE, nextRate) + yield takeEvery(playbar.types.TOGGLE_MUTE, toggleMute) + } +} diff --git a/apps/page/src/logic/sagas/router.sagas.ts b/apps/page/src/logic/sagas/router.sagas.ts new file mode 100644 index 000000000..d7766e457 --- /dev/null +++ b/apps/page/src/logic/sagas/router.sagas.ts @@ -0,0 +1,95 @@ +import { get } from 'lodash-es' +import { toHumanTime, toPlayerTime } from '@podlove/utils/time' +import { select, throttle, put, takeEvery, delay } from 'redux-saga/effects' +import { BACKEND_PLAYTIME } from '@podlove/player-actions/types' +import { takeOnce } from '@podlove/player-sagas/helper' +import { requestPlaytime } from '@podlove/player-actions/timepiece' + +import { actions as routerActions } from '../reducers/router.store' +import * as player from '../reducers/player.store' +import * as playbar from '../reducers/playbar.store' + +export default ({ + selectEpisode, + selectCurrentId, + selectPlaybarActive, + selectFollowContent, + router +}) => { + function* setPlaytime({ payload }) { + const searchParams = new URLSearchParams(window.location.search) + const playbar = yield select(selectPlaybarActive) + const episode = yield select(selectEpisode) + const current = yield select(selectCurrentId) + + if (!playbar || episode !== current) { + return + } + + searchParams.set('t', toHumanTime(payload)) + window.history.replaceState({}, '', `${location.pathname}?${searchParams}`) + } + + function* restoreEpisode({ payload }) { + yield delay(1000) + const id = get(payload, ['params', 'id']) + const playtime = get(payload, ['query', 't']) + + if (!id || !playtime) { + return + } + + yield put(player.actions.restoreEpisode({ id, playtime: toPlayerTime(playtime) })) + } + + function* restorePlaytime({ payload }) { + const id = get(payload, ['params', 'id']) + const playtime = get(payload, ['query', 't']) + + if (!id || !playtime) { + return + } + + yield put(requestPlaytime(toPlayerTime(playtime))) + } + + function* followContent() { + const follow = yield select(selectFollowContent) + const episode = yield select(selectEpisode) + const current = yield select(selectCurrentId) + + if (!follow) { + return + } + + if (episode === current) { + return + } + + router.push({ path: `/episode/${episode}` }) + } + + function* unfollowContent() { + const follow = yield select(selectFollowContent) + const episode = yield select(selectEpisode) + const current = yield select(selectCurrentId) + + if (!follow) { + return + } + + if (episode === current) { + return + } + + yield put(playbar.actions.toggleFollowContent()) + } + + return function* () { + yield throttle(1000, BACKEND_PLAYTIME, setPlaytime) + yield takeOnce(routerActions.routeTo, restoreEpisode) + yield takeEvery(routerActions.routeTo, restorePlaytime) + yield takeEvery(routerActions.routeTo, unfollowContent) + yield takeEvery(playbar.types.FOLLOW_CONTENT, followContent) + } +} diff --git a/apps/page/src/logic/sagas/search.sagas.ts b/apps/page/src/logic/sagas/search.sagas.ts new file mode 100644 index 000000000..c1ff22252 --- /dev/null +++ b/apps/page/src/logic/sagas/search.sagas.ts @@ -0,0 +1,184 @@ +import scrollIntoView from 'scroll-into-view-if-needed'; +import { types, actions } from '../reducers/search.store'; +import { channel } from '@podlove/player-sagas/helper'; +import { call, delay, put, select, takeEvery, throttle } from '@redux-saga/core/effects'; + +const focusSearch = () => { + setTimeout(() => { + const search = document.getElementById('search-input'); + search && search.focus(); + }, 300); +}; + +function nextResult({ selectResults, selectSelectedResult }) { + return function* (modifier) { + const results = yield select(selectResults); + const resultsMap = results.map(({ node }) => node.id); + + if (resultsMap.length === 0) { + return; + } + + const selectedResult = yield select(selectSelectedResult); + + const index = resultsMap.findIndex((result) => result === selectedResult); + const size = resultsMap.length - 1; + + let next; + + if (index === -1) { + next = 0; + } else { + next = index + modifier; + } + + if (next > size) { + next = 0; + } + + if (next < 0) { + next = size; + } + + focusResult(resultsMap[next]); + }; +} + +function registerKeyHandlers({ selectVisible, selectResults, selectSelectedResult }) { + return function* (event) { + const next = nextResult({ selectResults, selectSelectedResult }); + + const visible = yield select(selectVisible); + + if (visible && event.key === 'ArrowUp') { + yield next(-1); + event.preventDefault(); + } + + if (visible && (event.key === 'ArrowDown' || event.key === 'Tab')) { + yield next(1); + event.preventDefault(); + } + + if (event.metaKey && event.code === 'KeyK') { + if (!visible) { + yield put(actions.showSearch()); + } + + focusSearch(); + } + + if (visible && event.key === 'Escape') { + yield put(actions.hideSearch()); + } + }; +} + +function focusResult(id) { + const result = document.querySelector(`[data-result="${id}"]`); + result && result.focus(); +} + +function searchForResults({ selectInitialized, search }) { + return function* ({ payload }) { + const initialized = yield select(selectInitialized); + + if (!initialized) { + return; + } + + const results = search.search(payload); + yield put(actions.results(results)); + }; +} + +function* initSearch({ loadSearch, selectInitialized }) { + const initialized = yield select(selectInitialized); + + if (!initialized) { + yield put(actions.load()); + yield loadSearch(); + yield put(actions.initializedSearch()); + focusSearch(); + } +} + +function selectTranscript(router) { + return function* ({ payload }) { + yield router.push({ path: payload.node.episode.path }).catch((err) => {}); + + const result = document.evaluate( + `//span[contains(., "${payload.text}")]`, + document, + null, + XPathResult.ANY_TYPE, + null + ); + + if (result) { + const node = result.iterateNext(); + scrollIntoView(node, { behavior: 'auto', scrollMode: 'always', block: 'center' }); + node.style.background = 'yellow'; + } + yield put(actions.hideSearch()); + }; +} + +function selectContributor(router) { + return function* ({ payload }) { + yield router.push({ path: payload.path }).catch(() => {}); + yield put(actions.hideSearch()); + }; +} + +function selectEpisode(router) { + return function* ({ payload }) { + yield router.push({ path: payload.path }).catch(() => {}); + yield put(actions.hideSearch()); + }; +} + +function* disableOverflow() { + document.body.classList.add('overflow-hidden'); +} + +function* enableOverflow() { + document.body.classList.remove('overflow-hidden'); +} + +export default ({ + selectVisible, + selectResults, + selectInitialized, + selectSelectedResult, + Vue, + router +}) => { + return function* () { + const keyboardEvents = yield call(channel, (cb) => document.addEventListener('keydown', cb)); + + yield takeEvery( + keyboardEvents, + registerKeyHandlers({ selectVisible, selectResults, selectSelectedResult }) + ); + yield takeEvery(types.SEARCH_SHOW, initSearch, { + loadSearch: Vue.prototype.$searchLoad, + selectInitialized + }); + + yield takeEvery(types.SEARCH_SELECT_TRANSCRIPT, selectTranscript(router)); + yield takeEvery(types.SEARCH_SELECT_CONTRIBUTOR, selectContributor(router)); + yield takeEvery(types.SEARCH_SELECT_EPISODE, selectEpisode(router)); + yield takeEvery(types.SEARCH_SHOW, disableOverflow); + yield takeEvery(types.SEARCH_HIDE, enableOverflow); + + yield throttle( + 300, + types.SEARCH_QUERY, + searchForResults({ + selectInitialized, + search: Vue.prototype.$search + }) + ); + }; +}; diff --git a/apps/page/src/logic/store/actions.ts b/apps/page/src/logic/store/actions.ts new file mode 100644 index 000000000..652631516 --- /dev/null +++ b/apps/page/src/logic/store/actions.ts @@ -0,0 +1,27 @@ +import { setVolume } from '@podlove/player-actions/audio'; +import { setRate } from '@podlove/player-actions/audio'; +import { simulatePlaytime } from '@podlove/player-actions/timepiece'; +import { enableGhost, disableGhost } from '@podlove/player-actions/progress'; + +import { actions as lifecycle } from './stores/runtime.store'; +import { actions as episodes } from './stores/episodes.store'; +import { actions as search } from './stores/search.store'; +import { actions as player } from './stores/player.store'; +import { actions as playbar } from './stores/playbar.store'; +import { actions as subscribeButton } from './stores/subscribe-button.store'; +import { actions as router } from './stores/router.store'; + +export default { + ...episodes, + ...player, + ...playbar, + ...subscribeButton, + ...router, + ...search, + ...lifecycle, + setVolume, + setRate, + simulatePlaytime, + disableGhost, + enableGhost +}; diff --git a/apps/page/src/logic/store/helper.ts b/apps/page/src/logic/store/helper.ts new file mode 100644 index 000000000..d585cbfb2 --- /dev/null +++ b/apps/page/src/logic/store/helper.ts @@ -0,0 +1,3 @@ +import { get } from "lodash-es"; + +export const select = (prop: string, fallback = {}) => (data: any) => get(data, prop, fallback); diff --git a/apps/page/src/logic/store/index.ts b/apps/page/src/logic/store/index.ts new file mode 100644 index 000000000..d149c0878 --- /dev/null +++ b/apps/page/src/logic/store/index.ts @@ -0,0 +1,27 @@ +import { createStore as createReduxStore, applyMiddleware, compose, type Store } from 'redux'; +import sagasEngine from '@podlove/player-sagas/middleware'; + +import selectors from './selectors'; +import actions from './actions'; +import reducers from './reducers'; +import type State from './state'; + +export function createStore(): Store { + let composeEnhancers = compose; + let preloadedState = undefined; + + if (globalThis.window) { + composeEnhancers = (globalThis.window as any).__REDUX_DEVTOOLS_EXTENSION_COMPOSE__ || compose; + preloadedState = (globalThis.window as any).REDUX_STATE + } + + const store = createReduxStore( + reducers, + preloadedState, + composeEnhancers(applyMiddleware(sagasEngine.middleware)), + ); + + return store; +} + +export { selectors, actions, type State }; diff --git a/apps/page/src/logic/store/reducers.ts b/apps/page/src/logic/store/reducers.ts new file mode 100644 index 000000000..567450925 --- /dev/null +++ b/apps/page/src/logic/store/reducers.ts @@ -0,0 +1,47 @@ +import { combineReducers } from 'redux'; +import { reducer as driver } from '@podlove/player-state/driver'; +import { reducer as show } from '@podlove/player-state/show'; +import { reducer as media } from '@podlove/player-state/media'; +import { reducer as timepiece } from '@podlove/player-state/timepiece'; +import { reducer as episode } from '@podlove/player-state/episode'; +import { reducer as audio } from '@podlove/player-state/audio'; +import { reducer as network } from '@podlove/player-state/network'; +import { reducer as ghost } from '@podlove/player-state/ghost'; +import { reducer as chapters } from '@podlove/player-state/chapters'; +import { reducer as quantiles } from '@podlove/player-state/quantiles'; + +import { reducer as runtime } from './stores/runtime.store'; +import { reducer as theme } from './stores/theme.store'; +import { reducer as podcast } from './stores/podcast.store'; +import { reducer as action } from './stores/action.store'; +import { reducer as episodes } from './stores/episodes.store'; +import { reducer as playbar } from './stores/playbar.store'; +import { reducer as player } from './stores/player.store'; +import { reducer as router } from './stores/router.store'; +import { reducer as search } from './stores/search.store'; +import { reducer as subscribeButton } from './stores/subscribe-button.store'; + +export default combineReducers({ + runtime, + action, + episodes, + playbar, + podcast, + theme, + player: combineReducers({ + quantiles, + chapters, + ghost, + network, + driver, + show, + media, + timepiece, + episode, + audio, + current: player + }), + router, + search, + subscribeButton +}); diff --git a/apps/page/src/logic/store/selectors.ts b/apps/page/src/logic/store/selectors.ts new file mode 100644 index 000000000..91f5d49f8 --- /dev/null +++ b/apps/page/src/logic/store/selectors.ts @@ -0,0 +1,273 @@ +import { createSelector } from 'reselect'; +import { calcHours, calcMinutes, calcSeconds } from '@podlove/utils/time'; +import { selectors as driver } from '@podlove/player-state/driver'; +import { selectors as show } from '@podlove/player-state/show'; +import { selectors as media } from '@podlove/player-state/media'; +import { selectors as timepiece } from '@podlove/player-state/timepiece'; +import { selectors as episode } from '@podlove/player-state/episode'; +import { selectors as audio } from '@podlove/player-state/audio'; +import { selectors as network } from '@podlove/player-state/network'; +import { selectors as ghost } from '@podlove/player-state/ghost'; +import { selectors as chapters } from '@podlove/player-state/chapters'; +import { selectors as quantiles } from '@podlove/player-state/quantiles'; + +import { currentChapterByPlaytime } from '@podlove/utils/chapters'; + +import type State from './state'; + +import { selectors as runtime } from './stores/runtime.store'; +import { selectors as theme } from './stores/theme.store'; +import { selectors as podcast } from './stores/podcast.store'; +import { selectors as episodes } from './stores/episodes.store'; +import { selectors as player } from './stores/player.store'; +import { selectors as playbar } from './stores/playbar.store'; +import { selectors as subscribeButton } from './stores/subscribe-button.store'; +import { selectors as router } from './stores/router.store'; +import { selectors as search } from './stores/search.store'; +import { select } from './helper'; +import type { PodloveWebPlayerChapter } from '@podlove/types'; + +const slices = { + runtime: select('runtime'), + theme: select('theme'), + podcast: select('podcast'), + player: select('player'), + playbar: select('playbar'), + router: select('router'), + search: select('search'), + episodes: select('episodes'), + subscribeButton: select('subscribeButton') +}; + +const playtime = createSelector(slices.player, select('timepiece'), timepiece.playtime); +const duration = createSelector(slices.player, select('timepiece'), timepiece.duration); + +const showTitle = createSelector(slices.player, select('show'), show.title); +const showPoster = createSelector(slices.player, select('show'), show.poster); + +const episodeTitle = createSelector(slices.player, select('episode'), episode.title); +const episodePoster = createSelector(slices.player, select('episode'), episode.poster); + +const playing = createSelector(slices.player, select('driver'), driver.playing); +const currentEpisode = createSelector(slices.player, select('current'), player.episode); + +const volume = createSelector(slices.player, select('audio'), audio.volume); +const muted = createSelector(slices.player, select('audio'), audio.muted); +const rate = createSelector(slices.player, select('audio'), audio.rate); + +const playerGhostTime = createSelector(slices.player, select('ghost'), ghost.time); + +// chapters +const chaptersList = createSelector(slices.player, select('chapters'), chapters.list); +const chaptersNext = createSelector(slices.player, select('chapters'), chapters.next); +const chaptersPrevious = createSelector(slices.player, select('chapters'), chapters.previous); +const chaptersCurrent = createSelector(slices.player, select('chapters'), chapters.current); +const chaptersTitle = createSelector(slices.player, select('chapters'), chapters.title); +const chaptersImage = createSelector(slices.player, select('chapters'), chapters.image); + +const translation = (key: string, attr = {}) => ({ key, attr }); + +export default { + runtime: { + initialized: createSelector(slices.runtime, runtime.initialized), + locale: createSelector(slices.runtime, runtime.locale), + }, + theme: { + background: createSelector(slices.theme, theme.background) + }, + podcast: { + feed: createSelector(slices.podcast, podcast.feed), + title: createSelector(slices.podcast, podcast.title), + image: createSelector(slices.podcast, podcast.image), + description: createSelector(slices.podcast, podcast.description), + summary: createSelector(slices.podcast, podcast.summary), + episodes: createSelector(slices.podcast, podcast.episodes), + }, + current: { + episode: currentEpisode + }, + episode: { + data: (id: number | string) => createSelector(slices.episodes, episodes.item(id)), + title: episodeTitle, + poster: episodePoster, + loaded: (id: string) => + createSelector(currentEpisode, (episodeId: string | null) => episodeId === id), + playing: (id: string) => + createSelector( + [currentEpisode, playing], + (episodeId: string | null, isPlaying: boolean) => episodeId === id && isPlaying + ) + }, + show: { + poster: showPoster, + title: showTitle + }, + player: { + playtime, + duration, + playing, + title: createSelector( + [episodeTitle, showTitle], + (episode: string | null, show: string | null) => episode || show + ), + image: createSelector( + [episodePoster, showPoster], + (episode: string | null, show: string | null) => episode || show + ), + quantiles: createSelector(slices.player, select('quantiles'), quantiles.quantiles), + buffer: createSelector(slices.player, select('network'), network.buffer), + ghost: { + time: playerGhostTime, + active: createSelector(slices.player, select('ghost'), ghost.active), + chapter: createSelector( + [chaptersList, playerGhostTime], + (chapters: PodloveWebPlayerChapter[], ghostPlaytime: number | null) => + currentChapterByPlaytime(chapters, ghostPlaytime || 0) + ) + }, + media: createSelector(slices.player, select('media'), media.media), + audio: { + muted, + volume, + rate + }, + chapters: { + list: chaptersList, + next: chaptersNext, + previous: chaptersPrevious, + current: chaptersCurrent, + title: chaptersTitle, + image: chaptersImage + } + }, + playbar: { + active: createSelector(slices.playbar, playbar.active), + path: createSelector(slices.playbar, playbar.path), + button: createSelector(slices.playbar, playbar.button), + followContent: createSelector(slices.playbar, playbar.followContent), + volume: (state: State) => { + if (muted(state)) { + return 'speaker-0'; + } + + if (volume(state) >= 0.75) { + return 'speaker-75'; + } + + if (volume(state) >= 0.5) { + return 'speaker-50'; + } + + if (volume(state) > 0) { + return 'speaker-25'; + } + + return 'speaker-0'; + }, + rate: (state: State) => { + if (rate(state) <= 0.5) { + return 'speed-050'; + } + + if (rate(state) <= 0.75) { + return 'speed-075'; + } + + if (rate(state) <= 1) { + return 'speed-100'; + } + + if (rate(state) <= 1.25) { + return 'speed-125'; + } + + if (rate(state) <= 1.5) { + return 'speed-150'; + } + + if (rate(state) <= 1.75) { + return 'speed-175'; + } + + return 'speed-200'; + }, + chapters: createSelector(slices.playbar, playbar.chapters), + }, + subscribeButton: { + visible: createSelector(slices.subscribeButton, subscribeButton.visible) + }, + router: { + id: createSelector(slices.router, router.id), + episode: createSelector(slices.router, router.episode) + }, + search: { + query: createSelector(slices.search, search.query), + visible: createSelector(slices.search, search.visible), + initialized: createSelector(slices.search, search.initialized), + loading: createSelector(slices.search, search.loading), + contributors: createSelector(slices.search, search.contributors), + episodes: createSelector(slices.search, search.episodes), + transcripts: createSelector(slices.search, search.transcripts), + results: createSelector(slices.search, search.results), + hasResults: createSelector(slices.search, search.hasResults), + selectedResult: createSelector(slices.search, search.selectedResult) + }, + a11y: { + chapterNext: (state: State) => { + const next = chaptersNext(state); + + if (!next) { + return translation('A11Y.PLAYER_CHAPTER_END'); + } + + return translation('A11Y.PLAYER_CHAPTER_NEXT', next); + }, + chapterPrevious: (state: State) => { + const previous = chaptersPrevious(state); + const current = chaptersCurrent(state); + + if (!previous) { + return translation('A11Y.PLAYER_CHAPTER_START'); + } + + if (Number(current?.start) + 2000 > playtime(state)) { + return translation('A11Y.PLAYER_CHAPTER_CURRENT', current); + } + + return translation('A11Y.PLAYER_CHAPTER_PREVIOUS', previous); + }, + progressBar: () => { + return translation('A11Y.PROGRESSBAR_INPUT'); + }, + stepperBackwards: () => { + return translation('A11Y.PLAYER_STEPPER_BACK', { seconds: 15 }); + }, + stepperForward: () => { + return translation('A11Y.PLAYER_STEPPER_FORWARD', { seconds: 30 }); + }, + playButtonPause: (state: State) => { + return translation('A11Y.PLAYER_PAUSE', chaptersCurrent(state)); + }, + playButtonDuration: (state: State) => { + const time = { + duration: duration(state), + playtime: playtime(state) + }; + + return translation('A11Y.PLAYER_START', { + hours: calcHours(time.playtime > 0 ? time.playtime : time.duration), + minutes: calcMinutes(time.playtime > 0 ? time.playtime : time.duration), + seconds: calcSeconds(time.playtime > 0 ? playtime : time.duration) + }); + }, + playButtonReplay: () => { + return translation('A11Y.PLAYER_LOADING'); + }, + playButtonPlay: () => { + return translation('A11Y.PLAYER_PLAY'); + }, + playButtonError: () => { + return translation('A11Y.PLAYER_ERROR'); + } + } +}; diff --git a/apps/page/src/logic/store/state.ts b/apps/page/src/logic/store/state.ts new file mode 100644 index 000000000..e8e06d513 --- /dev/null +++ b/apps/page/src/logic/store/state.ts @@ -0,0 +1,46 @@ +import { type State as driver } from '@podlove/player-state/driver'; +import { type State as show } from '@podlove/player-state/show'; +import { type State as media } from '@podlove/player-state/media'; +import { type State as timepiece } from '@podlove/player-state/timepiece'; +import { type State as episode } from '@podlove/player-state/episode'; +import { type State as audio } from '@podlove/player-state/audio'; +import { type State as network } from '@podlove/player-state/network'; +import { type State as ghost } from '@podlove/player-state/ghost'; +import { type State as chapters } from '@podlove/player-state/chapters'; +import { type State as quantiles } from '@podlove/player-state/quantiles'; + +import { type State as runtime } from './stores/runtime.store'; +import { type State as theme } from './stores/theme.store'; +import { type State as podcast } from './stores/podcast.store'; +import { type State as action } from './stores/action.store'; +import { type State as episodes } from './stores/episodes.store'; +import { type State as playbar } from './stores/playbar.store'; +import { type State as player } from './stores/player.store'; +import { type State as router } from './stores/router.store'; +import { type State as search } from './stores/search.store'; +import { type State as subscribeButton } from './stores/subscribe-button.store'; + +export default interface State { + runtime: runtime, + podcast: podcast, + action: action, + episodes: episodes, + playbar: playbar, + theme: theme, + player: { + quantiles: quantiles, + chapters: chapters, + ghost: ghost, + network: network, + driver: driver, + show: show, + media: media, + timepiece: timepiece, + episode: episode, + audio: audio, + current: player + }, + router: router, + search: search, + subscribeButton: subscribeButton +}; diff --git a/apps/page/src/logic/store/stores/action.store.ts b/apps/page/src/logic/store/stores/action.store.ts new file mode 100644 index 000000000..7e4fd63fa --- /dev/null +++ b/apps/page/src/logic/store/stores/action.store.ts @@ -0,0 +1,10 @@ +import type { Action } from 'redux'; + +export const INITIAL_STATE = { + type: null, + payload: null +}; + +export type State = Action; + +export const reducer = (_state = INITIAL_STATE, action: Action) => action; diff --git a/apps/page/src/logic/store/stores/episodes.store.ts b/apps/page/src/logic/store/stores/episodes.store.ts new file mode 100644 index 000000000..95da11cea --- /dev/null +++ b/apps/page/src/logic/store/stores/episodes.store.ts @@ -0,0 +1,36 @@ +import { handleActions, createAction, type Action } from 'redux-actions'; + +import { get } from 'lodash-es'; + +import { actions as lifecycleActions, type dataFetchedPayload } from './runtime.store' +import type { Episode } from '../../../types/feed.types'; + +export interface State { + [key: string]: Episode; +} + +type addEpisodePayload = Episode + +export const actions = { + addEpisode: createAction('EPISODES_ADD') +}; + +export const reducer = handleActions({ + [lifecycleActions.dataFetched.toString()]: (state, { payload }: Action) => { + return payload.episodes.reduce((result, episode) => ({ + ...result, + [episode.id]: episode + }), state) + }, + [actions.addEpisode.toString()]: (state: State, { payload }: Action) => ({ + ...state, + [payload.id]: payload + }) + }, + {} +); + +export const selectors = { + item: (id: string | number) => (state: State) => get(state, id, {}) as Episode, + list: (state: State) => state +}; diff --git a/apps/page/src/logic/store/stores/playbar.store.ts b/apps/page/src/logic/store/stores/playbar.store.ts new file mode 100644 index 000000000..357f728a3 --- /dev/null +++ b/apps/page/src/logic/store/stores/playbar.store.ts @@ -0,0 +1,75 @@ +import { get } from 'lodash-es'; +import { ready, type readyPayload } from '@podlove/player-actions/lifecycle' +import { handleActions, createAction, type Action } from 'redux-actions' +import * as player from './player.store' + +export const actions = { + play: createAction('PLAYBAR_PLAY'), + pause: createAction('PLAYBAR_PAUSE'), + loading: createAction('PLAYBAR_LOADING'), + restart: createAction('PLAYBAR_RESTART'), + toggleMute: createAction('TOGGLE_MUTE'), + nextRate: createAction('NEXT_RATE'), + toggleFollowContent: createAction('FOLLOW_CONTENT'), + toggleChaptersOverlay: createAction('TOGGLE_CHAPTERS') +} + +export interface State { + active: boolean; + button: 'play' | 'pause' | 'loading' | 'restart'; + followContent: boolean; + chapters: boolean; + path: string; +} + +export const reducer = handleActions( + { + [actions.play.toString()]: (state) => ({ + ...state, + button: 'pause' + }), + [actions.pause.toString()]: (state) => ({ + ...state, + button: 'play' + }), + [actions.loading.toString()]: (state) => ({ + ...state, + button: 'loading' + }), + [actions.restart.toString()]: (state) => ({ + ...state, + button: 'restart' + }), + [actions.toggleFollowContent.toString()]: (state) => ({ + ...state, + followContent: !state.followContent + }), + [ready.toString()]: (state, { payload }: Action) => ({ + ...state, + path: get(payload, 'path', '') + }), + [actions.toggleChaptersOverlay.toString()]: (state) => ({ + ...state, + chapters: !state.chapters + }), + [player.actions.selectEpisode.toString()]: (state) => ({ + ...state, + active: true + }) + }, + { + active: false, + button: 'play', + followContent: false, + chapters: false, + path: '' + } +); + +export const selectors = { + active: (state: State) => state.active, + button: (state: State) => state.button, + followContent: (state: State) => state.followContent, + path: (state: State) => state.path, + chapters: (state: State) => state.chapters +} diff --git a/apps/page/src/logic/store/stores/player.store.ts b/apps/page/src/logic/store/stores/player.store.ts new file mode 100644 index 000000000..300bab809 --- /dev/null +++ b/apps/page/src/logic/store/stores/player.store.ts @@ -0,0 +1,30 @@ +import { handleActions, createAction, type Action } from 'redux-actions' + +type selectEpisodePayload = string; + +export const actions = { + playEpisode: createAction('EPISODE_PLAY'), + pauseEpisode: createAction('EPISODE_PAUSE'), + selectEpisode: createAction('EPISODE_SELECT'), + restoreEpisode: createAction('EPISODE_RESTORE') +} + +export interface State { + episode: string | null; +} + +export const reducer = handleActions( + { + [actions.selectEpisode.toString()]: (state, { payload }: Action) => ({ + ...state, + episode: payload + }) + }, + { + episode: null + } +); + +export const selectors = { + episode: (state: State) => state.episode +} diff --git a/apps/page/src/logic/store/stores/podcast.store.ts b/apps/page/src/logic/store/stores/podcast.store.ts new file mode 100644 index 000000000..2691b99fd --- /dev/null +++ b/apps/page/src/logic/store/stores/podcast.store.ts @@ -0,0 +1,43 @@ +import { handleActions, type Action } from 'redux-actions'; +import { actions as lifecycleActions, type dataFetchedPayload, type initializePayload } from './runtime.store' +import { get } from 'lodash-es'; + +export interface State { + feed: string | null; + title: string | null; + image: string | null; + description: string | null; + summary: string | null; + episodes: string[]; +} + +export const reducer = handleActions({ + [lifecycleActions.dataFetched.toString()]: (state, { payload }: Action) => ({ + ...state, + title: get(payload, ['show', 'title'], null), + image: get(payload, ['show', 'image'], null), + description: get(payload, ['show', 'description'], null), + summary: get(payload, ['show', 'summary'], null), + episodes: get(payload, ['episodes'], []).map(({ id }) => id) + }), + [lifecycleActions.initializeApp.toString()]: (state, { payload }: Action) => ({ + ...state, + feed: payload.feed + }) +}, { + feed: null, + title: null, + image: null, + description: null, + summary: null, + episodes: [] +}); + +export const selectors = { + feed: (state: State) => get(state, 'feed'), + title: (state: State) => get(state, 'title'), + image: (state: State) => get(state, 'image'), + description: (state: State) => get(state, 'description'), + summary: (state: State) => get(state, 'summary'), + episodes: (state: State) => get(state, 'episodes'), +} diff --git a/apps/page/src/logic/store/stores/router.store.ts b/apps/page/src/logic/store/stores/router.store.ts new file mode 100644 index 000000000..54c327b3c --- /dev/null +++ b/apps/page/src/logic/store/stores/router.store.ts @@ -0,0 +1,36 @@ +import { handleActions, createAction, type Action } from 'redux-actions' +import { get } from 'lodash-es' + +interface routeToPayload { + params: { + id: string; + }; + path: string; +} + +export const actions = { + routeTo: createAction('ROUTE') +} + +export interface State { + id: string | null; + episode: string | null; +} + +export const reducer = handleActions( + { + [actions.routeTo.toString()]: (_, { payload }: Action) => ({ + id: get(payload, ['params', 'id'], null), + episode: get(payload, 'path', null), + }) + }, + { + id: null, + episode: null + } +) + +export const selectors = { + id: (state: State) => state.id, + episode: (state: State) => state.episode, +} diff --git a/apps/page/src/logic/store/stores/runtime.store.ts b/apps/page/src/logic/store/stores/runtime.store.ts new file mode 100644 index 000000000..9b0af3e04 --- /dev/null +++ b/apps/page/src/logic/store/stores/runtime.store.ts @@ -0,0 +1,38 @@ +import { createAction, handleActions, type Action } from 'redux-actions'; +import type { Podcast } from '../../../types/feed.types'; + +export interface State { + initialized: boolean; + locale: string; +} + +export interface initializePayload { + feed: string; + locale: string; +} + +export type dataFetchedPayload = Podcast; + +export const actions = { + initializeApp: createAction('INITIALIZE'), + dataFetched: createAction('DATA_FETCHED') +}; + +export const reducer = handleActions( + { + [actions.initializeApp.toString()]: (state, { payload}: Action) => ({ + ...state, + locale: payload.locale + }), + [actions.dataFetched.toString()]: (state) => ({ + ...state, + initialized: true + }) + }, + { initialized: false, locale: 'en-US' } +); + +export const selectors = { + initialized: (state: State) => state.initialized, + locale: (state: State) => state.locale, +}; diff --git a/apps/page/src/logic/store/stores/search.store.ts b/apps/page/src/logic/store/stores/search.store.ts new file mode 100644 index 000000000..0e722a177 --- /dev/null +++ b/apps/page/src/logic/store/stores/search.store.ts @@ -0,0 +1,101 @@ +import type { PodloveWebPlayerContributor, PodloveWebPlayerTranscript } from '@podlove/types'; +import type { PodloveWebPlayerEpisode } from '@podlove/types'; +import { handleActions, createAction, type Action } from 'redux-actions'; + +type showSearchActionPayload = void; +type hideSearchActionPayload = void; +type loadActionPayload = void; +type initializedSearchPayload = void; +type searchActionPayload = string; +type resultsActionPayload = any[] +type selectSearchResultPayload = number; + +export const actions = { + initializedSearch: createAction('SEARCH_INITIALIZED'), + showSearch: createAction('SEARCH_SHOW'), + hideSearch: createAction('SEARCH_HIDE'), + search: createAction('SEARCH_QUERY'), + results: createAction('SEARCH_RESULTS'), + selectSearchResult: createAction('SEARCH_SELECT_RESULT'), + load: createAction('SEARCH_LOADING') +} + +export interface State { + visible: boolean; + loading: boolean; + hasResults: boolean; + query: string; + episodes: PodloveWebPlayerEpisode[]; + contributors: PodloveWebPlayerContributor[]; + transcripts: PodloveWebPlayerTranscript[]; + selectedResult: null | number; + initialized: boolean; +} + +export const reducer = handleActions( + { + [actions.showSearch.toString()]: (state) => ({ + ...state, + visible: true, + hasResults: false, + query: '', + episodes: [], + contributors: [], + transcripts: [], + selectedResult: null + }), + [actions.hideSearch.toString()]: (state) => ({ + ...state, + visible: false + }), + [actions.search.toString()]: (state, { payload }: Action) => ({ + ...state, + query: payload + }), + [actions.results.toString()]: (state, { payload }: Action) => ({ + ...state, + hasResults: payload.length > 0, + contributors: payload.filter(({ index }) => index === 'contributor').slice(0, 5), + episodes: payload.filter(({ index }) => index === 'episode').slice(0, 5), + transcripts: payload.filter(({ index }) => index === 'transcript').slice(0, 5) + }), + [actions.initializedSearch.toString()]: (state) => ({ + ...state, + initialized: true, + loading: false + }), + [actions.load.toString()]: (state) => ({ + ...state, + loading: true + }), + [actions.selectSearchResult.toString()]: (state, { payload }: Action) => ({ + ...state, + selectedResult: payload + }) + }, + { + visible: false, + loading: false, + hasResults: false, + query: '', + episodes: [], + contributors: [], + transcripts: [], + selectedResult: null, + initialized: false + } +) + + +export const selectors = { + initialized: (state: State) => state.initialized, + loading:(state: State) => state.loading, + visible: (state: State) => state.visible, + query: (state: State) => state.query, + contributors: (state: State) => state.contributors, + episodes: (state: State) => state.episodes, + transcripts: (state: State) => state.transcripts, + hasResults: (state: State) => state.hasResults, + selectedResult: (state: State) => state.selectedResult, + results: (state: State) => [...state.contributors, ...state.episodes, ...state.transcripts] +} diff --git a/apps/page/src/logic/store/stores/subscribe-button.store.ts b/apps/page/src/logic/store/stores/subscribe-button.store.ts new file mode 100644 index 000000000..31cd8a2a4 --- /dev/null +++ b/apps/page/src/logic/store/stores/subscribe-button.store.ts @@ -0,0 +1,25 @@ +import { handleActions, createAction } from 'redux-actions'; + +export interface State { + visible: boolean; +} + +export const actions = { + toggleSubscribeOverlay: createAction('TOGGLE_SUBSCRIBE_OVERLAY') +}; + +export const reducer = handleActions( + { + [actions.toggleSubscribeOverlay.toString()]: (state) => ({ + ...state, + visible: !state.visible + }) + }, + { + visible: false + } +); + +export const selectors = { + visible: (state: State) => state.visible +}; diff --git a/apps/page/src/logic/store/stores/theme.store.ts b/apps/page/src/logic/store/stores/theme.store.ts new file mode 100644 index 000000000..fe5dea56e --- /dev/null +++ b/apps/page/src/logic/store/stores/theme.store.ts @@ -0,0 +1,16 @@ +import { handleActions, type Action } from 'redux-actions'; + +export interface State { + background: string | null; +} + +export const reducer = handleActions( + { + + }, + { background: null } +); + +export const selectors = { + background: (state: State) => state.background +}; diff --git a/apps/page/src/middleware/index.ts b/apps/page/src/middleware/index.ts new file mode 100644 index 000000000..94ccb238c --- /dev/null +++ b/apps/page/src/middleware/index.ts @@ -0,0 +1,4 @@ +import { sequence } from 'astro:middleware'; +import { initializeStore } from './store'; + +export const onRequest = sequence(initializeStore); diff --git a/apps/page/src/middleware/store.ts b/apps/page/src/middleware/store.ts new file mode 100644 index 000000000..02134dddb --- /dev/null +++ b/apps/page/src/middleware/store.ts @@ -0,0 +1,31 @@ +import { defineMiddleware } from 'astro:middleware'; +import { waitFor } from '@podlove/utils/promise'; +import { get } from 'lodash-es'; +import { actions, store, selectors } from '../logic'; + +const FEED_COOKIE = 'PODCAST_FEED'; + +export const initializeStore = defineMiddleware(async ({ request, cookies }, next) => { + const url = new URL(request.url); + const acceptedLanguage = (request.headers.get('accept-language') || '') + + const locale = get(acceptedLanguage.split(','), 0, 'en-US'); + const feed = url.searchParams.get('feed') || cookies.get(FEED_COOKIE)?.value; + + if (!feed) { + throw Error('Missing Feed Url'); + } + + store.dispatch(actions.initializeApp({ feed, locale })); + + await waitFor(() => { + const initialized = selectors.runtime.initialized(store.getState()); + return initialized ? true : undefined; + }).catch((err) => { + console.error('timeout fetching data'); + }); + + cookies.set(FEED_COOKIE, feed, { path: '/' }); + + return next(); +}); diff --git a/apps/page/src/pages/episodes/[id].astro b/apps/page/src/pages/episodes/[id].astro new file mode 100644 index 000000000..c63796b01 --- /dev/null +++ b/apps/page/src/pages/episodes/[id].astro @@ -0,0 +1,84 @@ +--- +import Layout from '../../layouts/Layout.astro'; +import { store, selectors } from '../../logic'; +import Hero from '../../screens/episodes/Hero.vue' +import { useTranslations } from '../../i18n' + +const { id } = Astro.params; +const $t = useTranslations(); +const podcastTitle = selectors.podcast.title(store.getState()); +const episode = selectors.episode.data(id as string)(store.getState()); +--- + + + { id && } +
+
+
+

+ { $t('EPISODE.SUMMARY') } +

+
+ { episode.description } +
+
+ { episode.content &&
+

+ { $t('EPISODE.SHOWNOTES') } +

+
+
} +
+

+ { $t('EPISODE.TIMELINE') } +

+ +
+
+
+
+ + + diff --git a/apps/page/src/pages/index.astro b/apps/page/src/pages/index.astro new file mode 100644 index 000000000..b8eb7b07c --- /dev/null +++ b/apps/page/src/pages/index.astro @@ -0,0 +1,25 @@ +--- +import Layout from '../layouts/Layout.astro'; +import EpisodeItem from '../screens/archive/EpisodeItem.vue'; +import { selectors, store } from '../logic'; +import HeroIndex from '../screens/archive/Hero.vue'; + +const title = selectors.podcast.title(store.getState()); +const episodes = selectors.podcast.episodes(store.getState()); +--- + + + + +
+
+ { + episodes.map((episode, index) => ) + } +
+
+
+ + diff --git a/apps/page/src/screens/archive/EpisodeItem.vue b/apps/page/src/screens/archive/EpisodeItem.vue new file mode 100644 index 000000000..fe3902689 --- /dev/null +++ b/apps/page/src/screens/archive/EpisodeItem.vue @@ -0,0 +1,101 @@ + + + diff --git a/apps/page/src/screens/archive/Hero.vue b/apps/page/src/screens/archive/Hero.vue new file mode 100644 index 000000000..5f433c4aa --- /dev/null +++ b/apps/page/src/screens/archive/Hero.vue @@ -0,0 +1,56 @@ + + + diff --git a/apps/page/src/screens/episodes/Hero.vue b/apps/page/src/screens/episodes/Hero.vue new file mode 100644 index 000000000..9c8781cff --- /dev/null +++ b/apps/page/src/screens/episodes/Hero.vue @@ -0,0 +1,96 @@ + + + diff --git a/apps/page/src/screens/episodes/Navigation.vue b/apps/page/src/screens/episodes/Navigation.vue new file mode 100644 index 000000000..c766a4bdc --- /dev/null +++ b/apps/page/src/screens/episodes/Navigation.vue @@ -0,0 +1,140 @@ + + + + + diff --git a/apps/page/src/types/feed.types.ts b/apps/page/src/types/feed.types.ts new file mode 100644 index 000000000..8d5e12e54 --- /dev/null +++ b/apps/page/src/types/feed.types.ts @@ -0,0 +1,33 @@ +export interface Podcast { + show: Show; + episodes: Episode[]; + hosts: Person[]; +} + +export interface Show { + title: string; + description: string; + link: string; + image: string; + summary: string; +} + +export interface Episode { + id: string; + title: string | null; + publicationDate: string | null; + description: string | null; + subtitle: string | null; + duration: number | null; + content: string | null; + contributors: Person[]; + poster: string; +} + +export interface Person { + name: string | null; + role: string | null; + image: string | null; + id: string | null; + slug: string | null; +} diff --git a/apps/page/tailwind.config.cjs b/apps/page/tailwind.config.cjs new file mode 100644 index 000000000..55cd35284 --- /dev/null +++ b/apps/page/tailwind.config.cjs @@ -0,0 +1,102 @@ +/** @type {import('tailwindcss').Config} */ +module.exports = { + content: ['./src/**/*.{astro,html,js,jsx,md,mdx,svelte,ts,tsx,vue}'], + theme: { + colors: { + primary: { + 100: 'var(--primary-color-100)', + 200: 'var(--primary-color-200)', + 300: 'var(--primary-color-300)', + 400: 'var(--primary-color-400)', + 500: 'var(--primary-color-500)', + 600: 'var(--primary-color-600)', + 700: 'var(--primary-color-700)', + 800: 'var(--primary-color-900)', + 900: 'var(--primary-color-900)' + }, + secondary: { + 100: 'var(--secondary-color-100)', + 200: 'var(--secondary-color-200)', + 300: 'var(--secondary-color-300)', + 400: 'var(--secondary-color-400)', + 500: 'var(--secondary-color-500)', + 600: 'var(--secondary-color-600)', + 700: 'var(--secondary-color-700)', + 800: 'var(--secondary-color-800)', + 900: 'var(--secondary-color-900)' + }, + complementary: { + 100: 'var(--complementary-color-100)', + 200: 'var(--complementary-color-200)', + 300: 'var(--complementary-color-300)', + 400: 'var(--complementary-color-400)', + 500: 'var(--complementary-color-500)', + 600: 'var(--complementary-color-600)', + 700: 'var(--complementary-color-700)', + 800: 'var(--complementary-color-800)', + 900: 'var(--complementary-color-900)' + }, + gray: { + 100: 'var(--gray-color-100)', + 200: 'var(--gray-color-200)', + 300: 'var(--gray-color-300)', + 400: 'var(--gray-color-400)', + 500: 'var(--gray-color-500)', + 600: 'var(--gray-color-600)', + 700: 'var(--gray-color-700)', + 800: 'var(--gray-color-800)', + 900: 'var(--gray-color-900)' + } + }, + screens: { + sm: '640px', + md: '768px', + lg: '1024px', + xl: '1280px' + }, + fontFamily: { + sans: [ + 'Roboto', + 'system-ui', + '-apple-system', + 'BlinkMacSystemFont', + '"Segoe UI"', + '"Helvetica Neue"', + 'Arial', + '"Noto Sans"', + 'sans-serif', + '"Apple Color Emoji"', + '"Segoe UI Emoji"', + '"Segoe UI Symbol"', + '"Noto Color Emoji"' + ], + mono: [ + 'Roboto Mono', + 'Menlo', + 'Monaco', + 'Consolas', + '"Liberation Mono"', + '"Courier New"', + 'monospace' + ] + }, + inset: { + 0: 0, + auto: 'auto', + 100: '100%' + }, + extend: { + spacing: { + 96: '24rem', + 128: '32rem' + }, + width: { + app: '1024px' + } + } + }, + variants: { + visibility: ['responsive', 'hover', 'focus', 'group-hover'] + }, + plugins: [] +}; diff --git a/apps/page/tsconfig.json b/apps/page/tsconfig.json new file mode 100644 index 000000000..a70a5efd5 --- /dev/null +++ b/apps/page/tsconfig.json @@ -0,0 +1,6 @@ +{ + "extends": "astro/tsconfigs/strict", + "compilerOptions": { + "jsx": "preserve" + } +} diff --git a/apps/player/src/components/play-button/PlayButton.vue b/apps/player/src/components/play-button/PlayButton.vue index 07d85fcc7..4649a53ba 100644 --- a/apps/player/src/components/play-button/PlayButton.vue +++ b/apps/player/src/components/play-button/PlayButton.vue @@ -1,7 +1,7 @@ diff --git a/apps/page/src/features/timeline/Transcript.vue b/apps/page/src/features/timeline/Transcript.vue index 101e08284..5d388b44d 100644 --- a/apps/page/src/features/timeline/Transcript.vue +++ b/apps/page/src/features/timeline/Transcript.vue @@ -2,11 +2,16 @@
- - - + + + + - + + + + +

{{ speaker.name }}

@@ -32,7 +37,7 @@ }" class="mr-1 break-words cursor-pointer" @click="play(text.start)" - @mouseover="simulateSection(text.start, text.end)" + @mouseover="simulateSection(text.start)" @mouseout="disableGhost" v-for="(text, index) in texts" :key="text.start" @@ -43,103 +48,92 @@
- diff --git a/apps/page/src/layouts/Layout.astro b/apps/page/src/layouts/Layout.astro index 1f4d69425..a864854ce 100644 --- a/apps/page/src/layouts/Layout.astro +++ b/apps/page/src/layouts/Layout.astro @@ -1,12 +1,13 @@ --- import { ViewTransitions } from "astro:transitions"; import PageHeader from '../features/PageHeader.vue'; +import PlayBar from '../features/playbar/Playbar.vue'; +import { store } from '../logic'; +import { getLanguage } from "../i18n"; + const { title } = Astro.props; -import { selectors, store }from '../logic'; const state = store.getState(); const lang = getLanguage(); -import Test from '../components/Test.vue' -import { getLanguage } from "../i18n"; --- @@ -23,11 +24,10 @@ import { getLanguage } from "../i18n"; -
- + diff --git a/apps/page/src/logic/data/feed-parser.ts b/apps/page/src/logic/data/feed-parser.ts index 6cfb19eac..efd86e2d0 100644 --- a/apps/page/src/logic/data/feed-parser.ts +++ b/apps/page/src/logic/data/feed-parser.ts @@ -1,7 +1,17 @@ -import { get, castArray } from 'lodash-es'; +import { get, castArray, kebabCase } from 'lodash-es'; import { XMLParser } from 'fast-xml-parser'; -import type { Chapter, Episode, Person, Podcast, Show } from '../../types/feed.types'; +import type { + Audio, + Chapter, + Episode, + Person, + Podcast, + Show, + Transcript +} from '../../types/feed.types'; import { toPlayerTime } from '@podlove/utils/time'; +import { json } from '@podlove/utils/request'; +import type { PodloveWebPlayerTranscript } from '@podlove/types'; let CACHE = new Map>(); @@ -9,13 +19,15 @@ const parser = new XMLParser({ ignoreAttributes: false }); -const transformPerson = (input: any): Person => ({ - name: get(input, '#text', null), - role: get(input, '@_role', null), - image: get(input, '@_img', null), - slug: null, - id: null -}); +const transformPerson = (input: any): Person => { + const name = get(input, '#text', null); + + return { + name: get(input, '#text', null), + avatar: get(input, '@_img', null), + id: kebabCase(name) + }; +}; const transformChapter = (input: any): Chapter => ({ start: toPlayerTime(get(input, ['@_start'], null)), @@ -25,11 +37,23 @@ const transformChapter = (input: any): Chapter => ({ href: null }); +export const transformTranscript = (input: any): Transcript => { + const speaker = get(input, ['speaker'], null); + + return { + speaker: kebabCase(speaker), + voice: speaker, + start: get(input, ['startTime'], 0), + end: get(input, ['endTime'], 0), + text: get(input, ['body'], '') + }; +}; + const buildChapterList = (duration: number | null) => (input: Chapter, index: number, list: Chapter[]): Chapter => ({ ...input, - end: get(list, [index + 1, 'start'], duration) + end: get(list, [index + 1, 'start'], duration) as number }); const transformShow = (data: any): Show => ({ @@ -37,37 +61,79 @@ const transformShow = (data: any): Show => ({ description: get(data, ['channel', 'description'], null), link: get(data, ['channel', 'link'], null), summary: get(data, ['channel', 'itunes:summary'], null), - image: get(data, ['channel', 'image', 'url'], null) + poster: get(data, ['channel', 'image', 'url'], null) }); -const transformEpisode = (data: any): Episode => { - const duration = toPlayerTime(get(data, 'itunes:duration', 0)); +const getTranscriptUrl = async (data: any): Promise => + get(data, ['podcast:transcript'], []).find( + (item: { '@_type': string; '@_url': string }) => get(item, '@_type') === 'application/json' + )?.['@_url']; - return { - id: get(data, 'itunes:episode', null), - title: get(data, 'title', null), - description: get(data, 'description', null), - subtitle: get(data, 'itunes:subtitle', null), - publicationDate: get(data, 'pubDate', null), - duration, - content: get(data, 'content:encoded', null), - poster: get(data, ['itunes:image', '@_href'], null), - contributors: castArray(get(data, ['podcast:person'], [])).map(transformPerson), - chapters: castArray(get(data, ['psc:chapters', 'psc:chapter'], [])) - .map(transformChapter) - .map(buildChapterList(duration)) - }; +const resolveTranscripts = async (transcriptsUrl: string): Promise => { + return json(transcriptsUrl) + .then((result) => get(result, ['segments'], [])) + .then((items) => items.map(transformTranscript)); }; -const transform = (data: any): Podcast => ({ - show: transformShow(data), - episodes: castArray(get(data, ['channel', 'item'], [])).map(transformEpisode), - hosts: castArray(get(data, ['channel', 'podcast:person'], [])).map(transformPerson) -}); +const transformAudio = (input: any): Audio[] => { + const url = get(input, ['enclosure', '@_url'], null); + const size = get(input, ['enclosure', '@_length'], null); + const mimeType = get(input, ['enclosure', '@_type'], null); + + return [ + { + url, + size, + mimeType + } + ]; +}; + +const resolveEpisode = + (episodeId?: number) => + async (data: any): Promise => { + const id = get(data, 'itunes:episode', null); + const duration = toPlayerTime(get(data, 'itunes:duration', 0)); + const transcriptUrl = await getTranscriptUrl(data); + // console.log(data); + return { + id: get(data, 'itunes:episode', null), + title: get(data, 'title', null), + description: get(data, 'description', null), + subtitle: get(data, 'itunes:subtitle', null), + link: get(data, 'link', null), + publicationDate: get(data, 'pubDate', null), + duration, + content: get(data, 'content:encoded', null), + poster: get(data, ['itunes:image', '@_href'], null), + contributors: castArray(get(data, ['podcast:person'], [])).map(transformPerson), + chapters: castArray(get(data, ['psc:chapters', 'psc:chapter'], [])) + .map(transformChapter) + .map(buildChapterList(duration)), + transcripts: id === episodeId ? await resolveTranscripts(transcriptUrl) : transcriptUrl, + audio: transformAudio(data) + }; + }; + +const transform = + (episodeId?: number) => + async (data: any): Promise => ({ + show: transformShow(data), + episodes: await Promise.all( + castArray(get(data, ['channel', 'item'], [])).map(resolveEpisode(episodeId)) + ), + hosts: castArray(get(data, ['channel', 'podcast:person'], [])).map(transformPerson) + }); -export default async (feedUrl: string | null): Promise => { - if (!feedUrl) { - return transform({}); +export default async ({ + feed, + episodeId +}: { + feed: string | null; + episodeId?: number; +}): Promise => { + if (!feed) { + return transform(episodeId)({}); } // const existing = CACHE.get(feedUrl); @@ -76,7 +142,7 @@ export default async (feedUrl: string | null): Promise => { // return existing; // } - const result = fetch(feedUrl) + const result = fetch(feed) .then((result) => result.text()) .then((data) => parser.parse(data)) .then((data) => get(data, 'rss', {})) @@ -84,7 +150,7 @@ export default async (feedUrl: string | null): Promise => { // console.log(data); // return data; // }) - .then(transform); + .then(transform(episodeId)); // CACHE.set(feedUrl, result); diff --git a/apps/page/src/logic/sagas/data.sagas.ts b/apps/page/src/logic/sagas/data.sagas.ts index 2a3a938d6..c6109acbd 100644 --- a/apps/page/src/logic/sagas/data.sagas.ts +++ b/apps/page/src/logic/sagas/data.sagas.ts @@ -2,11 +2,11 @@ import type { Action } from 'redux-actions'; import { put, select, takeEvery } from 'redux-saga/effects'; import { actions } from '../store'; import parseFeed from '../data/feed-parser'; -import type { initializePayload } from '../store/stores/runtime.store'; +import type { initializeAppPayload } from '../store/stores/runtime.store'; import type { Podcast } from '../../types/feed.types'; -function* fetchData(input: Action) { - const feedData: Podcast = yield parseFeed(input.payload.feed); +function* fetchData(input: Action) { + const feedData: Podcast = yield parseFeed(input.payload); yield put(actions.dataFetched(feedData)); } diff --git a/apps/page/src/logic/sagas/episode.sagas.ts b/apps/page/src/logic/sagas/episode.sagas.ts index 124d5714c..40a230797 100644 --- a/apps/page/src/logic/sagas/episode.sagas.ts +++ b/apps/page/src/logic/sagas/episode.sagas.ts @@ -1,105 +1,117 @@ -import { fetch } from 'gridsome' -import { delay } from 'redux-saga/effects' -import { isEmpty, path, isNil } from 'ramda' -import { put, takeEvery, select } from 'redux-saga/effects' -import { READY, BACKEND_LOADING_START } from '@podlove/player-actions/types' -import { requestPlay, requestPause } from '@podlove/player-actions/play' -import { requestPlaytime } from '@podlove/player-actions/timepiece' -import { takeOnce } from '@podlove/player-sagas/helper' -import { setRate, setVolume, mute, unmute } from '@podlove/player-actions/audio' - -import * as player from '../reducers/player.store' -import * as episodes from '../reducers/episodes.store' +import { delay } from 'redux-saga/effects'; +import { put, takeEvery, select } from 'redux-saga/effects'; +import { requestPlay, requestPause, backendLoadingStart } from '@podlove/player-actions/play'; +import { requestPlaytime } from '@podlove/player-actions/timepiece'; +import { takeOnce } from '@podlove/player-sagas/helper'; +import { setRate, setVolume, mute, unmute } from '@podlove/player-actions/audio'; +import { ready } from '@podlove/player-actions/lifecycle'; +import { isNil } from 'lodash-es'; +import type { Action } from 'redux-actions'; + +import { actions } from '../store'; +import type { Episode, Show, Transcript } from '../../types/feed.types'; +import type { playEpisodePayload, restoreEpisodePayload } from '../store/stores/player.store'; +import { toPlayerEpisode } from '../transformations/player'; export default ({ selectEpisode, + selectShow, selectRate, selectVolume, selectMuted, selectCurrentEpisode, selectPlaying +}: { + selectEpisode: (id: string | number) => (input: any) => Episode; + selectShow: (input: any) => Show; + selectRate: (input: any) => number; + selectVolume: (input: any) => number; + selectMuted: (input: any) => boolean; + selectPlaying: (input: any) => boolean; + selectCurrentEpisode: (input: any) => string | null; }) => { function* resetMeta() { - const rate = yield select(selectRate) - const volume = yield select(selectVolume) - const muted = yield select(selectMuted) + const rate: number = yield select(selectRate); + const volume: number = yield select(selectVolume); + const muted: boolean = yield select(selectMuted); - yield put(setRate(rate)) - yield put(setVolume(volume)) + yield put(setRate(rate)); + yield put(setVolume(volume)); - yield put(muted ? mute() : unmute()) + yield put(muted ? mute() : unmute()); } - function* loadEpisode(id) { - let episode = yield select(selectEpisode(id)) + function* loadEpisode(id: string | number) { + let episode: Episode = yield select(selectEpisode(id)); - if (isEmpty(episode)) { - const result = yield fetch(`/episode/${id}`) - episode = path(['data', 'podcastEpisode'], result) - yield put(episodes.actions.addEpisode(episode)) + if (typeof episode.transcripts === 'string') { + const result: Transcript[] = yield fetch(episode.transcripts); + yield put(actions.updateEpisode({ id: episode.id, transcripts: result })); } - return episode + return episode; } - function* injectEpisode(episode) { - const playing = yield select(selectPlaying) + function* injectEpisode(episode: Episode) { + const playing: boolean = yield select(selectPlaying); if (playing) { - yield put(requestPause()) + yield put(requestPause()); } - yield put({ type: READY, payload: episode }) - yield delay(100) - yield put(requestPlay()) - yield takeOnce(BACKEND_LOADING_START, resetMeta) + // episode as + const show: Show = yield select(selectShow); + yield put(ready(toPlayerEpisode(episode, show))); + yield delay(100); + yield put(requestPlay()); + yield takeOnce(backendLoadingStart.toString(), resetMeta); } - function* playEpisode({ payload: { id, playtime } }) { - const currentEpisode = yield select(selectCurrentEpisode) - const playing = yield select(selectPlaying) + function* playEpisode({ payload: { id, playtime } }: Action) { + const currentEpisode: string = yield select(selectCurrentEpisode); + const playing: boolean = yield select(selectPlaying); - if (currentEpisode === id && playing) { - if (!isNil(playtime)) { - yield put(requestPlaytime(playtime)) - } - - return + if (currentEpisode === id && playing && !isNil(playtime)) { + yield put(requestPlaytime(playtime)); + return; } - yield put(player.actions.selectEpisode(id)) + yield put(actions.selectEpisode(id)); - const episode = yield loadEpisode(id) + const episode: Episode = yield loadEpisode(id); if (currentEpisode !== id) { - yield injectEpisode(episode) + yield injectEpisode(episode); } else { - yield put(requestPlay()) + yield put(requestPlay()); } if (playtime) { - yield put(requestPlaytime(playtime)) + yield put(requestPlaytime(playtime)); } } function* pauseEpisode() { - yield put(requestPause()) + yield put(requestPause()); } - function* restoreEpisode({ payload: { id, playtime } }) { - yield put(requestPause()) - yield put(player.actions.selectEpisode(id)) + function* restoreEpisode({ payload: { id, playtime } }: Action) { + yield put(requestPause()); + yield put(actions.selectEpisode(id)); - const episode = yield loadEpisode(id) - yield put({ type: READY, payload: episode }) - yield delay(100) - yield put(requestPlaytime(playtime)) - yield takeOnce(BACKEND_LOADING_START, resetMeta) + const episode: Episode = yield loadEpisode(id); + const show: Show = yield select(selectShow); + yield put(ready(toPlayerEpisode(episode, show))); + yield delay(100); + if (playtime) { + yield put(requestPlaytime(playtime)); + } + yield takeOnce(backendLoadingStart.toString(), resetMeta); } return function* () { - yield takeEvery(player.types.EPISODE_PLAY, playEpisode) - yield takeEvery(player.types.EPISODE_PAUSE, pauseEpisode) - yield takeEvery(player.types.EPISODE_RESTORE, restoreEpisode) - } -} + yield takeEvery(actions.playEpisode.toString(), playEpisode); + yield takeEvery(actions.pauseEpisode.toString(), pauseEpisode); + yield takeEvery(actions.restoreEpisode.toString(), restoreEpisode); + }; +}; diff --git a/apps/page/src/logic/sagas/index.ts b/apps/page/src/logic/sagas/index.ts index a0926dc09..5c5057265 100644 --- a/apps/page/src/logic/sagas/index.ts +++ b/apps/page/src/logic/sagas/index.ts @@ -2,8 +2,25 @@ import sagasEngine from '@podlove/player-sagas/middleware'; import { selectors } from '../store'; import dataSagas from './data.sagas'; +import episodeSagas from './episode.sagas'; +import playbarSagas from './playbar.sagas'; export function createSideEffects() { - const sagas = [dataSagas({ selectInitializedApp: selectors.runtime.initialized })]; + const sagas = [ + dataSagas({ selectInitializedApp: selectors.runtime.initialized }), + episodeSagas({ + selectEpisode: selectors.episode.data, + selectShow: selectors.podcast.show, + selectRate: selectors.player.audio.rate, + selectVolume: selectors.player.audio.volume, + selectMuted: selectors.player.audio.muted, + selectCurrentEpisode: selectors.current.episode, + selectPlaying: selectors.player.playing + }), + playbarSagas({ + selectRate: selectors.player.audio.rate, + selectMuted: selectors.player.audio.muted + }) + ]; sagasEngine.run(...sagas); } diff --git a/apps/page/src/logic/sagas/playbar.sagas.ts b/apps/page/src/logic/sagas/playbar.sagas.ts index 82f5b2adf..9db6b17ec 100644 --- a/apps/page/src/logic/sagas/playbar.sagas.ts +++ b/apps/page/src/logic/sagas/playbar.sagas.ts @@ -1,66 +1,73 @@ -import { put, takeEvery, select } from 'redux-saga/effects' +import { put, takeEvery, select } from 'redux-saga/effects'; import { - BACKEND_PLAY, - BACKEND_PAUSE, - BACKEND_LOADING_START, - BACKEND_LOADING_END, - BACKEND_END -} from '@podlove/player-actions/types' -import { setRate, mute, unmute } from '@podlove/player-actions/audio' + backendEnd, + backendLoadingEnd, + backendLoadingStart, + backendPause, + backendPlay, + type backendLoadingEndPayload +} from '@podlove/player-actions/play'; +import { setRate, mute, unmute } from '@podlove/player-actions/audio'; -import * as playbar from '~/store/reducers/playbar' +import actions from '../store/actions'; +import type { Action } from 'redux-actions'; -export default ({ selectRate, selectMuted }) => { +export default ({ + selectRate, + selectMuted +}: { + selectRate: (input: any) => number; + selectMuted: (input: any) => boolean; +}) => { function* play() { - yield put(playbar.actions.play()) + yield put(actions.play()); } function* pause() { - yield put(playbar.actions.pause()) + yield put(actions.pause()); } function* loading() { - yield put(playbar.actions.loading()) + yield put(actions.loading()); } function* restart() { - yield put(playbar.actions.restart()) + yield put(actions.restart()); } - function* loaded({ payload }) { + function* loaded({ payload }: Action) { if (payload.paused) { - yield pause() + yield pause(); } else { - yield play() + yield play(); } } function* nextRate() { - const steps = [0.5, 0.75, 1, 1.25, 1.5, 1.75, 2.0] - const rate = yield select(selectRate) + const steps = [0.5, 0.75, 1, 1.25, 1.5, 1.75, 2.0]; + const rate: number = yield select(selectRate); - const next = steps.indexOf(rate) + 1 + const next = steps.indexOf(rate) + 1; if (next < steps.length) { - yield put(setRate(steps[next])) + yield put(setRate(steps[next])); } else { - yield put(setRate(steps[0])) + yield put(setRate(steps[0])); } } function* toggleMute() { - const muted = yield select(selectMuted) - - yield put(muted ? unmute() : mute()) + const muted: boolean = yield select(selectMuted); + yield put(muted ? unmute() : mute()); } return function* () { - yield takeEvery(BACKEND_PLAY, play) - yield takeEvery(BACKEND_PAUSE, pause) - yield takeEvery(BACKEND_LOADING_START, loading) - yield takeEvery(BACKEND_LOADING_END, loaded) - yield takeEvery(BACKEND_END, restart) - yield takeEvery(playbar.types.NEXT_RATE, nextRate) - yield takeEvery(playbar.types.TOGGLE_MUTE, toggleMute) - } -} + yield takeEvery(backendPlay.toString(), play); + yield takeEvery(backendPause.toString(), pause); + yield takeEvery(backendLoadingStart.toString(), loading); + yield takeEvery(backendLoadingEnd.toString(), loaded); + yield takeEvery(backendEnd.toString(), restart); + yield takeEvery(actions.nextRate.toString(), nextRate); + yield takeEvery(actions.toggleMute.toString(), toggleMute); + }; +}; diff --git a/apps/page/src/logic/store/selectors.ts b/apps/page/src/logic/store/selectors.ts index 91f5d49f8..5b3fa9655 100644 --- a/apps/page/src/logic/store/selectors.ts +++ b/apps/page/src/logic/store/selectors.ts @@ -70,18 +70,19 @@ const translation = (key: string, attr = {}) => ({ key, attr }); export default { runtime: { initialized: createSelector(slices.runtime, runtime.initialized), - locale: createSelector(slices.runtime, runtime.locale), + locale: createSelector(slices.runtime, runtime.locale) }, theme: { background: createSelector(slices.theme, theme.background) }, podcast: { + show: createSelector(slices.podcast, podcast.show), feed: createSelector(slices.podcast, podcast.feed), title: createSelector(slices.podcast, podcast.title), - image: createSelector(slices.podcast, podcast.image), + poster: createSelector(slices.podcast, podcast.poster), description: createSelector(slices.podcast, podcast.description), summary: createSelector(slices.podcast, podcast.summary), - episodes: createSelector(slices.podcast, podcast.episodes), + episodes: createSelector(slices.podcast, podcast.episodes) }, current: { episode: currentEpisode @@ -122,7 +123,7 @@ export default { chapter: createSelector( [chaptersList, playerGhostTime], (chapters: PodloveWebPlayerChapter[], ghostPlaytime: number | null) => - currentChapterByPlaytime(chapters, ghostPlaytime || 0) + currentChapterByPlaytime(chapters || [], ghostPlaytime || 0) ) }, media: createSelector(slices.player, select('media'), media.media), @@ -142,7 +143,6 @@ export default { }, playbar: { active: createSelector(slices.playbar, playbar.active), - path: createSelector(slices.playbar, playbar.path), button: createSelector(slices.playbar, playbar.button), followContent: createSelector(slices.playbar, playbar.followContent), volume: (state: State) => { @@ -191,7 +191,7 @@ export default { return 'speed-200'; }, - chapters: createSelector(slices.playbar, playbar.chapters), + chapters: createSelector(slices.playbar, playbar.chapters) }, subscribeButton: { visible: createSelector(slices.subscribeButton, subscribeButton.visible) diff --git a/apps/page/src/logic/store/stores/episodes.store.ts b/apps/page/src/logic/store/stores/episodes.store.ts index 95da11cea..511574312 100644 --- a/apps/page/src/logic/store/stores/episodes.store.ts +++ b/apps/page/src/logic/store/stores/episodes.store.ts @@ -10,9 +10,11 @@ export interface State { } type addEpisodePayload = Episode +type updateEpisodePayload = {id: string} & Partial export const actions = { - addEpisode: createAction('EPISODES_ADD') + addEpisode: createAction('EPISODES_ADD'), + updateEpisode: createAction('EPISODES_UPDATE') }; export const reducer = handleActions({ @@ -25,6 +27,13 @@ export const reducer = handleActions({ [actions.addEpisode.toString()]: (state: State, { payload }: Action) => ({ ...state, [payload.id]: payload + }), + [actions.updateEpisode.toString()]: (state: State, { payload }: Action) => ({ + ...state, + [payload.id]: { + ...state[payload.id], + ...payload + } }) }, {} diff --git a/apps/page/src/logic/store/stores/playbar.store.ts b/apps/page/src/logic/store/stores/playbar.store.ts index 357f728a3..546ad5991 100644 --- a/apps/page/src/logic/store/stores/playbar.store.ts +++ b/apps/page/src/logic/store/stores/playbar.store.ts @@ -19,7 +19,6 @@ export interface State { button: 'play' | 'pause' | 'loading' | 'restart'; followContent: boolean; chapters: boolean; - path: string; } export const reducer = handleActions( @@ -44,10 +43,6 @@ export const reducer = handleActions( ...state, followContent: !state.followContent }), - [ready.toString()]: (state, { payload }: Action) => ({ - ...state, - path: get(payload, 'path', '') - }), [actions.toggleChaptersOverlay.toString()]: (state) => ({ ...state, chapters: !state.chapters @@ -61,8 +56,7 @@ export const reducer = handleActions( active: false, button: 'play', followContent: false, - chapters: false, - path: '' + chapters: false } ); @@ -70,6 +64,5 @@ export const selectors = { active: (state: State) => state.active, button: (state: State) => state.button, followContent: (state: State) => state.followContent, - path: (state: State) => state.path, chapters: (state: State) => state.chapters } diff --git a/apps/page/src/logic/store/stores/player.store.ts b/apps/page/src/logic/store/stores/player.store.ts index 300bab809..f564f16c5 100644 --- a/apps/page/src/logic/store/stores/player.store.ts +++ b/apps/page/src/logic/store/stores/player.store.ts @@ -2,11 +2,19 @@ import { handleActions, createAction, type Action } from 'redux-actions' type selectEpisodePayload = string; +export interface playEpisodePayload { + id: string; + playtime?: number; +} + +export type restoreEpisodePayload = playEpisodePayload; + + export const actions = { - playEpisode: createAction('EPISODE_PLAY'), + playEpisode: createAction('EPISODE_PLAY'), pauseEpisode: createAction('EPISODE_PAUSE'), selectEpisode: createAction('EPISODE_SELECT'), - restoreEpisode: createAction('EPISODE_RESTORE') + restoreEpisode: createAction('EPISODE_RESTORE') } export interface State { diff --git a/apps/page/src/logic/store/stores/podcast.store.ts b/apps/page/src/logic/store/stores/podcast.store.ts index 2691b99fd..76be86506 100644 --- a/apps/page/src/logic/store/stores/podcast.store.ts +++ b/apps/page/src/logic/store/stores/podcast.store.ts @@ -1,11 +1,12 @@ import { handleActions, type Action } from 'redux-actions'; -import { actions as lifecycleActions, type dataFetchedPayload, type initializePayload } from './runtime.store' +import { actions as lifecycleActions, type dataFetchedPayload, type initializeAppPayload } from './runtime.store' import { get } from 'lodash-es'; +import type { Show } from '../../../types/feed.types'; export interface State { feed: string | null; title: string | null; - image: string | null; + poster: string | null; description: string | null; summary: string | null; episodes: string[]; @@ -15,28 +16,35 @@ export const reducer = handleActions({ [lifecycleActions.dataFetched.toString()]: (state, { payload }: Action) => ({ ...state, title: get(payload, ['show', 'title'], null), - image: get(payload, ['show', 'image'], null), + poster: get(payload, ['show', 'poster'], null), description: get(payload, ['show', 'description'], null), summary: get(payload, ['show', 'summary'], null), episodes: get(payload, ['episodes'], []).map(({ id }) => id) }), - [lifecycleActions.initializeApp.toString()]: (state, { payload }: Action) => ({ + [lifecycleActions.initializeApp.toString()]: (state, { payload }: Action) => ({ ...state, feed: payload.feed }) }, { feed: null, title: null, - image: null, + poster: null, description: null, summary: null, episodes: [] }); export const selectors = { + show: (state: State): Show => ({ + title: get(state, 'title') || '', + description: get(state, 'description') || '', + link: get(state, 'link') || '', + poster: get(state, 'poster') || '', + summary: get(state, 'summary') || '', + }), feed: (state: State) => get(state, 'feed'), title: (state: State) => get(state, 'title'), - image: (state: State) => get(state, 'image'), + poster: (state: State) => get(state, 'poster'), description: (state: State) => get(state, 'description'), summary: (state: State) => get(state, 'summary'), episodes: (state: State) => get(state, 'episodes'), diff --git a/apps/page/src/logic/store/stores/runtime.store.ts b/apps/page/src/logic/store/stores/runtime.store.ts index 9b0af3e04..752574826 100644 --- a/apps/page/src/logic/store/stores/runtime.store.ts +++ b/apps/page/src/logic/store/stores/runtime.store.ts @@ -6,21 +6,23 @@ export interface State { locale: string; } -export interface initializePayload { +export interface initializeAppPayload { feed: string; locale: string; + episodeId?: number; } export type dataFetchedPayload = Podcast; export const actions = { - initializeApp: createAction('INITIALIZE'), + initializeApp: createAction('INITIALIZE'), + initializeEpisode: createAction('INITIALIZE_EPISODE'), dataFetched: createAction('DATA_FETCHED') }; export const reducer = handleActions( { - [actions.initializeApp.toString()]: (state, { payload}: Action) => ({ + [actions.initializeApp.toString()]: (state, { payload}: Action) => ({ ...state, locale: payload.locale }), diff --git a/apps/page/src/logic/transformations/player.ts b/apps/page/src/logic/transformations/player.ts new file mode 100644 index 000000000..0346f3bac --- /dev/null +++ b/apps/page/src/logic/transformations/player.ts @@ -0,0 +1,24 @@ +import type { PodloveWebPlayerEpisode } from '@podlove/types'; +import { toHumanTime } from '@podlove/utils/time'; +import type { Episode, Show } from '../../types/feed.types'; + +export const toPlayerEpisode = (episode: Episode, show: Show): PodloveWebPlayerEpisode => ({ + version: 6, + show: { + link: show.link, + poster: show.poster, + subtitle: show.description, + title: show.title, + summary: show.summary + }, + title: episode.title || '', + subtitle: episode.subtitle || '', + summary: episode.description || '', + audio: episode.audio, + publicationDate: episode.publicationDate || '', + + duration: toHumanTime(episode.duration || 0), + poster: episode.poster || '', + link: episode.link || '', + chapters: episode.chapters +}); diff --git a/apps/page/src/middleware/store.ts b/apps/page/src/middleware/store.ts index 8553028c6..afe1d7dab 100644 --- a/apps/page/src/middleware/store.ts +++ b/apps/page/src/middleware/store.ts @@ -1,18 +1,18 @@ import { defineMiddleware } from 'astro:middleware'; import { waitFor } from '@podlove/utils/promise'; -import { get } from 'lodash-es'; +import { get, toInteger } from 'lodash-es'; import { actions, store, selectors } from '../logic'; export const initializeStore = defineMiddleware(async ({ request, params }, next) => { const acceptedLanguage = request.headers.get('accept-language') || ''; const locale = get(acceptedLanguage.split(','), 0, 'en-US'); - const { feed } = params; + const { feed, episodeId } = params; if (!feed) { throw Error('Missing Feed Url'); } - store.dispatch(actions.initializeApp({ feed, locale })); + store.dispatch(actions.initializeApp({ feed, locale, episodeId: toInteger(episodeId) })); await waitFor(() => { const initialized = selectors.runtime.initialized(store.getState()); diff --git a/apps/page/src/pages/feed/[...feed]/episodes/[id].astro b/apps/page/src/pages/feed/[...feed]/episodes/[episodeId].astro similarity index 79% rename from apps/page/src/pages/feed/[...feed]/episodes/[id].astro rename to apps/page/src/pages/feed/[...feed]/episodes/[episodeId].astro index edbce0915..710db6b4c 100644 --- a/apps/page/src/pages/feed/[...feed]/episodes/[id].astro +++ b/apps/page/src/pages/feed/[...feed]/episodes/[episodeId].astro @@ -1,26 +1,28 @@ --- +import { createTimeline } from '@podlove/utils/transcripts' import Layout from '../../../../layouts/Layout.astro'; import Hero from '../../../../screens/episodes/Hero.vue' import Navigation from '../../../../screens/episodes/Navigation.vue' import Timeline from '../../../../features/timeline/Timeline.vue' +import { type Transcript } from '../../../../types/feed.types' import { store, selectors } from '../../../../logic'; import { useTranslations } from '../../../../i18n' -const { id } = Astro.params; +const { episodeId } = Astro.params; const $t = useTranslations(); const podcastTitle = selectors.podcast.title(store.getState()); -const episode = selectors.episode.data(id as string)(store.getState()); +const episode = selectors.episode.data(episodeId as string)(store.getState()); const timeline = [ - { start: 0, title: $t('TIMELINE.START'), type: 'marker' }, - ...episode.chapters.map(chapter => ({...chapter, type: 'chapter'})), - { start: episode.duration, title: $t('TIMELINE.END'), type: 'marker' } + { start: 0, title: $t('TIMELINE.START') as string, type: 'marker' } as any, + ...createTimeline(episode.transcripts as Transcript[], episode.chapters || [], episode.contributors || []), + { start: episode.duration, title: $t('TIMELINE.END') as string, type: 'marker' } as any, ]; --- - { id && + { episodeId && 0} discuss={false} /> }
@@ -47,7 +49,7 @@ const timeline = [ { $t('EPISODE.TIMELINE') } diff --git a/apps/page/src/screens/archive/EpisodeItem.vue b/apps/page/src/screens/archive/EpisodeItem.vue index b146d928d..f3f2f2298 100644 --- a/apps/page/src/screens/archive/EpisodeItem.vue +++ b/apps/page/src/screens/archive/EpisodeItem.vue @@ -38,7 +38,7 @@ class="mr-1 w-6" v-for="(contributor, index) in state.episode.contributors" :name="contributor.name" - :avatar="contributor.image" + :avatar="contributor.avatar" :role="contributor.role" :slug="contributor.slug" :id="contributor.id" @@ -84,7 +84,7 @@ const props = defineProps<{ const state = mapState({ episode: selectors.episode.data(props.id), - poster: selectors.podcast.image, + poster: selectors.podcast.poster, locale: selectors.runtime.locale }); diff --git a/apps/page/src/screens/archive/Hero.vue b/apps/page/src/screens/archive/Hero.vue index 5f433c4aa..40e04b8f9 100644 --- a/apps/page/src/screens/archive/Hero.vue +++ b/apps/page/src/screens/archive/Hero.vue @@ -48,7 +48,7 @@ import { selectors } from '../../logic'; import HeaderContainer from '../../components/HeaderContainer.vue'; const state = mapState({ - poster: selectors.podcast.image, + poster: selectors.podcast.poster, title: selectors.podcast.title, description: selectors.podcast.description, summary: selectors.podcast.summary diff --git a/apps/page/src/screens/episodes/Hero.vue b/apps/page/src/screens/episodes/Hero.vue index 9c8781cff..e01cc7d28 100644 --- a/apps/page/src/screens/episodes/Hero.vue +++ b/apps/page/src/screens/episodes/Hero.vue @@ -34,7 +34,7 @@ ・ {{ duration }}
- +

(); const state = mapState({ episode: selectors.episode.data(props.id), - poster: selectors.podcast.image, - locale: selectors.runtime.locale + poster: selectors.podcast.poster, + locale: selectors.runtime.locale, + feed: selectors.podcast.feed }); const publicationDate = computed(() => diff --git a/apps/page/src/screens/episodes/Navigation.vue b/apps/page/src/screens/episodes/Navigation.vue index c5adeeb95..bf4e6529f 100644 --- a/apps/page/src/screens/episodes/Navigation.vue +++ b/apps/page/src/screens/episodes/Navigation.vue @@ -18,7 +18,7 @@ diff --git a/packages/media-backend/cypress/e2e/actions.cy.ts b/packages/media-backend/cypress/e2e/actions.cy.ts index 2049ceaa4..f628bd8a7 100644 --- a/packages/media-backend/cypress/e2e/actions.cy.ts +++ b/packages/media-backend/cypress/e2e/actions.cy.ts @@ -24,7 +24,6 @@ describe('actions', () => { beforeEach(() => { audioElement = audio(audioFixture()); - console.log(audioElement) onError(audioElement, console.log); }); diff --git a/packages/player/sagas/src/transcripts.ts b/packages/player/sagas/src/transcripts.ts index 84cfc0a33..4c2a799cd 100644 --- a/packages/player/sagas/src/transcripts.ts +++ b/packages/player/sagas/src/transcripts.ts @@ -17,87 +17,16 @@ import { searchTranscripts, type searchTranscriptsPayload } from '@podlove/player-actions/transcripts'; -import { secondsToMilliseconds, toPlayerTime } from '@podlove/utils/time'; import { transcripts as getTranscripts } from '@podlove/player-config'; import { binarySearch, textSearch } from '@podlove/utils/search'; import { isDefinedAndNotNull } from '@podlove/utils/predicates'; import type { PodloveWebPlayerSpeaker, PodloveWebPlayerChapter, PodloveWebPlayerTimelineChapterEntry, - PodloveWebPlayerTimelineTranscriptEntry, PodloveWebPlayerTranscript } from '@podlove/types'; + PodloveWebPlayerTimelineTranscriptEntry } from '@podlove/types'; import { ready, type initPayload } from '@podlove/player-actions/lifecycle'; import type { Action } from 'redux-actions'; import { backendPlaytime, requestPlaytime, simulatePlaytime, type backendPlaytimePayload, type requestPlaytimePayload, type simulatePlaytimePayload } from '@podlove/player-actions/timepiece'; import { disableGhost } from '@podlove/player-actions/progress'; - -const transformTime = (time) => - is(Number, time) ? secondsToMilliseconds(time) : toPlayerTime(time); - -const isNewChunk = (current, last) => { - if (last === undefined) { - return true; - } - - const differentSpeaker = current.speaker !== last.speaker; - const text = last.texts.reduce((result, item) => result + ' ' + item.text, ''); - const endOfSentence = endsWith('.', text) || endsWith('!', text) || endsWith('?', text); - - return differentSpeaker || (text.length > 500 && endOfSentence); -}; - -const transformTranscript = reduce((transcripts: PodloveWebPlayerTimelineTranscriptEntry[], chunk: PodloveWebPlayerTranscript) => { - const lastChunk = last(transcripts); - - if (isNewChunk(chunk, lastChunk)) { - return [ - ...transcripts, - { - type: 'transcript', - start: transformTime(chunk.start), - end: transformTime(chunk.end), - speaker: chunk.speaker, - texts: [ - { - start: transformTime(chunk.start), - end: transformTime(chunk.end), - text: chunk.text - } - ] - } - ]; - } - - return [ - ...transcripts.slice(0, -1), - { - ...lastChunk, - end: transformTime(chunk.end), - texts: [ - ...lastChunk.texts, - { - start: transformTime(chunk.start), - end: transformTime(chunk.end), - text: chunk.text - } - ] - } - ]; -}, []) as (input: PodloveWebPlayerTranscript[]) => PodloveWebPlayerTimelineTranscriptEntry[]; - -const transformChapters = (chapters: PodloveWebPlayerChapter[]): PodloveWebPlayerTimelineChapterEntry[] => - chapters.map((chapter, index) => ({ - ...chapter, - type: 'chapter', - index: index - })) as PodloveWebPlayerTimelineChapterEntry[]; - -const mapSpeakers = (speakers: PodloveWebPlayerSpeaker[]) => - map((transcript: PodloveWebPlayerTimelineTranscriptEntry): PodloveWebPlayerTimelineTranscriptEntry => { - const result = speakers.find(({ id }) => id === transcript.speaker as unknown as string); - - return { - ...transcript, - speaker: result - }; - }); +import { createTimeline } from '@podlove/utils/transcripts'; export const transcriptsSaga = ({ selectSpeakers, @@ -117,12 +46,6 @@ export const searchText = (transcripts: (PodloveWebPlayerTimelineChapterEntry | ((entry as PodloveWebPlayerTimelineTranscriptEntry).texts || []).map(({ text }) => text).join(' ') )); -export const createTimeline = (transcripts: PodloveWebPlayerTranscript[], chapters: PodloveWebPlayerChapter[], speakers: PodloveWebPlayerSpeaker[]): (PodloveWebPlayerTimelineChapterEntry | PodloveWebPlayerTimelineTranscriptEntry)[] => { - const transcriptEntries: PodloveWebPlayerTimelineTranscriptEntry[] = compose(mapSpeakers(speakers), transformTranscript)(transcripts); - const chapterEntries: PodloveWebPlayerTimelineChapterEntry[] = transformChapters(chapters); - - return sortBy(prop('start'), [...transcriptEntries, ...chapterEntries]) as (PodloveWebPlayerTimelineChapterEntry | PodloveWebPlayerTimelineTranscriptEntry)[]; -} export function* init({ selectSpeakers, selectChapters, selectPlaytime }: { selectSpeakers: (input: any) => PodloveWebPlayerSpeaker[]; diff --git a/packages/types/src/chapter.ts b/packages/types/src/chapter.ts index 14fa1c3f5..cd92ada22 100644 --- a/packages/types/src/chapter.ts +++ b/packages/types/src/chapter.ts @@ -1,10 +1,10 @@ export interface PodloveWebPlayerChapter { start: number | string | null; duration?: number | null; - end?: number | null; + end?: number | string | null; index?: number; linkTitle?: string; - image?: string; + image?: string | null; title?: string | null; href?: string | null; active?: boolean | null; diff --git a/packages/types/src/transcript.ts b/packages/types/src/transcript.ts index 1478497b2..1e2f8aa3a 100644 --- a/packages/types/src/transcript.ts +++ b/packages/types/src/transcript.ts @@ -1,8 +1,6 @@ export interface PodloveWebPlayerTranscript { - start: string; - start_ms: number; - end: string; - end_ms: number; + start: string | number; + end: string | number; speaker: string; voice: string; text: string; @@ -23,7 +21,7 @@ export interface PodloveWebPlayerTimelineChapterEntry { export interface PodloveWebPlayerSpeaker { id: string; name: string; - avatar: string; + avatar?: string; role?: { id: string; slug: string; diff --git a/packages/utils/package.json b/packages/utils/package.json index 4ac405c18..1f49f13bf 100644 --- a/packages/utils/package.json +++ b/packages/utils/package.json @@ -92,6 +92,10 @@ "./promise": { "import": "./src/promise.ts", "types": "./src/promise.ts" + }, + "./transcripts": { + "import": "./src/transcripts.ts", + "types": "./src/transcripts.ts" } }, "publishConfig": { @@ -171,6 +175,10 @@ "./promise": { "import": "./dist/promise.mjs", "types": "./dist/promise.d.ts" + }, + "./transcripts": { + "import": "./dist/transcripts.mjs", + "types": "./dist/transcripts.d.ts" } } }, diff --git a/packages/utils/src/chapters.ts b/packages/utils/src/chapters.ts index 6d479c680..a3d4730c4 100644 --- a/packages/utils/src/chapters.ts +++ b/packages/utils/src/chapters.ts @@ -41,11 +41,11 @@ export const currentChapterByPlaytime = ( playtime: number ): PodloveWebPlayerChapter => find((chapter: PodloveWebPlayerChapter) => { - if (playtime < chapter.start) { + if (playtime < (chapter.start as number)) { return false; } - if (playtime >= chapter.end) { + if (playtime >= (chapter.end as number)) { return false; } @@ -65,11 +65,11 @@ export const activeChapter = (chapter: PodloveWebPlayerChapter): PodloveWebPlaye export const setActiveByPlaytime = (playtime: number) => (chapter: PodloveWebPlayerChapter): PodloveWebPlayerChapter => { - if (playtime < chapter.start) { + if (playtime < (chapter.start as number)) { return inactiveChapter(chapter); } - if (playtime >= chapter.end) { + if (playtime >= (chapter.end as number)) { return inactiveChapter(chapter); } diff --git a/packages/utils/src/transcripts.ts b/packages/utils/src/transcripts.ts new file mode 100644 index 000000000..228d90c99 --- /dev/null +++ b/packages/utils/src/transcripts.ts @@ -0,0 +1,109 @@ +import { last, compose, map, is, endsWith, sortBy, prop, reduce } from 'ramda'; + +import { + PodloveWebPlayerChapter, + PodloveWebPlayerSpeaker, + PodloveWebPlayerTimelineChapterEntry, + PodloveWebPlayerTimelineTranscriptEntry, + PodloveWebPlayerTranscript +} from '@podlove/types'; +import { secondsToMilliseconds, toPlayerTime } from './time.js'; + +const mapSpeakers = (speakers: PodloveWebPlayerSpeaker[]) => + map( + ( + transcript: PodloveWebPlayerTimelineTranscriptEntry + ): PodloveWebPlayerTimelineTranscriptEntry => { + const result = speakers.find(({ id }) => + id.startsWith(transcript.speaker as unknown as string) + ); + + return { + ...transcript, + speaker: result + }; + } + ); + +const transformChapters = ( + chapters: PodloveWebPlayerChapter[] +): PodloveWebPlayerTimelineChapterEntry[] => + chapters.map((chapter, index) => ({ + ...chapter, + type: 'chapter', + index: index + })) as PodloveWebPlayerTimelineChapterEntry[]; + +const transformTime = (time) => + is(Number, time) ? secondsToMilliseconds(time) : toPlayerTime(time); + +const isNewChunk = (current, last) => { + if (last === undefined) { + return true; + } + + const differentSpeaker = current.speaker !== last.speaker; + const text = last.texts.reduce((result, item) => result + ' ' + item.text, ''); + const endOfSentence = endsWith('.', text) || endsWith('!', text) || endsWith('?', text); + + return differentSpeaker || (text.length > 500 && endOfSentence); +}; + +const transformTranscript = reduce( + (transcripts: PodloveWebPlayerTimelineTranscriptEntry[], chunk: PodloveWebPlayerTranscript) => { + const lastChunk = last(transcripts); + + if (isNewChunk(chunk, lastChunk)) { + return [ + ...transcripts, + { + type: 'transcript', + start: transformTime(chunk.start), + end: transformTime(chunk.end), + speaker: chunk.speaker, + texts: [ + { + start: transformTime(chunk.start), + end: transformTime(chunk.end), + text: chunk.text + } + ] + } + ]; + } + + return [ + ...transcripts.slice(0, -1), + { + ...lastChunk, + end: transformTime(chunk.end), + texts: [ + ...lastChunk.texts, + { + start: transformTime(chunk.start), + end: transformTime(chunk.end), + text: chunk.text + } + ] + } + ]; + }, + [] +) as (input: PodloveWebPlayerTranscript[]) => PodloveWebPlayerTimelineTranscriptEntry[]; + +export const createTimeline = ( + transcripts: PodloveWebPlayerTranscript[], + chapters: PodloveWebPlayerChapter[], + speakers: PodloveWebPlayerSpeaker[] +): (PodloveWebPlayerTimelineChapterEntry | PodloveWebPlayerTimelineTranscriptEntry)[] => { + const transcriptEntries: PodloveWebPlayerTimelineTranscriptEntry[] = compose( + mapSpeakers(speakers), + transformTranscript + )(transcripts); + const chapterEntries: PodloveWebPlayerTimelineChapterEntry[] = transformChapters(chapters); + + return sortBy(prop('start'), [...transcriptEntries, ...chapterEntries]) as ( + | PodloveWebPlayerTimelineChapterEntry + | PodloveWebPlayerTimelineTranscriptEntry + )[]; +}; diff --git a/packages/utils/vite.config.ts b/packages/utils/vite.config.ts index 2865a4129..cbd6d1c32 100644 --- a/packages/utils/vite.config.ts +++ b/packages/utils/vite.config.ts @@ -19,7 +19,8 @@ const entries = [ 'time', 'url', 'useragent', - 'promise' + 'promise', + 'transcripts' ]; export default defineConfig({ From 9853b35c5aa8afad75a3ee7e0ac9064ff39bcd5d Mon Sep 17 00:00:00 2001 From: Alexander Heimbuch Date: Fri, 16 Feb 2024 18:58:55 +0100 Subject: [PATCH 05/20] dev bump --- .../components/chapter-progress.story.vue | 2 +- apps/page/package.json | 19 +- apps/page/service-worker.ts | 104 ++++++ apps/page/src/components/CustomTransition.vue | 10 +- apps/page/src/components/Loader.vue | 133 +++++++ apps/page/src/components/PlayButton.vue | 29 +- apps/page/src/components/PlayerTile.vue | 134 -------- apps/page/src/components/Test.vue | 15 - apps/page/src/features/PageHeader.vue | 15 +- apps/page/src/features/Search.vue | 299 ++++++++++++++++ apps/page/src/features/playbar/Chapter.vue | 45 ++- apps/page/src/features/playbar/PlayBar.vue | 220 ++++++++---- apps/page/src/features/timeline/Bullet.vue | 2 +- apps/page/src/features/timeline/Marker.vue | 2 +- apps/page/src/features/timeline/Timeline.vue | 14 +- .../page/src/features/timeline/Transcript.vue | 12 +- apps/page/src/i18n/messages.ts | 1 + apps/page/src/layouts/Layout.astro | 86 ++--- apps/page/src/lib/caching.ts | 9 + apps/page/src/lib/middleware.ts | 4 + apps/page/src/lib/persons.ts | 10 + apps/page/src/lib/runtime.ts | 2 + apps/page/src/lib/url.ts | 15 + apps/page/src/logic/data/feed-parser.ts | 28 +- apps/page/src/logic/index.ts | 6 +- apps/page/src/logic/sagas/data.sagas.ts | 5 +- apps/page/src/logic/sagas/episode.sagas.ts | 67 ++-- apps/page/src/logic/sagas/index.ts | 56 ++- apps/page/src/logic/sagas/playbar.sagas.ts | 46 ++- apps/page/src/logic/sagas/router.sagas.ts | 99 +----- apps/page/src/logic/sagas/search.sagas.ts | 324 +++++++++++------- .../src/logic/sagas/serviceworker.sagas.ts | 41 +++ apps/page/src/logic/store/actions.ts | 14 +- apps/page/src/logic/store/helper.ts | 7 +- apps/page/src/logic/store/reducers.ts | 8 +- apps/page/src/logic/store/selectors.ts | 126 ++++--- apps/page/src/logic/store/state.ts | 33 +- .../logic/store/stores/contributors.store.ts | 31 ++ .../src/logic/store/stores/episodes.store.ts | 14 +- .../src/logic/store/stores/player.store.ts | 72 +++- .../src/logic/store/stores/router.store.ts | 77 +++-- .../src/logic/store/stores/runtime.store.ts | 17 +- .../src/logic/store/stores/search.store.ts | 100 ++++-- apps/page/src/middleware/caching.ts | 18 + apps/page/src/middleware/index.ts | 8 +- apps/page/src/middleware/router.ts | 14 + apps/page/src/middleware/store.ts | 14 +- .../{episodes => episode}/[episodeId].astro | 5 +- .../page/src/pages/feed/[...feed]/index.astro | 9 +- apps/page/src/pages/manifest.json.ts | 32 ++ apps/page/src/pages/proxy.ts | 11 + apps/page/src/screens/archive/EpisodeItem.vue | 9 +- apps/page/src/types/feed.types.ts | 1 + apps/page/tailwind.config.cjs | 74 ++-- apps/page/tsconfig.json | 3 +- apps/player/src/store/index.ts | 3 +- packages/clients/package.json | 3 + packages/clients/src/apple-podcasts/index.ts | 8 +- .../clients/src/apple-podcasts/resolve.ts | 15 + packages/components/package.json | 4 +- .../chapter-progress/ChapterProgress.vue | 59 ++-- .../components/src/components/icons/Lock.vue | 19 + .../src/components/icons/SearchClear.vue | 1 - .../components/src/components/icons/User.vue | 6 +- .../components/src/components/icons/index.ts | 4 +- .../components/input-slider/InputSlider.vue | 2 +- packages/components/src/components/main.ts | 6 +- .../components/progress-bar/ProgressBar.vue | 123 +++---- packages/media-backend/src/audio.ts | 24 +- packages/media-backend/src/connect.ts | 14 +- packages/player/sagas/src/chapters.ts | 4 +- packages/player/sagas/src/player.ts | 10 +- packages/utils/src/request.ts | 6 +- packages/utils/src/transcripts.ts | 29 +- pnpm-lock.yaml | 33 ++ 75 files changed, 1931 insertions(+), 993 deletions(-) create mode 100644 apps/page/service-worker.ts create mode 100644 apps/page/src/components/Loader.vue delete mode 100644 apps/page/src/components/PlayerTile.vue delete mode 100644 apps/page/src/components/Test.vue create mode 100644 apps/page/src/features/Search.vue create mode 100644 apps/page/src/lib/caching.ts create mode 100644 apps/page/src/lib/middleware.ts create mode 100644 apps/page/src/lib/persons.ts create mode 100644 apps/page/src/lib/runtime.ts create mode 100644 apps/page/src/lib/url.ts create mode 100644 apps/page/src/logic/sagas/serviceworker.sagas.ts create mode 100644 apps/page/src/logic/store/stores/contributors.store.ts create mode 100644 apps/page/src/middleware/caching.ts create mode 100644 apps/page/src/middleware/router.ts rename apps/page/src/pages/feed/[...feed]/{episodes => episode}/[episodeId].astro (93%) create mode 100644 apps/page/src/pages/manifest.json.ts create mode 100644 apps/page/src/pages/proxy.ts create mode 100644 packages/clients/src/apple-podcasts/resolve.ts create mode 100644 packages/components/src/components/icons/Lock.vue diff --git a/apps/docs/src/stories/components/chapter-progress.story.vue b/apps/docs/src/stories/components/chapter-progress.story.vue index b950e2cae..c2026be17 100644 --- a/apps/docs/src/stories/components/chapter-progress.story.vue +++ b/apps/docs/src/stories/components/chapter-progress.story.vue @@ -28,7 +28,7 @@ const progressColor = ref(persianGreen); const ghostColor = ref(sandyBrown); const style = ref({ '--podlove-component--chapter-progress--background': progressColor, - '--podlove-component--chapter-progress--ghost-background': ghostColor + '--podlove-component--chapter-progress--ghost--background': ghostColor }); diff --git a/apps/page/package.json b/apps/page/package.json index d884f6419..f07c26359 100644 --- a/apps/page/package.json +++ b/apps/page/package.json @@ -9,6 +9,12 @@ "astro": "astro" }, "dependencies": { + "@podlove/player-sagas": "workspace:*", + "@podlove/utils": "workspace:*", + "@podlove/player-actions": "workspace:*", + "@podlove/player-state": "workspace:*", + "@podlove/components": "workspace:*", + "@podlove/types": "workspace:*", "@astrojs/check": "0.3.1", "@astrojs/node": "6.1.0", "@astrojs/tailwind": "5.0.2", @@ -17,24 +23,21 @@ "vue": "3.2.30", "fast-xml-parser": "4.3.2", "lodash-es": "4.17.21", - "@podlove/player-sagas": "workspace:*", - "@podlove/utils": "workspace:*", - "@podlove/player-actions": "workspace:*", - "@podlove/player-state": "workspace:*", - "@podlove/components": "workspace:*", - "@podlove/types": "workspace:*", "redux": "4.2.1", "redux-vuex": "3.0.2", "redux-actions": "3.0.0", "redux-saga": "1.2.3", "reselect": "4.1.8", "vue-i18n": "9.8.0", - "scroll-into-view-if-needed": "3.1.0" + "scroll-into-view-if-needed": "3.1.0", + "micromatch": "4.0.5", + "minisearch": "6.3.0" }, "devDependencies": { "tailwindcss": "3.0.24", "typescript": "5.3.2", "@types/lodash-es": "4.17.12", - "@types/redux-actions": "2.6.5" + "@types/redux-actions": "2.6.5", + "@types/micromatch":"4.0.6" } } diff --git a/apps/page/service-worker.ts b/apps/page/service-worker.ts new file mode 100644 index 000000000..a50082afa --- /dev/null +++ b/apps/page/service-worker.ts @@ -0,0 +1,104 @@ +/// +/// +const sw: ServiceWorkerGlobalScope & typeof globalThis = self as any; + +let CACHE: Cache | null = null; + +const getFeed = (): string | null => new URLSearchParams(sw.location.search).get('feed'); +const getCacheKey = (): string | null => new URLSearchParams(sw.location.search).get('cacheKey'); + +const getCache = async (): Promise => { + if (CACHE) { + return CACHE; + } + + const feed = getFeed(); + + if (!feed) { + return null; + } + + return caches.open(feed); +}; + +const handleRequest = async (request: Request) => { + const cache = await getCache(); + const cacheKey = await getCacheKey(); + + if (!cache || !cacheKey) { + return fetch(request); + } + + const cachedUrl = new URL(request.url); + cachedUrl.searchParams.set('cacheKey', cacheKey); + + // First try to get the resource from the cache + const responseFromCache = await cache.match(cachedUrl.toString()); + + if (responseFromCache) { + return responseFromCache; + } + + // Next try to get the resource from the network + const responseFromNetwork = await fetch(cachedUrl.toString(), { mode: 'no-cors' }); + if (responseFromNetwork.status <= 300) { + cache.put(cachedUrl.toString(), responseFromNetwork.clone()); + } + + return responseFromNetwork; +}; + +const getCacheKeyFromRequest = (request: Request) => + new URL(request.url).searchParams.get('cacheKey'); + +sw.addEventListener('fetch', (event: any) => { + const { request } = event; + const supportedDestinations = ['image', '']; + + // Bypass navigation requests. + if (request.mode === 'navigate') { + return; + } + + // Opening the DevTools triggers the "only-if-cached" request + // that cannot be handled by the worker. Bypass such requests. + if (request.cache === 'only-if-cached' && request.mode !== 'same-origin') { + return; + } + + if (request.method !== 'GET') { + return; + } + + if (!supportedDestinations.includes(request.destination)) { + return; + } + + event.respondWith(handleRequest(request)); +}); + +const cleanCache = async (cacheKey: string) => { + const cache = await getCache(); + + if (!cache) { + return; + } + + const requests = await cache.keys(); + + requests + ?.filter((request) => getCacheKeyFromRequest(request) !== cacheKey) + .forEach((request) => { + CACHE?.delete(request); + }); +}; + +sw.addEventListener('initialize', async (event: any) => { + const cacheKey = getCacheKey(); + + if (!cacheKey) { + return; + } + + event.waitUntil(cleanCache(cacheKey)); +}); diff --git a/apps/page/src/components/CustomTransition.vue b/apps/page/src/components/CustomTransition.vue index 0cf78e433..2cf8b1618 100644 --- a/apps/page/src/components/CustomTransition.vue +++ b/apps/page/src/components/CustomTransition.vue @@ -16,7 +16,7 @@ defineProps<{ .fade-leave-active { transition: opacity 0.5s; } -.fade-enter, +.fade-enter-from, .fade-leave-to { opacity: 0; } @@ -26,7 +26,7 @@ defineProps<{ .playbar-leave-active { transition: margin 0.5s, opacity 0.5s; } -.playbar-enter, +.playbar-enter-from, .playbar-leave-to { opacity: 0; margin-bottom: -70px; @@ -35,10 +35,10 @@ defineProps<{ /* Chapters */ .chapters-enter-active, .chapters-leave-active { - transition: bottom 0.5s; + transition: right 0.5s; } -.chapters-enter, +.chapters-enter-from, .chapters-leave-to { - bottom: -1000px !important; + right: -1000px !important; } diff --git a/apps/page/src/components/Loader.vue b/apps/page/src/components/Loader.vue new file mode 100644 index 000000000..cce490018 --- /dev/null +++ b/apps/page/src/components/Loader.vue @@ -0,0 +1,133 @@ + + + + + diff --git a/apps/page/src/components/PlayButton.vue b/apps/page/src/components/PlayButton.vue index 04e7aaed1..53907151a 100644 --- a/apps/page/src/components/PlayButton.vue +++ b/apps/page/src/components/PlayButton.vue @@ -2,38 +2,37 @@ diff --git a/apps/page/src/components/PlayerTile.vue b/apps/page/src/components/PlayerTile.vue deleted file mode 100644 index 6ff428acd..000000000 --- a/apps/page/src/components/PlayerTile.vue +++ /dev/null @@ -1,134 +0,0 @@ - - - - - diff --git a/apps/page/src/components/Test.vue b/apps/page/src/components/Test.vue deleted file mode 100644 index cefd88fb9..000000000 --- a/apps/page/src/components/Test.vue +++ /dev/null @@ -1,15 +0,0 @@ - - - diff --git a/apps/page/src/features/PageHeader.vue b/apps/page/src/features/PageHeader.vue index 647d34403..75b8b59ee 100644 --- a/apps/page/src/features/PageHeader.vue +++ b/apps/page/src/features/PageHeader.vue @@ -16,15 +16,15 @@ " > @@ -42,14 +42,15 @@ const store = injectStore(); const state = mapState({ title: selectors.podcast.title, poster: selectors.podcast.poster, - feed: selectors.podcast.feed + feed: selectors.podcast.feed, + index: selectors.router.index }); const showOverlay = () => { - store.dispatch(actions.toggleSubscribeOverlay()); + store.dispatch(actions.subscribeButton.toggleSubscribeOverlay()); }; const showSearch = () => { - store.dispatch(actions.showSearch()); + store.dispatch(actions.search.show()); }; diff --git a/apps/page/src/features/Search.vue b/apps/page/src/features/Search.vue new file mode 100644 index 000000000..165d63382 --- /dev/null +++ b/apps/page/src/features/Search.vue @@ -0,0 +1,299 @@ + + + + + diff --git a/apps/page/src/features/playbar/Chapter.vue b/apps/page/src/features/playbar/Chapter.vue index 6d73c2e02..9c907fb80 100644 --- a/apps/page/src/features/playbar/Chapter.vue +++ b/apps/page/src/features/playbar/Chapter.vue @@ -1,6 +1,6 @@ - -
+ +
- + + +
@@ -36,46 +40,46 @@ const lang = getLanguage(); diff --git a/apps/page/src/layouts/Layout.astro b/apps/page/src/layouts/Layout.astro index cf711a120..e19798ff3 100644 --- a/apps/page/src/layouts/Layout.astro +++ b/apps/page/src/layouts/Layout.astro @@ -3,6 +3,7 @@ import { ViewTransitions } from "astro:transitions"; import PageHeader from '../features/PageHeader.vue'; import PlayBar from '../features/playbar/PlayBar.vue'; import Search from '../features/Search.vue'; +import Subscribe from '../features/subscribe/Subscribe.vue'; import { store } from '../logic'; import { getLanguage } from "../i18n"; @@ -30,6 +31,7 @@ const lang = getLanguage();
+
+ + diff --git a/apps/page/src/features/PageFooter.vue b/apps/page/src/features/PageFooter.vue new file mode 100644 index 000000000..43403bab0 --- /dev/null +++ b/apps/page/src/features/PageFooter.vue @@ -0,0 +1,52 @@ + + + diff --git a/apps/page/src/features/PageHeader.vue b/apps/page/src/features/PageHeader.vue index 75b8b59ee..79cf68429 100644 --- a/apps/page/src/features/PageHeader.vue +++ b/apps/page/src/features/PageHeader.vue @@ -19,8 +19,7 @@ {{ state.title }} - {{ t('HEADER.EPISODES') }} - + {{ $t('HEADER.EPISODES') }} {{ $t('HEADER.SUBSCRIBE') }} @@ -30,13 +29,10 @@ + + diff --git a/apps/page/src/logic/data/feed-parser.ts b/apps/page/src/logic/data/feed-parser.ts index adf5192cf..83cc0b6a1 100644 --- a/apps/page/src/logic/data/feed-parser.ts +++ b/apps/page/src/logic/data/feed-parser.ts @@ -1,7 +1,11 @@ import { get, castArray, kebabCase } from 'lodash-es'; import { XMLParser } from 'fast-xml-parser'; +import { toPlayerTime } from '@podlove/utils/time'; +import { json } from '@podlove/utils/request'; + import type { Audio, + Author, Chapter, Episode, Person, @@ -9,10 +13,6 @@ import type { Show, Transcript } from '../../types/feed.types'; -import { toPlayerTime } from '@podlove/utils/time'; -import { json } from '@podlove/utils/request'; - -let CACHE = new Map>(); const parser = new XMLParser({ ignoreAttributes: false @@ -71,7 +71,9 @@ const getTranscriptUrl = async (data: any): Promise => export const resolveTranscripts = async (transcriptsUrl: string): Promise => json(transcriptsUrl) .then((result) => get(result, ['segments'], [])) - .then((items) => items.map(transformTranscript).filter((item: Transcript) => get(item, 'text'))); + .then((items) => + items.map(transformTranscript).filter((item: Transcript) => get(item, 'text')) + ); const transformAudio = (input: any): Audio[] => { const url = get(input, ['enclosure', '@_url'], null); @@ -113,10 +115,19 @@ const resolveEpisode = }; }; +const transformAuthor = (data: any): Author => ({ + copyright: get(data, ['channel', 'copyright'], null), + owner: get(data, ['channel', 'itunes:owner', 'itunes:name'], null), + name: get(data, ['channel', 'itunes:author'], null), + mail: get(data, ['channel', 'itunes:owner', 'itunes:email'], null) +}); + const transform = (episodeId?: number) => async (data: any): Promise => ({ etag: get(data, 'etag', null), + buildDate: get(data, ['channel', 'lastBuildDate'], null), + author: transformAuthor(data), show: transformShow(data), episodes: await Promise.all( castArray(get(data, ['channel', 'item'], [])).map(resolveEpisode(episodeId)) @@ -135,12 +146,6 @@ export default async ({ return transform(episodeId)({}); } - // const existing = CACHE.get(feedUrl); - - // if (existing) { - // return existing; - // } - return await fetch(feed) // TODO: add cache key .then(async (result) => { @@ -152,11 +157,5 @@ export default async ({ etag }; }) - // .then((data) => { - // console.log(data); - // return data; - // }) .then(transform(episodeId)); - - // CACHE.set(feedUrl, result); }; diff --git a/apps/page/src/logic/sagas/layout.sagas.ts b/apps/page/src/logic/sagas/layout.sagas.ts index af4ca975a..5de84d822 100644 --- a/apps/page/src/logic/sagas/layout.sagas.ts +++ b/apps/page/src/logic/sagas/layout.sagas.ts @@ -1,4 +1,8 @@ -import { select } from 'redux-saga/effects'; +import type { EventChannel } from 'redux-saga'; +import { call, put, select, takeEvery } from 'redux-saga/effects'; +import { channel } from '@podlove/player-sagas/helper'; + +import actions from '../store/actions'; function* disableOverflow() { document.body.classList.add('overflow-hidden'); @@ -8,6 +12,14 @@ function* enableOverflow() { document.body.classList.remove('overflow-hidden'); } +function* startLoading() { + yield put(actions.view.startLoading()) +} + +function* stopLoading() { + yield put(actions.view.stopLoading()) +} + export default function ({ selectSubscribeOverlayVisible, selectSearchOverlayVisible @@ -16,6 +28,16 @@ export default function ({ selectSearchOverlayVisible: (input: any) => boolean; }) { return function* () { + const pageLoadStart: EventChannel = yield call(channel, (cb: EventListener) => + document.addEventListener('astro:before-preparation', cb) + ); + const pageLoadEnd: EventChannel = yield call(channel, (cb: EventListener) => + document.addEventListener('astro:after-preparation', cb) + ); + + yield takeEvery(pageLoadStart, startLoading); + yield takeEvery(pageLoadEnd, stopLoading); + while (true) { const subscribeOverlayVisible: boolean = yield select(selectSubscribeOverlayVisible); const searchOverlayVisible: boolean = yield select(selectSearchOverlayVisible); diff --git a/apps/page/src/logic/sagas/serviceworker.sagas.ts b/apps/page/src/logic/sagas/serviceworker.sagas.ts index 6cb65d689..9b1123389 100644 --- a/apps/page/src/logic/sagas/serviceworker.sagas.ts +++ b/apps/page/src/logic/sagas/serviceworker.sagas.ts @@ -34,8 +34,8 @@ export default ({ } return function* () { - if(import.meta.env.MODE === 'production') { + // if(import.meta.env.MODE === 'production') { yield registerServiceWorker(); - } + // } }; }; diff --git a/apps/page/src/logic/store/actions.ts b/apps/page/src/logic/store/actions.ts index 67bffb655..42cf75003 100644 --- a/apps/page/src/logic/store/actions.ts +++ b/apps/page/src/logic/store/actions.ts @@ -10,6 +10,7 @@ import { actions as player } from './stores/player.store'; import { actions as playbar } from './stores/playbar.store'; import { actions as subscribeButton } from './stores/subscribe-button.store'; import { actions as router } from './stores/router.store'; +import { actions as view } from './stores/view.store'; export default { episodes, @@ -23,5 +24,6 @@ export default { setRate, simulatePlaytime, disableGhost, - enableGhost + enableGhost, + view }; diff --git a/apps/page/src/logic/store/reducers.ts b/apps/page/src/logic/store/reducers.ts index 0926f79ce..3a39974d8 100644 --- a/apps/page/src/logic/store/reducers.ts +++ b/apps/page/src/logic/store/reducers.ts @@ -21,6 +21,7 @@ import { reducer as search } from './stores/search.store'; import { reducer as subscribeButton } from './stores/subscribe-button.store'; import { reducer as router } from './stores/router.store'; import { reducer as contributors } from './stores/contributors.store'; +import { reducer as view } from './stores/view.store'; export default combineReducers({ runtime, @@ -45,5 +46,6 @@ export default combineReducers({ search, subscribeButton, router, - contributors + contributors, + view }); diff --git a/apps/page/src/logic/store/selectors.ts b/apps/page/src/logic/store/selectors.ts index c6e87f6d6..28aba2096 100644 --- a/apps/page/src/logic/store/selectors.ts +++ b/apps/page/src/logic/store/selectors.ts @@ -15,6 +15,7 @@ import { selectors as subscribeButton } from './stores/subscribe-button.store'; import { selectors as search } from './stores/search.store'; import { selectors as router } from './stores/router.store'; import { selectors as contributors } from './stores/contributors.store'; +import { selectors as view } from './stores/view.store'; const slices = { runtime: (state: State) => state.runtime, @@ -27,6 +28,7 @@ const slices = { subscribeButton: (state: State) => state.subscribeButton, router: (state: State) => state.router, contributors: (state: State) => state.contributors, + view: (state: State) => state.view, }; // runtime @@ -71,7 +73,8 @@ export default { runtime: { initialized: createSelector(slices.runtime, runtime.initialized), locale: createSelector(slices.runtime, runtime.locale), - cacheKey + cacheKey, + buildDate: createSelector(slices.runtime, runtime.buildDate), }, theme: { background: createSelector(slices.theme, theme.background) @@ -83,6 +86,9 @@ export default { poster: createSelector(slices.podcast, podcast.poster), description: createSelector(slices.podcast, podcast.description), summary: createSelector(slices.podcast, podcast.summary), + copyright: createSelector(slices.podcast, podcast.copyright), + mail: createSelector(slices.podcast, podcast.mail), + owner: createSelector(slices.podcast, podcast.owner), }, current: { episode: currentEpisode @@ -100,9 +106,15 @@ export default { ) }, episodes: { - ids: createSelector(slices.podcast, podcast.episodes), list: createSelector(slices.episodes, episodes.list), }, + view: { + archive: { + episodes: createSelector(slices.view, view.archiveEpisodes), + page: createSelector(slices.view, view.archiveEpisodesPage), + }, + loading: createSelector(slices.view, view.loading), + }, show: { poster: showPoster, title: showTitle diff --git a/apps/page/src/logic/store/state.ts b/apps/page/src/logic/store/state.ts index 8debfafbd..b33167852 100644 --- a/apps/page/src/logic/store/state.ts +++ b/apps/page/src/logic/store/state.ts @@ -9,6 +9,7 @@ import { type State as search } from './stores/search.store'; import { type State as subscribeButton } from './stores/subscribe-button.store'; import { type State as router } from './stores/router.store'; import { type State as contributors } from './stores/contributors.store'; +import { type State as view } from './stores/view.store'; export default interface State { runtime: runtime, @@ -21,5 +22,6 @@ export default interface State { subscribeButton: subscribeButton, player: player, router: router, - contributors: contributors + contributors: contributors, + view: view, }; diff --git a/apps/page/src/logic/store/stores/podcast.store.ts b/apps/page/src/logic/store/stores/podcast.store.ts index 76be86506..50aa442d1 100644 --- a/apps/page/src/logic/store/stores/podcast.store.ts +++ b/apps/page/src/logic/store/stores/podcast.store.ts @@ -1,7 +1,7 @@ import { handleActions, type Action } from 'redux-actions'; -import { actions as lifecycleActions, type dataFetchedPayload, type initializeAppPayload } from './runtime.store' import { get } from 'lodash-es'; -import type { Show } from '../../../types/feed.types'; +import { actions as lifecycleActions, type dataFetchedPayload, type initializeAppPayload } from './runtime.store' +import type { Author, Show } from '../../../types/feed.types'; export interface State { feed: string | null; @@ -9,7 +9,7 @@ export interface State { poster: string | null; description: string | null; summary: string | null; - episodes: string[]; + author: Author; } export const reducer = handleActions({ @@ -19,7 +19,12 @@ export const reducer = handleActions({ poster: get(payload, ['show', 'poster'], null), description: get(payload, ['show', 'description'], null), summary: get(payload, ['show', 'summary'], null), - episodes: get(payload, ['episodes'], []).map(({ id }) => id) + author: get(payload, ['author'], { + owner: null, + copyright: null, + name: null, + mail: null, + }), }), [lifecycleActions.initializeApp.toString()]: (state, { payload }: Action) => ({ ...state, @@ -31,7 +36,12 @@ export const reducer = handleActions({ poster: null, description: null, summary: null, - episodes: [] + author: { + owner: null, + copyright: null, + name: null, + mail: null, + } }); export const selectors = { @@ -47,5 +57,7 @@ export const selectors = { poster: (state: State) => get(state, 'poster'), description: (state: State) => get(state, 'description'), summary: (state: State) => get(state, 'summary'), - episodes: (state: State) => get(state, 'episodes'), + copyright: (state: State) => get(state, ['author', 'copyright']), + owner: (state: State) => get(state, ['author', 'owner']), + mail: (state: State) => get(state, ['author', 'mail']) } diff --git a/apps/page/src/logic/store/stores/runtime.store.ts b/apps/page/src/logic/store/stores/runtime.store.ts index 984530970..06ba5efda 100644 --- a/apps/page/src/logic/store/stores/runtime.store.ts +++ b/apps/page/src/logic/store/stores/runtime.store.ts @@ -2,17 +2,19 @@ import { createAction, handleActions, type Action } from 'redux-actions'; import { etag } from '../../../lib/caching.js'; import type { Podcast } from '../../../types/feed.types.js'; import { version } from '../../../../package.json'; +import { get } from 'lodash-es'; export interface State { initialized: boolean; locale: string; cacheKey : string | null; + buildDate: string | null; } export interface initializeAppPayload { feed: string; locale: string; - episodeId?: number; + episodeId?: number } export type dataFetchedPayload = Podcast; @@ -33,17 +35,19 @@ export const reducer = handleActions( [actions.dataFetched.toString()]: (state, { payload }: Action) => ({ ...state, initialized: true, + buildDate: get(payload, 'buildDate', null), cacheKey: payload.etag ? etag({ feed: payload.etag, version }) : null }) }, - { initialized: false, locale: 'en-US', cacheKey: null } + { initialized: false, locale: 'en-US', cacheKey: null, buildDate: null } ); export const selectors = { initialized: (state: State) => state.initialized, locale: (state: State) => state.locale, cacheKey: (state: State) => state.cacheKey, + buildDate: (state: State) => state.buildDate, }; diff --git a/apps/page/src/logic/store/stores/view.store.ts b/apps/page/src/logic/store/stores/view.store.ts new file mode 100644 index 000000000..7ba5b4ae9 --- /dev/null +++ b/apps/page/src/logic/store/stores/view.store.ts @@ -0,0 +1,54 @@ +import { createAction, handleActions, type Action } from 'redux-actions'; +import { type dataFetchedPayload, actions as runtimeActions } from './runtime.store.js'; + +export interface State { + archive: { + episodes: number[]; + page: number; + }, + loading: boolean; +} + +export type archiveLoadMorePayload = void; +export type startLoadingPayload = void; +export type stopLoadingPayload = void; + +export const actions = { + archiveLoadMore: createAction('ARCHIVE_LOAD_MORE'), + startLoading: createAction('START_LOADING'), + stopLoading: createAction('STOP_LOADING'), +}; + +export const reducer = handleActions( + { + [runtimeActions.dataFetched.toString()]: (state, { payload }: Action) => ({ + ...state, + archive: { + ...state.archive, + episodes: payload.episodes.map(({ id }) => id) + } + }), + [actions.archiveLoadMore.toString()]: (state) => ({ + ...state, + archive: { + ...state.archive, + page: state.archive.page + 1 + } + }), + [actions.startLoading.toString()]: (state) => ({ + ...state, + loading: true + }), + [actions.stopLoading.toString()]: (state) => ({ + ...state, + loading: false + }) + }, + { archive: { episodes: [], page: 1 }, loading: false } +); + +export const selectors = { + archiveEpisodesPage: (state: State) => state.archive.page, + archiveEpisodes: (state: State) => state.archive.episodes, + loading: (state: State) => state.loading, +}; diff --git a/apps/page/src/pages/feed/[...feed]/index.astro b/apps/page/src/pages/feed/[...feed]/index.astro index 8cf5deab2..1063a5f12 100644 --- a/apps/page/src/pages/feed/[...feed]/index.astro +++ b/apps/page/src/pages/feed/[...feed]/index.astro @@ -1,24 +1,22 @@ --- import Layout from '../../../layouts/Layout.astro'; -import EpisodeItem from '../../../screens/archive/EpisodeItem.vue'; +import EpisodeList from '../../../screens/archive/List.vue'; import { actions, selectors, store } from '../../../logic'; import HeroIndex from '../../../screens/archive/Hero.vue'; +import LoadMore from '../../../screens/archive/LoadMore.vue'; const title = selectors.podcast.title(store.getState()); -const episodes = selectors.episodes.ids(store.getState()); -store.dispatch(actions.router.setRoute(['feed'])) +store.dispatch(actions.router.setRoute(['feed'])); ---
-
- { - episodes.map((episode, index) => ) - } -
+
+ +
-Layout diff --git a/apps/page/src/features/Colors.vue b/apps/page/src/features/Colors.vue new file mode 100644 index 000000000..956e5ae7f --- /dev/null +++ b/apps/page/src/features/Colors.vue @@ -0,0 +1,36 @@ + + + diff --git a/apps/page/src/features/PageHeader.vue b/apps/page/src/features/PageHeader.vue index 79cf68429..34665092e 100644 --- a/apps/page/src/features/PageHeader.vue +++ b/apps/page/src/features/PageHeader.vue @@ -4,19 +4,19 @@ flex h-12 bg-primary-900 - text-gray-100 + text-complementary-900 font-light justify-center items-center px-16 - border-b border-gray-600 + border-b border-complementary-300 top-0 w-full overflow-hidden " >

-

+

{{ $t('SUBSCRIBE_BUTTON.CLIENTS') }}

-

+

{{ $t('SUBSCRIBE_BUTTON.FEED') }}

@@ -68,8 +67,8 @@ font-light cursor-pointer truncate - hover:bg-primary-200 - bg-primary-100 + hover:bg-complementary-900 + bg-complementary-100 appearance-none " @click="selectText" diff --git a/apps/page/src/features/timeline/Bullet.vue b/apps/page/src/features/timeline/Bullet.vue index c017ba0d6..6adeb877c 100644 --- a/apps/page/src/features/timeline/Bullet.vue +++ b/apps/page/src/features/timeline/Bullet.vue @@ -30,6 +30,6 @@ const bottom = computed(() => props.bottom || false); diff --git a/apps/page/src/layouts/Layout.astro b/apps/page/src/layouts/Layout.astro index fb0a8c049..8048cfca0 100644 --- a/apps/page/src/layouts/Layout.astro +++ b/apps/page/src/layouts/Layout.astro @@ -6,12 +6,14 @@ import Search from '../features/Search.vue'; import PageFooter from '../features/PageFooter.vue'; import LoadingBar from '../features/LoadingBar.vue'; import Subscribe from '../features/subscribe/Subscribe.vue'; +import Colors from '../features/Colors.vue'; import { store } from '../logic'; import { getLanguage } from '../i18n'; const { title } = Astro.props; const state = store.getState(); const lang = getLanguage(); + --- @@ -28,6 +30,7 @@ const lang = getLanguage(); +
@@ -46,49 +49,6 @@ const lang = getLanguage(); diff --git a/apps/page/src/features/timeline/Bullet.vue b/apps/page/src/features/timeline/Bullet.vue index 6adeb877c..39fcfcb6b 100644 --- a/apps/page/src/features/timeline/Bullet.vue +++ b/apps/page/src/features/timeline/Bullet.vue @@ -5,7 +5,7 @@ class="absolute top-0 left-0 h-4 border-gray-500 border-l-2 w-1 -mt-4 ml-4" > diff --git a/apps/page/src/features/timeline/Transcript.vue b/apps/page/src/features/timeline/Transcript.vue index 11388483f..faa021351 100644 --- a/apps/page/src/features/timeline/Transcript.vue +++ b/apps/page/src/features/timeline/Transcript.vue @@ -31,8 +31,8 @@ - +
diff --git a/apps/page/src/lib/transcripts.ts b/apps/page/src/lib/transcripts.ts deleted file mode 100644 index 616d179cd..000000000 --- a/apps/page/src/lib/transcripts.ts +++ /dev/null @@ -1,6 +0,0 @@ -import { parse as vttParser } from '@plussub/srt-vtt-parser'; - -export const parse = async (input: string): Promise => { - const result = await vttParser(input); - console.log(result); -}; diff --git a/apps/page/src/logic/data/feed-parser.ts b/apps/page/src/logic/data/feed-parser.ts index e605e12a7..93ae1e56a 100644 --- a/apps/page/src/logic/data/feed-parser.ts +++ b/apps/page/src/logic/data/feed-parser.ts @@ -1,7 +1,7 @@ import { get, castArray, kebabCase } from 'lodash-es'; import { XMLParser } from 'fast-xml-parser'; import { toPlayerTime } from '@podlove/utils/time'; -import { parse } from '../../lib/transcripts'; +import webVttParser from '@podlove/webvtt-parser'; import type { Audio, @@ -64,18 +64,30 @@ const transformShow = (data: any): Show => ({ }); const getTranscriptUrl = async (data: any): Promise => { - return get(data, ['podcast:transcript', '@_url'], null); + const transcripts: { '@_url': string; '@_type': string }[] = get( + data, + ['podcast:transcript'], + [] + ); + const vtt = transcripts.find((item) => get(item, ['@_type'], null) === 'text/vtt'); + + return get(vtt, ['@_url'], null); }; export const resolveTranscripts = async (transcriptsUrl: string): Promise => fetch(transcriptsUrl) - .then((result) => result.text()) - .then(parse) - .then(() => []); - // .then((result) => get(result, ['segments'], [])) - // .then((items) => - // items.map(transformTranscript).filter((item: Transcript) => get(item, 'text')) - // ); + .then((result) => result.text()) + .then(webVttParser) + .then((result) => get(result, ['cues'], [])) + .then((cues) => + cues.map((cue) => ({ + voice: cue.voice || null, + speaker: cue.identifier || kebabCase(cue.voice) || null, + start: cue.start, + end: cue.end, + text: cue.text + })) + ); const transformAudio = (input: any): Audio[] => { const url = get(input, ['enclosure', '@_url'], null); @@ -99,7 +111,7 @@ const resolveEpisode = const transcriptUrl = await getTranscriptUrl(data); return { - id: get(data, 'itunes:episode', null), + id, title: get(data, 'title', null), description: get(data, 'description', null), subtitle: get(data, 'itunes:subtitle', null), @@ -112,7 +124,7 @@ const resolveEpisode = chapters: castArray(get(data, ['psc:chapters', 'psc:chapter'], [])) .map(transformChapter) .map(buildChapterList(duration)), - transcripts: (id === episodeId && transcriptUrl) ? await resolveTranscripts(transcriptUrl) : [], + transcripts: id === episodeId && transcriptUrl ? await resolveTranscripts(transcriptUrl) : [], audio: transformAudio(data) }; }; diff --git a/apps/page/src/logic/sagas/search.sagas.ts b/apps/page/src/logic/sagas/search.sagas.ts index b2de1dc17..2daf752ba 100644 --- a/apps/page/src/logic/sagas/search.sagas.ts +++ b/apps/page/src/logic/sagas/search.sagas.ts @@ -52,7 +52,7 @@ export default ({ EPISODES.indexEntities( results, (e: any) => e.id, - (e: any) => [e.title, e.description, e.chapters, e.contributors] + (e: any) => [e.title, e.description, e.chapters, e.contributors, e.content] ); yield put(actions.search.initialize('episodes')); } diff --git a/apps/page/src/pages/feed/[...feed]/episode/[episodeId].astro b/apps/page/src/pages/feed/[...feed]/episode/[episodeId].astro index b05a4e791..4f6494239 100644 --- a/apps/page/src/pages/feed/[...feed]/episode/[episodeId].astro +++ b/apps/page/src/pages/feed/[...feed]/episode/[episodeId].astro @@ -4,10 +4,10 @@ import Layout from '../../../../layouts/Layout.astro'; import Hero from '../../../../screens/episodes/Hero.vue' import Navigation from '../../../../screens/episodes/Navigation.vue' import Timeline from '../../../../features/timeline/Timeline.vue' -import { type Transcript } from '../../../../types/feed.types' import { store, selectors, actions } from '../../../../logic'; import { useTranslations } from '../../../../i18n' +import type { PodloveWebPlayerTranscript } from '@podlove/types'; const { episodeId } = Astro.params; const $t = useTranslations(); @@ -17,9 +17,11 @@ const episode = selectors.episode.data(episodeId as string)(store.getState()); store.dispatch(actions.router.episodePage({ base: 'feed', episodeId: episodeId as string })); const timeline = [ { start: 0, title: $t('TIMELINE.START') as string, type: 'marker' } as any, - ...createTimeline(episode.transcripts as Transcript[], episode.chapters || [], episode.contributors || []), + ...createTimeline((episode.transcripts || []) as unknown as PodloveWebPlayerTranscript[], episode.chapters || [], episode.contributors || []), { start: episode.duration, title: $t('TIMELINE.END') as string, type: 'marker' } as any, ]; + +console.log('speakers', episode.contributors ) --- diff --git a/apps/page/src/screens/episodes/Hero.vue b/apps/page/src/screens/episodes/Hero.vue index b438b53f4..061e650c9 100644 --- a/apps/page/src/screens/episodes/Hero.vue +++ b/apps/page/src/screens/episodes/Hero.vue @@ -18,7 +18,7 @@ flex items-center justify-center - opacity-20 + opacity-50 hover:opacity-100 transition ease-in diff --git a/apps/page/src/screens/episodes/Navigation.vue b/apps/page/src/screens/episodes/Navigation.vue index bd22b5906..e081a7d70 100644 --- a/apps/page/src/screens/episodes/Navigation.vue +++ b/apps/page/src/screens/episodes/Navigation.vue @@ -8,12 +8,12 @@ class="h-20 relative w-full flex items-center justify-center" :class="{ 'bg-white -mb-4': !docked, 'bg-transparent': docked }" > - +
@@ -94,17 +94,6 @@ onMounted(() => { diff --git a/apps/page/src/layouts/Layout.astro b/apps/page/src/layouts/Layout.astro index 5fa98c07c..2bb88c887 100644 --- a/apps/page/src/layouts/Layout.astro +++ b/apps/page/src/layouts/Layout.astro @@ -34,7 +34,7 @@ const lang = getLanguage(); - +
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 8081a8a5d..3cdf19e1f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -71,13 +71,13 @@ importers: version: 4.2.3(vite@4.3.9)(vue@3.2.41) autoprefixer: specifier: 10.4.14 - version: 10.4.14(postcss@8.4.31) + version: 10.4.14(postcss@8.4.39) histoire: specifier: 0.16.1 version: 0.16.1(@types/node@18.18.14)(vite@4.3.9) postcss-import: specifier: 15.1.0 - version: 15.1.0(postcss@8.4.31) + version: 15.1.0(postcss@8.4.39) tailwindcss: specifier: 3.3.2 version: 3.3.2 @@ -88,17 +88,20 @@ importers: apps/page: dependencies: '@astrojs/check': - specifier: 0.3.1 - version: 0.3.1(prettier@2.3.2)(typescript@5.3.2) + specifier: 0.8.1 + version: 0.8.1(prettier@2.3.2)(typescript@5.3.2) + '@astrojs/cloudflare': + specifier: 11.0.1 + version: 11.0.1(astro@4.11.5) '@astrojs/node': - specifier: 6.1.0 - version: 6.1.0(astro@4.11.5) + specifier: 8.3.2 + version: 8.3.2(astro@4.11.5) '@astrojs/tailwind': - specifier: 5.0.2 - version: 5.0.2(astro@4.11.5)(tailwindcss@3.0.24) + specifier: 5.1.0 + version: 5.1.0(astro@4.11.5)(tailwindcss@3.0.24) '@astrojs/vue': - specifier: 4.0.0 - version: 4.0.0(@babel/core@7.23.5)(astro@4.11.5)(vite@4.3.9)(vue@3.2.30) + specifier: 4.5.0 + version: 4.5.0(astro@4.11.5)(vite@5.3.3)(vue@3.2.30) '@m31coding/fuzzy-search': specifier: 1.0.1 version: 1.0.1 @@ -180,7 +183,7 @@ importers: version: 2.6.5 tailwindcss: specifier: 3.0.24 - version: 3.0.24(postcss@8.4.31) + version: 3.0.24(postcss@8.4.39) typescript: specifier: 5.3.2 version: 5.3.2 @@ -240,7 +243,7 @@ importers: version: 4.1.8 tailwindcss: specifier: 3.2.4 - version: 3.2.4(postcss@8.4.31) + version: 3.2.4(postcss@8.4.39) vue: specifier: 3.2.41 version: 3.2.41 @@ -322,7 +325,7 @@ importers: version: 4.1.8 tailwindcss: specifier: 3.2.4 - version: 3.2.4(postcss@8.4.31) + version: 3.2.4(postcss@8.4.39) vue: specifier: 3.2.41 version: 3.2.41 @@ -332,7 +335,7 @@ importers: devDependencies: '@fullhuman/postcss-purgecss': specifier: 5.0.0 - version: 5.0.0(postcss@8.4.31) + version: 5.0.0(postcss@8.4.39) '@podlove/types': specifier: workspace:* version: link:../../packages/types @@ -543,7 +546,7 @@ importers: version: 2.0.1 tailwindcss: specifier: 3.2.4 - version: 3.2.4(postcss@8.4.31) + version: 3.2.4(postcss@8.4.39) vue: specifier: 3.2.41 version: 3.2.41 @@ -944,14 +947,18 @@ packages: '@jridgewell/gen-mapping': 0.3.3 '@jridgewell/trace-mapping': 0.3.20 - /@astrojs/check@0.3.1(prettier@2.3.2)(typescript@5.3.2): - resolution: {integrity: sha512-3LjEUvh7Z4v9NPokaqKMXQ0DwnSXfmtcyAuWVTjNt9yzjv54SxykobV5CTOB3TIko+Rqg59ejamJBxaJN6fvkw==} + /@antfu/utils@0.7.10: + resolution: {integrity: sha512-+562v9k4aI80m1+VuMHehNJWLOFjBnXn3tdOitzD0il5b7smkSBal4+a3oKiQTbrwMmN/TBUMDvbdoWDehgOww==} + dev: false + + /@astrojs/check@0.8.1(prettier@2.3.2)(typescript@5.3.2): + resolution: {integrity: sha512-QTzCuiBWll3SLSe7OsWtWyZRbwChXwxM4Y0Jb84jdPOdYobzHad9ubU7V23qmK3Y0BNwgzCbEP5C5FPVitb31Q==} hasBin: true peerDependencies: typescript: ^5.0.0 dependencies: - '@astrojs/language-server': 2.5.2(prettier@2.3.2)(typescript@5.3.2) - chokidar: 3.5.3 + '@astrojs/language-server': 2.11.1(prettier@2.3.2)(typescript@5.3.2) + chokidar: 3.6.0 fast-glob: 3.3.2 kleur: 4.1.5 typescript: 5.3.2 @@ -961,20 +968,41 @@ packages: - prettier-plugin-astro dev: false - /@astrojs/compiler@2.3.2: - resolution: {integrity: sha512-jkY7bCVxl27KeZsSxIZ+pqACe+g8VQUdTiSJRj/sXYdIaZlW3ZMq4qF2M17P/oDt3LBq0zLNwQr4Cb7fSpRGxQ==} + /@astrojs/cloudflare@11.0.1(astro@4.11.5): + resolution: {integrity: sha512-VuUSFS2ZhxWIfo7RgHvAvaMff3iqeWFVCgh+0WHywjWvJle2J5jlpdUK5seR3NkTWr9yYOPSSr1tP34C8E/w0w==} + peerDependencies: + astro: ^4.10.3 + dependencies: + '@astrojs/internal-helpers': 0.3.0 + '@astrojs/underscore-redirects': 0.3.4 + '@cloudflare/workers-types': 4.20240712.0 + astro: 4.11.5(@types/node@18.18.14)(typescript@5.3.2) + esbuild: 0.19.12 + estree-walker: 3.0.3 + magic-string: 0.30.10 + miniflare: 3.20240701.0 + tiny-glob: 0.2.9 + wrangler: 3.64.0(@cloudflare/workers-types@4.20240712.0) + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate dev: false /@astrojs/compiler@2.8.2: resolution: {integrity: sha512-2v2N2oDnMH6+CX1Wn6f45Afa4tdkUMutdx8pJaokfaOYnAU+u6+UK7o7sXqydKro1cLwVmmOIJv6AqiXnAdLDA==} dev: false + /@astrojs/internal-helpers@0.3.0: + resolution: {integrity: sha512-tGmHvrhpzuz0JBHaJX8GywN9g4rldVNHtkoVDC3m/DdzBO70jGoVuc0uuNVglRYnsdwkbG0K02Iw3nOOR3/Y4g==} + dev: false + /@astrojs/internal-helpers@0.4.1: resolution: {integrity: sha512-bMf9jFihO8YP940uD70SI/RDzIhUHJAolWVcO1v5PUivxGKvfLZTLTVVxEYzGYyPsA3ivdLNqMnL5VgmQySa+g==} dev: false - /@astrojs/language-server@2.5.2(prettier@2.3.2)(typescript@5.3.2): - resolution: {integrity: sha512-O5SMzoQ65wSxA1KygreI9UJYmHpgt15bSYBxceHwqX7OCDM4Ek8mr6mZn45LGDtwM3dp1uup7kp8exfRPwIFbA==} + /@astrojs/language-server@2.11.1(prettier@2.3.2)(typescript@5.3.2): + resolution: {integrity: sha512-WSIBBUK9lSeVD4KhPiZk2u3wsXdj7WEYvYPPs8ZsgbSVIOzUJWAKVcITHiXmcXlzZB5ubK44YUN/Hq+f2GeMyQ==} hasBin: true peerDependencies: prettier: ^3.0.0 @@ -985,24 +1013,23 @@ packages: prettier-plugin-astro: optional: true dependencies: - '@astrojs/compiler': 2.3.2 + '@astrojs/compiler': 2.8.2 '@jridgewell/sourcemap-codec': 1.4.15 - '@volar/kit': 1.10.10(typescript@5.3.2) - '@volar/language-core': 1.10.10 - '@volar/language-server': 1.10.10 - '@volar/language-service': 1.10.10 - '@volar/source-map': 1.10.10 - '@volar/typescript': 1.10.10 + '@volar/kit': 2.4.0-alpha.15(typescript@5.3.2) + '@volar/language-core': 2.4.0-alpha.15 + '@volar/language-server': 2.4.0-alpha.15 + '@volar/language-service': 2.4.0-alpha.15 + '@volar/typescript': 2.4.0-alpha.15 fast-glob: 3.3.2 - muggle-string: 0.3.1 + muggle-string: 0.4.1 prettier: 2.3.2 - volar-service-css: 0.0.16(@volar/language-service@1.10.10) - volar-service-emmet: 0.0.16(@volar/language-service@1.10.10) - volar-service-html: 0.0.16(@volar/language-service@1.10.10) - volar-service-prettier: 0.0.16(@volar/language-service@1.10.10)(prettier@2.3.2) - volar-service-typescript: 0.0.16(@volar/language-service@1.10.10)(@volar/typescript@1.10.10) - volar-service-typescript-twoslash-queries: 0.0.16(@volar/language-service@1.10.10) - vscode-html-languageservice: 5.1.1 + volar-service-css: 0.0.59(@volar/language-service@2.4.0-alpha.15) + volar-service-emmet: 0.0.59(@volar/language-service@2.4.0-alpha.15) + volar-service-html: 0.0.59(@volar/language-service@2.4.0-alpha.15) + volar-service-prettier: 0.0.59(@volar/language-service@2.4.0-alpha.15)(prettier@2.3.2) + volar-service-typescript: 0.0.59(@volar/language-service@2.4.0-alpha.15) + volar-service-typescript-twoslash-queries: 0.0.59(@volar/language-service@2.4.0-alpha.15) + vscode-html-languageservice: 5.3.0 vscode-uri: 3.0.8 transitivePeerDependencies: - typescript @@ -1033,10 +1060,10 @@ packages: - supports-color dev: false - /@astrojs/node@6.1.0(astro@4.11.5): - resolution: {integrity: sha512-rqhZuVDUHVynkBaI/a8Y/WjVeFvKaH4qyrTkC8ZFwYUVff2DPQHS5/wLlTtS3s1GglApYsvPB9DdTL7sqUe9Kg==} + /@astrojs/node@8.3.2(astro@4.11.5): + resolution: {integrity: sha512-Upv0D+9b3RXp7XViQTtrijaDqihHWbVHLdJQ2sxtPOEtw2GDrVxuC6LmXIUew5YvJ9Ylmpst6KizVwO8d/K9/Q==} peerDependencies: - astro: ^3.0.0 + astro: ^4.2.0 dependencies: astro: 4.11.5(@types/node@18.18.14)(typescript@5.3.2) send: 0.18.0 @@ -1052,17 +1079,17 @@ packages: prismjs: 1.29.0 dev: false - /@astrojs/tailwind@5.0.2(astro@4.11.5)(tailwindcss@3.0.24): - resolution: {integrity: sha512-oXqeqmBlkQmsltrsU9nEWeXOtrZIAHW8dcmX7BCdrjzPnU6dPwWzAwhddNQ9ihKiWwsLnlbwQZIo2CDigcZlIA==} + /@astrojs/tailwind@5.1.0(astro@4.11.5)(tailwindcss@3.0.24): + resolution: {integrity: sha512-BJoCDKuWhU9FT2qYg+fr6Nfb3qP4ShtyjXGHKA/4mHN94z7BGcmauQK23iy+YH5qWvTnhqkd6mQPQ1yTZTe9Ig==} peerDependencies: - astro: ^3.2.4 + astro: ^3.0.0 || ^4.0.0 tailwindcss: ^3.0.24 dependencies: astro: 4.11.5(@types/node@18.18.14)(typescript@5.3.2) - autoprefixer: 10.4.16(postcss@8.4.31) - postcss: 8.4.31 - postcss-load-config: 4.0.2(postcss@8.4.31) - tailwindcss: 3.0.24(postcss@8.4.31) + autoprefixer: 10.4.16(postcss@8.4.39) + postcss: 8.4.39 + postcss-load-config: 4.0.2(postcss@8.4.39) + tailwindcss: 3.0.24(postcss@8.4.39) transitivePeerDependencies: - ts-node dev: false @@ -1082,21 +1109,26 @@ packages: - supports-color dev: false - /@astrojs/vue@4.0.0(@babel/core@7.23.5)(astro@4.11.5)(vite@4.3.9)(vue@3.2.30): - resolution: {integrity: sha512-OZYMEUsjAdK4Rs4VBYikjthHkaM8uw6rfzlCeCBU17Xi/VHdNGI6DdCTJnla3vVMlqYglwSrdDw5OX85jNXnhA==} - engines: {node: '>=18.14.1'} + /@astrojs/underscore-redirects@0.3.4: + resolution: {integrity: sha512-vYuYtIrTwxFlDRIhuekscorsHdLL8Hr3mgOczfM1tRWVPn54dDNcKG0DmfL4DlC5YJRoqVaVdUs508Hw643NTw==} + dev: false + + /@astrojs/vue@4.5.0(astro@4.11.5)(vite@5.3.3)(vue@3.2.30): + resolution: {integrity: sha512-yVrTwuGBpX/BPLlU29eje3/bUkHe9ftFeoiAJcskbaWeori86ojNCheMGKCS3NZwuXHj+bXcatoKdPEQiFfX5A==} + engines: {node: ^18.17.1 || ^20.3.0 || >=21.0.0} peerDependencies: - astro: ^4.0.0-beta.0 + astro: ^4.0.0 vue: ^3.2.30 dependencies: - '@vitejs/plugin-vue': 4.5.0(vite@4.3.9)(vue@3.2.30) - '@vitejs/plugin-vue-jsx': 3.1.0(vite@4.3.9)(vue@3.2.30) - '@vue/babel-plugin-jsx': 1.1.5(@babel/core@7.23.5) - '@vue/compiler-sfc': 3.3.9 + '@vitejs/plugin-vue': 5.0.5(vite@5.3.3)(vue@3.2.30) + '@vitejs/plugin-vue-jsx': 4.0.0(vite@5.3.3)(vue@3.2.30) + '@vue/compiler-sfc': 3.4.31 astro: 4.11.5(@types/node@18.18.14)(typescript@5.3.2) + vite-plugin-vue-devtools: 7.3.5(vite@5.3.3)(vue@3.2.30) vue: 3.2.30 transitivePeerDependencies: - - '@babel/core' + - '@nuxt/kit' + - rollup - supports-color - vite dev: false @@ -1107,18 +1139,20 @@ packages: dependencies: '@babel/highlight': 7.23.4 chalk: 2.4.2 + dev: true /@babel/code-frame@7.24.7: resolution: {integrity: sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA==} engines: {node: '>=6.9.0'} dependencies: '@babel/highlight': 7.24.7 - picocolors: 1.0.0 + picocolors: 1.0.1 dev: false /@babel/compat-data@7.23.5: resolution: {integrity: sha512-uU27kfDRlhfKl+w1U6vp16IuvSLtjAxdArVXPa9BvLkrr7CYIsxH5adpHObeAGY/41+syctUWOZ140a2Rvkgjw==} engines: {node: '>=6.9.0'} + dev: true /@babel/compat-data@7.24.8: resolution: {integrity: sha512-c4IM7OTg6k1Q+AJ153e2mc2QVTezTwnb4VzquwcyiEzGnW0Kedv4do/TrkU98qPeC5LNiMt/QXwIjzYXLBpyZg==} @@ -1146,6 +1180,7 @@ packages: semver: 6.3.1 transitivePeerDependencies: - supports-color + dev: true /@babel/core@7.24.8: resolution: {integrity: sha512-6AWcmZC/MZCO0yKys4uhg5NlxL0ESF3K6IAaoQ+xSXvPyPyxNWRafP+GDbI88Oh68O7QkJgmEtedWPM9U0pZNg==} @@ -1178,6 +1213,7 @@ packages: '@jridgewell/gen-mapping': 0.3.3 '@jridgewell/trace-mapping': 0.3.20 jsesc: 2.5.2 + dev: true /@babel/generator@7.24.8: resolution: {integrity: sha512-47DG+6F5SzOi0uEvK4wMShmn5yY0mVjVJoWTphdY2B4Rx9wHgjK7Yhtr0ru6nE+sn0v38mzrWOlah0p/YlHHOQ==} @@ -1189,13 +1225,6 @@ packages: jsesc: 2.5.2 dev: false - /@babel/helper-annotate-as-pure@7.22.5: - resolution: {integrity: sha512-LvBTxu8bQSQkcyKOU+a1btnNFQ1dMAd0R6PyW3arXes06F6QLWLIrd681bxRPIXlrMGR3XYnW9JyML7dP3qgxg==} - engines: {node: '>=6.9.0'} - dependencies: - '@babel/types': 7.23.5 - dev: false - /@babel/helper-annotate-as-pure@7.24.7: resolution: {integrity: sha512-BaDeOonYvhdKw+JoMVkAixAAJzG2jVPIwWoKBPdYuY9b452e2rPuI9QPYh3KpofZ3pW2akOmwZLOiOsHMiqRAg==} engines: {node: '>=6.9.0'} @@ -1212,6 +1241,7 @@ packages: browserslist: 4.22.1 lru-cache: 5.1.1 semver: 6.3.1 + dev: true /@babel/helper-compilation-targets@7.24.8: resolution: {integrity: sha512-oU+UoqCHdp+nWVDkpldqIQL/i/bvAv53tRqLG/s+cOXxe66zOYLU7ar/Xs3LdmBihrUMEUhwu6dMZwbNOYDwvw==} @@ -1224,27 +1254,48 @@ packages: semver: 6.3.1 dev: false - /@babel/helper-create-class-features-plugin@7.23.5(@babel/core@7.23.5): + /@babel/helper-create-class-features-plugin@7.23.5(@babel/core@7.24.8): resolution: {integrity: sha512-QELlRWxSpgdwdJzSJn4WAhKC+hvw/AtHbbrIoncKHkhKKR/luAlKkgBDcri1EzWAo8f8VvYVryEHN4tax/V67A==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 dependencies: - '@babel/core': 7.23.5 - '@babel/helper-annotate-as-pure': 7.22.5 - '@babel/helper-environment-visitor': 7.22.20 - '@babel/helper-function-name': 7.23.0 + '@babel/core': 7.24.8 + '@babel/helper-annotate-as-pure': 7.24.7 + '@babel/helper-environment-visitor': 7.24.7 + '@babel/helper-function-name': 7.24.7 '@babel/helper-member-expression-to-functions': 7.23.0 '@babel/helper-optimise-call-expression': 7.22.5 - '@babel/helper-replace-supers': 7.22.20(@babel/core@7.23.5) + '@babel/helper-replace-supers': 7.22.20(@babel/core@7.24.8) '@babel/helper-skip-transparent-expression-wrappers': 7.22.5 - '@babel/helper-split-export-declaration': 7.22.6 + '@babel/helper-split-export-declaration': 7.24.7 semver: 6.3.1 dev: false + /@babel/helper-create-class-features-plugin@7.24.8(@babel/core@7.24.8): + resolution: {integrity: sha512-4f6Oqnmyp2PP3olgUMmOwC3akxSm5aBYraQ6YDdKy7NcAMkDECHWG0DEnV6M2UAkERgIBhYt8S27rURPg7SxWA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + dependencies: + '@babel/core': 7.24.8 + '@babel/helper-annotate-as-pure': 7.24.7 + '@babel/helper-environment-visitor': 7.24.7 + '@babel/helper-function-name': 7.24.7 + '@babel/helper-member-expression-to-functions': 7.24.8 + '@babel/helper-optimise-call-expression': 7.24.7 + '@babel/helper-replace-supers': 7.24.7(@babel/core@7.24.8) + '@babel/helper-skip-transparent-expression-wrappers': 7.24.7 + '@babel/helper-split-export-declaration': 7.24.7 + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + dev: false + /@babel/helper-environment-visitor@7.22.20: resolution: {integrity: sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==} engines: {node: '>=6.9.0'} + dev: true /@babel/helper-environment-visitor@7.24.7: resolution: {integrity: sha512-DoiN84+4Gnd0ncbBOM9AZENV4a5ZiL39HYMyZJGZ/AZEykHYdJw0wW3kdcsh9/Kn+BRXHLkkklZ51ecPKmI1CQ==} @@ -1259,6 +1310,7 @@ packages: dependencies: '@babel/template': 7.22.15 '@babel/types': 7.23.5 + dev: true /@babel/helper-function-name@7.24.7: resolution: {integrity: sha512-FyoJTsj/PEUWu1/TYRiXTIHc8lbw+TDYkZuoE43opPS5TrI7MyONBE1oNvfguEXAD9yhQRrVBnXdXzSLQl9XnA==} @@ -1273,6 +1325,7 @@ packages: engines: {node: '>=6.9.0'} dependencies: '@babel/types': 7.23.5 + dev: true /@babel/helper-hoist-variables@7.24.7: resolution: {integrity: sha512-MJJwhkoGy5c4ehfoRyrJ/owKeMl19U54h27YYftT0o2teQ3FJ3nQUf/I3LlJsX4l3qlw7WRXUmiyajvHXoTubQ==} @@ -1285,7 +1338,17 @@ packages: resolution: {integrity: sha512-6gfrPwh7OuT6gZyJZvd6WbTfrqAo7vm4xCzAXOusKqq/vWdKXphTpj5klHKNmRUU6/QRGlBsyU9mAIPaWHlqJA==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.23.5 + '@babel/types': 7.24.8 + dev: false + + /@babel/helper-member-expression-to-functions@7.24.8: + resolution: {integrity: sha512-LABppdt+Lp/RlBxqrh4qgf1oEH/WxdzQNDJIu5gC/W1GyvPVrOBiItmmM8wan2fm4oYqFuFfkXmlGpLQhPY8CA==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/traverse': 7.24.8 + '@babel/types': 7.24.8 + transitivePeerDependencies: + - supports-color dev: false /@babel/helper-module-imports@7.22.15: @@ -1316,6 +1379,7 @@ packages: '@babel/helper-simple-access': 7.22.5 '@babel/helper-split-export-declaration': 7.22.6 '@babel/helper-validator-identifier': 7.22.20 + dev: true /@babel/helper-module-transforms@7.24.8(@babel/core@7.24.8): resolution: {integrity: sha512-m4vWKVqvkVAWLXfHCCfff2luJj86U+J0/x+0N3ArG/tP0Fq7zky2dYwMbtPmkc/oulkkbjdL3uWzuoBwQ8R00Q==} @@ -1337,12 +1401,14 @@ packages: resolution: {integrity: sha512-HBwaojN0xFRx4yIvpwGqxiV2tUfl7401jlok564NgB9EHS1y6QT17FmKWm4ztqjeVdXLuC4fSvHc5ePpQjoTbw==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.23.5 + '@babel/types': 7.24.8 dev: false - /@babel/helper-plugin-utils@7.22.5: - resolution: {integrity: sha512-uLls06UVKgFG9QD4OeFYLEGteMIAa5kpTPcFL28yuCIIzsf6ZyKZMllKVOCZFhiZ5ptnwX4mtKdWCBE/uT4amg==} + /@babel/helper-optimise-call-expression@7.24.7: + resolution: {integrity: sha512-jKiTsW2xmWwxT1ixIdfXUZp+P5yURx2suzLZr5Hi64rURpDYdMW0pv+Uf17EYk2Rd428Lx4tLsnjGJzYKDM/6A==} engines: {node: '>=6.9.0'} + dependencies: + '@babel/types': 7.24.8 dev: false /@babel/helper-plugin-utils@7.24.8: @@ -1350,23 +1416,38 @@ packages: engines: {node: '>=6.9.0'} dev: false - /@babel/helper-replace-supers@7.22.20(@babel/core@7.23.5): + /@babel/helper-replace-supers@7.22.20(@babel/core@7.24.8): resolution: {integrity: sha512-qsW0In3dbwQUbK8kejJ4R7IHVGwHJlV6lpG6UA7a9hSa2YEiAib+N1T2kr6PEeUT+Fl7najmSOS6SmAwCHK6Tw==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0 dependencies: - '@babel/core': 7.23.5 - '@babel/helper-environment-visitor': 7.22.20 + '@babel/core': 7.24.8 + '@babel/helper-environment-visitor': 7.24.7 '@babel/helper-member-expression-to-functions': 7.23.0 '@babel/helper-optimise-call-expression': 7.22.5 dev: false + /@babel/helper-replace-supers@7.24.7(@babel/core@7.24.8): + resolution: {integrity: sha512-qTAxxBM81VEyoAY0TtLrx1oAEJc09ZK67Q9ljQToqCnA+55eNwCORaxlKyu+rNfX86o8OXRUSNUnrtsAZXM9sg==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0 + dependencies: + '@babel/core': 7.24.8 + '@babel/helper-environment-visitor': 7.24.7 + '@babel/helper-member-expression-to-functions': 7.24.8 + '@babel/helper-optimise-call-expression': 7.24.7 + transitivePeerDependencies: + - supports-color + dev: false + /@babel/helper-simple-access@7.22.5: resolution: {integrity: sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==} engines: {node: '>=6.9.0'} dependencies: '@babel/types': 7.23.5 + dev: true /@babel/helper-simple-access@7.24.7: resolution: {integrity: sha512-zBAIvbCMh5Ts+b86r/CjU+4XGYIs+R1j951gxI3KmmxBMhCg4oQMsv6ZXQ64XOm/cvzfU1FmoCyt6+owc5QMYg==} @@ -1382,7 +1463,17 @@ packages: resolution: {integrity: sha512-tK14r66JZKiC43p8Ki33yLBVJKlQDFoA8GYN67lWCDCqoL6EMMSuM9b+Iff2jHaM/RRFYl7K+iiru7hbRqNx8Q==} engines: {node: '>=6.9.0'} dependencies: - '@babel/types': 7.23.5 + '@babel/types': 7.24.8 + dev: false + + /@babel/helper-skip-transparent-expression-wrappers@7.24.7: + resolution: {integrity: sha512-IO+DLT3LQUElMbpzlatRASEyQtfhSE0+m465v++3jyyXeBTBUjtVZg28/gHeV5mrTJqvEKhKroBGAvhW+qPHiQ==} + engines: {node: '>=6.9.0'} + dependencies: + '@babel/traverse': 7.24.8 + '@babel/types': 7.24.8 + transitivePeerDependencies: + - supports-color dev: false /@babel/helper-split-export-declaration@7.22.6: @@ -1390,6 +1481,7 @@ packages: engines: {node: '>=6.9.0'} dependencies: '@babel/types': 7.23.5 + dev: true /@babel/helper-split-export-declaration@7.24.7: resolution: {integrity: sha512-oy5V7pD+UvfkEATUKvIjvIAH/xCzfsFVw7ygW2SI6NClZzquT+mwdTfgfdbUiceh6iQO0CHtCPsyze/MZ2YbAA==} @@ -1419,6 +1511,7 @@ packages: /@babel/helper-validator-option@7.23.5: resolution: {integrity: sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw==} engines: {node: '>=6.9.0'} + dev: true /@babel/helper-validator-option@7.24.8: resolution: {integrity: sha512-xb8t9tD1MHLungh/AIoWYN+gVHaB9kwlu8gffXGSt3FFEIT7RjS+xWbc2vUD1UTZdIpKj/ab3rdqJ7ufngyi2Q==} @@ -1434,6 +1527,7 @@ packages: '@babel/types': 7.23.5 transitivePeerDependencies: - supports-color + dev: true /@babel/helpers@7.24.8: resolution: {integrity: sha512-gV2265Nkcz7weJJfvDoAEVzC1e2OTDpkGbEsebse8koXUJUXPsCMi7sRo/+SPMuMZ9MtUPnGwITTnQnU5YjyaQ==} @@ -1450,6 +1544,7 @@ packages: '@babel/helper-validator-identifier': 7.22.20 chalk: 2.4.2 js-tokens: 4.0.0 + dev: true /@babel/highlight@7.24.7: resolution: {integrity: sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==} @@ -1458,7 +1553,7 @@ packages: '@babel/helper-validator-identifier': 7.24.7 chalk: 2.4.2 js-tokens: 4.0.0 - picocolors: 1.0.0 + picocolors: 1.0.1 dev: false /@babel/parser@7.23.5: @@ -1476,14 +1571,47 @@ packages: '@babel/types': 7.24.8 dev: false - /@babel/plugin-syntax-jsx@7.23.3(@babel/core@7.23.5): - resolution: {integrity: sha512-EB2MELswq55OHUoRZLGg/zC7QWUKfNLpE57m/S2yr1uEneIgsTgrSzXP3NXEsMkVn76OlaVVnzN+ugObuYGwhg==} + /@babel/plugin-proposal-decorators@7.24.7(@babel/core@7.24.8): + resolution: {integrity: sha512-RL9GR0pUG5Kc8BUWLNDm2T5OpYwSX15r98I0IkgmRQTXuELq/OynH8xtMTMvTJFjXbMWFVTKtYkTaYQsuAwQlQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.23.5 - '@babel/helper-plugin-utils': 7.22.5 + '@babel/core': 7.24.8 + '@babel/helper-create-class-features-plugin': 7.24.8(@babel/core@7.24.8) + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-decorators': 7.24.7(@babel/core@7.24.8) + transitivePeerDependencies: + - supports-color + dev: false + + /@babel/plugin-syntax-decorators@7.24.7(@babel/core@7.24.8): + resolution: {integrity: sha512-Ui4uLJJrRV1lb38zg1yYTmRKmiZLiftDEvZN2iq3kd9kUFU+PttmzTbAFC2ucRk/XJmtek6G23gPsuZbhrT8fQ==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.8 + '@babel/helper-plugin-utils': 7.24.8 + dev: false + + /@babel/plugin-syntax-import-attributes@7.24.7(@babel/core@7.24.8): + resolution: {integrity: sha512-hbX+lKKeUMGihnK8nvKqmXBInriT3GVjzXKFriV3YC6APGxMbP8RZNFwy91+hocLXq90Mta+HshoB31802bb8A==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.8 + '@babel/helper-plugin-utils': 7.24.8 + dev: false + + /@babel/plugin-syntax-import-meta@7.10.4(@babel/core@7.24.8): + resolution: {integrity: sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.8 + '@babel/helper-plugin-utils': 7.24.8 dev: false /@babel/plugin-syntax-jsx@7.24.7(@babel/core@7.24.8): @@ -1496,14 +1624,24 @@ packages: '@babel/helper-plugin-utils': 7.24.8 dev: false - /@babel/plugin-syntax-typescript@7.23.3(@babel/core@7.23.5): + /@babel/plugin-syntax-typescript@7.23.3(@babel/core@7.24.8): resolution: {integrity: sha512-9EiNjVJOMwCO+43TqoTrgQ8jMwcAd0sWyXi9RPfIsLTj4R2MADDDQXELhffaUx/uJv2AYcxBgPwH6j4TIA4ytQ==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.23.5 - '@babel/helper-plugin-utils': 7.22.5 + '@babel/core': 7.24.8 + '@babel/helper-plugin-utils': 7.24.8 + dev: false + + /@babel/plugin-syntax-typescript@7.24.7(@babel/core@7.24.8): + resolution: {integrity: sha512-c/+fVeJBB0FeKsFvwytYiUD+LBvhHjGSI0g446PRGdSVGZLRNArBUno2PETbAly3tpiNAQR5XaZ+JslxkotsbA==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.8 + '@babel/helper-plugin-utils': 7.24.8 dev: false /@babel/plugin-transform-react-jsx@7.24.7(@babel/core@7.24.8): @@ -1522,17 +1660,32 @@ packages: - supports-color dev: false - /@babel/plugin-transform-typescript@7.23.5(@babel/core@7.23.5): + /@babel/plugin-transform-typescript@7.23.5(@babel/core@7.24.8): resolution: {integrity: sha512-2fMkXEJkrmwgu2Bsv1Saxgj30IXZdJ+84lQcKKI7sm719oXs0BBw2ZENKdJdR1PjWndgLCEBNXJOri0fk7RYQA==} engines: {node: '>=6.9.0'} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.23.5 - '@babel/helper-annotate-as-pure': 7.22.5 - '@babel/helper-create-class-features-plugin': 7.23.5(@babel/core@7.23.5) - '@babel/helper-plugin-utils': 7.22.5 - '@babel/plugin-syntax-typescript': 7.23.3(@babel/core@7.23.5) + '@babel/core': 7.24.8 + '@babel/helper-annotate-as-pure': 7.24.7 + '@babel/helper-create-class-features-plugin': 7.23.5(@babel/core@7.24.8) + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-typescript': 7.23.3(@babel/core@7.24.8) + dev: false + + /@babel/plugin-transform-typescript@7.24.8(@babel/core@7.24.8): + resolution: {integrity: sha512-CgFgtN61BbdOGCP4fLaAMOPkzWUh6yQZNMr5YSt8uz2cZSSiQONCQFWqsE4NeVfOIhqDOlS9CR3WD91FzMeB2Q==} + engines: {node: '>=6.9.0'} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/core': 7.24.8 + '@babel/helper-annotate-as-pure': 7.24.7 + '@babel/helper-create-class-features-plugin': 7.24.8(@babel/core@7.24.8) + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-typescript': 7.24.7(@babel/core@7.24.8) + transitivePeerDependencies: + - supports-color dev: false /@babel/runtime@7.23.5: @@ -1549,6 +1702,7 @@ packages: '@babel/code-frame': 7.23.5 '@babel/parser': 7.23.5 '@babel/types': 7.23.5 + dev: true /@babel/template@7.24.7: resolution: {integrity: sha512-jYqfPrU9JTF0PmPy1tLYHW4Mp4KlgxJD9l2nP9fD6yT/ICi554DmrWBAEYpIelzjHf1msDP3PxJIRt/nFNfBig==} @@ -1575,6 +1729,7 @@ packages: globals: 11.12.0 transitivePeerDependencies: - supports-color + dev: true /@babel/traverse@7.24.8: resolution: {integrity: sha512-t0P1xxAPzEDcEPmjprAQq19NWum4K0EQPjMwZQZbHt+GiZqvjCHjj755Weq1YRPVzBI+3zSfvScfpnuIecVFJQ==} @@ -1611,6 +1766,62 @@ packages: to-fast-properties: 2.0.0 dev: false + /@cloudflare/kv-asset-handler@0.3.4: + resolution: {integrity: sha512-YLPHc8yASwjNkmcDMQMY35yiWjoKAKnhUbPRszBRS0YgH+IXtsMp61j+yTcnCE3oO2DgP0U3iejLC8FTtKDC8Q==} + engines: {node: '>=16.13'} + dependencies: + mime: 3.0.0 + dev: false + + /@cloudflare/workerd-darwin-64@1.20240701.0: + resolution: {integrity: sha512-XAZa4ZP+qyTn6JQQACCPH09hGZXP2lTnWKkmg5mPwT8EyRzCKLkczAf98vPP5bq7JZD/zORdFWRY0dOTap8zTQ==} + engines: {node: '>=16'} + cpu: [x64] + os: [darwin] + requiresBuild: true + dev: false + optional: true + + /@cloudflare/workerd-darwin-arm64@1.20240701.0: + resolution: {integrity: sha512-w80ZVAgfH4UwTz7fXZtk7KmS2FzlXniuQm4ku4+cIgRTilBAuKqjpOjwUCbx5g13Gqcm9NuiHce+IDGtobRTIQ==} + engines: {node: '>=16'} + cpu: [arm64] + os: [darwin] + requiresBuild: true + dev: false + optional: true + + /@cloudflare/workerd-linux-64@1.20240701.0: + resolution: {integrity: sha512-UWLr/Anxwwe/25nGv451MNd2jhREmPt/ws17DJJqTLAx6JxwGWA15MeitAIzl0dbxRFAJa+0+R8ag2WR3F/D6g==} + engines: {node: '>=16'} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /@cloudflare/workerd-linux-arm64@1.20240701.0: + resolution: {integrity: sha512-3kCnF9kYgov1ggpuWbgpXt4stPOIYtVmPCa7MO2xhhA0TWP6JDUHRUOsnmIgKrvDjXuXqlK16cdg3v+EWsaPJg==} + engines: {node: '>=16'} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: false + optional: true + + /@cloudflare/workerd-windows-64@1.20240701.0: + resolution: {integrity: sha512-6IPGITRAeS67j3BH1rN4iwYWDt47SqJG7KlZJ5bB4UaNAia4mvMBSy/p2p4vA89bbXoDRjMtEvRu7Robu6O7hQ==} + engines: {node: '>=16'} + cpu: [x64] + os: [win32] + requiresBuild: true + dev: false + optional: true + + /@cloudflare/workers-types@4.20240712.0: + resolution: {integrity: sha512-C+C0ZnkRrxR2tPkZKAXwBsWEse7bWaA7iMbaG6IKaxaPTo/5ilx7Ei3BkI2izxmOJMsC05VS1eFUf95urXzhmw==} + dev: false + /@codemirror/commands@6.3.2: resolution: {integrity: sha512-tjoi4MCWDNxgIpoLZ7+tezdS9OEB6pkiDKhfKx9ReJ/XBcs2G2RXIu+/FxXBlWsPTsz6C9q/r4gjzrsxpcnqCQ==} dependencies: @@ -1736,6 +1947,13 @@ packages: dev: true optional: true + /@cspotcode/source-map-support@0.8.1: + resolution: {integrity: sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==} + engines: {node: '>=12'} + dependencies: + '@jridgewell/trace-mapping': 0.3.9 + dev: false + /@cypress/request@3.0.1: resolution: {integrity: sha512-TWivJlJi8ZDx2wGOw1dbLuHJKUYX7bWySw377nlnGOW3hP9/MUKIsEdXT/YngWxVdgNCHRBmFlBipE+5/2ZZlQ==} engines: {node: '>= 6'} @@ -1781,10 +1999,31 @@ packages: '@emmetio/scanner': 1.0.4 dev: false + /@emmetio/css-parser@0.4.0: + resolution: {integrity: sha512-z7wkxRSZgrQHXVzObGkXG+Vmj3uRlpM11oCZ9pbaz0nFejvCDmAiNDpY75+wgXOcffKpj4rzGtwGaZxfJKsJxw==} + dependencies: + '@emmetio/stream-reader': 2.2.0 + '@emmetio/stream-reader-utils': 0.1.0 + dev: false + + /@emmetio/html-matcher@1.3.0: + resolution: {integrity: sha512-NTbsvppE5eVyBMuyGfVu2CRrLvo7J4YHb6t9sBFLyY03WYhXET37qA4zOYUjBWFCRHO7pS1B9khERtY0f5JXPQ==} + dependencies: + '@emmetio/scanner': 1.0.4 + dev: false + /@emmetio/scanner@1.0.4: resolution: {integrity: sha512-IqRuJtQff7YHHBk4G8YZ45uB9BaAGcwQeVzgj/zj8/UdOhtQpEIupUhSk8dys6spFIWVZVeK20CzGEnqR5SbqA==} dev: false + /@emmetio/stream-reader-utils@0.1.0: + resolution: {integrity: sha512-ZsZ2I9Vzso3Ho/pjZFsmmZ++FWeEd/txqybHTm4OgaZzdS8V9V/YYWQwg5TC38Z7uLWUV1vavpLLbjJtKubR1A==} + dev: false + + /@emmetio/stream-reader@2.2.0: + resolution: {integrity: sha512-fXVXEyFA5Yv3M3n8sUGT7+fvecGrZP4k6FnWWMSZVQf69kAq0LLpaBQLGcPR30m3zMmKYhECP4k/ZkzvhEW5kw==} + dev: false + /@emnapi/runtime@1.2.0: resolution: {integrity: sha512-bV21/9LQmcQeCPEg3BDFtvwL6cwiTMksYNWQQ4KOxCZikEGalWtenoZ0wCiukJINlGCIi2KXx01g4FoH/LxpzQ==} requiresBuild: true @@ -1793,6 +2032,33 @@ packages: dev: false optional: true + /@esbuild-plugins/node-globals-polyfill@0.2.3(esbuild@0.17.19): + resolution: {integrity: sha512-r3MIryXDeXDOZh7ih1l/yE9ZLORCd5e8vWg02azWRGj5SPTuoh69A2AIyn0Z31V/kHBfZ4HgWJ+OK3GTTwLmnw==} + peerDependencies: + esbuild: '*' + dependencies: + esbuild: 0.17.19 + dev: false + + /@esbuild-plugins/node-modules-polyfill@0.2.2(esbuild@0.17.19): + resolution: {integrity: sha512-LXV7QsWJxRuMYvKbiznh+U1ilIop3g2TeKRzUxOG5X3YITc8JyyTa90BmLwqqv0YnX4v32CSlG+vsziZp9dMvA==} + peerDependencies: + esbuild: '*' + dependencies: + esbuild: 0.17.19 + escape-string-regexp: 4.0.0 + rollup-plugin-node-polyfills: 0.2.1 + dev: false + + /@esbuild/aix-ppc64@0.19.12: + resolution: {integrity: sha512-bmoCYyWdEL3wDQIVbcyzRyeKLgk2WtWLTWz1ZIAZF/EGbNOwSA6ew3PftJ1PqMiOOGu0OyFMzG53L0zqIpPeNA==} + engines: {node: '>=12'} + cpu: [ppc64] + os: [aix] + requiresBuild: true + dev: false + optional: true + /@esbuild/aix-ppc64@0.21.5: resolution: {integrity: sha512-1SDgH6ZSPTlggy1yI6+Dbkiz8xzpHJEVAlF/AM1tHPLsf5STom9rwtjE4hKAF20FfXXNTFqEYXyJNWh1GiZedQ==} engines: {node: '>=12'} @@ -1810,6 +2076,15 @@ packages: requiresBuild: true optional: true + /@esbuild/android-arm64@0.19.12: + resolution: {integrity: sha512-P0UVNGIienjZv3f5zq0DP3Nt2IE/3plFzuaS96vihvD0Hd6H/q4WXUGpCxD/E8YrSXfNyRPbpTq+T8ZQioSuPA==} + engines: {node: '>=12'} + cpu: [arm64] + os: [android] + requiresBuild: true + dev: false + optional: true + /@esbuild/android-arm64@0.21.5: resolution: {integrity: sha512-c0uX9VAUBQ7dTDCjq+wdyGLowMdtR/GoC2U5IYk/7D1H1JYC0qseD7+11iMP2mRLN9RcCMRcjC4YMclCzGwS/A==} engines: {node: '>=12'} @@ -1836,6 +2111,15 @@ packages: requiresBuild: true optional: true + /@esbuild/android-arm@0.19.12: + resolution: {integrity: sha512-qg/Lj1mu3CdQlDEEiWrlC4eaPZ1KztwGJ9B6J+/6G+/4ewxJg7gqj8eVYWvao1bXrqGiW2rsBZFSX3q2lcW05w==} + engines: {node: '>=12'} + cpu: [arm] + os: [android] + requiresBuild: true + dev: false + optional: true + /@esbuild/android-arm@0.21.5: resolution: {integrity: sha512-vCPvzSjpPHEi1siZdlvAlsPxXl7WbOVUBBAowWug4rJHb68Ox8KualB+1ocNvT5fjv6wpkX6o/iEpbDrf68zcg==} engines: {node: '>=12'} @@ -1853,6 +2137,15 @@ packages: requiresBuild: true optional: true + /@esbuild/android-x64@0.19.12: + resolution: {integrity: sha512-3k7ZoUW6Q6YqhdhIaq/WZ7HwBpnFBlW905Fa4s4qWJyiNOgT1dOqDiVAQFwBH7gBRZr17gLrlFCRzF6jFh7Kew==} + engines: {node: '>=12'} + cpu: [x64] + os: [android] + requiresBuild: true + dev: false + optional: true + /@esbuild/android-x64@0.21.5: resolution: {integrity: sha512-D7aPRUUNHRBwHxzxRvp856rjUHRFW1SdQATKXH2hqA0kAZb1hKmi02OpYRacl0TxIGz/ZmXWlbZgjwWYaCakTA==} engines: {node: '>=12'} @@ -1870,6 +2163,15 @@ packages: requiresBuild: true optional: true + /@esbuild/darwin-arm64@0.19.12: + resolution: {integrity: sha512-B6IeSgZgtEzGC42jsI+YYu9Z3HKRxp8ZT3cqhvliEHovq8HSX2YX8lNocDn79gCKJXOSaEot9MVYky7AKjCs8g==} + engines: {node: '>=12'} + cpu: [arm64] + os: [darwin] + requiresBuild: true + dev: false + optional: true + /@esbuild/darwin-arm64@0.21.5: resolution: {integrity: sha512-DwqXqZyuk5AiWWf3UfLiRDJ5EDd49zg6O9wclZ7kUMv2WRFr4HKjXp/5t8JZ11QbQfUS6/cRCKGwYhtNAY88kQ==} engines: {node: '>=12'} @@ -1887,6 +2189,15 @@ packages: requiresBuild: true optional: true + /@esbuild/darwin-x64@0.19.12: + resolution: {integrity: sha512-hKoVkKzFiToTgn+41qGhsUJXFlIjxI/jSYeZf3ugemDYZldIXIxhvwN6erJGlX4t5h417iFuheZ7l+YVn05N3A==} + engines: {node: '>=12'} + cpu: [x64] + os: [darwin] + requiresBuild: true + dev: false + optional: true + /@esbuild/darwin-x64@0.21.5: resolution: {integrity: sha512-se/JjF8NlmKVG4kNIuyWMV/22ZaerB+qaSi5MdrXtd6R08kvs2qCN4C09miupktDitvh8jRFflwGFBQcxZRjbw==} engines: {node: '>=12'} @@ -1904,6 +2215,15 @@ packages: requiresBuild: true optional: true + /@esbuild/freebsd-arm64@0.19.12: + resolution: {integrity: sha512-4aRvFIXmwAcDBw9AueDQ2YnGmz5L6obe5kmPT8Vd+/+x/JMVKCgdcRwH6APrbpNXsPz+K653Qg8HB/oXvXVukA==} + engines: {node: '>=12'} + cpu: [arm64] + os: [freebsd] + requiresBuild: true + dev: false + optional: true + /@esbuild/freebsd-arm64@0.21.5: resolution: {integrity: sha512-5JcRxxRDUJLX8JXp/wcBCy3pENnCgBR9bN6JsY4OmhfUtIHe3ZW0mawA7+RDAcMLrMIZaf03NlQiX9DGyB8h4g==} engines: {node: '>=12'} @@ -1921,6 +2241,15 @@ packages: requiresBuild: true optional: true + /@esbuild/freebsd-x64@0.19.12: + resolution: {integrity: sha512-EYoXZ4d8xtBoVN7CEwWY2IN4ho76xjYXqSXMNccFSx2lgqOG/1TBPW0yPx1bJZk94qu3tX0fycJeeQsKovA8gg==} + engines: {node: '>=12'} + cpu: [x64] + os: [freebsd] + requiresBuild: true + dev: false + optional: true + /@esbuild/freebsd-x64@0.21.5: resolution: {integrity: sha512-J95kNBj1zkbMXtHVH29bBriQygMXqoVQOQYA+ISs0/2l3T9/kj42ow2mpqerRBxDJnmkUDCaQT/dfNXWX/ZZCQ==} engines: {node: '>=12'} @@ -1938,6 +2267,15 @@ packages: requiresBuild: true optional: true + /@esbuild/linux-arm64@0.19.12: + resolution: {integrity: sha512-EoTjyYyLuVPfdPLsGVVVC8a0p1BFFvtpQDB/YLEhaXyf/5bczaGeN15QkR+O4S5LeJ92Tqotve7i1jn35qwvdA==} + engines: {node: '>=12'} + cpu: [arm64] + os: [linux] + requiresBuild: true + dev: false + optional: true + /@esbuild/linux-arm64@0.21.5: resolution: {integrity: sha512-ibKvmyYzKsBeX8d8I7MH/TMfWDXBF3db4qM6sy+7re0YXya+K1cem3on9XgdT2EQGMu4hQyZhan7TeQ8XkGp4Q==} engines: {node: '>=12'} @@ -1955,6 +2293,15 @@ packages: requiresBuild: true optional: true + /@esbuild/linux-arm@0.19.12: + resolution: {integrity: sha512-J5jPms//KhSNv+LO1S1TX1UWp1ucM6N6XuL6ITdKWElCu8wXP72l9MM0zDTzzeikVyqFE6U8YAV9/tFyj0ti+w==} + engines: {node: '>=12'} + cpu: [arm] + os: [linux] + requiresBuild: true + dev: false + optional: true + /@esbuild/linux-arm@0.21.5: resolution: {integrity: sha512-bPb5AHZtbeNGjCKVZ9UGqGwo8EUu4cLq68E95A53KlxAPRmUyYv2D6F0uUI65XisGOL1hBP5mTronbgo+0bFcA==} engines: {node: '>=12'} @@ -1972,6 +2319,15 @@ packages: requiresBuild: true optional: true + /@esbuild/linux-ia32@0.19.12: + resolution: {integrity: sha512-Thsa42rrP1+UIGaWz47uydHSBOgTUnwBwNq59khgIwktK6x60Hivfbux9iNR0eHCHzOLjLMLfUMLCypBkZXMHA==} + engines: {node: '>=12'} + cpu: [ia32] + os: [linux] + requiresBuild: true + dev: false + optional: true + /@esbuild/linux-ia32@0.21.5: resolution: {integrity: sha512-YvjXDqLRqPDl2dvRODYmmhz4rPeVKYvppfGYKSNGdyZkA01046pLWyRKKI3ax8fbJoK5QbxblURkwK/MWY18Tg==} engines: {node: '>=12'} @@ -1998,6 +2354,15 @@ packages: requiresBuild: true optional: true + /@esbuild/linux-loong64@0.19.12: + resolution: {integrity: sha512-LiXdXA0s3IqRRjm6rV6XaWATScKAXjI4R4LoDlvO7+yQqFdlr1Bax62sRwkVvRIrwXxvtYEHHI4dm50jAXkuAA==} + engines: {node: '>=12'} + cpu: [loong64] + os: [linux] + requiresBuild: true + dev: false + optional: true + /@esbuild/linux-loong64@0.21.5: resolution: {integrity: sha512-uHf1BmMG8qEvzdrzAqg2SIG/02+4/DHB6a9Kbya0XDvwDEKCoC8ZRWI5JJvNdUjtciBGFQ5PuBlpEOXQj+JQSg==} engines: {node: '>=12'} @@ -2015,6 +2380,15 @@ packages: requiresBuild: true optional: true + /@esbuild/linux-mips64el@0.19.12: + resolution: {integrity: sha512-fEnAuj5VGTanfJ07ff0gOA6IPsvrVHLVb6Lyd1g2/ed67oU1eFzL0r9WL7ZzscD+/N6i3dWumGE1Un4f7Amf+w==} + engines: {node: '>=12'} + cpu: [mips64el] + os: [linux] + requiresBuild: true + dev: false + optional: true + /@esbuild/linux-mips64el@0.21.5: resolution: {integrity: sha512-IajOmO+KJK23bj52dFSNCMsz1QP1DqM6cwLUv3W1QwyxkyIWecfafnI555fvSGqEKwjMXVLokcV5ygHW5b3Jbg==} engines: {node: '>=12'} @@ -2032,6 +2406,15 @@ packages: requiresBuild: true optional: true + /@esbuild/linux-ppc64@0.19.12: + resolution: {integrity: sha512-nYJA2/QPimDQOh1rKWedNOe3Gfc8PabU7HT3iXWtNUbRzXS9+vgB0Fjaqr//XNbd82mCxHzik2qotuI89cfixg==} + engines: {node: '>=12'} + cpu: [ppc64] + os: [linux] + requiresBuild: true + dev: false + optional: true + /@esbuild/linux-ppc64@0.21.5: resolution: {integrity: sha512-1hHV/Z4OEfMwpLO8rp7CvlhBDnjsC3CttJXIhBi+5Aj5r+MBvy4egg7wCbe//hSsT+RvDAG7s81tAvpL2XAE4w==} engines: {node: '>=12'} @@ -2049,6 +2432,15 @@ packages: requiresBuild: true optional: true + /@esbuild/linux-riscv64@0.19.12: + resolution: {integrity: sha512-2MueBrlPQCw5dVJJpQdUYgeqIzDQgw3QtiAHUC4RBz9FXPrskyyU3VI1hw7C0BSKB9OduwSJ79FTCqtGMWqJHg==} + engines: {node: '>=12'} + cpu: [riscv64] + os: [linux] + requiresBuild: true + dev: false + optional: true + /@esbuild/linux-riscv64@0.21.5: resolution: {integrity: sha512-2HdXDMd9GMgTGrPWnJzP2ALSokE/0O5HhTUvWIbD3YdjME8JwvSCnNGBnTThKGEB91OZhzrJ4qIIxk/SBmyDDA==} engines: {node: '>=12'} @@ -2066,6 +2458,15 @@ packages: requiresBuild: true optional: true + /@esbuild/linux-s390x@0.19.12: + resolution: {integrity: sha512-+Pil1Nv3Umes4m3AZKqA2anfhJiVmNCYkPchwFJNEJN5QxmTs1uzyy4TvmDrCRNT2ApwSari7ZIgrPeUx4UZDg==} + engines: {node: '>=12'} + cpu: [s390x] + os: [linux] + requiresBuild: true + dev: false + optional: true + /@esbuild/linux-s390x@0.21.5: resolution: {integrity: sha512-zus5sxzqBJD3eXxwvjN1yQkRepANgxE9lgOW2qLnmr8ikMTphkjgXu1HR01K4FJg8h1kEEDAqDcZQtbrRnB41A==} engines: {node: '>=12'} @@ -2083,6 +2484,15 @@ packages: requiresBuild: true optional: true + /@esbuild/linux-x64@0.19.12: + resolution: {integrity: sha512-B71g1QpxfwBvNrfyJdVDexenDIt1CiDN1TIXLbhOw0KhJzE78KIFGX6OJ9MrtC0oOqMWf+0xop4qEU8JrJTwCg==} + engines: {node: '>=12'} + cpu: [x64] + os: [linux] + requiresBuild: true + dev: false + optional: true + /@esbuild/linux-x64@0.21.5: resolution: {integrity: sha512-1rYdTpyv03iycF1+BhzrzQJCdOuAOtaqHTWJZCWvijKD2N5Xu0TtVC8/+1faWqcP9iBCWOmjmhoH94dH82BxPQ==} engines: {node: '>=12'} @@ -2100,6 +2510,15 @@ packages: requiresBuild: true optional: true + /@esbuild/netbsd-x64@0.19.12: + resolution: {integrity: sha512-3ltjQ7n1owJgFbuC61Oj++XhtzmymoCihNFgT84UAmJnxJfm4sYCiSLTXZtE00VWYpPMYc+ZQmB6xbSdVh0JWA==} + engines: {node: '>=12'} + cpu: [x64] + os: [netbsd] + requiresBuild: true + dev: false + optional: true + /@esbuild/netbsd-x64@0.21.5: resolution: {integrity: sha512-Woi2MXzXjMULccIwMnLciyZH4nCIMpWQAs049KEeMvOcNADVxo0UBIQPfSmxB3CWKedngg7sWZdLvLczpe0tLg==} engines: {node: '>=12'} @@ -2117,6 +2536,15 @@ packages: requiresBuild: true optional: true + /@esbuild/openbsd-x64@0.19.12: + resolution: {integrity: sha512-RbrfTB9SWsr0kWmb9srfF+L933uMDdu9BIzdA7os2t0TXhCRjrQyCeOt6wVxr79CKD4c+p+YhCj31HBkYcXebw==} + engines: {node: '>=12'} + cpu: [x64] + os: [openbsd] + requiresBuild: true + dev: false + optional: true + /@esbuild/openbsd-x64@0.21.5: resolution: {integrity: sha512-HLNNw99xsvx12lFBUwoT8EVCsSvRNDVxNpjZ7bPn947b8gJPzeHWyNVhFsaerc0n3TsbOINvRP2byTZ5LKezow==} engines: {node: '>=12'} @@ -2134,6 +2562,15 @@ packages: requiresBuild: true optional: true + /@esbuild/sunos-x64@0.19.12: + resolution: {integrity: sha512-HKjJwRrW8uWtCQnQOz9qcU3mUZhTUQvi56Q8DPTLLB+DawoiQdjsYq+j+D3s9I8VFtDr+F9CjgXKKC4ss89IeA==} + engines: {node: '>=12'} + cpu: [x64] + os: [sunos] + requiresBuild: true + dev: false + optional: true + /@esbuild/sunos-x64@0.21.5: resolution: {integrity: sha512-6+gjmFpfy0BHU5Tpptkuh8+uw3mnrvgs+dSPQXQOv3ekbordwnzTVEb4qnIvQcYXq6gzkyTnoZ9dZG+D4garKg==} engines: {node: '>=12'} @@ -2151,6 +2588,15 @@ packages: requiresBuild: true optional: true + /@esbuild/win32-arm64@0.19.12: + resolution: {integrity: sha512-URgtR1dJnmGvX864pn1B2YUYNzjmXkuJOIqG2HdU62MVS4EHpU2946OZoTMnRUHklGtJdJZ33QfzdjGACXhn1A==} + engines: {node: '>=12'} + cpu: [arm64] + os: [win32] + requiresBuild: true + dev: false + optional: true + /@esbuild/win32-arm64@0.21.5: resolution: {integrity: sha512-Z0gOTd75VvXqyq7nsl93zwahcTROgqvuAcYDUr+vOv8uHhNSKROyU961kgtCD1e95IqPKSQKH7tBTslnS3tA8A==} engines: {node: '>=12'} @@ -2168,6 +2614,15 @@ packages: requiresBuild: true optional: true + /@esbuild/win32-ia32@0.19.12: + resolution: {integrity: sha512-+ZOE6pUkMOJfmxmBZElNOx72NKpIa/HFOMGzu8fqzQJ5kgf6aTGrcJaFsNiVMH4JKpMipyK+7k0n2UXN7a8YKQ==} + engines: {node: '>=12'} + cpu: [ia32] + os: [win32] + requiresBuild: true + dev: false + optional: true + /@esbuild/win32-ia32@0.21.5: resolution: {integrity: sha512-SWXFF1CL2RVNMaVs+BBClwtfZSvDgtL//G/smwAc5oVK/UPu2Gu9tIaRgFmYFFKrmg3SyAjSrElf0TiJ1v8fYA==} engines: {node: '>=12'} @@ -2185,6 +2640,15 @@ packages: requiresBuild: true optional: true + /@esbuild/win32-x64@0.19.12: + resolution: {integrity: sha512-T1QyPSDCyMXaO3pzBkF96E8xMkiRYbUEZADd29SyPGabqxMViNoii+NcK7eWJAEoU6RZyEm5lVSIjTmcdoB9HA==} + engines: {node: '>=12'} + cpu: [x64] + os: [win32] + requiresBuild: true + dev: false + optional: true + /@esbuild/win32-x64@0.21.5: resolution: {integrity: sha512-tQd/1efJuzPC6rCFwEvLtci/xNFcTZknmXs98FYDfGE4wP9ClFV98nyKrzJKVPMhdDnjzLhdUyMX4PsQAPjwIw==} engines: {node: '>=12'} @@ -2246,6 +2710,11 @@ packages: engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0} dev: true + /@fastify/busboy@2.1.1: + resolution: {integrity: sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA==} + engines: {node: '>=14'} + dev: false + /@floating-ui/core@0.3.1: resolution: {integrity: sha512-ensKY7Ub59u16qsVIFEo2hwTCqZ/r9oZZFh51ivcLGHfUwTn8l1Xzng8RJUe91H/UP8PeqeBronAGx0qmzwk2g==} dev: false @@ -2272,12 +2741,12 @@ packages: resolution: {integrity: sha512-OfX7E2oUDYxtBvsuS4e/jSn4Q9Qb6DzgeYtsAdkPZ47znpoNsMgZw0+tVijiv3uGNR6dgNlty6r9rzIzHjtd/A==} dev: false - /@fullhuman/postcss-purgecss@5.0.0(postcss@8.4.31): + /@fullhuman/postcss-purgecss@5.0.0(postcss@8.4.39): resolution: {integrity: sha512-onDS/b/2pMRzqSoj4qOs2tYFmOpaspjTAgvACIHMPiicu1ptajiBruTrjBzTKdxWdX0ldaBb7wj8nEaTLyFkJw==} peerDependencies: postcss: ^8.0.0 dependencies: - postcss: 8.4.31 + postcss: 8.4.39 purgecss: 5.0.0 dev: true @@ -2692,6 +3161,13 @@ packages: '@jridgewell/sourcemap-codec': 1.4.15 dev: false + /@jridgewell/trace-mapping@0.3.9: + resolution: {integrity: sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==} + dependencies: + '@jridgewell/resolve-uri': 3.1.1 + '@jridgewell/sourcemap-codec': 1.4.15 + dev: false + /@lerna/create@8.0.0(typescript@5.0.4): resolution: {integrity: sha512-mCeEhjFDRwPY7J4uxCjqdzPwPFBUGlkdlQjBidaX5XaoQcxR2hAAvgHZKfVGkUUEZKfyPcWwKzen4KydNB2G7A==} engines: {node: '>=18.0.0'} @@ -3240,6 +3716,10 @@ packages: resolution: {integrity: sha512-C16M+IYz0rgRhWZdCmK+h58JMv8vijAA61gmz2rspCSwKwzBebpdcsiUmwrtJRdphuY30i6BSLEOP8ppbNLyLg==} dev: true + /@polka/url@1.0.0-next.25: + resolution: {integrity: sha512-j7P6Rgr3mmtdkeDGTe0E/aYyWEWVtc5yFXtHCRHs28/jptDEWfaVOc5T7cblqy1XKPPfCxJc/8DwQ5YgLOZOVQ==} + dev: false + /@redux-saga/core@1.2.3: resolution: {integrity: sha512-U1JO6ncFBAklFTwoQ3mjAeQZ6QGutsJzwNBjgVLSWDpZTRhobUzuVDS1qH3SKGJD8fvqoaYOjp6XJ3gCmeZWgA==} dependencies: @@ -3290,7 +3770,6 @@ packages: '@types/estree': 1.0.5 estree-walker: 2.0.2 picomatch: 2.3.1 - dev: true /@rollup/rollup-android-arm-eabi@4.18.1: resolution: {integrity: sha512-lncuC4aHicncmbORnx+dUaAgzee9cm/PbIqgWz1PpXuwc+sa1Ct83tnqUDy/GFKleLiN7ZIeytM6KJ4cAn1SxA==} @@ -3940,6 +4419,12 @@ packages: '@types/unist': 3.0.2 dev: false + /@types/node-forge@1.3.11: + resolution: {integrity: sha512-FQx220y22OKNTqaByeBGqHWYz4cl94tpcxeFdvBo3wjG6XPBuZ0BNgNZRV5J5TFmmcsJ4IzsLkmGRiQbnYsBEQ==} + dependencies: + '@types/node': 20.8.4 + dev: false + /@types/node@18.18.14: resolution: {integrity: sha512-iSOeNeXYNYNLLOMDSVPvIFojclvMZ/HDY2dU17kUlcsOsSQETbWIslJbYLZgA+ox8g2XQwSHKTkght1a5X26lQ==} dependencies: @@ -3949,7 +4434,6 @@ packages: resolution: {integrity: sha512-ZVPnqU58giiCjSxjVUESDtdPk4QR5WQhhINbc9UBrKLU68MX5BF6kbQzTrkwbolyr0X8ChBpXfavr5mZFKZQ5A==} dependencies: undici-types: 5.25.3 - dev: true /@types/normalize-package-data@2.4.4: resolution: {integrity: sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA==} @@ -4723,17 +5207,17 @@ packages: /@ungap/structured-clone@1.2.0: resolution: {integrity: sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==} - /@vitejs/plugin-vue-jsx@3.1.0(vite@4.3.9)(vue@3.2.30): - resolution: {integrity: sha512-w9M6F3LSEU5kszVb9An2/MmXNxocAnUb3WhRr8bHlimhDrXNt6n6D2nJQR3UXpGlZHh/EsgouOHCsM8V3Ln+WA==} - engines: {node: ^14.18.0 || >=16.0.0} + /@vitejs/plugin-vue-jsx@4.0.0(vite@5.3.3)(vue@3.2.30): + resolution: {integrity: sha512-A+6wL2AdQhDsLsDnY+2v4rRDI1HLJGIMc97a8FURO9tqKsH5QvjWrzsa5DH3NlZsM742W2wODl2fF+bfcTWtXw==} + engines: {node: ^18.0.0 || >=20.0.0} peerDependencies: - vite: ^4.0.0 || ^5.0.0 + vite: ^5.0.0 vue: ^3.0.0 dependencies: - '@babel/core': 7.23.5 - '@babel/plugin-transform-typescript': 7.23.5(@babel/core@7.23.5) - '@vue/babel-plugin-jsx': 1.1.5(@babel/core@7.23.5) - vite: 4.3.9(@types/node@18.18.14) + '@babel/core': 7.24.8 + '@babel/plugin-transform-typescript': 7.24.8(@babel/core@7.24.8) + '@vue/babel-plugin-jsx': 1.2.2(@babel/core@7.24.8) + vite: 5.3.3(@types/node@18.18.14) vue: 3.2.30 transitivePeerDependencies: - supports-color @@ -4772,14 +5256,14 @@ packages: vue: 3.2.41 dev: true - /@vitejs/plugin-vue@4.5.0(vite@4.3.9)(vue@3.2.30): - resolution: {integrity: sha512-a2WSpP8X8HTEww/U00bU4mX1QpLINNuz/2KMNpLsdu3BzOpak3AGI1CJYBTXcc4SPhaD0eNRUp7IyQK405L5dQ==} - engines: {node: ^14.18.0 || >=16.0.0} + /@vitejs/plugin-vue@5.0.5(vite@5.3.3)(vue@3.2.30): + resolution: {integrity: sha512-LOjm7XeIimLBZyzinBQ6OSm3UBCNVCpLkxGC0oWmm2YPzVZoxMsdvNVimLTBzpAnR9hl/yn1SHGuRfe6/Td9rQ==} + engines: {node: ^18.0.0 || >=20.0.0} peerDependencies: - vite: ^4.0.0 || ^5.0.0 + vite: ^5.0.0 vue: ^3.2.25 dependencies: - vite: 4.3.9(@types/node@18.18.14) + vite: 5.3.3(@types/node@18.18.14) vue: 3.2.30 dev: false @@ -4861,37 +5345,38 @@ packages: pretty-format: 27.5.1 dev: true - /@volar/kit@1.10.10(typescript@5.3.2): - resolution: {integrity: sha512-V2SyUPCPUhueqH8j5t48LJ0QsjExGSXzTv/XOdkUHV7hJ/ekyRGFqKxcfBtMq/nK6Tgu2G1ba+6u0d7e6wKcQw==} + /@volar/kit@2.4.0-alpha.15(typescript@5.3.2): + resolution: {integrity: sha512-ZCBErTebCVdzpSo/0wBlrjnZfqQfVIaHUJa3kOQe3TbVR/8Ny/3mij9gSkBTUcSyVtlUFpJpJo/B8aQp0xt/mQ==} peerDependencies: typescript: '*' dependencies: - '@volar/language-service': 1.10.10 + '@volar/language-service': 2.4.0-alpha.15 + '@volar/typescript': 2.4.0-alpha.15 typesafe-path: 0.2.2 typescript: 5.3.2 vscode-languageserver-textdocument: 1.0.11 vscode-uri: 3.0.8 dev: false - /@volar/language-core@1.10.10: - resolution: {integrity: sha512-nsV1o3AZ5n5jaEAObrS3MWLBWaGwUj/vAsc15FVNIv+DbpizQRISg9wzygsHBr56ELRH8r4K75vkYNMtsSNNWw==} - dependencies: - '@volar/source-map': 1.10.10 - dev: false - /@volar/language-core@1.11.1: resolution: {integrity: sha512-dOcNn3i9GgZAcJt43wuaEykSluAuOkQgzni1cuxLxTV0nJKanQztp7FxyswdRILaKH+P2XZMPRp2S4MV/pElCw==} dependencies: '@volar/source-map': 1.11.1 dev: true - /@volar/language-server@1.10.10: - resolution: {integrity: sha512-F2PRBU+CRjT7L9qe8bjof/uz/LbAXVmgwNU2gOSX2y1bUl3E8DHmD0dB6pwIVublvkx+Ivg/0r3Z6oyxfPPruQ==} + /@volar/language-core@2.4.0-alpha.15: + resolution: {integrity: sha512-mt8z4Fm2WxfQYoQHPcKVjLQV6PgPqyKLbkCVY2cr5RSaamqCHjhKEpsFX66aL4D/7oYguuaUw9Bx03Vt0TpIIA==} + dependencies: + '@volar/source-map': 2.4.0-alpha.15 + dev: false + + /@volar/language-server@2.4.0-alpha.15: + resolution: {integrity: sha512-epaF7Rllb29nr25F8hX5bq7ivgStNZzXGkhuPlHCUM+Ij/aQnsBeYQsfm7EttPqqO3abCctpRWyd+icklFEBoQ==} dependencies: - '@volar/language-core': 1.10.10 - '@volar/language-service': 1.10.10 - '@volar/typescript': 1.10.10 - '@vscode/l10n': 0.0.16 + '@volar/language-core': 2.4.0-alpha.15 + '@volar/language-service': 2.4.0-alpha.15 + '@volar/snapshot-document': 2.4.0-alpha.15 + '@volar/typescript': 2.4.0-alpha.15 path-browserify: 1.0.1 request-light: 0.7.0 vscode-languageserver: 9.0.1 @@ -4900,20 +5385,20 @@ packages: vscode-uri: 3.0.8 dev: false - /@volar/language-service@1.10.10: - resolution: {integrity: sha512-P4fiPWDI6fLGO6BghlksCVHs1nr9gvWAMDyma3Bca4aowxXusxjUVTsnJq0EVorIN5uIr1Xel4B/tNdXt/IKyw==} + /@volar/language-service@2.4.0-alpha.15: + resolution: {integrity: sha512-H5T5JvvqvWhG0PvvKPTM0nczTbTKQ+U87a8r0eahlH/ySi2HvIHO/7PiNKLxKqLNsiT8SX4U3QcGC8ZaNcC07g==} dependencies: - '@volar/language-core': 1.10.10 - '@volar/source-map': 1.10.10 + '@volar/language-core': 2.4.0-alpha.15 vscode-languageserver-protocol: 3.17.5 vscode-languageserver-textdocument: 1.0.11 vscode-uri: 3.0.8 dev: false - /@volar/source-map@1.10.10: - resolution: {integrity: sha512-GVKjLnifV4voJ9F0vhP56p4+F3WGf+gXlRtjFZsv6v3WxBTWU3ZVeaRaEHJmWrcv5LXmoYYpk/SC25BKemPRkg==} + /@volar/snapshot-document@2.4.0-alpha.15: + resolution: {integrity: sha512-8lnX0eZ7/lM+hakO5kspWABi4nijppxTy9XU0f9ns2lZ/JCE0t9EurNNiOaw4MWFO9USr0H72Ut0LCB9o4rpqA==} dependencies: - muggle-string: 0.3.1 + vscode-languageserver-protocol: 3.17.5 + vscode-languageserver-textdocument: 1.0.11 dev: false /@volar/source-map@1.11.1: @@ -4922,11 +5407,8 @@ packages: muggle-string: 0.3.1 dev: true - /@volar/typescript@1.10.10: - resolution: {integrity: sha512-4a2r5bdUub2m+mYVnLu2wt59fuoYWe7nf0uXtGHU8QQ5LDNfzAR0wK7NgDiQ9rcl2WT3fxT2AA9AylAwFtj50A==} - dependencies: - '@volar/language-core': 1.10.10 - path-browserify: 1.0.1 + /@volar/source-map@2.4.0-alpha.15: + resolution: {integrity: sha512-8Htngw5TmBY4L3ClDqBGyfLhsB8EmoEXUH1xydyEtEoK0O6NX5ur4Jw8jgvscTlwzizyl/wsN1vn0cQXVbbXYg==} dev: false /@volar/typescript@1.11.1: @@ -4936,8 +5418,16 @@ packages: path-browserify: 1.0.1 dev: true - /@vscode/emmet-helper@2.9.2: - resolution: {integrity: sha512-MaGuyW+fa13q3aYsluKqclmh62Hgp0BpKIqS66fCxfOaBcVQ1OnMQxRRgQUYnCkxFISAQlkJ0qWWPyXjro1Qrg==} + /@volar/typescript@2.4.0-alpha.15: + resolution: {integrity: sha512-U3StRBbDuxV6Woa4hvGS4kz3XcOzrWUKgFdEFN+ba1x3eaYg7+ytau8ul05xgA+UNGLXXsKur7fTUhDFyISk0w==} + dependencies: + '@volar/language-core': 2.4.0-alpha.15 + path-browserify: 1.0.1 + vscode-uri: 3.0.8 + dev: false + + /@vscode/emmet-helper@2.9.3: + resolution: {integrity: sha512-rB39LHWWPQYYlYfpv9qCoZOVioPCftKXXqrsyqN1mTWZM6dTnONT63Db+03vgrBbHzJN45IrgS/AGxw9iiqfEw==} dependencies: emmet: 2.4.6 jsonc-parser: 2.3.1 @@ -4946,25 +5436,29 @@ packages: vscode-uri: 2.1.2 dev: false - /@vscode/l10n@0.0.16: - resolution: {integrity: sha512-JT5CvrIYYCrmB+dCana8sUqJEcGB1ZDXNLMQ2+42bW995WmNoenijWMUdZfwmuQUTQcEVVIa2OecZzTYWUW9Cg==} + /@vscode/l10n@0.0.18: + resolution: {integrity: sha512-KYSIHVmslkaCDyw013pphY+d7x1qV8IZupYfeIfzNA+nsaWHbn5uPuQRvdRFsa9zFzGeudPuoGoZ1Op4jrJXIQ==} dev: false /@vue/babel-helper-vue-transform-on@1.1.5: resolution: {integrity: sha512-SgUymFpMoAyWeYWLAY+MkCK3QEROsiUnfaw5zxOVD/M64KQs8D/4oK6Q5omVA2hnvEOE0SCkH2TZxs/jnnUj7w==} dev: false - /@vue/babel-plugin-jsx@1.1.5(@babel/core@7.23.5): + /@vue/babel-helper-vue-transform-on@1.2.2: + resolution: {integrity: sha512-nOttamHUR3YzdEqdM/XXDyCSdxMA9VizUKoroLX6yTyRtggzQMHXcmwh8a7ZErcJttIBIc9s68a1B8GZ+Dmvsw==} + dev: false + + /@vue/babel-plugin-jsx@1.1.5(@babel/core@7.24.8): resolution: {integrity: sha512-nKs1/Bg9U1n3qSWnsHhCVQtAzI6aQXqua8j/bZrau8ywT1ilXQbK4FwEJGmU8fV7tcpuFvWmmN7TMmV1OBma1g==} peerDependencies: '@babel/core': ^7.0.0-0 dependencies: - '@babel/core': 7.23.5 - '@babel/helper-module-imports': 7.22.15 - '@babel/plugin-syntax-jsx': 7.23.3(@babel/core@7.23.5) - '@babel/template': 7.22.15 - '@babel/traverse': 7.23.5 - '@babel/types': 7.23.5 + '@babel/core': 7.24.8 + '@babel/helper-module-imports': 7.24.7 + '@babel/plugin-syntax-jsx': 7.24.7(@babel/core@7.24.8) + '@babel/template': 7.24.7 + '@babel/traverse': 7.24.8 + '@babel/types': 7.24.8 '@vue/babel-helper-vue-transform-on': 1.1.5 camelcase: 6.3.0 html-tags: 3.3.1 @@ -4973,6 +5467,43 @@ packages: - supports-color dev: false + /@vue/babel-plugin-jsx@1.2.2(@babel/core@7.24.8): + resolution: {integrity: sha512-nYTkZUVTu4nhP199UoORePsql0l+wj7v/oyQjtThUVhJl1U+6qHuoVhIvR3bf7eVKjbCK+Cs2AWd7mi9Mpz9rA==} + peerDependencies: + '@babel/core': ^7.0.0-0 + peerDependenciesMeta: + '@babel/core': + optional: true + dependencies: + '@babel/core': 7.24.8 + '@babel/helper-module-imports': 7.22.15 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/plugin-syntax-jsx': 7.24.7(@babel/core@7.24.8) + '@babel/template': 7.24.7 + '@babel/traverse': 7.24.8 + '@babel/types': 7.24.8 + '@vue/babel-helper-vue-transform-on': 1.2.2 + '@vue/babel-plugin-resolve-type': 1.2.2(@babel/core@7.24.8) + camelcase: 6.3.0 + html-tags: 3.3.1 + svg-tags: 1.0.0 + transitivePeerDependencies: + - supports-color + dev: false + + /@vue/babel-plugin-resolve-type@1.2.2(@babel/core@7.24.8): + resolution: {integrity: sha512-EntyroPwNg5IPVdUJupqs0CFzuf6lUrVvCspmv2J1FITLeGnUCuoGNNk78dgCusxEiYj6RMkTJflGSxk5aIC4A==} + peerDependencies: + '@babel/core': ^7.0.0-0 + dependencies: + '@babel/code-frame': 7.24.7 + '@babel/core': 7.24.8 + '@babel/helper-module-imports': 7.22.15 + '@babel/helper-plugin-utils': 7.24.8 + '@babel/parser': 7.24.8 + '@vue/compiler-sfc': 3.4.31 + dev: false + /@vue/compiler-core@3.2.30: resolution: {integrity: sha512-64fq1KfcR+k3Vlw+IsBM2VhV5B+2IP3YxvKU8LWCDLrkmlXtbf2eMK6+0IwX5KP41D0f1gzryIiXR7P8cB9O5Q==} dependencies: @@ -4998,6 +5529,16 @@ packages: estree-walker: 2.0.2 source-map-js: 1.0.2 + /@vue/compiler-core@3.4.31: + resolution: {integrity: sha512-skOiodXWTV3DxfDhB4rOf3OGalpITLlgCeOwb+Y9GJpfQ8ErigdBUHomBzvG78JoVE8MJoQsb+qhZiHfKeNeEg==} + dependencies: + '@babel/parser': 7.24.8 + '@vue/shared': 3.4.31 + entities: 4.5.0 + estree-walker: 2.0.2 + source-map-js: 1.2.0 + dev: false + /@vue/compiler-dom@3.2.30: resolution: {integrity: sha512-t7arHz2SXLCXlF2fdGDFVbhENbGMez254Z5edUqb//6WXJU1lC7GvSkUE7i5x8WSjgfqt60i0V8zdmk16rvLdw==} dependencies: @@ -5017,6 +5558,13 @@ packages: '@vue/compiler-core': 3.3.9 '@vue/shared': 3.3.9 + /@vue/compiler-dom@3.4.31: + resolution: {integrity: sha512-wK424WMXsG1IGMyDGyLqB+TbmEBFM78hIsOJ9QwUVLGrcSk0ak6zYty7Pj8ftm7nEtdU/DGQxAXp0/lM/2cEpQ==} + dependencies: + '@vue/compiler-core': 3.4.31 + '@vue/shared': 3.4.31 + dev: false + /@vue/compiler-sfc@3.2.30: resolution: {integrity: sha512-P/5YpILtcQY92z72gxhkyOUPHVskEzhSrvYi91Xcr+csOxaDaYU5OqOxCzZKcf3Og70Tat404vO1OHrwprN90A==} dependencies: @@ -5046,19 +5594,18 @@ packages: postcss: 8.4.31 source-map: 0.6.1 - /@vue/compiler-sfc@3.3.9: - resolution: {integrity: sha512-wy0CNc8z4ihoDzjASCOCsQuzW0A/HP27+0MDSSICMjVIFzk/rFViezkR3dzH+miS2NDEz8ywMdbjO5ylhOLI2A==} + /@vue/compiler-sfc@3.4.31: + resolution: {integrity: sha512-einJxqEw8IIJxzmnxmJBuK2usI+lJonl53foq+9etB2HAzlPjAS/wa7r0uUpXw5ByX3/0uswVSrjNb17vJm1kQ==} dependencies: - '@babel/parser': 7.23.5 - '@vue/compiler-core': 3.3.9 - '@vue/compiler-dom': 3.3.9 - '@vue/compiler-ssr': 3.3.9 - '@vue/reactivity-transform': 3.3.9 - '@vue/shared': 3.3.9 + '@babel/parser': 7.24.8 + '@vue/compiler-core': 3.4.31 + '@vue/compiler-dom': 3.4.31 + '@vue/compiler-ssr': 3.4.31 + '@vue/shared': 3.4.31 estree-walker: 2.0.2 - magic-string: 0.30.5 - postcss: 8.4.31 - source-map-js: 1.0.2 + magic-string: 0.30.10 + postcss: 8.4.39 + source-map-js: 1.2.0 dev: false /@vue/compiler-ssr@3.2.30: @@ -5080,11 +5627,54 @@ packages: dependencies: '@vue/compiler-dom': 3.3.9 '@vue/shared': 3.3.9 + dev: true + optional: true + + /@vue/compiler-ssr@3.4.31: + resolution: {integrity: sha512-RtefmITAje3fJ8FSg1gwgDhdKhZVntIVbwupdyZDSifZTRMiWxWehAOTCc8/KZDnBOcYQ4/9VWxsTbd3wT0hAA==} + dependencies: + '@vue/compiler-dom': 3.4.31 + '@vue/shared': 3.4.31 + dev: false /@vue/devtools-api@6.5.1: resolution: {integrity: sha512-+KpckaAQyfbvshdDW5xQylLni1asvNSGme1JFs8I1+/H5pHEhqUKMEQD/qn3Nx5+/nycBq11qAEi8lk+LXI2dA==} dev: false + /@vue/devtools-core@7.3.5(vite@5.3.3)(vue@3.2.30): + resolution: {integrity: sha512-uSC3IkIp6MtyJYSh5xzY99sgqlAXLq+peE2KKXTi6JeRHOtMngFWFWENXi70IJ1EVGYztiFQoHhI9WZcgKBz8g==} + peerDependencies: + vue: ^3.0.0 + dependencies: + '@vue/devtools-kit': 7.3.5 + '@vue/devtools-shared': 7.3.5 + mitt: 3.0.1 + nanoid: 3.3.7 + pathe: 1.1.2 + vite-hot-client: 0.2.3(vite@5.3.3) + vue: 3.2.30 + transitivePeerDependencies: + - vite + dev: false + + /@vue/devtools-kit@7.3.5: + resolution: {integrity: sha512-wwfi10gJ1HMtjzcd8aIOnzBHlIRqsYDgcDyrKvkeyc0Gbcoe7UrkXRVHZUOtcxxoplHA0PwpT6wFg0uUCmi8Ww==} + dependencies: + '@vue/devtools-shared': 7.3.5 + birpc: 0.2.17 + hookable: 5.5.3 + mitt: 3.0.1 + perfect-debounce: 1.0.0 + speakingurl: 14.0.1 + superjson: 2.2.1 + dev: false + + /@vue/devtools-shared@7.3.5: + resolution: {integrity: sha512-Rqii3VazmWTi67a86rYopi61n5Ved05EybJCwyrfoO9Ok3MaS/4yRFl706ouoISMlyrASJFEzM0/AiDA6w4f9A==} + dependencies: + rfdc: 1.4.1 + dev: false + /@vue/language-core@1.8.24(typescript@5.0.4): resolution: {integrity: sha512-2ClHvij0WlsDWryPzXJCSpPc6rusZFNoVtRZGgGGkKCmKuIREDDKmH8j+1tYyxPYyH0qL6pZ6+IHD8KIm5nWAw==} peerDependencies: @@ -5144,16 +5734,6 @@ packages: estree-walker: 2.0.2 magic-string: 0.25.9 - /@vue/reactivity-transform@3.3.9: - resolution: {integrity: sha512-HnUFm7Ry6dFa4Lp63DAxTixUp8opMtQr6RxQCpDI1vlh12rkGIeYqMvJtK+IKyEfEOa2I9oCkD1mmsPdaGpdVg==} - dependencies: - '@babel/parser': 7.23.5 - '@vue/compiler-core': 3.3.9 - '@vue/shared': 3.3.9 - estree-walker: 2.0.2 - magic-string: 0.30.5 - dev: false - /@vue/reactivity@3.2.30: resolution: {integrity: sha512-qlNKbkRn2JiGxVUEdoXbLAy+vcuHUCcq+YH2uXWz0BNMvXY2plmz+oqsw+694llwmYLkke5lbdYF4DIupisIkg==} dependencies: @@ -5233,6 +5813,10 @@ packages: /@vue/shared@3.3.9: resolution: {integrity: sha512-ZE0VTIR0LmYgeyhurPTpy4KzKsuDyQbMSdM49eKkMnT5X4VfFBLysMzjIZhLEFQYjjOVVfbvUDHckwjDFiO2eA==} + /@vue/shared@3.4.31: + resolution: {integrity: sha512-Yp3wtJk//8cO4NItOPpi3QkLExAr/aLBGZMmTtW9WpdwBCJpRM6zj9WgWktXAl8IDIozwNMByT45JP3tO3ACWA==} + dev: false + /@vue/test-utils@2.3.2(vue@3.2.41): resolution: {integrity: sha512-hJnVaYhbrIm0yBS0+e1Y0Sj85cMyAi+PAbK4JHqMRUZ6S622Goa+G7QzkRSyvCteG8wop7tipuEbHoZo26wsSA==} peerDependencies: @@ -5310,7 +5894,6 @@ packages: /acorn-walk@8.3.0: resolution: {integrity: sha512-FS7hV565M5l1R08MXqo8odwMTB02C2UqzB17RVgu9EyuYFBqJZ3/ZY97sQD5FewVu1UyDFc1yztUDrAwT0EypA==} engines: {node: '>=0.4.0'} - dev: true /acorn@7.4.1: resolution: {integrity: sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==} @@ -5553,6 +6136,12 @@ packages: engines: {node: '>=8'} dev: true + /as-table@1.0.55: + resolution: {integrity: sha512-xvsWESUJn0JN421Xb9MQw6AsMHRCUknCe0Wjlxvjud80mU4E6hQf1A6NzQKcYNmYw62MfzEtXc+badstZP3JpQ==} + dependencies: + printable-characters: 1.0.42 + dev: false + /asn1@0.2.6: resolution: {integrity: sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==} dependencies: @@ -5678,7 +6267,7 @@ packages: hasBin: true dev: true - /autoprefixer@10.4.14(postcss@8.4.31): + /autoprefixer@10.4.14(postcss@8.4.39): resolution: {integrity: sha512-FQzyfOsTlwVzjHxKEqRIAdJx9niO6VCBCoEwax/VLSoQF29ggECcPuBqUMZ+u8jCZOPSy8b8/8KnuFbp0SaFZQ==} engines: {node: ^10 || ^12 || >=14} hasBin: true @@ -5690,23 +6279,23 @@ packages: fraction.js: 4.3.7 normalize-range: 0.1.2 picocolors: 1.0.0 - postcss: 8.4.31 + postcss: 8.4.39 postcss-value-parser: 4.2.0 dev: true - /autoprefixer@10.4.16(postcss@8.4.31): + /autoprefixer@10.4.16(postcss@8.4.39): resolution: {integrity: sha512-7vd3UC6xKp0HLfua5IjZlcXvGAGy7cBAXTg2lyQ/8WpNhd6SiZ8Be+xm3FyBSYJx5GKcpRCzBh7RH4/0dnY+uQ==} engines: {node: ^10 || ^12 || >=14} hasBin: true peerDependencies: postcss: ^8.1.0 dependencies: - browserslist: 4.22.1 - caniuse-lite: 1.0.30001565 + browserslist: 4.23.2 + caniuse-lite: 1.0.30001641 fraction.js: 4.3.7 normalize-range: 0.1.2 - picocolors: 1.0.0 - postcss: 8.4.31 + picocolors: 1.0.1 + postcss: 8.4.39 postcss-value-parser: 4.2.0 dev: false @@ -5786,6 +6375,10 @@ packages: resolution: {integrity: sha512-B64AGL4ug2IS2jvV/zjTYDD1L+2gOJTT7Rv+VaK7KVQtQOo/xZbCDsh7g727ipckmU+QJYRqo5RcifVr0Kgcmg==} dev: true + /birpc@0.2.17: + resolution: {integrity: sha512-+hkTxhot+dWsLpp3gia5AkVHIsKlZybNT5gIYiDlNzJrmYPcTM9k5/w2uaj3IPpd7LlEYpmCj4Jj1nC41VhDFg==} + dev: false + /bl@4.1.0: resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==} dependencies: @@ -5794,6 +6387,10 @@ packages: readable-stream: 3.6.2 dev: true + /blake3-wasm@2.1.5: + resolution: {integrity: sha512-F1+K8EbfOZE49dtoPtmxUQrpXaBIl3ICvasLh+nJta0xkz+9kF/7uet9fLnwKqhDrmj6g+6K3Tw9yQPUg2ka5g==} + dev: false + /blob-util@2.0.2: resolution: {integrity: sha512-T7JQa+zsXXEa6/8ZhHcQEW1UFfVM49Ts65uBkFL6fz2QmrElqmbajIDJvuA0tEhRe5eIjpV9ZF+0RfZR9voJFQ==} dev: true @@ -5870,6 +6467,7 @@ packages: electron-to-chromium: 1.4.597 node-releases: 2.0.13 update-browserslist-db: 1.0.13(browserslist@4.22.1) + dev: true /browserslist@4.23.2: resolution: {integrity: sha512-qkqSyistMYdxAcw+CzbZwlBy8AGmS/eEWs+sEV5TnLRGDOL+C5M2EnH6tlZyg0YoAxGJAFKh61En9BR941GnHA==} @@ -5907,6 +6505,13 @@ packages: semver: 7.5.4 dev: true + /bundle-name@4.1.0: + resolution: {integrity: sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==} + engines: {node: '>=18'} + dependencies: + run-applescript: 7.0.0 + dev: false + /byte-size@8.1.1: resolution: {integrity: sha512-tUkzZWK0M/qdoLEqikxBWe4kumyuwjl3HO6zHTr4yEI23EojPtLYXdG1+AQY7MN0cGyNDvEaJ8wiYQm6P2bPxg==} engines: {node: '>=12.17'} @@ -6053,6 +6658,7 @@ packages: /caniuse-lite@1.0.30001565: resolution: {integrity: sha512-xrE//a3O7TP0vaJ8ikzkD2c2NgcVUvsEe2IvFTntV4Yd1Z9FVzh+gW+enX96L0psrbaFMcVcH2l90xNuGDWc8w==} + dev: true /caniuse-lite@1.0.30001641: resolution: {integrity: sha512-Phv5thgl67bHYo1TtMY/MurjkHhV4EDaCosezRXgZ8jzA/Ub+wjxAvbGvjoFENStinwi5kCyOYV3mi5tOGykwA==} @@ -6066,6 +6672,15 @@ packages: upper-case-first: 2.0.2 dev: true + /capnp-ts@0.7.0: + resolution: {integrity: sha512-XKxXAC3HVPv7r674zP0VC3RTXz+/JKhfyw94ljvF80yynK6VkTnqE3jMuN8b3dUVmmc43TjyxjW4KTsmB3c86g==} + dependencies: + debug: 4.3.5 + tslib: 2.6.2 + transitivePeerDependencies: + - supports-color + dev: false + /caseless@0.12.0: resolution: {integrity: sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==} dev: true @@ -6529,6 +7144,11 @@ packages: - supports-color dev: true + /consola@3.2.3: + resolution: {integrity: sha512-I5qxpzLv+sJhTVEoLYNcTW+bThDCPsit0vLNKShZx6rLtpilNpmmeTPaeqJb9ZE9dV3DGaeby6Vuhrw38WjeyQ==} + engines: {node: ^14.18.0 || >=16.10.0} + dev: false + /console-control-strings@1.1.0: resolution: {integrity: sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==} dev: true @@ -6624,11 +7244,23 @@ packages: /convert-source-map@2.0.0: resolution: {integrity: sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==} + /cookie@0.5.0: + resolution: {integrity: sha512-YZ3GUyn/o8gfKJlnlX7g7xq4gyO6OSuhGPKaaGssGB2qgDUS0gPgtTvoyZLTt9Ab6dC4hfc9dV5arkvc/OCmrw==} + engines: {node: '>= 0.6'} + dev: false + /cookie@0.6.0: resolution: {integrity: sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==} engines: {node: '>= 0.6'} dev: false + /copy-anything@3.0.5: + resolution: {integrity: sha512-yCEafptTtb4bk7GLEQoM8KVJpxAfdBJYaXyzQEgQQQgYrZiDp8SJmGKlYza6CYjEDNstAdNdKA3UuoULlEbS6w==} + engines: {node: '>=12.13'} + dependencies: + is-what: 4.1.16 + dev: false + /copy-descriptor@0.1.1: resolution: {integrity: sha512-XgZ0pFcakEUlbwQEVNg3+QAis1FyTL3Qel9FYy8pSkQqoG3PNoT0bOCQtOXcOkur21r2Eq2kI+IE+gsmAEVlYw==} engines: {node: '>=0.10.0'} @@ -6913,6 +7545,10 @@ packages: assert-plus: 1.0.0 dev: true + /data-uri-to-buffer@2.0.2: + resolution: {integrity: sha512-ND9qDTLc6diwj+Xe5cdAgVTbLVdXbtxTJRXRhli8Mowuaan+0EJOtdqJ0QCHNSSPyoXGx9HX2/VMnKeC34AChA==} + dev: false + /data-urls@3.0.2: resolution: {integrity: sha512-Jy/tj3ldjZJo63sVAvg6LHt2mHvl4V6AgRAmNDtLdm7faqtsx+aJG42rsyCo9JCoRVKwPFzKlIPx3DIibwSIaQ==} engines: {node: '>=12'} @@ -6927,6 +7563,10 @@ packages: engines: {node: '>=0.11'} dev: false + /date-fns@3.6.0: + resolution: {integrity: sha512-fRHTG8g/Gif+kSh50gaGEdToemgfj74aRX3swtiouboip5JDLAyDE9F11nHMIcvOaXeOC6D7SpNhi7uFyB7Uww==} + dev: false + /date-time@3.1.0: resolution: {integrity: sha512-uqCUKXE5q1PNBXjPqvwhwJf9SwMoAHBgWJ6DcrnS5o+W2JOiIILl0JEdVD8SGujrNS02GGxgwAg2PN2zONgtjg==} engines: {node: '>=6'} @@ -6984,6 +7624,7 @@ packages: dependencies: ms: 2.1.2 supports-color: 8.1.1 + dev: true /debug@4.3.5: resolution: {integrity: sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==} @@ -7045,6 +7686,19 @@ packages: resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==} dev: true + /default-browser-id@5.0.0: + resolution: {integrity: sha512-A6p/pu/6fyBcA1TRz/GqWYPViplrftcW2gZC9q79ngNCKAeR/X3gcEdXQHl4KNXV+3wgIJ1CPkJQ3IHM6lcsyA==} + engines: {node: '>=18'} + dev: false + + /default-browser@5.2.1: + resolution: {integrity: sha512-WY/3TUME0x3KPYdRRxEJJvXRHV4PyPoUsxtZa78lwItwRQRHhd2U9xOscaT/YTf8uCXIAjeJOFBVEh/7FtD8Xg==} + engines: {node: '>=18'} + dependencies: + bundle-name: 4.1.0 + default-browser-id: 5.0.0 + dev: false + /defaults@1.0.4: resolution: {integrity: sha512-eFuaLoy/Rxalv2kr+lqMlUnrDWV+3j4pljOIJgLIhI058IQfWJ7vXhyEIHu+HtC738klGALYxOKDO0bQP3tg8A==} dependencies: @@ -7065,6 +7719,11 @@ packages: engines: {node: '>=8'} dev: true + /define-lazy-prop@3.0.0: + resolution: {integrity: sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==} + engines: {node: '>=12'} + dev: false + /define-properties@1.2.1: resolution: {integrity: sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==} engines: {node: '>= 0.4'} @@ -7103,6 +7762,10 @@ packages: resolution: {integrity: sha512-Vy2wmG3NTkmHNg/kzpuvHhkqeIx3ODWqasgCRbKtbXEN0G+HpEEv9BtJLp7ZG1CZloFaC41Ah3ZFbq7aqCqMeQ==} dev: true + /defu@6.1.4: + resolution: {integrity: sha512-mEQCMmwJu317oSz8CwdIOdwf3xMif1ttiM8LTufzc3g6kR+9Pe236twL8j3IYT1F7GfRgGcW6MWxzZjLIkuHIg==} + dev: false + /delayed-stream@1.0.0: resolution: {integrity: sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==} engines: {node: '>=0.4.0'} @@ -7303,6 +7966,7 @@ packages: /electron-to-chromium@1.4.597: resolution: {integrity: sha512-0XOQNqHhg2YgRVRUrS4M4vWjFCFIP2ETXcXe/0KIQBjXE9Cpy+tgzzYfuq6HGai3hWq0YywtG+5XK8fyG08EjA==} + dev: true /electron-to-chromium@1.4.827: resolution: {integrity: sha512-VY+J0e4SFcNfQy19MEoMdaIcZLmDCprqvBtkii1WTCTQHpRvf5N8+3kTYCgL/PcntvwQvmMJWTuDPsq+IlhWKQ==} @@ -7387,6 +8051,10 @@ packages: is-arrayish: 0.2.1 dev: true + /error-stack-parser-es@0.1.4: + resolution: {integrity: sha512-l0uy0kAoo6toCgVOYaAayqtPa2a1L15efxUMEnQebKwLQX2X0OpS6wMMQdc4juJXmxd9i40DuaUHq+mjIya9TQ==} + dev: false + /es-abstract@1.22.3: resolution: {integrity: sha512-eiiY8HQeYfYH2Con2berK+To6GrK2RxbPawDkGq4UiCQQfZHb6wX9qQqkbpPqaxQFcl8d9QzZqo0tGE0VcrdwA==} engines: {node: '>= 0.4'} @@ -7693,6 +8361,37 @@ packages: '@esbuild/win32-ia32': 0.17.19 '@esbuild/win32-x64': 0.17.19 + /esbuild@0.19.12: + resolution: {integrity: sha512-aARqgq8roFBj054KvQr5f1sFu0D65G+miZRCuJyJ0G13Zwx7vRar5Zhn2tkQNzIXcBrNVsv/8stehpj+GAjgbg==} + engines: {node: '>=12'} + hasBin: true + requiresBuild: true + optionalDependencies: + '@esbuild/aix-ppc64': 0.19.12 + '@esbuild/android-arm': 0.19.12 + '@esbuild/android-arm64': 0.19.12 + '@esbuild/android-x64': 0.19.12 + '@esbuild/darwin-arm64': 0.19.12 + '@esbuild/darwin-x64': 0.19.12 + '@esbuild/freebsd-arm64': 0.19.12 + '@esbuild/freebsd-x64': 0.19.12 + '@esbuild/linux-arm': 0.19.12 + '@esbuild/linux-arm64': 0.19.12 + '@esbuild/linux-ia32': 0.19.12 + '@esbuild/linux-loong64': 0.19.12 + '@esbuild/linux-mips64el': 0.19.12 + '@esbuild/linux-ppc64': 0.19.12 + '@esbuild/linux-riscv64': 0.19.12 + '@esbuild/linux-s390x': 0.19.12 + '@esbuild/linux-x64': 0.19.12 + '@esbuild/netbsd-x64': 0.19.12 + '@esbuild/openbsd-x64': 0.19.12 + '@esbuild/sunos-x64': 0.19.12 + '@esbuild/win32-arm64': 0.19.12 + '@esbuild/win32-ia32': 0.19.12 + '@esbuild/win32-x64': 0.19.12 + dev: false + /esbuild@0.21.5: resolution: {integrity: sha512-mg3OPMV4hXywwpoDxu3Qda5xCKQi+vCTZq8S9J/EpkhB2HzKXq4SNFZE3+NK93JYxc8VMSep+lOUSC/RVKaBqw==} engines: {node: '>=12'} @@ -7743,7 +8442,6 @@ packages: /escape-string-regexp@4.0.0: resolution: {integrity: sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==} engines: {node: '>=10'} - dev: true /escape-string-regexp@5.0.0: resolution: {integrity: sha512-/veY75JbMK4j1yjvuUxuVsiS/hr/4iHs9FTT6cgTexxdE0Ly/glccBAkloH/DofkjRbZU3bnoj38mOmhkZ0lHw==} @@ -7938,6 +8636,10 @@ packages: engines: {node: '>=4.0'} dev: true + /estree-walker@0.6.1: + resolution: {integrity: sha512-SqmZANLWS0mnatqbSfRP5g8OXZC12Fgg1IwNtLsyHDzJizORW4khDfjPqJZsemPWBB2uqykUah5YpQ6epsqC/w==} + dev: false + /estree-walker@2.0.2: resolution: {integrity: sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==} @@ -8042,6 +8744,11 @@ packages: pretty-hrtime: 1.0.3 dev: true + /exit-hook@2.2.1: + resolution: {integrity: sha512-eNTPlAD67BmP31LDINZ3U7HSF8l57TxOY2PmBJ1shpCvpnxBF93mWCE8YHBnXs8qiUZJc9WDcWIeC3a2HIAMfw==} + engines: {node: '>=6'} + dev: false + /expand-brackets@2.1.4: resolution: {integrity: sha512-w/ozOKR9Obk3qoWeY/WDi6MFta9AoMR+zud60mdnbniMcBxRuFJyDt2LdX/14A1UABeqk+Uk+LDfUpvoGKppZA==} engines: {node: '>=0.10.0'} @@ -8429,7 +9136,6 @@ packages: graceful-fs: 4.2.11 jsonfile: 6.1.0 universalify: 2.0.1 - dev: true /fs-extra@7.0.1: resolution: {integrity: sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==} @@ -8552,6 +9258,13 @@ packages: engines: {node: '>=8'} dev: true + /get-source@2.0.12: + resolution: {integrity: sha512-X5+4+iD+HoSeEED+uwrQ07BOQr0kEDFMVqqpBuI+RaZBpBpHCuXxo70bjar6f0b0u/DQJsJ7ssurpP0V60Az+w==} + dependencies: + data-uri-to-buffer: 2.0.2 + source-map: 0.6.1 + dev: false + /get-stream@5.2.0: resolution: {integrity: sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==} engines: {node: '>=8'} @@ -8679,6 +9392,10 @@ packages: resolution: {integrity: sha512-Iozmtbqv0noj0uDDqoL0zNq0VBEfK2YFoMAZoxJe4cwphvLR+JskfF30QhXHOR4m3KrE6NLRYw+U9MRXvifyig==} dev: true + /glob-to-regexp@0.4.1: + resolution: {integrity: sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==} + dev: false + /glob@10.3.10: resolution: {integrity: sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==} engines: {node: '>=16 || 14 >=14.17'} @@ -8799,6 +9516,10 @@ packages: define-properties: 1.2.1 dev: true + /globalyzer@0.1.0: + resolution: {integrity: sha512-40oNTM9UfG6aBmuKxk/giHn5nQ8RVz/SS4Ir6zgzOv9/qC3kKZ9v4etGTcJbEl/NyVQH7FGU7d+X1egr57Md2Q==} + dev: false + /globby@11.1.0: resolution: {integrity: sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==} engines: {node: '>=10'} @@ -8837,6 +9558,10 @@ packages: - supports-color dev: true + /globrex@0.1.2: + resolution: {integrity: sha512-uHJgbwAMwNFf5mLst7IWLNg14x1CkeqglJb/K3doi4dw6q2IvAAmM/Y81kevy83wP+Sst+nutFTYOGg3d1lsxg==} + dev: false + /gopd@1.0.1: resolution: {integrity: sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==} dependencies: @@ -8899,6 +9624,7 @@ packages: /has-flag@4.0.0: resolution: {integrity: sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==} engines: {node: '>=8'} + dev: true /has-property-descriptors@1.0.1: resolution: {integrity: sha512-VsX8eaIewvas0xnvinAe9bw4WfIeODpGYikiWYLH+dma0Jw6KHYqWiWfhQlgOVK8D6PvjubK5Uc4P0iIhIcNVg==} @@ -9150,6 +9876,10 @@ packages: parse-passwd: 1.0.0 dev: true + /hookable@5.5.3: + resolution: {integrity: sha512-Yc+BQe8SvoXH1643Qez1zqLRmbA5rCL+sSmk6TVos0LWVfNIB7PGncdlId77WzLGSIB5KaWgTaNTs2lNVEI6VQ==} + dev: false + /hosted-git-info@2.8.9: resolution: {integrity: sha512-mxIDAb9Lsm6DoOJ7xH+5+X4y1LU/4Hi50L9C5sIswK3JzULS4bwk1FvjdBgvYR4bzT4tuUQiC15FE2f5HbLvYw==} dev: true @@ -9811,6 +10541,11 @@ packages: call-bind: 1.0.5 dev: true + /is-what@4.1.16: + resolution: {integrity: sha512-ZhMwEosbFJkA0YhFnNDgTM4ZxDRsS6HqTo7qsZM08fehyRYIYa0yHu5R6mgo1n/8MgaPBXiPimPD77baVFYg+A==} + engines: {node: '>=12.13'} + dev: false + /is-windows@1.0.2: resolution: {integrity: sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==} engines: {node: '>=0.10.0'} @@ -10046,7 +10781,6 @@ packages: universalify: 2.0.1 optionalDependencies: graceful-fs: 4.2.11 - dev: true /jsonparse@1.3.1: resolution: {integrity: sha512-POQXvpdL69+CluYsillJ7SUhKvytYjW9vG/GKpnf+xP8UWgYEM/RaMzHHofbALDiKbbP1W8UEYmgGl39WkPZsg==} @@ -10103,7 +10837,6 @@ packages: /kolorist@1.8.0: resolution: {integrity: sha512-Y+60/zizpJ3HRH8DCss+q95yr6145JXZo46OTpFvDZWLfRCE4qChOyk1b26nMaNpfHHgxagk9dXT5OP0Tfe+dQ==} - dev: true /launch-editor@2.6.1: resolution: {integrity: sha512-eB/uXmFVpY4zezmGp5XtU21kwo7GBbKB+EQ+UZeWtGb9yAM5xt/Evk+lYH3eRNAtId+ej4u7TYPFZ07w4s7rRw==} @@ -10512,6 +11245,7 @@ packages: engines: {node: '>=10'} dependencies: yallist: 4.0.0 + dev: true /lru-cache@7.18.3: resolution: {integrity: sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==} @@ -10541,6 +11275,7 @@ packages: engines: {node: '>=12'} dependencies: '@jridgewell/sourcemap-codec': 1.4.15 + dev: true /make-dir@2.1.0: resolution: {integrity: sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==} @@ -11173,6 +11908,12 @@ packages: hasBin: true dev: false + /mime@3.0.0: + resolution: {integrity: sha512-jSCU7/VB1loIWBZe14aEYHU/+1UMEHoaO7qxCOVJOw9GgH72VAWppxNcjU+x9a2k3GSIBXNKxXQFqRvvZ7vr3A==} + engines: {node: '>=10.0.0'} + hasBin: true + dev: false + /mimic-fn@2.1.0: resolution: {integrity: sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==} engines: {node: '>=6'} @@ -11187,6 +11928,29 @@ packages: engines: {node: '>=4'} dev: true + /miniflare@3.20240701.0: + resolution: {integrity: sha512-m9+I+7JNyqDGftCMKp9cK9pCZkK72hAL2mM9IWwhct+ZmucLBA8Uu6+rHQqA5iod86cpwOkrB2PrPA3wx9YNgw==} + engines: {node: '>=16.13'} + hasBin: true + dependencies: + '@cspotcode/source-map-support': 0.8.1 + acorn: 8.12.1 + acorn-walk: 8.3.0 + capnp-ts: 0.7.0 + exit-hook: 2.2.1 + glob-to-regexp: 0.4.1 + stoppable: 1.1.0 + undici: 5.28.4 + workerd: 1.20240701.0 + ws: 8.18.0 + youch: 3.3.3 + zod: 3.23.8 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + dev: false + /minimatch@3.0.5: resolution: {integrity: sha512-tUpxzX0VAzJHjLu0xUfFv1gwVp9ba3IOuRAVH2EGuRW8a5emA2FlACLqiT/lDVtS1W+TGNwqz3sWaNyLgDJWuw==} dependencies: @@ -11338,6 +12102,10 @@ packages: yallist: 4.0.0 dev: true + /mitt@3.0.1: + resolution: {integrity: sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==} + dev: false + /mixin-deep@1.3.2: resolution: {integrity: sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==} engines: {node: '>=0.10.0'} @@ -11398,6 +12166,11 @@ packages: /muggle-string@0.3.1: resolution: {integrity: sha512-ckmWDJjphvd/FvZawgygcUeQCxzvohjFO5RxTjj4eq8kw359gFF3E1brjfI+viLMxss5JrHTDRHZvu2/tuy0Qg==} + dev: true + + /muggle-string@0.4.1: + resolution: {integrity: sha512-VNTrAak/KhO2i8dqqnqnAHOa3cYBwXEZe9h+D5h/1ZqFSTEFHdM65lR7RoIqq3tBBYavsOXV84NoHXZ0AkPyqQ==} + dev: false /multimatch@5.0.0: resolution: {integrity: sha512-ypMKuglUrZUD99Tk2bUQ+xNQj43lPEfAeX2o9cTteAmShXy2VHDJpuwu1o0xqoKCt9jLVAvwyFKdLTPXKAfJyA==} @@ -11410,6 +12183,11 @@ packages: minimatch: 3.0.5 dev: true + /mustache@4.2.0: + resolution: {integrity: sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ==} + hasBin: true + dev: false + /mute-stream@0.0.8: resolution: {integrity: sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==} dev: true @@ -11481,6 +12259,10 @@ packages: tslib: 2.6.2 dev: true + /node-fetch-native@1.6.4: + resolution: {integrity: sha512-IhOigYzAKHd244OC0JIMIUrjzctirCmPkaIfhDeGcEETWof5zKYUW7e7MYvChGWh/4CJeXEgsRyGzuF334rOOQ==} + dev: false + /node-fetch@2.6.7: resolution: {integrity: sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==} engines: {node: 4.x || >=6.0.0} @@ -11493,6 +12275,11 @@ packages: whatwg-url: 5.0.0 dev: true + /node-forge@1.3.1: + resolution: {integrity: sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==} + engines: {node: '>= 6.13.0'} + dev: false + /node-gyp@9.4.1: resolution: {integrity: sha512-OQkWKbjQKbGkMf/xqI1jjy3oCTgMKJac58G2+bjZb3fza6gW2YrCSdMQYaoTb70crvE//Gngr4f0AgVHmqHvBQ==} engines: {node: ^12.13 || ^14.13 || >=16} @@ -11520,6 +12307,7 @@ packages: /node-releases@2.0.13: resolution: {integrity: sha512-uYr7J37ae/ORWdZeQ1xxMJe3NtdmqMC/JZK+geofDrkLUApKRHPd18/TxtBOJ4A0/+uUIliorNrfYV6s1b02eQ==} + dev: true /node-releases@2.0.14: resolution: {integrity: sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==} @@ -11862,6 +12650,16 @@ packages: mimic-fn: 4.0.0 dev: false + /open@10.1.0: + resolution: {integrity: sha512-mnkeQ1qP5Ue2wd+aivTD3NHd/lZ96Lu0jgf0pwktLPtx6cTZiH7tyeGRRHs0zX0rbrahXPnXlUnbeXyaBBuIaw==} + engines: {node: '>=18'} + dependencies: + default-browser: 5.2.1 + define-lazy-prop: 3.0.0 + is-inside-container: 1.0.0 + is-wsl: 3.1.0 + dev: false + /open@8.4.2: resolution: {integrity: sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==} engines: {node: '>=12'} @@ -12232,6 +13030,10 @@ packages: resolution: {integrity: sha512-d+RQGp0MAYTIaDBIMmOfMwz3E+LOZnxx1HZd5R18mmCZY0QBlK0LDZfPc8FW8Ed2DlvsuE6PRjroDY+wg4+j/Q==} dev: true + /pathe@1.1.2: + resolution: {integrity: sha512-whLdWMYL2TwI08hn8/ZqAbrVemu0LNaNNJZX73O6qaIdCTfXutsLhMkjdENX0qhsQ9uIimo4/aQOmXkoon2nDQ==} + dev: false + /pathval@1.1.1: resolution: {integrity: sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==} dev: true @@ -12240,6 +13042,10 @@ packages: resolution: {integrity: sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==} dev: true + /perfect-debounce@1.0.0: + resolution: {integrity: sha512-xCy9V055GLEqoFaHoC1SoLIaLmWctgCUaBaWxDZ7/Zx4CTyX7cJQLJOok/orfjZAh9kEYpjJa4d0KcJmCbctZA==} + dev: false + /performance-now@2.1.0: resolution: {integrity: sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==} dev: true @@ -12249,7 +13055,6 @@ packages: /picocolors@1.0.1: resolution: {integrity: sha512-anP1Z8qwhkbmu7MFP5iTt+wQKXgwzf7zTyGlcdzabySa9vd0Xt392U0rVmz9poOaBj0uHJKyyo9/upk0HrEQew==} - dev: false /picomatch@2.3.1: resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} @@ -12309,13 +13114,13 @@ packages: engines: {node: '>=0.10.0'} dev: true - /postcss-import@14.1.0(postcss@8.4.31): + /postcss-import@14.1.0(postcss@8.4.39): resolution: {integrity: sha512-flwI+Vgm4SElObFVPpTIT7SU7R3qk2L7PyduMcokiaVKuWv9d/U+Gm/QAd8NDLuykTWTkcrjOeD2Pp1rMeBTGw==} engines: {node: '>=10.0.0'} peerDependencies: postcss: ^8.0.0 dependencies: - postcss: 8.4.31 + postcss: 8.4.39 postcss-value-parser: 4.2.0 read-cache: 1.0.0 resolve: 1.22.8 @@ -12333,6 +13138,18 @@ packages: resolve: 1.22.8 dev: true + /postcss-import@15.1.0(postcss@8.4.39): + resolution: {integrity: sha512-hpr+J05B2FVYUAXHeK1YyI267J/dDDhMU6B6civm8hSY1jYJnBXxzKDKDswzJmtLHryrjhnDjqqp/49t8FALew==} + engines: {node: '>=14.0.0'} + peerDependencies: + postcss: ^8.0.0 + dependencies: + postcss: 8.4.39 + postcss-value-parser: 4.2.0 + read-cache: 1.0.0 + resolve: 1.22.8 + dev: true + /postcss-js@4.0.1(postcss@8.4.31): resolution: {integrity: sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==} engines: {node: ^12 || ^14 || >= 16} @@ -12341,8 +13158,18 @@ packages: dependencies: camelcase-css: 2.0.1 postcss: 8.4.31 + dev: true - /postcss-load-config@3.1.4(postcss@8.4.31): + /postcss-js@4.0.1(postcss@8.4.39): + resolution: {integrity: sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==} + engines: {node: ^12 || ^14 || >= 16} + peerDependencies: + postcss: ^8.4.21 + dependencies: + camelcase-css: 2.0.1 + postcss: 8.4.39 + + /postcss-load-config@3.1.4(postcss@8.4.39): resolution: {integrity: sha512-6DiM4E7v4coTE4uzA8U//WhtPwyhiim3eyjEMFCnUpzbrkK9wJHgKDT2mR+HbtSrd/NubVaYTOpSpjUl8NQeRg==} engines: {node: '>= 10'} peerDependencies: @@ -12355,7 +13182,7 @@ packages: optional: true dependencies: lilconfig: 2.1.0 - postcss: 8.4.31 + postcss: 8.4.39 yaml: 1.10.2 /postcss-load-config@4.0.2(postcss@8.4.31): @@ -12373,23 +13200,41 @@ packages: lilconfig: 3.0.0 postcss: 8.4.31 yaml: 2.3.4 + dev: true + + /postcss-load-config@4.0.2(postcss@8.4.39): + resolution: {integrity: sha512-bSVhyJGL00wMVoPUzAVAnbEoWyqRxkjv64tUl427SKnPrENtq6hJwUojroMz2VB+Q1edmi4IfrAPpami5VVgMQ==} + engines: {node: '>= 14'} + peerDependencies: + postcss: '>=8.0.9' + ts-node: '>=9.0.0' + peerDependenciesMeta: + postcss: + optional: true + ts-node: + optional: true + dependencies: + lilconfig: 3.0.0 + postcss: 8.4.39 + yaml: 2.3.4 + dev: false - /postcss-nested@5.0.6(postcss@8.4.31): + /postcss-nested@5.0.6(postcss@8.4.39): resolution: {integrity: sha512-rKqm2Fk0KbA8Vt3AdGN0FB9OBOMDVajMG6ZCf/GoHgdxUJ4sBFp0A/uMIRm+MJUdo33YXEtjqIz8u7DAp8B7DA==} engines: {node: '>=12.0'} peerDependencies: postcss: ^8.2.14 dependencies: - postcss: 8.4.31 + postcss: 8.4.39 postcss-selector-parser: 6.0.13 - /postcss-nested@6.0.0(postcss@8.4.31): + /postcss-nested@6.0.0(postcss@8.4.39): resolution: {integrity: sha512-0DkamqrPcmkBDsLn+vQDIrtkSbNkv5AD/M322ySo9kqFkCIYklym2xEmWkwo+Y3/qZo34tzEPNUw4y7yMCdv5w==} engines: {node: '>=12.0'} peerDependencies: postcss: ^8.2.14 dependencies: - postcss: 8.4.31 + postcss: 8.4.39 postcss-selector-parser: 6.0.13 dev: false @@ -12428,7 +13273,6 @@ packages: nanoid: 3.3.7 picocolors: 1.0.1 source-map-js: 1.2.0 - dev: false /preferred-pm@3.1.4: resolution: {integrity: sha512-lEHd+yEm22jXdCphDrkvIJQU66EuLojPPtvZkpKIkiD+l0DMThF/niqZKJSoU8Vl7iuvtmzyMhir9LdVy5WMnA==} @@ -12478,6 +13322,10 @@ packages: engines: {node: '>= 0.8'} dev: true + /printable-characters@1.0.42: + resolution: {integrity: sha512-dKp+C4iXWK4vVYZmYSd0KBH5F/h1HoZRsbJ82AVKRO3PEo8L4lBS/vLwhVtpwwuYcoIsVY+1JYKR268yn480uQ==} + dev: false + /prismjs@1.29.0: resolution: {integrity: sha512-Kx/1w86q/epKcmte75LNrEoT+lX8pBpavuAbvJWRXar7Hz8jrtF+e3vY751p0R8H9HdArwaCTNDDzHg/ScJK1Q==} engines: {node: '>=6'} @@ -13007,6 +13855,11 @@ packages: deprecated: https://github.com/lydell/resolve-url#deprecated dev: true + /resolve.exports@2.0.2: + resolution: {integrity: sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg==} + engines: {node: '>=10'} + dev: false + /resolve@1.19.0: resolution: {integrity: sha512-rArEXAgsBG4UgRGcynxWIWKFvh/XZCcS8UJdHhwy91zwAvCZIbcs+vAbflgBnNjYMs/i/i+/Ux6IZhML1yPvxg==} dependencies: @@ -13089,6 +13942,10 @@ packages: resolution: {integrity: sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA==} dev: true + /rfdc@1.4.1: + resolution: {integrity: sha512-q1b3N5QkRUWUl7iyylaaj3kOpIT0N2i9MqIEQXP73GVsN9cw3fdx8X63cEmWhJGi2PPCF23Ijp7ktmd39rawIA==} + dev: false + /rimraf@3.0.2: resolution: {integrity: sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==} hasBin: true @@ -13104,6 +13961,27 @@ packages: glob: 9.3.5 dev: true + /rollup-plugin-inject@3.0.2: + resolution: {integrity: sha512-ptg9PQwzs3orn4jkgXJ74bfs5vYz1NCZlSQMBUA0wKcGp5i5pA1AO3fOUEte8enhGUC+iapTCzEWw2jEFFUO/w==} + deprecated: This package has been deprecated and is no longer maintained. Please use @rollup/plugin-inject. + dependencies: + estree-walker: 0.6.1 + magic-string: 0.25.9 + rollup-pluginutils: 2.8.2 + dev: false + + /rollup-plugin-node-polyfills@0.2.1: + resolution: {integrity: sha512-4kCrKPTJ6sK4/gLL/U5QzVT8cxJcofO0OU74tnB19F40cmuAKSzH5/siithxlofFEjwvw1YAhPmbvGNA6jEroA==} + dependencies: + rollup-plugin-inject: 3.0.2 + dev: false + + /rollup-pluginutils@2.8.2: + resolution: {integrity: sha512-EEp9NhnUkwY8aif6bxgovPHMoMoNr2FulJziTndpt5H9RdwC47GSGuII9XxpSdzVGM0GWrNPHV6ie1LTNJPaLQ==} + dependencies: + estree-walker: 0.6.1 + dev: false + /rollup@2.79.1: resolution: {integrity: sha512-uKxbd0IhMZOhjAiD5oAFp7BqvkA4Dv47qpOCtaNvng4HBwdbWtdOh8f5nZNuk2rp51PMGk3bzfWu5oayNEuYnw==} engines: {node: '>=10.0.0'} @@ -13118,6 +13996,7 @@ packages: hasBin: true optionalDependencies: fsevents: 2.3.3 + dev: true /rollup@4.18.1: resolution: {integrity: sha512-Elx2UT8lzxxOXMpy5HWQGZqkrQOtrVDDa/bm9l10+U4rQnVzbL/LgZ4NOM1MPIDyHk69W4InuYDF5dzRh4Kw1A==} @@ -13145,6 +14024,11 @@ packages: fsevents: 2.3.3 dev: false + /run-applescript@7.0.0: + resolution: {integrity: sha512-9by4Ij99JUr/MCFBUkDKLWK3G9HVXmabKz9U5MlIAIuvuzkiOicRYs8XJLxX+xahD+mLiiCYDqF9dKAgtzKP1A==} + engines: {node: '>=18'} + dev: false + /run-async@2.4.1: resolution: {integrity: sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==} engines: {node: '>=0.12.0'} @@ -13241,6 +14125,14 @@ packages: extend-shallow: 2.0.1 kind-of: 6.0.3 + /selfsigned@2.4.1: + resolution: {integrity: sha512-th5B4L2U+eGLq1TVh7zNRGBapioSORUeymIydxgFpwww9d2qyKvtuPU2jJuHvYAwwqi2Y596QBL3eEqcPEYL8Q==} + engines: {node: '>=10'} + dependencies: + '@types/node-forge': 1.3.11 + node-forge: 1.3.1 + dev: false + /semver-compare@1.0.0: resolution: {integrity: sha512-YM3/ITh2MJ5MtzaM429anh+x2jiLVjqILF4m4oyQB18W7Ggea7BfqdH/wGMK7dDiMghv/6WG7znWMwUDzJiXow==} dev: true @@ -13268,6 +14160,7 @@ packages: hasBin: true dependencies: lru-cache: 6.0.0 + dev: true /semver@7.6.2: resolution: {integrity: sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==} @@ -13482,6 +14375,15 @@ packages: totalist: 3.0.1 dev: true + /sirv@2.0.4: + resolution: {integrity: sha512-94Bdh3cC2PKrbgSOUqTiGPWVZeSiXfKOVZNJniWoqrWrRkB1CJzBU3NEbiTsPcYy1lDsANA/THzS+9WBiy5nfQ==} + engines: {node: '>= 10'} + dependencies: + '@polka/url': 1.0.0-next.25 + mrmime: 2.0.0 + totalist: 3.0.1 + dev: false + /sisteransi@1.0.5: resolution: {integrity: sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==} dev: false @@ -13596,7 +14498,6 @@ packages: /source-map-js@1.2.0: resolution: {integrity: sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==} engines: {node: '>=0.10.0'} - dev: false /source-map-resolve@0.5.3: resolution: {integrity: sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw==} @@ -13660,6 +14561,11 @@ packages: resolution: {integrity: sha512-eWN+LnM3GR6gPu35WxNgbGl8rmY1AEmoMDvL/QD6zYmPWgywxWqJWNdLGT+ke8dKNWrcYgYjPpG5gbTfghP8rw==} dev: true + /speakingurl@14.0.1: + resolution: {integrity: sha512-1POYv7uv2gXoyGFpBCmpDVSNV74IfsWlDW216UPjbWufNf+bSU6GdbDsxdcxtfwb4xlI3yxzOTKClUosxARYrQ==} + engines: {node: '>=0.10.0'} + dev: false + /split-on-first@3.0.0: resolution: {integrity: sha512-qxQJTx2ryR0Dw0ITYyekNQWpz6f8dGd7vffGNflQQ3Iqj9NJ6qiZ7ELpZsJ/QBhIVAiDfXdag3+Gp8RvWa62AA==} engines: {node: '>=12'} @@ -13721,6 +14627,13 @@ packages: resolution: {integrity: sha512-1XMJE5fQo1jGH6Y/7ebnwPOBEkIEnT4QF32d5R1+VXdXveM0IBMJt8zfaxX1P3QhVwrYe+576+jkANtSS2mBbw==} dev: true + /stacktracey@2.1.8: + resolution: {integrity: sha512-Kpij9riA+UNg7TnphqjH7/CzctQ/owJGNbFkfEeve4Z4uxT5+JapVLFXcsurIfN34gnTWZNJ/f7NMG0E8JDzTw==} + dependencies: + as-table: 1.0.55 + get-source: 2.0.12 + dev: false + /static-extend@0.1.2: resolution: {integrity: sha512-72E9+uLc27Mt718pMHt9VMNiAL4LMsmDbBva8mxWUCkT07fSzEGMYUCk0XWY6lp0j6RBAG4cJ3mWuZv2OE3s0g==} engines: {node: '>=0.10.0'} @@ -13748,6 +14661,11 @@ packages: engines: {node: '>=18'} dev: false + /stoppable@1.1.0: + resolution: {integrity: sha512-KXDYZ9dszj6bzvnEMRYvxgeTHU74QBFL54XKtP3nyMuJ81CFYtABZ3bAzL2EdFUaEwJOBOgENyFj3R7oTzDyyw==} + engines: {node: '>=4', npm: '>=6'} + dev: false + /string-argv@0.3.1: resolution: {integrity: sha512-a1uQGz7IyVy9YwhqjZIZu1c8JO8dNIe20xBmSS6qu9kv++k3JGzCVmprbNN5Kn+BgzD5E7YYwg1CcjuJMRNsvg==} engines: {node: '>=0.6.19'} @@ -13935,6 +14853,13 @@ packages: ts-interface-checker: 0.1.13 dev: true + /superjson@2.2.1: + resolution: {integrity: sha512-8iGv75BYOa0xRJHK5vRLEjE2H/i4lulTjzpUXic3Eg8akftYjkmQDa8JARQ42rlczXyFR3IeRoeFCc7RxHsYZA==} + engines: {node: '>=16'} + dependencies: + copy-anything: 3.0.5 + dev: false + /supports-color@5.5.0: resolution: {integrity: sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==} engines: {node: '>=4'} @@ -13953,6 +14878,7 @@ packages: engines: {node: '>=10'} dependencies: has-flag: 4.0.0 + dev: true /supports-preserve-symlinks-flag@1.0.0: resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==} @@ -13970,7 +14896,7 @@ packages: resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==} dev: true - /tailwindcss@3.0.24(postcss@8.4.31): + /tailwindcss@3.0.24(postcss@8.4.39): resolution: {integrity: sha512-H3uMmZNWzG6aqmg9q07ZIRNIawoiEcNFKDfL+YzOPuPsXuDXxJxB9icqzLgdzKNwjG3SAro2h9SYav8ewXNgig==} engines: {node: '>=12.13.0'} hasBin: true @@ -13990,10 +14916,10 @@ packages: normalize-path: 3.0.0 object-hash: 3.0.0 picocolors: 1.0.0 - postcss: 8.4.31 - postcss-js: 4.0.1(postcss@8.4.31) - postcss-load-config: 3.1.4(postcss@8.4.31) - postcss-nested: 5.0.6(postcss@8.4.31) + postcss: 8.4.39 + postcss-js: 4.0.1(postcss@8.4.39) + postcss-load-config: 3.1.4(postcss@8.4.39) + postcss-nested: 5.0.6(postcss@8.4.39) postcss-selector-parser: 6.0.13 postcss-value-parser: 4.2.0 quick-lru: 5.1.1 @@ -14001,7 +14927,7 @@ packages: transitivePeerDependencies: - ts-node - /tailwindcss@3.2.4(postcss@8.4.31): + /tailwindcss@3.2.4(postcss@8.4.39): resolution: {integrity: sha512-AhwtHCKMtR71JgeYDaswmZXhPcW9iuI9Sp2LvZPo9upDZ7231ZJ7eA9RaURbhpXGVlrjX4cFNlB4ieTetEb7hQ==} engines: {node: '>=12.13.0'} hasBin: true @@ -14022,11 +14948,11 @@ packages: normalize-path: 3.0.0 object-hash: 3.0.0 picocolors: 1.0.0 - postcss: 8.4.31 - postcss-import: 14.1.0(postcss@8.4.31) - postcss-js: 4.0.1(postcss@8.4.31) - postcss-load-config: 3.1.4(postcss@8.4.31) - postcss-nested: 6.0.0(postcss@8.4.31) + postcss: 8.4.39 + postcss-import: 14.1.0(postcss@8.4.39) + postcss-js: 4.0.1(postcss@8.4.39) + postcss-load-config: 3.1.4(postcss@8.4.39) + postcss-nested: 6.0.0(postcss@8.4.39) postcss-selector-parser: 6.0.13 postcss-value-parser: 4.2.0 quick-lru: 5.1.1 @@ -14137,6 +15063,13 @@ packages: engines: {node: '>=4'} dev: true + /tiny-glob@0.2.9: + resolution: {integrity: sha512-g/55ssRPUjShh+xkfx9UPDXqhckHEsHr4Vd9zX55oSdGZc/MD0m3sferOkwWtp98bv+kcVfEHtRJgBVJzelrzg==} + dependencies: + globalyzer: 0.1.0 + globrex: 0.1.2 + dev: false + /tinybench@2.5.1: resolution: {integrity: sha512-65NKvSuAVDP/n4CqH+a9w2kTlLReS9vhsAP06MWx+/89nMinJyB2icyl58RIcqCmIggpojIGeuJGhjU1aGMBSg==} dev: true @@ -14218,7 +15151,6 @@ packages: /totalist@3.0.1: resolution: {integrity: sha512-sf4i37nQ2LBx4m3wB74y+ubopq6W/dIzXg0FDGjsYnZHVa1Da8FH853wlL2gtUhg+xJXjfk3kUZS3BRoQeoQBQ==} engines: {node: '>=6'} - dev: true /tough-cookie@4.1.3: resolution: {integrity: sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw==} @@ -14448,10 +15380,10 @@ packages: resolution: {integrity: sha512-OJabfkAg1WLZSqJAJ0Z6Sdt3utnbzr/jh+NAHoyWHJe8CMSy79Gm085094M9nvTPy22KzTVn5Zq5mbapCI/hPA==} dev: false - /typescript-auto-import-cache@0.3.0: - resolution: {integrity: sha512-Rq6/q4O9iyqUdjvOoyas7x/Qf9nWUMeqpP3YeTaLA+uECgfy5wOhfOS+SW/+fZ/uI/ZcKaf+2/ZhFzXh8xfofQ==} + /typescript-auto-import-cache@0.3.3: + resolution: {integrity: sha512-ojEC7+Ci1ij9eE6hp8Jl9VUNnsEKzztktP5gtYNRMrTmfXVwA1PITYYAkpxCvvupdSYa/Re51B6KMcv1CTZEUA==} dependencies: - semver: 7.5.4 + semver: 7.6.2 dev: false /typescript-compare@0.0.2: @@ -14489,6 +15421,10 @@ packages: resolution: {integrity: sha512-o+ORpgGwaYQXgqGDwd+hkS4PuZ3QnmqMMxRuajK/a38L6fTpcE5GPIfrf+L/KemFzfUpeUQc1rRS1iDBozvnFA==} dev: true + /ufo@1.5.3: + resolution: {integrity: sha512-Y7HYmWaFwPUmkoQCUIAYpKqkOf+SbVj/2fJJZ4RJMCfZp0rTGwRbzQD+HghfnhKOjL9E01okqz+ncJskGYfBNw==} + dev: false + /uglify-js@3.17.4: resolution: {integrity: sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g==} engines: {node: '>=0.8.0'} @@ -14508,11 +15444,28 @@ packages: /undici-types@5.25.3: resolution: {integrity: sha512-Ga1jfYwRn7+cP9v8auvEXN1rX3sWqlayd4HP7OKk4mZWylEmu3KzXDUGrQUN6Ol7qo1gPvB2e5gX6udnyEPgdA==} - dev: true /undici-types@5.26.5: resolution: {integrity: sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==} + /undici@5.28.4: + resolution: {integrity: sha512-72RFADWFqKmUb2hmmvNODKL3p9hcB6Gt2DOQMis1SEBaV6a4MH8soBvzg+95CYhCKPFedut2JY9bMfrDl9D23g==} + engines: {node: '>=14.0'} + dependencies: + '@fastify/busboy': 2.1.1 + dev: false + + /unenv-nightly@1.10.0-1717606461.a117952: + resolution: {integrity: sha512-u3TfBX02WzbHTpaEfWEKwDijDSFAHcgXkayUZ+MVDrjhLFvgAJzFGTSTmwlEhwWi2exyRQey23ah9wELMM6etg==} + dependencies: + consola: 3.2.3 + defu: 6.1.4 + mime: 3.0.0 + node-fetch-native: 1.6.4 + pathe: 1.1.2 + ufo: 1.5.3 + dev: false + /unified@11.0.5: resolution: {integrity: sha512-xKvGhPWw3k84Qjh8bI3ZeJjqnyadK+GEFtazSfZv/rKeTkTjOJho6mFqh2SM96iIcZokxiOpg78GazTSg8+KHA==} dependencies: @@ -14640,7 +15593,6 @@ packages: /universalify@2.0.1: resolution: {integrity: sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==} engines: {node: '>= 10.0.0'} - dev: true /unpipe@1.0.0: resolution: {integrity: sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==} @@ -14674,6 +15626,7 @@ packages: browserslist: 4.22.1 escalade: 3.1.1 picocolors: 1.0.0 + dev: true /update-browserslist-db@1.1.0(browserslist@4.23.2): resolution: {integrity: sha512-EdRAaAyk2cUE1wOf2DkEhzxqOQvFOoRJFNS6NeyJ01Gp2beMRpBAINjM2iDXE3KCuKhwnvHIQCJm6ThL2Z+HzQ==} @@ -14799,6 +15752,14 @@ packages: vfile-message: 4.0.2 dev: false + /vite-hot-client@0.2.3(vite@5.3.3): + resolution: {integrity: sha512-rOGAV7rUlUHX89fP2p2v0A2WWvV3QMX2UYq0fRqsWSvFvev4atHWqjwGoKaZT1VTKyLGk533ecu3eyd0o59CAg==} + peerDependencies: + vite: ^2.6.0 || ^3.0.0 || ^4.0.0 || ^5.0.0-0 + dependencies: + vite: 5.3.3(@types/node@18.18.14) + dev: false + /vite-node@0.28.4(@types/node@18.18.14): resolution: {integrity: sha512-KM0Q0uSG/xHHKOJvVHc5xDBabgt0l70y7/lWTR7Q0pR5/MrYxadT+y32cJOE65FfjGmJgxpVEEY+69btJgcXOQ==} engines: {node: '>=v14.16.0'} @@ -15019,6 +15980,31 @@ packages: vite: 4.3.9(@types/node@18.18.14) dev: true + /vite-plugin-inspect@0.8.4(vite@5.3.3): + resolution: {integrity: sha512-G0N3rjfw+AiiwnGw50KlObIHYWfulVwaCBUBLh2xTW9G1eM9ocE5olXkEYUbwyTmX+azM8duubi+9w5awdCz+g==} + engines: {node: '>=14'} + peerDependencies: + '@nuxt/kit': '*' + vite: ^3.1.0 || ^4.0.0 || ^5.0.0-0 + peerDependenciesMeta: + '@nuxt/kit': + optional: true + dependencies: + '@antfu/utils': 0.7.10 + '@rollup/pluginutils': 5.1.0 + debug: 4.3.5 + error-stack-parser-es: 0.1.4 + fs-extra: 11.2.0 + open: 10.1.0 + perfect-debounce: 1.0.0 + picocolors: 1.0.1 + sirv: 2.0.4 + vite: 5.3.3(@types/node@18.18.14) + transitivePeerDependencies: + - rollup + - supports-color + dev: false + /vite-plugin-svgr@3.2.0(typescript@5.0.4)(vite@4.3.5): resolution: {integrity: sha512-Uvq6niTvhqJU6ga78qLKBFJSDvxWhOnyfQSoKpDPMAGxJPo5S3+9hyjExE5YDj6Lpa4uaLkGc1cBgxXov+LjSw==} peerDependencies: @@ -15049,6 +16035,46 @@ packages: - typescript dev: true + /vite-plugin-vue-devtools@7.3.5(vite@5.3.3)(vue@3.2.30): + resolution: {integrity: sha512-6omLXTfYu0bmSmncPSbj4mdMPB3t5dAZkUyriJikahGEnvv5gynHlydDsJShHT6l/5dCkvmSesSji/2a6FfutQ==} + engines: {node: '>=v14.21.3'} + peerDependencies: + vite: ^3.1.0 || ^4.0.0-0 || ^5.0.0-0 + dependencies: + '@vue/devtools-core': 7.3.5(vite@5.3.3)(vue@3.2.30) + '@vue/devtools-kit': 7.3.5 + '@vue/devtools-shared': 7.3.5 + execa: 8.0.1 + sirv: 2.0.4 + vite: 5.3.3(@types/node@18.18.14) + vite-plugin-inspect: 0.8.4(vite@5.3.3) + vite-plugin-vue-inspector: 5.1.2(vite@5.3.3) + transitivePeerDependencies: + - '@nuxt/kit' + - rollup + - supports-color + - vue + dev: false + + /vite-plugin-vue-inspector@5.1.2(vite@5.3.3): + resolution: {integrity: sha512-M+yH2LlQtVNzJAljQM+61CqDXBvHim8dU5ImGaQuwlo13tMDHue5D7IC20YwDJuWDODiYc/cZBUYspVlyPf2vQ==} + peerDependencies: + vite: ^3.0.0-0 || ^4.0.0-0 || ^5.0.0-0 + dependencies: + '@babel/core': 7.24.8 + '@babel/plugin-proposal-decorators': 7.24.7(@babel/core@7.24.8) + '@babel/plugin-syntax-import-attributes': 7.24.7(@babel/core@7.24.8) + '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.24.8) + '@babel/plugin-transform-typescript': 7.23.5(@babel/core@7.24.8) + '@vue/babel-plugin-jsx': 1.1.5(@babel/core@7.24.8) + '@vue/compiler-dom': 3.3.9 + kolorist: 1.8.0 + magic-string: 0.30.10 + vite: 5.3.3(@types/node@18.18.14) + transitivePeerDependencies: + - supports-color + dev: false + /vite@3.2.5(@types/node@18.18.14): resolution: {integrity: sha512-4mVEpXpSOgrssFZAOmGIr85wPHKvaDAcXqxVxVRZhljkJOMZi1ibLibzjLHzJvcok8BMguLc7g1W6W/GqZbLdQ==} engines: {node: ^14.18.0 || >=16.0.0} @@ -15215,6 +16241,7 @@ packages: rollup: 3.29.4 optionalDependencies: fsevents: 2.3.3 + dev: true /vite@4.3.9(@types/node@20.8.4): resolution: {integrity: sha512-qsTNZjO9NoJNW7KnOrgYwczm0WctJ8m/yqYAMAK9Lxt4SoySUfS5S8ia9K7JHpa3KEeMfyF8LoJ3c5NeBJy6pg==} @@ -15475,49 +16502,53 @@ packages: - terser dev: true - /volar-service-css@0.0.16(@volar/language-service@1.10.10): - resolution: {integrity: sha512-gK/XD35t/P3SQrUuS8LMlCnE2ItIk+kXI6gPvBYl1NZ7O+tLH8rUWXA32YgpwNoITxYrm/G1seaq08zs4aiPvg==} + /volar-service-css@0.0.59(@volar/language-service@2.4.0-alpha.15): + resolution: {integrity: sha512-gLNjJnECbalPvQB7qeJjhkDN8sR5M3ItbVYjnyio61aHaWptIiXm/HfDahcQ2ApwmvWidkMWWegjGq5L0BENDA==} peerDependencies: - '@volar/language-service': ~1.10.0 + '@volar/language-service': ~2.4.0-alpha.12 peerDependenciesMeta: '@volar/language-service': optional: true dependencies: - '@volar/language-service': 1.10.10 - vscode-css-languageservice: 6.2.11 + '@volar/language-service': 2.4.0-alpha.15 + vscode-css-languageservice: 6.3.0 + vscode-languageserver-textdocument: 1.0.11 vscode-uri: 3.0.8 dev: false - /volar-service-emmet@0.0.16(@volar/language-service@1.10.10): - resolution: {integrity: sha512-8sWWywzVJOD+PWDArOXDWbiRlM7+peydFhXJT71i4X1WPW32RyPxn6FypvciO+amqpfZP2rXfB9eibIJ+EofSQ==} + /volar-service-emmet@0.0.59(@volar/language-service@2.4.0-alpha.15): + resolution: {integrity: sha512-6EynHcuMwMBETpK29TbZvIMmvzdVG+Tkokk9VWfZeI+SwDptk2tgdhEqiXXvIkqYNgbuu73Itp66lpH76cAU+Q==} peerDependencies: - '@volar/language-service': ~1.10.0 + '@volar/language-service': ~2.4.0-alpha.12 peerDependenciesMeta: '@volar/language-service': optional: true dependencies: - '@volar/language-service': 1.10.10 - '@vscode/emmet-helper': 2.9.2 - volar-service-html: 0.0.16(@volar/language-service@1.10.10) + '@emmetio/css-parser': 0.4.0 + '@emmetio/html-matcher': 1.3.0 + '@volar/language-service': 2.4.0-alpha.15 + '@vscode/emmet-helper': 2.9.3 + vscode-uri: 3.0.8 dev: false - /volar-service-html@0.0.16(@volar/language-service@1.10.10): - resolution: {integrity: sha512-/oEXXgry++1CnTXQBUNf9B8MZfTlYZuJfZA7Zx9MN7WS4ZPxk3BFOdal/cXH6RNR2ruNEYr5QTW9rsqtoUscag==} + /volar-service-html@0.0.59(@volar/language-service@2.4.0-alpha.15): + resolution: {integrity: sha512-hEXOsYpILDlITZxnqRLV9OepVWD63GZBsyjMxszwdzlxvGZjzbGcBBinJGGJRwFIV8djdJwnt91bkdg1V5tj6Q==} peerDependencies: - '@volar/language-service': ~1.10.0 + '@volar/language-service': ~2.4.0-alpha.12 peerDependenciesMeta: '@volar/language-service': optional: true dependencies: - '@volar/language-service': 1.10.10 - vscode-html-languageservice: 5.1.1 + '@volar/language-service': 2.4.0-alpha.15 + vscode-html-languageservice: 5.3.0 + vscode-languageserver-textdocument: 1.0.11 vscode-uri: 3.0.8 dev: false - /volar-service-prettier@0.0.16(@volar/language-service@1.10.10)(prettier@2.3.2): - resolution: {integrity: sha512-Kj2ZdwJGEvfYbsHW8Sjrew/7EB4PgRoas4f8yAJzUUVxIC/kvhUwLDxQc8+N2IibomN76asJGWe+i6VZZvgIkw==} + /volar-service-prettier@0.0.59(@volar/language-service@2.4.0-alpha.15)(prettier@2.3.2): + resolution: {integrity: sha512-FmBR4lsgFRGR3V0LnxZZal0WqdOJjuLL6mQSj4p57M15APtQwuocG/FiF+ONGFnwRXMOIBDBTCARdth+TKgL3A==} peerDependencies: - '@volar/language-service': ~1.10.0 + '@volar/language-service': ~2.4.0-alpha.12 prettier: ^2.2 || ^3.0 peerDependenciesMeta: '@volar/language-service': @@ -15525,53 +16556,53 @@ packages: prettier: optional: true dependencies: - '@volar/language-service': 1.10.10 + '@volar/language-service': 2.4.0-alpha.15 prettier: 2.3.2 + vscode-uri: 3.0.8 dev: false - /volar-service-typescript-twoslash-queries@0.0.16(@volar/language-service@1.10.10): - resolution: {integrity: sha512-0gPrkDTD2bMj2AnSNykOKhfmPnBFE2LS1lF3LWA7qu1ChRnJF0sodwCCbbeNYJ9+yth956ApoU1BVQ8UrMg+yw==} + /volar-service-typescript-twoslash-queries@0.0.59(@volar/language-service@2.4.0-alpha.15): + resolution: {integrity: sha512-skm8e6yhCIkqLwJB6S9MqT5lO9LNFuMD3dYxKpmOZs1CKbXmCZZTmLfEaD5VkJae1xdleEDZFFTHl2O5HLjOGQ==} peerDependencies: - '@volar/language-service': ~1.10.0 + '@volar/language-service': ~2.4.0-alpha.12 peerDependenciesMeta: '@volar/language-service': optional: true dependencies: - '@volar/language-service': 1.10.10 + '@volar/language-service': 2.4.0-alpha.15 + vscode-uri: 3.0.8 dev: false - /volar-service-typescript@0.0.16(@volar/language-service@1.10.10)(@volar/typescript@1.10.10): - resolution: {integrity: sha512-k/qFKM2oxs/3fhbr/vcBSHnCLZ1HN3Aeh+bGvV9Lc9qIhrNyCVsDFOUJN1Qp4dI72+Y+eFSIDCLHmFEZdsP2EA==} + /volar-service-typescript@0.0.59(@volar/language-service@2.4.0-alpha.15): + resolution: {integrity: sha512-VCOpfiu+lUo5lapWLB5L5vmQGtwzmNWn5MueV915eku7blpphmE+Z7hCNcL1NApn7AetXWhiblv8ZhmUx/dGIA==} peerDependencies: - '@volar/language-service': ~1.10.0 - '@volar/typescript': ~1.10.0 + '@volar/language-service': ~2.4.0-alpha.12 peerDependenciesMeta: '@volar/language-service': optional: true dependencies: - '@volar/language-service': 1.10.10 - '@volar/typescript': 1.10.10 + '@volar/language-service': 2.4.0-alpha.15 path-browserify: 1.0.1 - semver: 7.5.4 - typescript-auto-import-cache: 0.3.0 + semver: 7.6.2 + typescript-auto-import-cache: 0.3.3 vscode-languageserver-textdocument: 1.0.11 vscode-nls: 5.2.0 vscode-uri: 3.0.8 dev: false - /vscode-css-languageservice@6.2.11: - resolution: {integrity: sha512-qn49Wa6K94LnizpVxmlYrcPf1Cb36gq1nNueW0COhi4shylXBzET5wuDbH8ZWQlJD0HM5Mmnn7WE9vQVVs+ULA==} + /vscode-css-languageservice@6.3.0: + resolution: {integrity: sha512-nU92imtkgzpCL0xikrIb8WvedV553F2BENzgz23wFuok/HLN5BeQmroMy26pUwFxV2eV8oNRmYCUv8iO7kSMhw==} dependencies: - '@vscode/l10n': 0.0.16 + '@vscode/l10n': 0.0.18 vscode-languageserver-textdocument: 1.0.11 vscode-languageserver-types: 3.17.5 vscode-uri: 3.0.8 dev: false - /vscode-html-languageservice@5.1.1: - resolution: {integrity: sha512-JenrspIIG/Q+93R6G3L6HdK96itSisMynE0glURqHpQbL3dKAKzdm8L40lAHNkwJeBg+BBPpAshZKv/38onrTQ==} + /vscode-html-languageservice@5.3.0: + resolution: {integrity: sha512-C4Z3KsP5Ih+fjHpiBc5jxmvCl+4iEwvXegIrzu2F5pktbWvQaBT3YkVPk8N+QlSSMk8oCG6PKtZ/Sq2YHb5e8g==} dependencies: - '@vscode/l10n': 0.0.16 + '@vscode/l10n': 0.0.18 vscode-languageserver-textdocument: 1.0.11 vscode-languageserver-types: 3.17.5 vscode-uri: 3.0.8 @@ -15884,6 +16915,54 @@ packages: resolution: {integrity: sha512-gvVzJFlPycKc5dZN4yPkP8w7Dc37BtP1yczEneOb4uq34pXZcvrtRTmWV8W+Ume+XCxKgbjM+nevkyFPMybd4Q==} dev: true + /workerd@1.20240701.0: + resolution: {integrity: sha512-qSgNVqauqzNCij9MaJLF2c2ko3AnFioVSIxMSryGbRK+LvtGr9BKBt6JOxCb24DoJASoJDx3pe3DJHBVydUiBg==} + engines: {node: '>=16'} + hasBin: true + requiresBuild: true + optionalDependencies: + '@cloudflare/workerd-darwin-64': 1.20240701.0 + '@cloudflare/workerd-darwin-arm64': 1.20240701.0 + '@cloudflare/workerd-linux-64': 1.20240701.0 + '@cloudflare/workerd-linux-arm64': 1.20240701.0 + '@cloudflare/workerd-windows-64': 1.20240701.0 + dev: false + + /wrangler@3.64.0(@cloudflare/workers-types@4.20240712.0): + resolution: {integrity: sha512-q2VQADJXzuOkXs9KIfPSx7UCZHBoxsqSNbJDLkc2pHpGmsyNQXsJRqjMoTg/Kls7O3K9A7EGnzGr7+Io2vE6AQ==} + engines: {node: '>=16.17.0'} + hasBin: true + peerDependencies: + '@cloudflare/workers-types': ^4.20240620.0 + peerDependenciesMeta: + '@cloudflare/workers-types': + optional: true + dependencies: + '@cloudflare/kv-asset-handler': 0.3.4 + '@cloudflare/workers-types': 4.20240712.0 + '@esbuild-plugins/node-globals-polyfill': 0.2.3(esbuild@0.17.19) + '@esbuild-plugins/node-modules-polyfill': 0.2.2(esbuild@0.17.19) + blake3-wasm: 2.1.5 + chokidar: 3.6.0 + date-fns: 3.6.0 + esbuild: 0.17.19 + miniflare: 3.20240701.0 + nanoid: 3.3.7 + path-to-regexp: 6.2.2 + resolve: 1.22.8 + resolve.exports: 2.0.2 + selfsigned: 2.4.1 + source-map: 0.6.1 + unenv: /unenv-nightly@1.10.0-1717606461.a117952 + xxhash-wasm: 1.0.2 + optionalDependencies: + fsevents: 2.3.3 + transitivePeerDependencies: + - bufferutil + - supports-color + - utf-8-validate + dev: false + /wrap-ansi@6.2.0: resolution: {integrity: sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==} engines: {node: '>=8'} @@ -15963,6 +17042,19 @@ packages: optional: true dev: true + /ws@8.18.0: + resolution: {integrity: sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==} + engines: {node: '>=10.0.0'} + peerDependencies: + bufferutil: ^4.0.1 + utf-8-validate: '>=5.0.2' + peerDependenciesMeta: + bufferutil: + optional: true + utf-8-validate: + optional: true + dev: false + /xml-name-validator@4.0.0: resolution: {integrity: sha512-ICP2e+jsHvAj2E2lIHxa5tjXRlKDJo4IdvPvCXbXQGdzSfmSpNVyIKMvoZHjDY9DP0zV17iI85o90vRFXNccRw==} engines: {node: '>=12'} @@ -15976,6 +17068,10 @@ packages: resolution: {integrity: sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==} engines: {node: '>=0.4'} + /xxhash-wasm@1.0.2: + resolution: {integrity: sha512-ibF0Or+FivM9lNrg+HGJfVX8WJqgo+kCLDc4vx6xMeTce7Aj+DLttKbxxRR/gNLSAelRc1omAPlJ77N/Jem07A==} + dev: false + /y18n@5.0.8: resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} engines: {node: '>=10'} @@ -15989,6 +17085,7 @@ packages: /yallist@4.0.0: resolution: {integrity: sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==} + dev: true /yaml@1.10.2: resolution: {integrity: sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==} @@ -16047,6 +17144,14 @@ packages: resolution: {integrity: sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==} engines: {node: '>=12.20'} + /youch@3.3.3: + resolution: {integrity: sha512-qSFXUk3UZBLfggAW3dJKg0BMblG5biqSF8M34E06o5CSsZtH92u9Hqmj2RzGiHDi64fhe83+4tENFP2DB6t6ZA==} + dependencies: + cookie: 0.5.0 + mustache: 4.2.0 + stacktracey: 2.1.8 + dev: false + /z-schema@5.0.5: resolution: {integrity: sha512-D7eujBWkLa3p2sIpJA0d1pr7es+a7m0vFAnZLlCEKq/Ij2k0MLi9Br2UPxoxdYystm5K1yeBGzub0FlYUEWj2Q==} engines: {node: '>=8.0.0'} From 8b5f9f600a9d2e7cd36d47ed1d3a1318ada639ad Mon Sep 17 00:00:00 2001 From: Alexander Heimbuch Date: Mon, 15 Jul 2024 10:03:53 +0200 Subject: [PATCH 17/20] fix(page): compatibility with cloudflare --- apps/page/astro.config.mjs | 2 +- apps/page/package.json | 7 +- apps/page/service-worker.ts | 2 +- apps/page/src/app.ts | 4 +- apps/page/src/features/PageFooter.vue | 11 +- apps/page/src/features/PageHeader.vue | 6 +- apps/page/src/features/Search.vue | 16 +- apps/page/src/features/playbar/PlayBar.vue | 12 +- .../page/src/features/subscribe/Subscribe.vue | 8 +- apps/page/src/layouts/Layout.astro | 2 +- apps/page/src/lib/caching.ts | 16 +- apps/page/src/logic/sagas/data.sagas.ts | 12 +- apps/page/src/logic/sagas/episode.sagas.ts | 9 +- apps/page/src/logic/sagas/index.ts | 2 +- apps/page/src/logic/sagas/search.sagas.ts | 56 ++-- apps/page/src/logic/store/selectors.ts | 1 - apps/page/src/logic/store/state.ts | 2 - .../logic/store/stores/contributors.store.ts | 2 +- .../src/logic/store/stores/episodes.store.ts | 2 +- .../src/logic/store/stores/playbar.store.ts | 10 +- .../src/logic/store/stores/podcast.store.ts | 10 +- .../src/logic/store/stores/runtime.store.ts | 16 +- .../page/src/logic/store/stores/view.store.ts | 2 +- apps/page/src/middleware/router.ts | 7 +- apps/page/src/middleware/store.ts | 2 +- apps/page/src/screens/archive/LoadMore.vue | 21 +- apps/page/src/screens/episodes/Navigation.vue | 12 +- apps/page/src/types/feed.types.ts | 2 - pnpm-lock.yaml | 271 ++++++++---------- 29 files changed, 261 insertions(+), 264 deletions(-) diff --git a/apps/page/astro.config.mjs b/apps/page/astro.config.mjs index f648b7a03..ab108a2c5 100644 --- a/apps/page/astro.config.mjs +++ b/apps/page/astro.config.mjs @@ -1,6 +1,6 @@ import { defineConfig } from 'astro/config'; import cloudflare from '@astrojs/cloudflare'; -import node from '@astrojs/node'; +// import node from '@astrojs/node'; import vue from '@astrojs/vue'; import tailwind from '@astrojs/tailwind'; diff --git a/apps/page/package.json b/apps/page/package.json index 34fcdc239..d8063cfa1 100644 --- a/apps/page/package.json +++ b/apps/page/package.json @@ -23,7 +23,7 @@ "@astrojs/vue": "4.5.0", "@astrojs/cloudflare": "11.0.1", "astro": "4.11.5", - "vue": "3.2.30", + "vue": "3.4.31", "fast-xml-parser": "4.3.2", "lodash-es": "4.17.21", "redux": "4.2.1", @@ -33,7 +33,7 @@ "reselect": "4.1.8", "vue-i18n": "9.8.0", "scroll-into-view-if-needed": "3.1.0", - "micromatch": "4.0.5", + "multimatch": "7.0.0", "@m31coding/fuzzy-search": "1.0.1", "color.js": "1.2.0", "farbraum": "0.2.1" @@ -42,7 +42,6 @@ "tailwindcss": "3.0.24", "typescript": "5.3.2", "@types/lodash-es": "4.17.12", - "@types/redux-actions": "2.6.5", - "@types/micromatch":"4.0.6" + "@types/redux-actions": "2.6.5" } } diff --git a/apps/page/service-worker.ts b/apps/page/service-worker.ts index a50082afa..3262de9a1 100644 --- a/apps/page/service-worker.ts +++ b/apps/page/service-worker.ts @@ -23,7 +23,7 @@ const getCache = async (): Promise => { const handleRequest = async (request: Request) => { const cache = await getCache(); - const cacheKey = await getCacheKey(); + const cacheKey = getCacheKey(); if (!cache || !cacheKey) { return fetch(request); diff --git a/apps/page/src/app.ts b/apps/page/src/app.ts index ee99c0ea3..436b62a13 100644 --- a/apps/page/src/app.ts +++ b/apps/page/src/app.ts @@ -2,7 +2,7 @@ import { provideStore } from 'redux-vuex'; import { createI18n } from 'vue-i18n'; import type { App } from 'vue'; import { messages, defaultLang, getLanguage } from './i18n'; -import { store, actions } from './logic'; +import { store } from './logic'; export default (app: App) => { const i18n = createI18n({ @@ -13,5 +13,5 @@ export default (app: App) => { }); app.use(i18n); - provideStore({ app, store, actions }); + provideStore({ app, store }); }; diff --git a/apps/page/src/features/PageFooter.vue b/apps/page/src/features/PageFooter.vue index 43403bab0..605c2d99c 100644 --- a/apps/page/src/features/PageFooter.vue +++ b/apps/page/src/features/PageFooter.vue @@ -4,7 +4,7 @@ >
- {{ $t('FOOTER.COPYRIGHT', { copyright: state.copyright }) }} + {{ t('FOOTER.COPYRIGHT', { copyright: state.copyright }) }}
{{ $t('FOOTER.CONTACT', { name: state.owner }) }}{{ t('FOOTER.CONTACT', { name: state.owner }) }} - {{ $t('FOOTER.CONTACT', { name: state.owner }) }} + {{ t('FOOTER.CONTACT', { name: state.owner }) }}
@@ -26,7 +26,7 @@ href="https://podlove.org" target="_blank" rel="nofollow noopener" - >{{ $t('FOOTER.CREATED_WITH', { name: 'Podlove', buildDate }) }}{{ t('FOOTER.CREATED_WITH', { name: 'Podlove', buildDate }) }}
@@ -36,8 +36,11 @@ + diff --git a/apps/page/src/lib/caching.ts b/apps/page/src/lib/caching.ts index c664a5df7..d35cf9394 100644 --- a/apps/page/src/lib/caching.ts +++ b/apps/page/src/lib/caching.ts @@ -1,9 +1,15 @@ -import crypto from 'crypto'; -export const etag = (input: any): string => { +export const etag = async (input: any): Promise => { const entity = JSON.stringify(input); - const hash = crypto.createHash('sha1').update(entity, 'utf8').digest('base64').substring(0, 27); + + const textAsBuffer = new TextEncoder().encode(entity); + const hashBuffer = await crypto.subtle.digest("SHA-1", textAsBuffer); + const hashArray = Array.from(new Uint8Array(hashBuffer)); + const hash = hashArray + .map((item) => item.toString(16).padStart(2, "0")) + .join(""); + const len = Buffer.byteLength(entity, 'utf8'); - return len.toString(16) + '-' + hash; -}; + return len.toString(16) + '-' + Buffer.from(hash).toString('base64').substring(0, 27); +} diff --git a/apps/page/src/logic/sagas/data.sagas.ts b/apps/page/src/logic/sagas/data.sagas.ts index 7c7e67c6c..fb34ee2fe 100644 --- a/apps/page/src/logic/sagas/data.sagas.ts +++ b/apps/page/src/logic/sagas/data.sagas.ts @@ -4,10 +4,18 @@ import { actions } from '../store'; import parseFeed from '../data/feed-parser'; import type { initializeAppPayload } from '../store/stores/runtime.store'; import type { Podcast } from '../../types/feed.types'; +import { version } from '../../../package.json'; +import { etag } from '../../lib/caching.js'; function* fetchData(input: Action) { - const feedData: Podcast = yield parseFeed(input.payload); - yield put(actions.lifecycle.dataFetched(feedData)); + const data: Podcast = yield parseFeed(input.payload); + + const cacheKey: string | null = data.etag ? yield etag({ + feed: data.etag, + version + }) : null + + yield put(actions.lifecycle.dataFetched({ data, cacheKey })); } export default ({ selectInitializedApp }: { selectInitializedApp: (input: any) => boolean }) => { diff --git a/apps/page/src/logic/sagas/episode.sagas.ts b/apps/page/src/logic/sagas/episode.sagas.ts index 0a3034a35..e912779b0 100644 --- a/apps/page/src/logic/sagas/episode.sagas.ts +++ b/apps/page/src/logic/sagas/episode.sagas.ts @@ -1,24 +1,21 @@ -import { put, takeEvery, select, delay, all } from 'redux-saga/effects'; +import { put, takeEvery, select } from 'redux-saga/effects'; import { requestPlay, requestPause, backendLoadingStart, requestLoad, - backendLoadingEnd } from '@podlove/player-actions/play'; import { backendPlaytime, requestPlaytime } from '@podlove/player-actions/timepiece'; import { takeOnce } from '@podlove/player-sagas/helper'; import { setRate, setVolume, mute, unmute } from '@podlove/player-actions/audio'; import { init, ready } from '@podlove/player-actions/lifecycle'; -import { castArray, isNil } from 'lodash-es'; +import { isNil } from 'lodash-es'; import type { Action } from 'redux-actions'; import { actions } from '../store'; -import type { Episode, Show, Transcript } from '../../types/feed.types'; +import type { Episode, Show } from '../../types/feed.types'; import type { playEpisodePayload } from '../store/stores/player.store'; import { toPlayerEpisode } from '../transformations/player'; -import { resolveTranscripts } from '../data/feed-parser'; -import type { requestEpisodePayload } from '../store/stores/episodes.store'; export default ({ selectEpisode, diff --git a/apps/page/src/logic/sagas/index.ts b/apps/page/src/logic/sagas/index.ts index 879728e3a..599190f5b 100644 --- a/apps/page/src/logic/sagas/index.ts +++ b/apps/page/src/logic/sagas/index.ts @@ -61,7 +61,7 @@ export async function createSideEffects() { sagas.push(searchSaga({ selectInitialized: selectors.search.initialized, selectEpisodes: selectors.episodes.list, - selectContributors: selectors.contributors.list, + // selectContributors: selectors.contributors.list, selectVisible: selectors.search.visible, selectResults: selectors.search.results, selectSelectedResult: selectors.search.selectedResult, diff --git a/apps/page/src/logic/sagas/search.sagas.ts b/apps/page/src/logic/sagas/search.sagas.ts index 2daf752ba..aab3aa59a 100644 --- a/apps/page/src/logic/sagas/search.sagas.ts +++ b/apps/page/src/logic/sagas/search.sagas.ts @@ -12,21 +12,21 @@ import type { import { actions } from '../store'; import { resolveTranscripts } from '../data/feed-parser'; import type { Episode, Person, Transcript } from '../../types/feed.types'; -import { findPerson } from '../../lib/persons'; +// import { findPerson } from '../../lib/persons'; import { proxy } from '../../lib/url'; export default ({ selectVisible, selectInitialized, selectEpisodes, - selectContributors, + // selectContributors, selectResults, selectSelectedResult }: { selectVisible: (input: any) => boolean; selectInitialized: (input: any) => boolean; selectEpisodes: (input: any) => Episode[]; - selectContributors: (input: any) => Person[]; + // selectContributors: (input: any) => Person[]; selectResults: (input: any) => { id: string | number }[]; selectSelectedResult: (input: any) => string | null; }) => { @@ -87,34 +87,34 @@ export default ({ yield put(actions.search.initialize('transcripts')); } - function* createContributorsSearchIndex(contributors: Person[], episodes: Episode[]) { - const results = contributors.map((contributor) => { - const attendedEpisodes = episodes.filter((episode) => - findPerson(episode.contributors, contributor.id) - ); - - return { - ...contributor, - id: `contributor-${contributor.id}`, - episode: { - title: attendedEpisodes.map(({ title }) => title).join(' '), - description: attendedEpisodes.map(({ description }) => description).join(' ') - } - }; - }); - - CONTRIBUTORS.indexEntities( - flattenDeep(results), - (e: any) => e.id, - (e: any) => [e.episode.title, e.episode.description] - ); - - yield put(actions.search.initialize('contributors')); - } + // function* createContributorsSearchIndex(contributors: Person[], episodes: Episode[]) { + // const results = contributors.map((contributor) => { + // const attendedEpisodes = episodes.filter((episode) => + // findPerson(episode.contributors, contributor.id) + // ); + + // return { + // ...contributor, + // id: `contributor-${contributor.id}`, + // episode: { + // title: attendedEpisodes.map(({ title }) => title).join(' '), + // description: attendedEpisodes.map(({ description }) => description).join(' ') + // } + // }; + // }); + + // CONTRIBUTORS.indexEntities( + // flattenDeep(results), + // (e: any) => e.id, + // (e: any) => [e.episode.title, e.episode.description] + // ); + + // yield put(actions.search.initialize('contributors')); + // } function* createSearchIndex() { const episodes: Episode[] = yield select(selectEpisodes); - const contributors: Person[] = yield select(selectContributors); + // const contributors: Person[] = yield select(selectContributors); const resolvedEpisodes: Episode[] = yield all(episodes.map(fetchTranscripts)); yield createEpisodesSearchIndex(resolvedEpisodes); yield createTranscriptsSearchIndex(resolvedEpisodes); diff --git a/apps/page/src/logic/store/selectors.ts b/apps/page/src/logic/store/selectors.ts index 49802a3ec..d0c44d205 100644 --- a/apps/page/src/logic/store/selectors.ts +++ b/apps/page/src/logic/store/selectors.ts @@ -19,7 +19,6 @@ import { selectors as colors } from './stores/colors.store'; const slices = { runtime: (state: State) => state.runtime, - theme: (state: State) => state.theme, podcast: (state: State) => state.podcast, player: (state: State) => state.player, playbar: (state: State) => state.playbar, diff --git a/apps/page/src/logic/store/state.ts b/apps/page/src/logic/store/state.ts index d1cf42b21..075dfcaab 100644 --- a/apps/page/src/logic/store/state.ts +++ b/apps/page/src/logic/store/state.ts @@ -1,5 +1,4 @@ import { type State as runtime } from './stores/runtime.store'; -import { type State as theme } from './stores/theme.store'; import { type State as podcast } from './stores/podcast.store'; import { type State as action } from './stores/action.store'; import { type State as episodes } from './stores/episodes.store'; @@ -18,7 +17,6 @@ export default interface State { action: action, episodes: episodes, playbar: playbar, - theme: theme, search: search, subscribeButton: subscribeButton, player: player, diff --git a/apps/page/src/logic/store/stores/contributors.store.ts b/apps/page/src/logic/store/stores/contributors.store.ts index 01d93dd20..35903e909 100644 --- a/apps/page/src/logic/store/stores/contributors.store.ts +++ b/apps/page/src/logic/store/stores/contributors.store.ts @@ -15,7 +15,7 @@ export type requestEpisodePayload = string | string[]; export const reducer = handleActions({ [lifecycleActions.dataFetched.toString()]: (state, { payload }: Action) => { - return flattenDeep(payload.episodes.map(episode => episode.contributors || [])).reduce((result, contributor) => ({ + return flattenDeep(payload.data.episodes.map(episode => episode.contributors || [])).reduce((result, contributor) => ({ ...result, [contributor.id]: contributor }), state) diff --git a/apps/page/src/logic/store/stores/episodes.store.ts b/apps/page/src/logic/store/stores/episodes.store.ts index 4ec269eac..b9082dfd3 100644 --- a/apps/page/src/logic/store/stores/episodes.store.ts +++ b/apps/page/src/logic/store/stores/episodes.store.ts @@ -23,7 +23,7 @@ export const actions = { export const reducer = handleActions({ [lifecycleActions.dataFetched.toString()]: (state, { payload }: Action) => { - return payload.episodes.reduce((result, episode) => ({ + return payload.data.episodes.reduce((result, episode) => ({ ...result, [episode.id]: episode }), state) diff --git a/apps/page/src/logic/store/stores/playbar.store.ts b/apps/page/src/logic/store/stores/playbar.store.ts index 546ad5991..fc3c4348a 100644 --- a/apps/page/src/logic/store/stores/playbar.store.ts +++ b/apps/page/src/logic/store/stores/playbar.store.ts @@ -1,7 +1,5 @@ -import { get } from 'lodash-es'; -import { ready, type readyPayload } from '@podlove/player-actions/lifecycle' -import { handleActions, createAction, type Action } from 'redux-actions' -import * as player from './player.store' +import { handleActions, createAction } from 'redux-actions'; +import * as player from './player.store'; export const actions = { play: createAction('PLAYBAR_PLAY'), @@ -12,7 +10,7 @@ export const actions = { nextRate: createAction('NEXT_RATE'), toggleFollowContent: createAction('FOLLOW_CONTENT'), toggleChaptersOverlay: createAction('TOGGLE_CHAPTERS') -} +}; export interface State { active: boolean; @@ -65,4 +63,4 @@ export const selectors = { button: (state: State) => state.button, followContent: (state: State) => state.followContent, chapters: (state: State) => state.chapters -} +}; diff --git a/apps/page/src/logic/store/stores/podcast.store.ts b/apps/page/src/logic/store/stores/podcast.store.ts index 50aa442d1..d9ae764ed 100644 --- a/apps/page/src/logic/store/stores/podcast.store.ts +++ b/apps/page/src/logic/store/stores/podcast.store.ts @@ -15,11 +15,11 @@ export interface State { export const reducer = handleActions({ [lifecycleActions.dataFetched.toString()]: (state, { payload }: Action) => ({ ...state, - title: get(payload, ['show', 'title'], null), - poster: get(payload, ['show', 'poster'], null), - description: get(payload, ['show', 'description'], null), - summary: get(payload, ['show', 'summary'], null), - author: get(payload, ['author'], { + title: get(payload, ['data', 'show', 'title'], null), + poster: get(payload, ['data', 'show', 'poster'], null), + description: get(payload, ['data', 'show', 'description'], null), + summary: get(payload, ['data', 'show', 'summary'], null), + author: get(payload, ['data', 'author'], { owner: null, copyright: null, name: null, diff --git a/apps/page/src/logic/store/stores/runtime.store.ts b/apps/page/src/logic/store/stores/runtime.store.ts index b3430ece7..72d2dce96 100644 --- a/apps/page/src/logic/store/stores/runtime.store.ts +++ b/apps/page/src/logic/store/stores/runtime.store.ts @@ -1,8 +1,6 @@ import { get } from 'lodash-es'; import { createAction, handleActions, type Action } from 'redux-actions'; -import { etag } from '../../../lib/caching.js'; import type { Podcast } from '../../../types/feed.types.js'; -import { version } from '../../../../package.json'; export interface State { initialized: boolean; @@ -17,7 +15,10 @@ export interface initializeAppPayload { episodeId?: number } -export type dataFetchedPayload = Podcast; +export type dataFetchedPayload = { + data: Podcast, + cacheKey: string | null; +}; export const actions = { initializeApp: createAction('INITIALIZE'), @@ -27,7 +28,7 @@ export const actions = { export const reducer = handleActions( { - [actions.initializeApp.toString()]: (state, { payload}: Action) => ({ + [actions.initializeApp.toString()]: (state, { payload }: Action) => ({ ...state, initialized: false, locale: payload.locale @@ -35,11 +36,8 @@ export const reducer = handleActions( [actions.dataFetched.toString()]: (state, { payload }: Action) => ({ ...state, initialized: true, - buildDate: get(payload, 'buildDate', null), - cacheKey: payload.etag ? etag({ - feed: payload.etag, - version - }) : null + buildDate: get(payload, ['data', 'buildDate'], null), + cacheKey: get(payload, 'cacheKey', null) }), }, diff --git a/apps/page/src/logic/store/stores/view.store.ts b/apps/page/src/logic/store/stores/view.store.ts index 7ba5b4ae9..547b1377f 100644 --- a/apps/page/src/logic/store/stores/view.store.ts +++ b/apps/page/src/logic/store/stores/view.store.ts @@ -25,7 +25,7 @@ export const reducer = handleActions( ...state, archive: { ...state.archive, - episodes: payload.episodes.map(({ id }) => id) + episodes: payload.data.episodes.map(({ id }) => id) } }), [actions.archiveLoadMore.toString()]: (state) => ({ diff --git a/apps/page/src/middleware/router.ts b/apps/page/src/middleware/router.ts index 245e1e763..3d4d98ff2 100644 --- a/apps/page/src/middleware/router.ts +++ b/apps/page/src/middleware/router.ts @@ -1,13 +1,12 @@ -import type { MiddlewareEndpointHandler } from 'astro'; import { defineMiddleware, sequence } from 'astro:middleware'; -import micromatch from 'micromatch'; +import multimatch from 'multimatch'; -export function defineMiddlewareRouter(router: Record) { +export function defineMiddlewareRouter(router: Record) { const entries = Object.entries(router); return defineMiddleware((context, next) => sequence( ...entries - .filter(([path]) => micromatch.isMatch(context.url.pathname, path)) + .filter(([path]) => multimatch(context.url.pathname, path).length > 0) .map(([_, handler]) => handler) )(context, next) ); diff --git a/apps/page/src/middleware/store.ts b/apps/page/src/middleware/store.ts index d247df77d..1167d90ff 100644 --- a/apps/page/src/middleware/store.ts +++ b/apps/page/src/middleware/store.ts @@ -17,7 +17,7 @@ export const initializeStore = defineMiddleware(async ({ request, params }, next await waitFor(() => { const initialized = selectors.runtime.initialized(store.getState()); return initialized ? true : undefined; - }, 10000).catch((err) => { + }, 10000).catch(() => { throw Error('Request timed out'); }); diff --git a/apps/page/src/screens/archive/LoadMore.vue b/apps/page/src/screens/archive/LoadMore.vue index be2a269c5..e142a947b 100644 --- a/apps/page/src/screens/archive/LoadMore.vue +++ b/apps/page/src/screens/archive/LoadMore.vue @@ -1,14 +1,31 @@ diff --git a/apps/page/src/screens/episodes/Navigation.vue b/apps/page/src/screens/episodes/Navigation.vue index e081a7d70..5f696ce52 100644 --- a/apps/page/src/screens/episodes/Navigation.vue +++ b/apps/page/src/screens/episodes/Navigation.vue @@ -21,7 +21,7 @@ @click="scrollTo('summary')" > - +
@@ -61,9 +61,11 @@ import { ref, type Ref } from 'vue' import scrollIntoView from 'scroll-into-view-if-needed' import { TimelineIcon, SummaryIcon, ShownotesIcon, DiscussIcon } from '@podlove/components'; - import { onMounted } from 'vue'; import { throttle } from 'lodash-es'; +import { useI18n } from 'vue-i18n'; + +const { t } = useI18n(); defineProps<{ shownotes: boolean; diff --git a/apps/page/src/types/feed.types.ts b/apps/page/src/types/feed.types.ts index 328d2f7ca..7bc967c77 100644 --- a/apps/page/src/types/feed.types.ts +++ b/apps/page/src/types/feed.types.ts @@ -1,5 +1,3 @@ -import type { PodloveWebPlayerTranscript } from "@podlove/types"; - export interface Podcast { etag: string | null; buildDate: string | null; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 3cdf19e1f..28fae8d22 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -101,7 +101,7 @@ importers: version: 5.1.0(astro@4.11.5)(tailwindcss@3.0.24) '@astrojs/vue': specifier: 4.5.0 - version: 4.5.0(astro@4.11.5)(vite@5.3.3)(vue@3.2.30) + version: 4.5.0(astro@4.11.5)(vite@5.3.3)(vue@3.4.31) '@m31coding/fuzzy-search': specifier: 1.0.1 version: 1.0.1 @@ -144,9 +144,9 @@ importers: lodash-es: specifier: 4.17.21 version: 4.17.21 - micromatch: - specifier: 4.0.5 - version: 4.0.5 + multimatch: + specifier: 7.0.0 + version: 7.0.0 redux: specifier: 4.2.1 version: 4.2.1 @@ -158,7 +158,7 @@ importers: version: 1.2.3 redux-vuex: specifier: 3.1.2 - version: 3.1.2(redux@4.2.1)(vue@3.2.30) + version: 3.1.2(redux@4.2.1)(vue@3.4.31) reselect: specifier: 4.1.8 version: 4.1.8 @@ -166,18 +166,15 @@ importers: specifier: 3.1.0 version: 3.1.0 vue: - specifier: 3.2.30 - version: 3.2.30 + specifier: 3.4.31 + version: 3.4.31(typescript@5.3.2) vue-i18n: specifier: 9.8.0 - version: 9.8.0(vue@3.2.30) + version: 9.8.0(vue@3.4.31) devDependencies: '@types/lodash-es': specifier: 4.17.12 version: 4.17.12 - '@types/micromatch': - specifier: 4.0.6 - version: 4.0.6 '@types/redux-actions': specifier: 2.6.5 version: 2.6.5 @@ -1113,19 +1110,19 @@ packages: resolution: {integrity: sha512-vYuYtIrTwxFlDRIhuekscorsHdLL8Hr3mgOczfM1tRWVPn54dDNcKG0DmfL4DlC5YJRoqVaVdUs508Hw643NTw==} dev: false - /@astrojs/vue@4.5.0(astro@4.11.5)(vite@5.3.3)(vue@3.2.30): + /@astrojs/vue@4.5.0(astro@4.11.5)(vite@5.3.3)(vue@3.4.31): resolution: {integrity: sha512-yVrTwuGBpX/BPLlU29eje3/bUkHe9ftFeoiAJcskbaWeori86ojNCheMGKCS3NZwuXHj+bXcatoKdPEQiFfX5A==} engines: {node: ^18.17.1 || ^20.3.0 || >=21.0.0} peerDependencies: astro: ^4.0.0 vue: ^3.2.30 dependencies: - '@vitejs/plugin-vue': 5.0.5(vite@5.3.3)(vue@3.2.30) - '@vitejs/plugin-vue-jsx': 4.0.0(vite@5.3.3)(vue@3.2.30) + '@vitejs/plugin-vue': 5.0.5(vite@5.3.3)(vue@3.4.31) + '@vitejs/plugin-vue-jsx': 4.0.0(vite@5.3.3)(vue@3.4.31) '@vue/compiler-sfc': 3.4.31 astro: 4.11.5(@types/node@18.18.14)(typescript@5.3.2) - vite-plugin-vue-devtools: 7.3.5(vite@5.3.3)(vue@3.2.30) - vue: 3.2.30 + vite-plugin-vue-devtools: 7.3.5(vite@5.3.3)(vue@3.4.31) + vue: 3.4.31(typescript@5.3.2) transitivePeerDependencies: - '@nuxt/kit' - rollup @@ -1497,7 +1494,6 @@ packages: /@babel/helper-string-parser@7.24.8: resolution: {integrity: sha512-pO9KhhRcuUyGnJWwyEgnRJTSIZHiT+vMD0kPeD+so0l7mxkMT19g3pjY9GTnHySck/hDzq+dtW/4VgnMkippsQ==} engines: {node: '>=6.9.0'} - dev: false /@babel/helper-validator-identifier@7.22.20: resolution: {integrity: sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==} @@ -1506,7 +1502,6 @@ packages: /@babel/helper-validator-identifier@7.24.7: resolution: {integrity: sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==} engines: {node: '>=6.9.0'} - dev: false /@babel/helper-validator-option@7.23.5: resolution: {integrity: sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw==} @@ -1569,7 +1564,6 @@ packages: hasBin: true dependencies: '@babel/types': 7.24.8 - dev: false /@babel/plugin-proposal-decorators@7.24.7(@babel/core@7.24.8): resolution: {integrity: sha512-RL9GR0pUG5Kc8BUWLNDm2T5OpYwSX15r98I0IkgmRQTXuELq/OynH8xtMTMvTJFjXbMWFVTKtYkTaYQsuAwQlQ==} @@ -1764,7 +1758,6 @@ packages: '@babel/helper-string-parser': 7.24.8 '@babel/helper-validator-identifier': 7.24.7 to-fast-properties: 2.0.0 - dev: false /@cloudflare/kv-asset-handler@0.3.4: resolution: {integrity: sha512-YLPHc8yASwjNkmcDMQMY35yiWjoKAKnhUbPRszBRS0YgH+IXtsMp61j+yTcnCE3oO2DgP0U3iejLC8FTtKDC8Q==} @@ -4311,10 +4304,6 @@ packages: '@babel/types': 7.24.8 dev: false - /@types/braces@3.0.4: - resolution: {integrity: sha512-0WR3b8eaISjEW7RpZnclONaLFDf7buaowRHdqLp4vLj54AsSAYWfh3DRbfiYJY9XDxMgx1B4sE1Afw2PGpuHOA==} - dev: true - /@types/chai-subset@1.3.5: resolution: {integrity: sha512-c2mPnw+xHtXDoHmdtcCXGwyLMiauiAyxWMzhGpqHC4nqI/Y5G2XhTampslK2rb59kpcuHon03UH8W6iYUzw88A==} dependencies: @@ -4395,12 +4384,6 @@ packages: resolution: {integrity: sha512-6L6VymKTzYSrEf4Nev4Xa1LCHKrlTlYCBMTlQKFuddo1CvQcE52I0mwfOJayueUC7MJuXOeHTcIU683lzd0cUA==} dev: true - /@types/micromatch@4.0.6: - resolution: {integrity: sha512-2eulCHWqjEpk9/vyic4tBhI8a9qQEl6DaK2n/sF7TweX9YESlypgKyhXMDGt4DAOy/jhLPvVrZc8pTDAMsplJA==} - dependencies: - '@types/braces': 3.0.4 - dev: true - /@types/minimatch@3.0.5: resolution: {integrity: sha512-Klz949h02Gz2uZCMGwDUSDS1YBlTdDDgbWHi+81l29tQALUtvz4rAYi5uoVhE5Lagoq6DeqAUlbrHvW/mXDgdQ==} dev: true @@ -5207,7 +5190,7 @@ packages: /@ungap/structured-clone@1.2.0: resolution: {integrity: sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==} - /@vitejs/plugin-vue-jsx@4.0.0(vite@5.3.3)(vue@3.2.30): + /@vitejs/plugin-vue-jsx@4.0.0(vite@5.3.3)(vue@3.4.31): resolution: {integrity: sha512-A+6wL2AdQhDsLsDnY+2v4rRDI1HLJGIMc97a8FURO9tqKsH5QvjWrzsa5DH3NlZsM742W2wODl2fF+bfcTWtXw==} engines: {node: ^18.0.0 || >=20.0.0} peerDependencies: @@ -5218,7 +5201,7 @@ packages: '@babel/plugin-transform-typescript': 7.24.8(@babel/core@7.24.8) '@vue/babel-plugin-jsx': 1.2.2(@babel/core@7.24.8) vite: 5.3.3(@types/node@18.18.14) - vue: 3.2.30 + vue: 3.4.31(typescript@5.3.2) transitivePeerDependencies: - supports-color dev: false @@ -5256,7 +5239,7 @@ packages: vue: 3.2.41 dev: true - /@vitejs/plugin-vue@5.0.5(vite@5.3.3)(vue@3.2.30): + /@vitejs/plugin-vue@5.0.5(vite@5.3.3)(vue@3.4.31): resolution: {integrity: sha512-LOjm7XeIimLBZyzinBQ6OSm3UBCNVCpLkxGC0oWmm2YPzVZoxMsdvNVimLTBzpAnR9hl/yn1SHGuRfe6/Td9rQ==} engines: {node: ^18.0.0 || >=20.0.0} peerDependencies: @@ -5264,7 +5247,7 @@ packages: vue: ^3.2.25 dependencies: vite: 5.3.3(@types/node@18.18.14) - vue: 3.2.30 + vue: 3.4.31(typescript@5.3.2) dev: false /@vitest/expect@0.30.0: @@ -5504,15 +5487,6 @@ packages: '@vue/compiler-sfc': 3.4.31 dev: false - /@vue/compiler-core@3.2.30: - resolution: {integrity: sha512-64fq1KfcR+k3Vlw+IsBM2VhV5B+2IP3YxvKU8LWCDLrkmlXtbf2eMK6+0IwX5KP41D0f1gzryIiXR7P8cB9O5Q==} - dependencies: - '@babel/parser': 7.23.5 - '@vue/shared': 3.2.30 - estree-walker: 2.0.2 - source-map: 0.6.1 - dev: false - /@vue/compiler-core@3.2.41: resolution: {integrity: sha512-oA4mH6SA78DT+96/nsi4p9DX97PHcNROxs51lYk7gb9Z4BPKQ3Mh+BLn6CQZBw857Iuhu28BfMSRHAlPvD4vlw==} dependencies: @@ -5537,14 +5511,6 @@ packages: entities: 4.5.0 estree-walker: 2.0.2 source-map-js: 1.2.0 - dev: false - - /@vue/compiler-dom@3.2.30: - resolution: {integrity: sha512-t7arHz2SXLCXlF2fdGDFVbhENbGMez254Z5edUqb//6WXJU1lC7GvSkUE7i5x8WSjgfqt60i0V8zdmk16rvLdw==} - dependencies: - '@vue/compiler-core': 3.2.30 - '@vue/shared': 3.2.30 - dev: false /@vue/compiler-dom@3.2.41: resolution: {integrity: sha512-xe5TbbIsonjENxJsYRbDJvthzqxLNk+tb3d/c47zgREDa/PCp6/Y4gC/skM4H6PIuX5DAxm7fFJdbjjUH2QTMw==} @@ -5563,22 +5529,6 @@ packages: dependencies: '@vue/compiler-core': 3.4.31 '@vue/shared': 3.4.31 - dev: false - - /@vue/compiler-sfc@3.2.30: - resolution: {integrity: sha512-P/5YpILtcQY92z72gxhkyOUPHVskEzhSrvYi91Xcr+csOxaDaYU5OqOxCzZKcf3Og70Tat404vO1OHrwprN90A==} - dependencies: - '@babel/parser': 7.23.5 - '@vue/compiler-core': 3.2.30 - '@vue/compiler-dom': 3.2.30 - '@vue/compiler-ssr': 3.2.30 - '@vue/reactivity-transform': 3.2.30 - '@vue/shared': 3.2.30 - estree-walker: 2.0.2 - magic-string: 0.25.9 - postcss: 8.4.31 - source-map: 0.6.1 - dev: false /@vue/compiler-sfc@3.2.41: resolution: {integrity: sha512-+1P2m5kxOeaxVmJNXnBskAn3BenbTmbxBxWOtBq3mQTCokIreuMULFantBUclP0+KnzNCMOvcnKinqQZmiOF8w==} @@ -5608,40 +5558,23 @@ packages: source-map-js: 1.2.0 dev: false - /@vue/compiler-ssr@3.2.30: - resolution: {integrity: sha512-OUh3MwAu/PsD7VN3UOdBbTkltkrUCNouSht47+CMRzpUR5+ta7+xyMAVHeq8wg4YZenWaJimbR5TL35Ka4Vk6g==} - dependencies: - '@vue/compiler-dom': 3.2.30 - '@vue/shared': 3.2.30 - dev: false - /@vue/compiler-ssr@3.2.41: resolution: {integrity: sha512-Y5wPiNIiaMz/sps8+DmhaKfDm1xgj6GrH99z4gq2LQenfVQcYXmHIOBcs5qPwl7jaW3SUQWjkAPKMfQemEQZwQ==} dependencies: '@vue/compiler-dom': 3.2.41 '@vue/shared': 3.2.41 - /@vue/compiler-ssr@3.3.9: - resolution: {integrity: sha512-NO5oobAw78R0G4SODY5A502MGnDNiDjf6qvhn7zD7TJGc8XDeIEw4fg6JU705jZ/YhuokBKz0A5a/FL/XZU73g==} - requiresBuild: true - dependencies: - '@vue/compiler-dom': 3.3.9 - '@vue/shared': 3.3.9 - dev: true - optional: true - /@vue/compiler-ssr@3.4.31: resolution: {integrity: sha512-RtefmITAje3fJ8FSg1gwgDhdKhZVntIVbwupdyZDSifZTRMiWxWehAOTCc8/KZDnBOcYQ4/9VWxsTbd3wT0hAA==} dependencies: '@vue/compiler-dom': 3.4.31 '@vue/shared': 3.4.31 - dev: false /@vue/devtools-api@6.5.1: resolution: {integrity: sha512-+KpckaAQyfbvshdDW5xQylLni1asvNSGme1JFs8I1+/H5pHEhqUKMEQD/qn3Nx5+/nycBq11qAEi8lk+LXI2dA==} dev: false - /@vue/devtools-core@7.3.5(vite@5.3.3)(vue@3.2.30): + /@vue/devtools-core@7.3.5(vite@5.3.3)(vue@3.4.31): resolution: {integrity: sha512-uSC3IkIp6MtyJYSh5xzY99sgqlAXLq+peE2KKXTi6JeRHOtMngFWFWENXi70IJ1EVGYztiFQoHhI9WZcgKBz8g==} peerDependencies: vue: ^3.0.0 @@ -5652,7 +5585,7 @@ packages: nanoid: 3.3.7 pathe: 1.1.2 vite-hot-client: 0.2.3(vite@5.3.3) - vue: 3.2.30 + vue: 3.4.31(typescript@5.3.2) transitivePeerDependencies: - vite dev: false @@ -5715,16 +5648,6 @@ packages: vue-template-compiler: 2.7.15 dev: true - /@vue/reactivity-transform@3.2.30: - resolution: {integrity: sha512-Le5XzCJyK3qTjoTnvQG/Ehu8fYjayauMNFyMaEnwFlm/avDofpuibpS9u+/6AgzsGnVWN+i0Jgf25bJd9DIwMw==} - dependencies: - '@babel/parser': 7.23.5 - '@vue/compiler-core': 3.2.30 - '@vue/shared': 3.2.30 - estree-walker: 2.0.2 - magic-string: 0.25.9 - dev: false - /@vue/reactivity-transform@3.2.41: resolution: {integrity: sha512-mK5+BNMsL4hHi+IR3Ft/ho6Za+L3FA5j8WvreJ7XzHrqkPq8jtF/SMo7tuc9gHjLDwKZX1nP1JQOKo9IEAn54A==} dependencies: @@ -5734,22 +5657,15 @@ packages: estree-walker: 2.0.2 magic-string: 0.25.9 - /@vue/reactivity@3.2.30: - resolution: {integrity: sha512-qlNKbkRn2JiGxVUEdoXbLAy+vcuHUCcq+YH2uXWz0BNMvXY2plmz+oqsw+694llwmYLkke5lbdYF4DIupisIkg==} - dependencies: - '@vue/shared': 3.2.30 - dev: false - /@vue/reactivity@3.2.41: resolution: {integrity: sha512-9JvCnlj8uc5xRiQGZ28MKGjuCoPhhTwcoAdv3o31+cfGgonwdPNuvqAXLhlzu4zwqavFEG5tvaoINQEfxz+l6g==} dependencies: '@vue/shared': 3.2.41 - /@vue/runtime-core@3.2.30: - resolution: {integrity: sha512-RTi7xH0Ht/6wfbo2WFBMJTEiyWFTqGhrksJm8lz6E+auO6lXZ6Eq3gPNfLt47GDWCm4xyrv+rs5R4UbarPEQ1Q==} + /@vue/reactivity@3.4.31: + resolution: {integrity: sha512-VGkTani8SOoVkZNds1PfJ/T1SlAIOf8E58PGAhIOUDYPC4GAmFA2u/E14TDAFcf3vVDKunc4QqCe/SHr8xC65Q==} dependencies: - '@vue/reactivity': 3.2.30 - '@vue/shared': 3.2.30 + '@vue/shared': 3.4.31 dev: false /@vue/runtime-core@3.2.41: @@ -5758,12 +5674,11 @@ packages: '@vue/reactivity': 3.2.41 '@vue/shared': 3.2.41 - /@vue/runtime-dom@3.2.30: - resolution: {integrity: sha512-a3+jrncDvEFQmB+v9k0VyT4/Y3XO6OAueCroXXY4yLyr6PJeyxljweV5TzvW0rvVzH9sZO0QAvG76Lo+6C92Qw==} + /@vue/runtime-core@3.4.31: + resolution: {integrity: sha512-LDkztxeUPazxG/p8c5JDDKPfkCDBkkiNLVNf7XZIUnJ+66GVGkP+TIh34+8LtPisZ+HMWl2zqhIw0xN5MwU1cw==} dependencies: - '@vue/runtime-core': 3.2.30 - '@vue/shared': 3.2.30 - csstype: 2.6.21 + '@vue/reactivity': 3.4.31 + '@vue/shared': 3.4.31 dev: false /@vue/runtime-dom@3.2.41: @@ -5773,14 +5688,13 @@ packages: '@vue/shared': 3.2.41 csstype: 2.6.21 - /@vue/server-renderer@3.2.30(vue@3.2.30): - resolution: {integrity: sha512-pzb8J/w+JdZVOtuKFlirGqrs4GP60FXGDJySw3WV2pCetuFstaacDrnymEeSo3ohAD+Qjv7zAG+Y7OvkdxQxmQ==} - peerDependencies: - vue: 3.2.30 + /@vue/runtime-dom@3.4.31: + resolution: {integrity: sha512-2Auws3mB7+lHhTFCg8E9ZWopA6Q6L455EcU7bzcQ4x6Dn4cCPuqj6S2oBZgN2a8vJRS/LSYYxwFFq2Hlx3Fsaw==} dependencies: - '@vue/compiler-ssr': 3.2.30 - '@vue/shared': 3.2.30 - vue: 3.2.30 + '@vue/reactivity': 3.4.31 + '@vue/runtime-core': 3.4.31 + '@vue/shared': 3.4.31 + csstype: 3.1.3 dev: false /@vue/server-renderer@3.2.41(vue@3.2.41): @@ -5792,19 +5706,25 @@ packages: '@vue/shared': 3.2.41 vue: 3.2.41 - /@vue/server-renderer@3.3.9(vue@3.2.41): - resolution: {integrity: sha512-w0zT/s5l3Oa3ZjtLW88eO4uV6AQFqU8X5GOgzq7SkQQu6vVr+8tfm+OI2kDBplS/W/XgCBuFXiPw6T5EdwXP0A==} + /@vue/server-renderer@3.4.31(vue@3.2.41): + resolution: {integrity: sha512-D5BLbdvrlR9PE3by9GaUp1gQXlCNadIZytMIb8H2h3FMWJd4oUfkUTEH2wAr3qxoRz25uxbTcbqd3WKlm9EHQA==} peerDependencies: - vue: 3.3.9 + vue: 3.4.31 dependencies: - '@vue/compiler-ssr': 3.3.9 - '@vue/shared': 3.3.9 + '@vue/compiler-ssr': 3.4.31 + '@vue/shared': 3.4.31 vue: 3.2.41 dev: true optional: true - /@vue/shared@3.2.30: - resolution: {integrity: sha512-B3HouBtUxcfu2w2d+VhdLcVBXKYYhXiFMAfQ+hoe8NUhKkPRkWDIqhpuehCZxVQ3S2dN1P1WfKGlxGC+pfmxGg==} + /@vue/server-renderer@3.4.31(vue@3.4.31): + resolution: {integrity: sha512-D5BLbdvrlR9PE3by9GaUp1gQXlCNadIZytMIb8H2h3FMWJd4oUfkUTEH2wAr3qxoRz25uxbTcbqd3WKlm9EHQA==} + peerDependencies: + vue: 3.4.31 + dependencies: + '@vue/compiler-ssr': 3.4.31 + '@vue/shared': 3.4.31 + vue: 3.4.31(typescript@5.3.2) dev: false /@vue/shared@3.2.41: @@ -5815,7 +5735,6 @@ packages: /@vue/shared@3.4.31: resolution: {integrity: sha512-Yp3wtJk//8cO4NItOPpi3QkLExAr/aLBGZMmTtW9WpdwBCJpRM6zj9WgWktXAl8IDIozwNMByT45JP3tO3ACWA==} - dev: false /@vue/test-utils@2.3.2(vue@3.2.41): resolution: {integrity: sha512-hJnVaYhbrIm0yBS0+e1Y0Sj85cMyAi+PAbK4JHqMRUZ6S622Goa+G7QzkRSyvCteG8wop7tipuEbHoZo26wsSA==} @@ -5825,8 +5744,8 @@ packages: js-beautify: 1.14.6 vue: 3.2.41 optionalDependencies: - '@vue/compiler-dom': 3.3.9 - '@vue/server-renderer': 3.3.9(vue@3.2.41) + '@vue/compiler-dom': 3.4.31 + '@vue/server-renderer': 3.4.31(vue@3.2.41) dev: true /@yarnpkg/lockfile@1.1.0: @@ -6078,6 +5997,11 @@ packages: engines: {node: '>=8'} dev: true + /array-differ@4.0.0: + resolution: {integrity: sha512-Q6VPTLMsmXZ47ENG3V+wQyZS1ZxXMxFyYzA+Z/GMrJ6yIutAIEf9wTyroTzmGjNfox9/h3GdGBCVh43GVFx4Uw==} + engines: {node: ^12.20.0 || ^14.13.1 || >=16.0.0} + dev: false + /array-find-index@1.0.2: resolution: {integrity: sha512-M1HQyIXcBGtVywBt8WVdim+lrNaK7VHp99Qt5pSNziXznKHViIBbXWtfRTpEFpF/c4FdfxNAsCCwPp5phBYJtw==} engines: {node: '>=0.10.0'} @@ -6103,6 +6027,11 @@ packages: engines: {node: '>=8'} dev: true + /array-union@3.0.1: + resolution: {integrity: sha512-1OvF9IbWwaeiM9VhzYXVQacMibxpXOMYVNIvMtKRyX9SImBXpKcFr8XvFDeEslCyuH/t6KRt7HEO94AlP8Iatw==} + engines: {node: '>=12'} + dev: false + /array-uniq@1.0.3: resolution: {integrity: sha512-MNha4BWQ6JbwhFhj03YK552f7cb3AzoE8SzeljgChvL1dl3IcvggXVz1DilzySZkCja+CXuZbdW7yATchWn8/Q==} engines: {node: '>=0.10.0'} @@ -6334,7 +6263,6 @@ packages: /balanced-match@1.0.2: resolution: {integrity: sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==} - dev: true /base-64@1.0.0: resolution: {integrity: sha512-kwDPIFCGx0NZHog36dj+tHiwP4QMzsZ3AgMViUBKI0+V5n4U0ufTCUMhnQ04diaRI8EX/QcPfql7zlhZ7j4zgg==} @@ -6432,7 +6360,6 @@ packages: resolution: {integrity: sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==} dependencies: balanced-match: 1.0.2 - dev: true /braces@2.3.2: resolution: {integrity: sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==} @@ -6458,6 +6385,12 @@ packages: dependencies: fill-range: 7.0.1 + /braces@3.0.3: + resolution: {integrity: sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==} + engines: {node: '>=8'} + dependencies: + fill-range: 7.1.1 + /browserslist@4.22.1: resolution: {integrity: sha512-FEVc202+2iuClEhZhrWy6ZiAcRLvNMyYcxZ8raemul1DYVOVdFsbqckWLdsixQZCpJlwe77Z3UTalE7jsjnKfQ==} engines: {node: ^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7} @@ -7384,6 +7317,10 @@ packages: /csstype@2.6.21: resolution: {integrity: sha512-Z1PhmomIfypOpoMjRQB70jfvy/wxT50qW08YXO5lMIJkrdq4yOTR+AW7FqutScmB9NkLwxo+jU+kZLbofZZq/w==} + /csstype@3.1.3: + resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} + dev: false + /currently-unhandled@0.4.1: resolution: {integrity: sha512-/fITjgjGU50vjQ4FH6eUoYu+iUoUKIXws2hL15JJpIR+BbTxaXQsMuuyjtNh2WqsSBS5nsaZHFsFecyw5CCAng==} engines: {node: '>=0.10.0'} @@ -8880,7 +8817,7 @@ packages: '@nodelib/fs.walk': 1.2.8 glob-parent: 5.1.2 merge2: 1.4.1 - micromatch: 4.0.5 + micromatch: 4.0.6 /fast-json-stable-stringify@2.1.0: resolution: {integrity: sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==} @@ -8944,6 +8881,12 @@ packages: dependencies: to-regex-range: 5.0.1 + /fill-range@7.1.1: + resolution: {integrity: sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==} + engines: {node: '>=8'} + dependencies: + to-regex-range: 5.0.1 + /filter-obj@5.1.0: resolution: {integrity: sha512-qWeTREPoT7I0bifpPUXtxkZJ1XJzxWtfoWWkdVGqa+eCr3SHW/Ocp89o8vLvbUuQnadybJpjOKu4V+RwO6sGng==} engines: {node: '>=14.16'} @@ -8999,7 +8942,7 @@ packages: /find-yarn-workspace-root2@1.2.16: resolution: {integrity: sha512-hr6hb1w8ePMpPVUK39S4RlwJzi+xPLuVuG8XlwXU3KD5Yn3qgBWVfy3AzNlDhWvE1EORCE65/Qm26rFQt3VLVA==} dependencies: - micromatch: 4.0.5 + micromatch: 4.0.6 pkg-dir: 4.2.0 dev: false @@ -9009,7 +8952,7 @@ packages: dependencies: detect-file: 1.0.0 is-glob: 4.0.3 - micromatch: 4.0.5 + micromatch: 4.0.6 resolve-dir: 1.0.1 dev: true @@ -11882,6 +11825,14 @@ packages: dependencies: braces: 3.0.2 picomatch: 2.3.1 + dev: true + + /micromatch@4.0.6: + resolution: {integrity: sha512-Y4Ypn3oujJYxJcMacVgcs92wofTHxp9FzfDpQON4msDefoC0lb3ETvQLOdLcbhSwU1bz8HrL/1sygfBIHudrkQ==} + engines: {node: '>=8.6'} + dependencies: + braces: 3.0.3 + picomatch: 4.0.2 /milligram@1.4.0: resolution: {integrity: sha512-ZkuBd7r3NVNLmaG/LPV8/lJJg09rK6qZn3cwEY5Pm7biosrJG1/KW6KNRMHeeJScVJLmmRcorROBXYaOH8WtNQ==} @@ -11989,7 +11940,6 @@ packages: engines: {node: '>=16 || 14 >=14.17'} dependencies: brace-expansion: 2.0.1 - dev: true /minimist-options@3.0.2: resolution: {integrity: sha512-FyBrT/d0d4+uiZRbqznPXqw3IpZZG3gl3wKWiX784FycUKVwBt0uLBFkQrtE4tZOrgo78nZp2jnKz3L65T5LdQ==} @@ -12183,6 +12133,15 @@ packages: minimatch: 3.0.5 dev: true + /multimatch@7.0.0: + resolution: {integrity: sha512-SYU3HBAdF4psHEL/+jXDKHO95/m5P2RvboHT2Y0WtTttvJLP4H/2WS9WlQPFvF6C8d6SpLw8vjCnQOnVIVOSJQ==} + engines: {node: '>=18'} + dependencies: + array-differ: 4.0.0 + array-union: 3.0.1 + minimatch: 9.0.3 + dev: false + /mustache@4.2.0: resolution: {integrity: sha512-71ippSywq5Yb7/tVYyGbkBggbU8H3u5Rz56fH60jGFgr8uHwxs+aSKeqmluIVzM0m0kB7xQjKS6qPfd0b2ZoqQ==} hasBin: true @@ -13060,6 +13019,10 @@ packages: resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==} engines: {node: '>=8.6'} + /picomatch@4.0.2: + resolution: {integrity: sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==} + engines: {node: '>=12'} + /pidtree@0.3.1: resolution: {integrity: sha512-qQbW94hLHEqCg7nhby4yRC7G2+jYHY4Rguc2bjw7Uug4GIJuu1tvf2uHaZv5Q8zdt+WKJ6qK1FOI6amaWUo5FA==} engines: {node: '>=0.10'} @@ -13647,7 +13610,7 @@ packages: vue: 3.2.41 dev: false - /redux-vuex@3.1.2(redux@4.2.1)(vue@3.2.30): + /redux-vuex@3.1.2(redux@4.2.1)(vue@3.4.31): resolution: {integrity: sha512-ge4wh2z1v3cYiNE8s7/rSvy3YIe27sFXcHRrWjYXw40q8e/7WdJZXV1gqvEnZTvJmr9T9Fb6f5owaQOnSKtD2w==} peerDependencies: redux: 5.x @@ -13656,7 +13619,7 @@ packages: get-value: 3.0.1 redux: 4.2.1 set-value: 4.1.0 - vue: 3.2.30 + vue: 3.4.31(typescript@5.3.2) dev: false /redux@4.2.0: @@ -14944,7 +14907,7 @@ packages: glob-parent: 6.0.2 is-glob: 4.0.3 lilconfig: 2.1.0 - micromatch: 4.0.5 + micromatch: 4.0.6 normalize-path: 3.0.0 object-hash: 3.0.0 picocolors: 1.0.0 @@ -16035,13 +15998,13 @@ packages: - typescript dev: true - /vite-plugin-vue-devtools@7.3.5(vite@5.3.3)(vue@3.2.30): + /vite-plugin-vue-devtools@7.3.5(vite@5.3.3)(vue@3.4.31): resolution: {integrity: sha512-6omLXTfYu0bmSmncPSbj4mdMPB3t5dAZkUyriJikahGEnvv5gynHlydDsJShHT6l/5dCkvmSesSji/2a6FfutQ==} engines: {node: '>=v14.21.3'} peerDependencies: vite: ^3.1.0 || ^4.0.0-0 || ^5.0.0-0 dependencies: - '@vue/devtools-core': 7.3.5(vite@5.3.3)(vue@3.2.30) + '@vue/devtools-core': 7.3.5(vite@5.3.3)(vue@3.4.31) '@vue/devtools-kit': 7.3.5 '@vue/devtools-shared': 7.3.5 execa: 8.0.1 @@ -16696,7 +16659,7 @@ packages: vue: 3.2.41 dev: false - /vue-i18n@9.8.0(vue@3.2.30): + /vue-i18n@9.8.0(vue@3.4.31): resolution: {integrity: sha512-Izho+6PYjejsTq2mzjcRdBZ5VLRQoSuuexvR8029h5CpN03FYqiqBrShMyf2I1DKkN6kw/xmujcbvC+4QybpsQ==} engines: {node: '>= 16'} peerDependencies: @@ -16705,7 +16668,7 @@ packages: '@intlify/core-base': 9.8.0 '@intlify/shared': 9.8.0 '@vue/devtools-api': 6.5.1 - vue: 3.2.30 + vue: 3.4.31(typescript@5.3.2) dev: false /vue-resize@2.0.0-alpha.1(vue@3.2.41): @@ -16747,16 +16710,6 @@ packages: typescript: 5.3.2 dev: true - /vue@3.2.30: - resolution: {integrity: sha512-ZmTFWVJUX2XADkuOB8GcLTuxnBLogjJBTNVrM7WsTnjqRQ+VR8bLNrvNsbn8vj/LaP5+0WFAPrpngOYE2x+e+Q==} - dependencies: - '@vue/compiler-dom': 3.2.30 - '@vue/compiler-sfc': 3.2.30 - '@vue/runtime-dom': 3.2.30 - '@vue/server-renderer': 3.2.30(vue@3.2.30) - '@vue/shared': 3.2.30 - dev: false - /vue@3.2.41: resolution: {integrity: sha512-uuuvnrDXEeZ9VUPljgHkqB5IaVO8SxhPpqF2eWOukVrBnRBx2THPSGQBnVRt0GrIG1gvCmFXMGbd7FqcT1ixNQ==} dependencies: @@ -16766,6 +16719,22 @@ packages: '@vue/server-renderer': 3.2.41(vue@3.2.41) '@vue/shared': 3.2.41 + /vue@3.4.31(typescript@5.3.2): + resolution: {integrity: sha512-njqRrOy7W3YLAlVqSKpBebtZpDVg21FPoaq1I7f/+qqBThK9ChAIjkRWgeP6Eat+8C+iia4P3OYqpATP21BCoQ==} + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true + dependencies: + '@vue/compiler-dom': 3.4.31 + '@vue/compiler-sfc': 3.4.31 + '@vue/runtime-dom': 3.4.31 + '@vue/server-renderer': 3.4.31(vue@3.4.31) + '@vue/shared': 3.4.31 + typescript: 5.3.2 + dev: false + /w3c-keyname@2.2.8: resolution: {integrity: sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==} dev: true From 121d0c7ced68bed1f6dfa7e1fcdca0f0d3d62823 Mon Sep 17 00:00:00 2001 From: Alexander Heimbuch Date: Mon, 15 Jul 2024 10:12:15 +0200 Subject: [PATCH 18/20] fix(page): filter episodes without valid ids --- apps/page/src/logic/data/feed-parser.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/apps/page/src/logic/data/feed-parser.ts b/apps/page/src/logic/data/feed-parser.ts index 93ae1e56a..c0c925f22 100644 --- a/apps/page/src/logic/data/feed-parser.ts +++ b/apps/page/src/logic/data/feed-parser.ts @@ -145,7 +145,7 @@ const transform = show: transformShow(data), episodes: await Promise.all( castArray(get(data, ['channel', 'item'], [])).map(resolveEpisode(episodeId)) - ), + ).then(episodes => episodes.filter(episode => episode.id !== null)), hosts: castArray(get(data, ['channel', 'podcast:person'], [])).map(transformPerson) }); @@ -161,7 +161,6 @@ export default async ({ } return await fetch(feed) - // TODO: add cache key .then(async (result) => { const feedXml = await result.text(); const etag: string | null = result.headers.get('etag'); From a6a9fef57d096bd9a97b901a5d17910efbed5fce Mon Sep 17 00:00:00 2001 From: Alexander Heimbuch Date: Mon, 15 Jul 2024 15:09:01 +0200 Subject: [PATCH 19/20] fix(tests): update tests --- apps/docs/package.json | 2 +- apps/page/package.json | 2 +- apps/player/package.json | 4 +- apps/subscribe-button/package.json | 4 +- packages/components/package.json | 4 +- .../chapter-progress.test.ts.snap | 35 +- .../chapter-progress/chapter-progress.test.ts | 2 +- .../image/__snapshots__/image.test.ts.snap | 89 ---- .../__snapshots__/input-select.test.ts.snap | 2 + .../__snapshots__/input-slider.test.ts.snap | 21 +- .../__snapshots__/input-text.test.ts.snap | 7 + .../__snapshots__/play-button.test.ts.snap | 24 +- .../components/progress-bar/ProgressBar.vue | 12 +- .../__snapshots__/progress-bar.test.ts.snap | 306 ++----------- .../progress-bar/progress-bar.test.ts | 86 ++-- .../media-backend/cypress/e2e/actions.cy.ts | 19 +- packages/media-backend/package.json | 2 +- packages/player/sagas/src/transcripts.ts | 11 - pnpm-lock.yaml | 414 ++++++------------ 19 files changed, 265 insertions(+), 781 deletions(-) diff --git a/apps/docs/package.json b/apps/docs/package.json index 709def1fb..320796d22 100644 --- a/apps/docs/package.json +++ b/apps/docs/package.json @@ -15,7 +15,7 @@ "@podlove/types": "workspace:*", "@podlove/utils": "workspace:*", "farbraum": "0.2.1", - "vue": "3.2.41" + "vue": "3.4.31" }, "devDependencies": { "@histoire/app": "0.16.1", diff --git a/apps/page/package.json b/apps/page/package.json index d8063cfa1..e3a5c01eb 100644 --- a/apps/page/package.json +++ b/apps/page/package.json @@ -31,7 +31,7 @@ "redux-actions": "3.0.0", "redux-saga": "1.2.3", "reselect": "4.1.8", - "vue-i18n": "9.8.0", + "vue-i18n": "9.13.1", "scroll-into-view-if-needed": "3.1.0", "multimatch": "7.0.0", "@m31coding/fuzzy-search": "1.0.1", diff --git a/apps/player/package.json b/apps/player/package.json index db05cbc4b..1fa251844 100644 --- a/apps/player/package.json +++ b/apps/player/package.json @@ -37,8 +37,8 @@ "redux-vuex": "3.0.0", "reselect": "4.1.8", "tailwindcss": "3.2.4", - "vue": "3.2.41", - "vue-i18n": "9.2.2" + "vue": "3.4.31", + "vue-i18n": "9.13.1" }, "devDependencies": { "@types/node": "20.8.4", diff --git a/apps/subscribe-button/package.json b/apps/subscribe-button/package.json index b4c4dadfa..7267ffdc4 100644 --- a/apps/subscribe-button/package.json +++ b/apps/subscribe-button/package.json @@ -27,8 +27,8 @@ "redux-vuex": "3.0.2", "reselect": "4.1.8", "tailwindcss": "3.2.4", - "vue": "3.2.41", - "vue-i18n": "9.2.2" + "vue": "3.4.31", + "vue-i18n": "9.13.1" }, "devDependencies": { "@fullhuman/postcss-purgecss": "5.0.0", diff --git a/packages/components/package.json b/packages/components/package.json index 3ef45dd91..9935d1733 100644 --- a/packages/components/package.json +++ b/packages/components/package.json @@ -38,7 +38,7 @@ "ramda": "0.29.0", "rangetouch": "2.0.1", "tailwindcss": "3.2.4", - "vue": "3.2.41", + "vue": "3.4.31", "lodash-es": "4.17.21" }, "peerDependencies": { @@ -51,7 +51,7 @@ "@typescript-eslint/eslint-plugin": "6.11.0", "@typescript-eslint/parser": "6.11.0", "@vitejs/plugin-vue": "4.2.1", - "@vue/test-utils": "2.3.2", + "@vue/test-utils": "2.4.6", "eslint": "8.54.0", "eslint-plugin-vue": "9.18.1", "happy-dom": "9.1.9", diff --git a/packages/components/src/components/chapter-progress/__snapshots__/chapter-progress.test.ts.snap b/packages/components/src/components/chapter-progress/__snapshots__/chapter-progress.test.ts.snap index fbce30c48..1a42a4edd 100644 --- a/packages/components/src/components/chapter-progress/__snapshots__/chapter-progress.test.ts.snap +++ b/packages/components/src/components/chapter-progress/__snapshots__/chapter-progress.test.ts.snap @@ -1,44 +1,15 @@ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html -exports[`ChapterProgress > props > should render 'chapter' 1`] = ` - -`; - exports[`ChapterProgress > props > should render 1`] = ` `; - -exports[`Image > props > should render with prop alt 1`] = ` -
- -
- - -
-`; - -exports[`Image > props > should render with prop color 1`] = ` -
- -
- - -
-`; - -exports[`Image > props > should render with prop url 1`] = ` -
- -
- - -
-`; - -exports[`Image > props > should render without props 1`] = ` -
- -
- - -
-`; diff --git a/packages/components/src/components/input-select/__snapshots__/input-select.test.ts.snap b/packages/components/src/components/input-select/__snapshots__/input-select.test.ts.snap index e26c843fb..9ee95276b 100644 --- a/packages/components/src/components/input-select/__snapshots__/input-select.test.ts.snap +++ b/packages/components/src/components/input-select/__snapshots__/input-select.test.ts.snap @@ -108,10 +108,12 @@ exports[`InputSelect > props > should render type 'value' 1`] = ` `; @@ -51,5 +57,6 @@ exports[`InputText > props > should render without props 1`] = ` `; diff --git a/packages/components/src/components/play-button/__snapshots__/play-button.test.ts.snap b/packages/components/src/components/play-button/__snapshots__/play-button.test.ts.snap index fd7dbb7ca..cd6d49d28 100644 --- a/packages/components/src/components/play-button/__snapshots__/play-button.test.ts.snap +++ b/packages/components/src/components/play-button/__snapshots__/play-button.test.ts.snap @@ -8,7 +8,7 @@ exports[`PlayButton > props > should render type 'loading' with 'background' 1`] id="play-button--loading" >
props > should render type 'loading' with 'color' 1`] = ` id="play-button--loading" >
props > should render type 'loading' with 'label' 1`] = ` id="play-button--loading" >
props > should render type 'pause' with 'background' 1`] = id="play-button--pause" >
props > should render type 'pause' with 'color' 1`] = ` id="play-button--pause" >
props > should render type 'pause' with 'label' 1`] = ` id="play-button--pause" >
props > should render type 'play' with 'background' 1`] = id="play-button--play" >
props > should render type 'play' with 'color' 1`] = ` id="play-button--play" >
props > should render type 'play' with 'label' 1`] = ` id="play-button--play" >
props > should render type 'restart' with 'background' 1`] id="play-button--restart" >
props > should render type 'restart' with 'color' 1`] = ` id="play-button--restart" >
props > should render type 'restart' with 'label' 1`] = ` id="play-button--restart" >
(); const time = computed(() => interpolate(props.time || 0)); diff --git a/packages/components/src/components/progress-bar/__snapshots__/progress-bar.test.ts.snap b/packages/components/src/components/progress-bar/__snapshots__/progress-bar.test.ts.snap index 35240bd72..00da58b99 100644 --- a/packages/components/src/components/progress-bar/__snapshots__/progress-bar.test.ts.snap +++ b/packages/components/src/components/progress-bar/__snapshots__/progress-bar.test.ts.snap @@ -1,102 +1,64 @@ // Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html -exports[`ProgressBar > props > should render 'buffer' 1`] = ` +exports[`ProgressBar > props > should render with custom props 1`] = `
-
-`; - -exports[`ProgressBar > props > should render 'chapters' 1`] = ` -
- - - - -
+
-
-`; - -exports[`ProgressBar > props > should render 'ghost' 1`] = ` -
- - - - - - -
- -
-`; - -exports[`ProgressBar > props > should render 'quantiles' 1`] = ` -
props > should render 'quantiles' 1`] = ` min="0" tabindex="-1" type="range" - /> - - - - -
`; -exports[`ProgressBar > props > should render 'time' 1`] = ` +exports[`ProgressBar > props > should render with default props 1`] = `
- @@ -283,13 +129,13 @@ exports[`ProgressBar > props > should render 'time' 1`] = ` aria-hidden="true" class="ghost-thumb absolute border-transparent border bg-opacity-75 pointer-events-none hidden" data-v-0f66235d="" - style="left: 0%;" + style="left: 100%;" />
-`; - -exports[`ProgressBar > props > should render 'title' 1`] = ` -
- - - - - - -
- - -
-
-`; - -exports[`ProgressBar > props > should render with default props 1`] = ` -
props > should render with default props 1`] = ` min="0" tabindex="-1" type="range" - /> - - - - - -
- - -
-
`; diff --git a/packages/components/src/components/progress-bar/progress-bar.test.ts b/packages/components/src/components/progress-bar/progress-bar.test.ts index 2955db6c7..89fa4ed32 100644 --- a/packages/components/src/components/progress-bar/progress-bar.test.ts +++ b/packages/components/src/components/progress-bar/progress-bar.test.ts @@ -14,6 +14,26 @@ describe('ProgressBar', () => { }); }); + const props = { + duration: 10000, + time: 5000, + ghost: 30, + buffer: [ + [0, 1000], + [5000, 6000] + ], + quantiles: [ + [0, 300], + [5500, 6000] + ], + title: 'title', + chapters: [ + { start: 0, end: 1000 }, + { start: 1000, end: 5000 }, + { start: 5000, end: 10000 } + ] + }; + describe('props', () => { test('should render with default props', async () => { const wrapper = await mount(ProgressBar); @@ -21,90 +41,46 @@ describe('ProgressBar', () => { expect(wrapper.element).toMatchSnapshot(); }); - const props = [ - { - prop: 'time', - value: 5000 - }, - { - prop: 'ghost', - value: 30 - }, - { - prop: 'buffer', - value: [ - [0, 1000], - [5000, 6000] - ] - }, - { - prop: 'quantiles', - value: [ - [0, 300], - [5500, 6000] - ] - }, - { - prop: 'title', - value: 'title' - }, - { - prop: 'chapters', - value: [1000, 5000] - } - ]; - - props.forEach(({ prop, value }) => { - test(`should render '${prop}'`, async () => { - const wrapper = await mount(ProgressBar, { - props: { - [prop]: value, - duration: 10000 - } - }); - - expect(wrapper.element).toMatchSnapshot(); + test(`should render with custom props`, async () => { + const wrapper = await mount(ProgressBar, { + props }); + + expect(wrapper.element).toMatchSnapshot(); }); }); describe('events', () => { test('should emit REQUEST_PLAYTIME on input event', async () => { const wrapper = await mount(ProgressBar, { - props: { - duration: 10000 - } + props }); await wrapper.find('input').trigger('input'); expect(wrapper.emitted().ghost).toEqual([[disableGhost()]]); - expect(wrapper.emitted().time).toEqual([[requestPlaytime(0)]]); + expect(wrapper.emitted().time).toEqual([[requestPlaytime(5000)]]); }); test('should emit REQUEST_PLAYTIME on input event', async () => { const wrapper = await mount(ProgressBar, { - props: { - duration: 10000 - } + props }); await wrapper.find('input').trigger('input'); expect(wrapper.emitted().ghost).toEqual([[disableGhost()]]); - expect(wrapper.emitted().time).toEqual([[requestPlaytime(0)]]); + expect(wrapper.emitted().time).toEqual([[requestPlaytime(5000)]]); }); test('should emit DISABLE_GHOST on input event', async () => { const wrapper = await mount(ProgressBar, { - props: { - duration: 10000 - } + props }); await wrapper.find('input').trigger('input'); expect(wrapper.emitted().ghost).toEqual([[disableGhost()]]); - expect(wrapper.emitted().time).toEqual([[requestPlaytime(0)]]); + expect(wrapper.emitted().time).toEqual([[requestPlaytime(5000)]]); }); }); }); diff --git a/packages/media-backend/cypress/e2e/actions.cy.ts b/packages/media-backend/cypress/e2e/actions.cy.ts index f628bd8a7..9d9d66b35 100644 --- a/packages/media-backend/cypress/e2e/actions.cy.ts +++ b/packages/media-backend/cypress/e2e/actions.cy.ts @@ -24,6 +24,7 @@ describe('actions', () => { beforeEach(() => { audioElement = audio(audioFixture()); + load(audioElement); onError(audioElement, console.log); }); @@ -48,12 +49,22 @@ describe('actions', () => { expect(typeof playtimeSetter).to.equal('function'); }); - it('should set the playtime', () => { - expect(playtimeSetter(9).playtime).to.equal(9); + it('should set the playtime', (done) => { + audioLoader( + audioElement, + compose(done, () => { + expect(playtimeSetter(9).playtime).to.equal(9); + }) + ); }); - it('should prevent playtimes less than 0', () => { - expect(playtimeSetter(-10).playtime).to.equal(0); + it('should prevent playtimes less than 0', (done) => { + audioLoader( + audioElement, + compose(done, () => { + expect(playtimeSetter(-10).playtime).to.equal(0); + }) + ); }); it('should prevent playtime larger than duration', (done) => { diff --git a/packages/media-backend/package.json b/packages/media-backend/package.json index 7b4d4bc16..6e42a100f 100644 --- a/packages/media-backend/package.json +++ b/packages/media-backend/package.json @@ -117,7 +117,7 @@ "integration:setup": "cypress install --force" }, "dependencies": { - "hls.js": "1.4.12", + "hls.js": "1.5.13", "ramda": "0.29.0" }, "devDependencies": { diff --git a/packages/player/sagas/src/transcripts.ts b/packages/player/sagas/src/transcripts.ts index 4c2a799cd..1bbf867ff 100644 --- a/packages/player/sagas/src/transcripts.ts +++ b/packages/player/sagas/src/transcripts.ts @@ -1,14 +1,4 @@ import { put, takeEvery, select, debounce, delay } from 'redux-saga/effects'; -import { - last, - compose, - map, - is, - endsWith, - sortBy, - prop, - reduce -} from 'ramda'; import { setTranscriptsTimeline, @@ -46,7 +36,6 @@ export const searchText = (transcripts: (PodloveWebPlayerTimelineChapterEntry | ((entry as PodloveWebPlayerTimelineTranscriptEntry).texts || []).map(({ text }) => text).join(' ') )); - export function* init({ selectSpeakers, selectChapters, selectPlaytime }: { selectSpeakers: (input: any) => PodloveWebPlayerSpeaker[]; selectChapters: (input: any) => PodloveWebPlayerChapter[]; diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 28fae8d22..bac54a08b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -54,21 +54,21 @@ importers: specifier: 0.2.1 version: 0.2.1 vue: - specifier: 3.2.41 - version: 3.2.41 + specifier: 3.4.31 + version: 3.4.31(typescript@5.3.2) devDependencies: '@histoire/app': specifier: 0.16.1 version: 0.16.1(vite@4.3.9) '@histoire/plugin-vue': specifier: 0.16.1 - version: 0.16.1(histoire@0.16.1)(vite@4.3.9)(vue@3.2.41) + version: 0.16.1(histoire@0.16.1)(vite@4.3.9)(vue@3.4.31) '@histoire/vendors': specifier: 0.16.0 version: 0.16.0 '@vitejs/plugin-vue': specifier: 4.2.3 - version: 4.2.3(vite@4.3.9)(vue@3.2.41) + version: 4.2.3(vite@4.3.9)(vue@3.4.31) autoprefixer: specifier: 10.4.14 version: 10.4.14(postcss@8.4.39) @@ -169,8 +169,8 @@ importers: specifier: 3.4.31 version: 3.4.31(typescript@5.3.2) vue-i18n: - specifier: 9.8.0 - version: 9.8.0(vue@3.4.31) + specifier: 9.13.1 + version: 9.13.1(vue@3.4.31) devDependencies: '@types/lodash-es': specifier: 4.17.12 @@ -234,7 +234,7 @@ importers: version: 4.2.0 redux-vuex: specifier: 3.0.0 - version: 3.0.0(redux@4.2.0)(vue@3.2.41) + version: 3.0.0(redux@4.2.0)(vue@3.4.31) reselect: specifier: 4.1.8 version: 4.1.8 @@ -242,11 +242,11 @@ importers: specifier: 3.2.4 version: 3.2.4(postcss@8.4.39) vue: - specifier: 3.2.41 - version: 3.2.41 + specifier: 3.4.31 + version: 3.4.31(typescript@5.0.4) vue-i18n: - specifier: 9.2.2 - version: 9.2.2(vue@3.2.41) + specifier: 9.13.1 + version: 9.13.1(vue@3.4.31) devDependencies: '@types/node': specifier: 20.8.4 @@ -259,7 +259,7 @@ importers: version: 6.10.0(eslint@8.53.0)(typescript@5.0.4) '@vitejs/plugin-vue': specifier: 4.5.0 - version: 4.5.0(vite@4.3.5)(vue@3.2.41) + version: 4.5.0(vite@4.3.5)(vue@3.4.31) cypress: specifier: 13.5.1 version: 13.5.1 @@ -316,7 +316,7 @@ importers: version: 1.2.3 redux-vuex: specifier: 3.0.2 - version: 3.0.2(redux@4.2.1)(vue@3.2.41) + version: 3.0.2(redux@4.2.1)(vue@3.4.31) reselect: specifier: 4.1.8 version: 4.1.8 @@ -324,11 +324,11 @@ importers: specifier: 3.2.4 version: 3.2.4(postcss@8.4.39) vue: - specifier: 3.2.41 - version: 3.2.41 + specifier: 3.4.31 + version: 3.4.31(typescript@5.0.4) vue-i18n: - specifier: 9.2.2 - version: 9.2.2(vue@3.2.41) + specifier: 9.13.1 + version: 9.13.1(vue@3.4.31) devDependencies: '@fullhuman/postcss-purgecss': specifier: 5.0.0 @@ -347,7 +347,7 @@ importers: version: 6.11.0(eslint@8.53.0)(typescript@5.0.4) '@vitejs/plugin-vue': specifier: 4.2.3 - version: 4.2.3(vite@4.3.9)(vue@3.2.41) + version: 4.2.3(vite@4.3.9)(vue@3.4.31) eslint: specifier: 8.53.0 version: 8.53.0 @@ -531,7 +531,7 @@ importers: version: link:../utils floating-vue: specifier: 2.0.0-beta.20 - version: 2.0.0-beta.20(vue@3.2.41) + version: 2.0.0-beta.20(vue@3.4.31) lodash-es: specifier: 4.17.21 version: 4.17.21 @@ -545,8 +545,8 @@ importers: specifier: 3.2.4 version: 3.2.4(postcss@8.4.39) vue: - specifier: 3.2.41 - version: 3.2.41 + specifier: 3.4.31 + version: 3.4.31(typescript@5.0.4) devDependencies: '@podlove/types': specifier: workspace:* @@ -565,10 +565,10 @@ importers: version: 6.11.0(eslint@8.54.0)(typescript@5.0.4) '@vitejs/plugin-vue': specifier: 4.2.1 - version: 4.2.1(vite@4.3.5)(vue@3.2.41) + version: 4.2.1(vite@4.3.5)(vue@3.4.31) '@vue/test-utils': - specifier: 2.3.2 - version: 2.3.2(vue@3.2.41) + specifier: 2.4.6 + version: 2.4.6 eslint: specifier: 8.54.0 version: 8.54.0 @@ -597,8 +597,8 @@ importers: packages/media-backend: dependencies: hls.js: - specifier: 1.4.12 - version: 1.4.12 + specifier: 1.5.13 + version: 1.5.13 ramda: specifier: 0.29.0 version: 0.29.0 @@ -1557,6 +1557,7 @@ packages: hasBin: true dependencies: '@babel/types': 7.23.5 + dev: true /@babel/parser@7.24.8: resolution: {integrity: sha512-WzfbgXOkGzZiXXCqk43kKwZjzwx4oulxZi3nq2TYL9mOjQv6kYwul9mz6ID36njuL7Xkp6nJEfok848Zj10j/w==} @@ -2776,7 +2777,7 @@ packages: - vite dev: true - /@histoire/plugin-vue@0.16.1(histoire@0.16.1)(vite@4.3.9)(vue@3.2.41): + /@histoire/plugin-vue@0.16.1(histoire@0.16.1)(vite@4.3.9)(vue@3.4.31): resolution: {integrity: sha512-K7ZZl5tA8PWHjQsWFmFX3xa4HlRs+S8+nxym1Smh4dudQ6XSVwdF+gsPQ+RE4zwf6YQ8HDPsvOobI31dz6F4Tg==} peerDependencies: histoire: ^0.16.1 @@ -2790,7 +2791,7 @@ packages: histoire: 0.16.1(@types/node@18.18.14)(vite@4.3.9) launch-editor: 2.6.1 pathe: 0.2.0 - vue: 3.2.41 + vue: 3.4.31(typescript@5.3.2) transitivePeerDependencies: - vite dev: true @@ -3030,65 +3031,27 @@ packages: dev: false optional: true - /@intlify/core-base@9.2.2: - resolution: {integrity: sha512-JjUpQtNfn+joMbrXvpR4hTF8iJQ2sEFzzK3KIESOx+f+uwIjgw20igOyaIdhfsVVBCds8ZM64MoeNSx+PHQMkA==} - engines: {node: '>= 14'} - dependencies: - '@intlify/devtools-if': 9.2.2 - '@intlify/message-compiler': 9.2.2 - '@intlify/shared': 9.2.2 - '@intlify/vue-devtools': 9.2.2 - dev: false - - /@intlify/core-base@9.8.0: - resolution: {integrity: sha512-UxaSZVZ1DwqC/CltUZrWZNaWNhfmKtfyV4BJSt/Zt4Or/fZs1iFj0B+OekYk1+MRHfIOe3+x00uXGQI4PbO/9g==} + /@intlify/core-base@9.13.1: + resolution: {integrity: sha512-+bcQRkJO9pcX8d0gel9ZNfrzU22sZFSA0WVhfXrf5jdJOS24a+Bp8pozuS9sBI9Hk/tGz83pgKfmqcn/Ci7/8w==} engines: {node: '>= 16'} dependencies: - '@intlify/message-compiler': 9.8.0 - '@intlify/shared': 9.8.0 - dev: false - - /@intlify/devtools-if@9.2.2: - resolution: {integrity: sha512-4ttr/FNO29w+kBbU7HZ/U0Lzuh2cRDhP8UlWOtV9ERcjHzuyXVZmjyleESK6eVP60tGC9QtQW9yZE+JeRhDHkg==} - engines: {node: '>= 14'} - dependencies: - '@intlify/shared': 9.2.2 - dev: false - - /@intlify/message-compiler@9.2.2: - resolution: {integrity: sha512-IUrQW7byAKN2fMBe8z6sK6riG1pue95e5jfokn8hA5Q3Bqy4MBJ5lJAofUsawQJYHeoPJ7svMDyBaVJ4d0GTtA==} - engines: {node: '>= 14'} - dependencies: - '@intlify/shared': 9.2.2 - source-map: 0.6.1 + '@intlify/message-compiler': 9.13.1 + '@intlify/shared': 9.13.1 dev: false - /@intlify/message-compiler@9.8.0: - resolution: {integrity: sha512-McnYWhcoYmDJvssVu6QGR0shqlkJuL1HHdi5lK7fNqvQqRYaQ4lSLjYmZxwc8tRNMdIe9/KUKfyPxU9M6yCtNQ==} + /@intlify/message-compiler@9.13.1: + resolution: {integrity: sha512-SKsVa4ajYGBVm7sHMXd5qX70O2XXjm55zdZB3VeMFCvQyvLew/dLvq3MqnaIsTMF1VkkOb9Ttr6tHcMlyPDL9w==} engines: {node: '>= 16'} dependencies: - '@intlify/shared': 9.8.0 - source-map-js: 1.0.2 - dev: false - - /@intlify/shared@9.2.2: - resolution: {integrity: sha512-wRwTpsslgZS5HNyM7uDQYZtxnbI12aGiBZURX3BTR9RFIKKRWpllTsgzHWvj3HKm3Y2Sh5LPC1r0PDCKEhVn9Q==} - engines: {node: '>= 14'} + '@intlify/shared': 9.13.1 + source-map-js: 1.2.0 dev: false - /@intlify/shared@9.8.0: - resolution: {integrity: sha512-TmgR0RCLjzrSo+W3wT0ALf9851iFMlVI9EYNGeWvZFUQTAJx0bvfsMlPdgVtV1tDNRiAfhkFsMKu6jtUY1ZLKQ==} + /@intlify/shared@9.13.1: + resolution: {integrity: sha512-u3b6BKGhE6j/JeRU6C/RL2FgyJfy6LakbtfeVF8fJXURpZZTzfh3e05J0bu0XPw447Q6/WUp3C4ajv4TMS4YsQ==} engines: {node: '>= 16'} dev: false - /@intlify/vue-devtools@9.2.2: - resolution: {integrity: sha512-+dUyqyCHWHb/UcvY1MlIpO87munedm3Gn6E9WWYdWrMuYLcoIoOEVDWSS8xSwtlPU+kA+MEQTP6Q1iI/ocusJg==} - engines: {node: '>= 14'} - dependencies: - '@intlify/core-base': 9.2.2 - '@intlify/shared': 9.2.2 - dev: false - /@isaacs/cliui@8.0.2: resolution: {integrity: sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==} engines: {node: '>=12'} @@ -3698,6 +3661,10 @@ packages: '@octokit/openapi-types': 18.1.1 dev: true + /@one-ini/wasm@0.1.1: + resolution: {integrity: sha512-XuySG1E38YScSJoMlqovLru4KTUNSjgVTIjyh7qMX6aNN5HY5Ct5LhRJdxO79JtTzKfzV/bnWpz+zquYrISsvw==} + dev: true + /@pkgjs/parseargs@0.11.0: resolution: {integrity: sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==} engines: {node: '>=14'} @@ -5206,7 +5173,7 @@ packages: - supports-color dev: false - /@vitejs/plugin-vue@4.2.1(vite@4.3.5)(vue@3.2.41): + /@vitejs/plugin-vue@4.2.1(vite@4.3.5)(vue@3.4.31): resolution: {integrity: sha512-ZTZjzo7bmxTRTkb8GSTwkPOYDIP7pwuyV+RV53c9PYUouwcbkIZIvWvNWlX2b1dYZqtOv7D6iUAnJLVNGcLrSw==} engines: {node: ^14.18.0 || >=16.0.0} peerDependencies: @@ -5214,10 +5181,10 @@ packages: vue: ^3.2.25 dependencies: vite: 4.3.5(@types/node@18.18.14) - vue: 3.2.41 + vue: 3.4.31(typescript@5.0.4) dev: true - /@vitejs/plugin-vue@4.2.3(vite@4.3.9)(vue@3.2.41): + /@vitejs/plugin-vue@4.2.3(vite@4.3.9)(vue@3.4.31): resolution: {integrity: sha512-R6JDUfiZbJA9cMiguQ7jxALsgiprjBeHL5ikpXfJCH62pPHtI+JdJ5xWj6Ev73yXSlYl86+blXn1kZHQ7uElxw==} engines: {node: ^14.18.0 || >=16.0.0} peerDependencies: @@ -5225,10 +5192,10 @@ packages: vue: ^3.2.25 dependencies: vite: 4.3.9(@types/node@18.18.14) - vue: 3.2.41 + vue: 3.4.31(typescript@5.3.2) dev: true - /@vitejs/plugin-vue@4.5.0(vite@4.3.5)(vue@3.2.41): + /@vitejs/plugin-vue@4.5.0(vite@4.3.5)(vue@3.4.31): resolution: {integrity: sha512-a2WSpP8X8HTEww/U00bU4mX1QpLINNuz/2KMNpLsdu3BzOpak3AGI1CJYBTXcc4SPhaD0eNRUp7IyQK405L5dQ==} engines: {node: ^14.18.0 || >=16.0.0} peerDependencies: @@ -5236,7 +5203,7 @@ packages: vue: ^3.2.25 dependencies: vite: 4.3.5(@types/node@20.8.4)(sass@1.69.5) - vue: 3.2.41 + vue: 3.4.31(typescript@5.0.4) dev: true /@vitejs/plugin-vue@5.0.5(vite@5.3.3)(vue@3.4.31): @@ -5487,22 +5454,6 @@ packages: '@vue/compiler-sfc': 3.4.31 dev: false - /@vue/compiler-core@3.2.41: - resolution: {integrity: sha512-oA4mH6SA78DT+96/nsi4p9DX97PHcNROxs51lYk7gb9Z4BPKQ3Mh+BLn6CQZBw857Iuhu28BfMSRHAlPvD4vlw==} - dependencies: - '@babel/parser': 7.23.5 - '@vue/shared': 3.2.41 - estree-walker: 2.0.2 - source-map: 0.6.1 - - /@vue/compiler-core@3.3.9: - resolution: {integrity: sha512-+/Lf68Vr/nFBA6ol4xOtJrW+BQWv3QWKfRwGSm70jtXwfhZNF4R/eRgyVJYoxFRhdCTk/F6g99BP0ffPgZihfQ==} - dependencies: - '@babel/parser': 7.23.5 - '@vue/shared': 3.3.9 - estree-walker: 2.0.2 - source-map-js: 1.0.2 - /@vue/compiler-core@3.4.31: resolution: {integrity: sha512-skOiodXWTV3DxfDhB4rOf3OGalpITLlgCeOwb+Y9GJpfQ8ErigdBUHomBzvG78JoVE8MJoQsb+qhZiHfKeNeEg==} dependencies: @@ -5512,38 +5463,12 @@ packages: estree-walker: 2.0.2 source-map-js: 1.2.0 - /@vue/compiler-dom@3.2.41: - resolution: {integrity: sha512-xe5TbbIsonjENxJsYRbDJvthzqxLNk+tb3d/c47zgREDa/PCp6/Y4gC/skM4H6PIuX5DAxm7fFJdbjjUH2QTMw==} - dependencies: - '@vue/compiler-core': 3.2.41 - '@vue/shared': 3.2.41 - - /@vue/compiler-dom@3.3.9: - resolution: {integrity: sha512-nfWubTtLXuT4iBeDSZ5J3m218MjOy42Vp2pmKVuBKo2/BLcrFUX8nCSr/bKRFiJ32R8qbdnnnBgRn9AdU5v0Sg==} - dependencies: - '@vue/compiler-core': 3.3.9 - '@vue/shared': 3.3.9 - /@vue/compiler-dom@3.4.31: resolution: {integrity: sha512-wK424WMXsG1IGMyDGyLqB+TbmEBFM78hIsOJ9QwUVLGrcSk0ak6zYty7Pj8ftm7nEtdU/DGQxAXp0/lM/2cEpQ==} dependencies: '@vue/compiler-core': 3.4.31 '@vue/shared': 3.4.31 - /@vue/compiler-sfc@3.2.41: - resolution: {integrity: sha512-+1P2m5kxOeaxVmJNXnBskAn3BenbTmbxBxWOtBq3mQTCokIreuMULFantBUclP0+KnzNCMOvcnKinqQZmiOF8w==} - dependencies: - '@babel/parser': 7.23.5 - '@vue/compiler-core': 3.2.41 - '@vue/compiler-dom': 3.2.41 - '@vue/compiler-ssr': 3.2.41 - '@vue/reactivity-transform': 3.2.41 - '@vue/shared': 3.2.41 - estree-walker: 2.0.2 - magic-string: 0.25.9 - postcss: 8.4.31 - source-map: 0.6.1 - /@vue/compiler-sfc@3.4.31: resolution: {integrity: sha512-einJxqEw8IIJxzmnxmJBuK2usI+lJonl53foq+9etB2HAzlPjAS/wa7r0uUpXw5ByX3/0uswVSrjNb17vJm1kQ==} dependencies: @@ -5556,13 +5481,6 @@ packages: magic-string: 0.30.10 postcss: 8.4.39 source-map-js: 1.2.0 - dev: false - - /@vue/compiler-ssr@3.2.41: - resolution: {integrity: sha512-Y5wPiNIiaMz/sps8+DmhaKfDm1xgj6GrH99z4gq2LQenfVQcYXmHIOBcs5qPwl7jaW3SUQWjkAPKMfQemEQZwQ==} - dependencies: - '@vue/compiler-dom': 3.2.41 - '@vue/shared': 3.2.41 /@vue/compiler-ssr@3.4.31: resolution: {integrity: sha512-RtefmITAje3fJ8FSg1gwgDhdKhZVntIVbwupdyZDSifZTRMiWxWehAOTCc8/KZDnBOcYQ4/9VWxsTbd3wT0hAA==} @@ -5618,8 +5536,8 @@ packages: dependencies: '@volar/language-core': 1.11.1 '@volar/source-map': 1.11.1 - '@vue/compiler-dom': 3.3.9 - '@vue/shared': 3.3.9 + '@vue/compiler-dom': 3.4.31 + '@vue/shared': 3.4.31 computeds: 0.0.1 minimatch: 9.0.3 muggle-string: 0.3.1 @@ -5638,8 +5556,8 @@ packages: dependencies: '@volar/language-core': 1.11.1 '@volar/source-map': 1.11.1 - '@vue/compiler-dom': 3.3.9 - '@vue/shared': 3.3.9 + '@vue/compiler-dom': 3.4.31 + '@vue/shared': 3.4.31 computeds: 0.0.1 minimatch: 9.0.3 muggle-string: 0.3.1 @@ -5648,45 +5566,16 @@ packages: vue-template-compiler: 2.7.15 dev: true - /@vue/reactivity-transform@3.2.41: - resolution: {integrity: sha512-mK5+BNMsL4hHi+IR3Ft/ho6Za+L3FA5j8WvreJ7XzHrqkPq8jtF/SMo7tuc9gHjLDwKZX1nP1JQOKo9IEAn54A==} - dependencies: - '@babel/parser': 7.23.5 - '@vue/compiler-core': 3.2.41 - '@vue/shared': 3.2.41 - estree-walker: 2.0.2 - magic-string: 0.25.9 - - /@vue/reactivity@3.2.41: - resolution: {integrity: sha512-9JvCnlj8uc5xRiQGZ28MKGjuCoPhhTwcoAdv3o31+cfGgonwdPNuvqAXLhlzu4zwqavFEG5tvaoINQEfxz+l6g==} - dependencies: - '@vue/shared': 3.2.41 - /@vue/reactivity@3.4.31: resolution: {integrity: sha512-VGkTani8SOoVkZNds1PfJ/T1SlAIOf8E58PGAhIOUDYPC4GAmFA2u/E14TDAFcf3vVDKunc4QqCe/SHr8xC65Q==} dependencies: '@vue/shared': 3.4.31 - dev: false - - /@vue/runtime-core@3.2.41: - resolution: {integrity: sha512-0LBBRwqnI0p4FgIkO9q2aJBBTKDSjzhnxrxHYengkAF6dMOjeAIZFDADAlcf2h3GDALWnblbeprYYpItiulSVQ==} - dependencies: - '@vue/reactivity': 3.2.41 - '@vue/shared': 3.2.41 /@vue/runtime-core@3.4.31: resolution: {integrity: sha512-LDkztxeUPazxG/p8c5JDDKPfkCDBkkiNLVNf7XZIUnJ+66GVGkP+TIh34+8LtPisZ+HMWl2zqhIw0xN5MwU1cw==} dependencies: '@vue/reactivity': 3.4.31 '@vue/shared': 3.4.31 - dev: false - - /@vue/runtime-dom@3.2.41: - resolution: {integrity: sha512-U7zYuR1NVIP8BL6jmOqmapRAHovEFp7CSw4pR2FacqewXNGqZaRfHoNLQsqQvVQ8yuZNZtxSZy0FFyC70YXPpA==} - dependencies: - '@vue/runtime-core': 3.2.41 - '@vue/shared': 3.2.41 - csstype: 2.6.21 /@vue/runtime-dom@3.4.31: resolution: {integrity: sha512-2Auws3mB7+lHhTFCg8E9ZWopA6Q6L455EcU7bzcQ4x6Dn4cCPuqj6S2oBZgN2a8vJRS/LSYYxwFFq2Hlx3Fsaw==} @@ -5695,27 +5584,6 @@ packages: '@vue/runtime-core': 3.4.31 '@vue/shared': 3.4.31 csstype: 3.1.3 - dev: false - - /@vue/server-renderer@3.2.41(vue@3.2.41): - resolution: {integrity: sha512-7YHLkfJdTlsZTV0ae5sPwl9Gn/EGr2hrlbcS/8naXm2CDpnKUwC68i1wGlrYAfIgYWL7vUZwk2GkYLQH5CvFig==} - peerDependencies: - vue: 3.2.41 - dependencies: - '@vue/compiler-ssr': 3.2.41 - '@vue/shared': 3.2.41 - vue: 3.2.41 - - /@vue/server-renderer@3.4.31(vue@3.2.41): - resolution: {integrity: sha512-D5BLbdvrlR9PE3by9GaUp1gQXlCNadIZytMIb8H2h3FMWJd4oUfkUTEH2wAr3qxoRz25uxbTcbqd3WKlm9EHQA==} - peerDependencies: - vue: 3.4.31 - dependencies: - '@vue/compiler-ssr': 3.4.31 - '@vue/shared': 3.4.31 - vue: 3.2.41 - dev: true - optional: true /@vue/server-renderer@3.4.31(vue@3.4.31): resolution: {integrity: sha512-D5BLbdvrlR9PE3by9GaUp1gQXlCNadIZytMIb8H2h3FMWJd4oUfkUTEH2wAr3qxoRz25uxbTcbqd3WKlm9EHQA==} @@ -5725,27 +5593,15 @@ packages: '@vue/compiler-ssr': 3.4.31 '@vue/shared': 3.4.31 vue: 3.4.31(typescript@5.3.2) - dev: false - - /@vue/shared@3.2.41: - resolution: {integrity: sha512-W9mfWLHmJhkfAmV+7gDjcHeAWALQtgGT3JErxULl0oz6R6+3ug91I7IErs93eCFhPCZPHBs4QJS7YWEV7A3sxw==} - - /@vue/shared@3.3.9: - resolution: {integrity: sha512-ZE0VTIR0LmYgeyhurPTpy4KzKsuDyQbMSdM49eKkMnT5X4VfFBLysMzjIZhLEFQYjjOVVfbvUDHckwjDFiO2eA==} /@vue/shared@3.4.31: resolution: {integrity: sha512-Yp3wtJk//8cO4NItOPpi3QkLExAr/aLBGZMmTtW9WpdwBCJpRM6zj9WgWktXAl8IDIozwNMByT45JP3tO3ACWA==} - /@vue/test-utils@2.3.2(vue@3.2.41): - resolution: {integrity: sha512-hJnVaYhbrIm0yBS0+e1Y0Sj85cMyAi+PAbK4JHqMRUZ6S622Goa+G7QzkRSyvCteG8wop7tipuEbHoZo26wsSA==} - peerDependencies: - vue: ^3.0.1 + /@vue/test-utils@2.4.6: + resolution: {integrity: sha512-FMxEjOpYNYiFe0GkaHsnJPXFHxQ6m4t8vI/ElPGpMWxZKpmRvQ33OIrvRXemy6yha03RxhOlQuy+gZMC3CQSow==} dependencies: - js-beautify: 1.14.6 - vue: 3.2.41 - optionalDependencies: - '@vue/compiler-dom': 3.4.31 - '@vue/server-renderer': 3.4.31(vue@3.2.41) + js-beautify: 1.15.1 + vue-component-type-helpers: 2.0.26 dev: true /@yarnpkg/lockfile@1.1.0: @@ -5784,6 +5640,11 @@ packages: resolution: {integrity: sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==} dev: true + /abbrev@2.0.0: + resolution: {integrity: sha512-6/mh1E2u2YgEsCHdY0Yx5oW+61gZU+1vXaoiHHrpKeuRNNgFvS+/jrwHiQhB5apAf5oB7UB7E19ol2R2LKH8hQ==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + dev: true + /acorn-globals@7.0.1: resolution: {integrity: sha512-umOSDSDrfHbTNPuNpC2NSnnA3LUrqpevPb4T9jRx4MagXNS0rs+gwiTcAvqCRmsD6utzsrzNt+ebm00SNWiC3Q==} dependencies: @@ -6955,8 +6816,9 @@ packages: resolution: {integrity: sha512-Fu4hJdvzeylCfQPp9SGWidpzrMs7tTrlu6Vb8XGaRGck8QSNZJJp538Wrb60Lax4fPwR64ViY468OIUTbRlGZg==} dev: false - /commander@2.20.3: - resolution: {integrity: sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==} + /commander@10.0.1: + resolution: {integrity: sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==} + engines: {node: '>=14'} dev: true /commander@4.1.1: @@ -7314,12 +7176,8 @@ packages: cssom: 0.3.8 dev: true - /csstype@2.6.21: - resolution: {integrity: sha512-Z1PhmomIfypOpoMjRQB70jfvy/wxT50qW08YXO5lMIJkrdq4yOTR+AW7FqutScmB9NkLwxo+jU+kZLbofZZq/w==} - /csstype@3.1.3: resolution: {integrity: sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw==} - dev: false /currently-unhandled@0.4.1: resolution: {integrity: sha512-/fITjgjGU50vjQ4FH6eUoYu+iUoUKIXws2hL15JJpIR+BbTxaXQsMuuyjtNh2WqsSBS5nsaZHFsFecyw5CCAng==} @@ -7880,14 +7738,15 @@ packages: safer-buffer: 2.1.2 dev: true - /editorconfig@0.15.3: - resolution: {integrity: sha512-M9wIMFx96vq0R4F+gRpY3o2exzb8hEj/n9S8unZtHSvYjibBp/iMufSzvmOcV/laG0ZtuTVGtiJggPOSW2r93g==} + /editorconfig@1.0.4: + resolution: {integrity: sha512-L9Qe08KWTlqYMVvMcTIvMAdl1cDUubzRNYL+WfA4bLDMHe4nemKkpmYzkznE1FwLKu0EEmy6obgQKzMJrg4x9Q==} + engines: {node: '>=14'} hasBin: true dependencies: - commander: 2.20.3 - lru-cache: 4.1.5 - semver: 5.7.2 - sigmund: 1.0.1 + '@one-ini/wasm': 0.1.1 + commander: 10.0.1 + minimatch: 9.0.1 + semver: 7.6.2 dev: true /ee-first@1.1.1: @@ -8983,14 +8842,14 @@ packages: resolution: {integrity: sha512-W7cHV7Hrwjid6lWmy0IhsWDFQboWSng25U3VVywpHOTJnnAZNPScog67G+cVpeX9f7yDD21ih0WDrMMT+JoaYg==} dev: true - /floating-vue@2.0.0-beta.20(vue@3.2.41): + /floating-vue@2.0.0-beta.20(vue@3.4.31): resolution: {integrity: sha512-N68otcpp6WwcYC7zP8GeJqNZVdfvS7tEY88lwmuAHeqRgnfWx1Un8enzLxROyVnBDZ3TwUoUdj5IFg+bUT7JeA==} peerDependencies: vue: ^3.2.0 dependencies: '@floating-ui/dom': 0.1.10 - vue: 3.2.41 - vue-resize: 2.0.0-alpha.1(vue@3.2.41) + vue: 3.4.31(typescript@5.0.4) + vue-resize: 2.0.0-alpha.1(vue@3.4.31) dev: false /follow-redirects@1.15.3: @@ -9808,8 +9667,8 @@ packages: - utf-8-validate dev: true - /hls.js@1.4.12: - resolution: {integrity: sha512-1RBpx2VihibzE3WE9kGoVCtrhhDWTzydzElk/kyRbEOLnb1WIE+3ZabM/L8BqKFTCL3pUy4QzhXgD1Q6Igr1JA==} + /hls.js@1.5.13: + resolution: {integrity: sha512-xRgKo84nsC7clEvSfIdgn/Tc0NOT+d7vdiL/wvkLO+0k0juc26NRBPPG1SfB8pd5bHXIjMW/F5VM8VYYkOYYdw==} dev: false /homedir-polyfill@1.0.3: @@ -10578,15 +10437,21 @@ packages: resolution: {integrity: sha512-8wb9Yw966OSxApiCt0K3yNJL8pnNeIv+OEq2YMidz4FKP6nonSRoOXc80iXY4JaN2FC11B9qsNmDsm+ZOfMROA==} dev: true - /js-beautify@1.14.6: - resolution: {integrity: sha512-GfofQY5zDp+cuHc+gsEXKPpNw2KbPddreEo35O6jT6i0RVK6LhsoYBhq5TvK4/n74wnA0QbK8gGd+jUZwTMKJw==} - engines: {node: '>=10'} + /js-beautify@1.15.1: + resolution: {integrity: sha512-ESjNzSlt/sWE8sciZH8kBF8BPlwXPwhR6pWKAw8bw4Bwj+iZcnKW6ONWUutJ7eObuBZQpiIb8S7OYspWrKt7rA==} + engines: {node: '>=14'} hasBin: true dependencies: config-chain: 1.1.13 - editorconfig: 0.15.3 - glob: 8.1.0 - nopt: 6.0.0 + editorconfig: 1.0.4 + glob: 10.3.10 + js-cookie: 3.0.5 + nopt: 7.2.1 + dev: true + + /js-cookie@3.0.5: + resolution: {integrity: sha512-cEiJEAEoIbWfCZYKWhVwFuvPX1gETRYPw6LlaTKoxD3s2AkXzkCjnp6h0V77ozyqj0jakteJ4YqDJT830+lVGw==} + engines: {node: '>=14'} dev: true /js-string-escape@1.0.1: @@ -11171,13 +11036,6 @@ packages: engines: {node: 14 || >=16.14} dev: true - /lru-cache@4.1.5: - resolution: {integrity: sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==} - dependencies: - pseudomap: 1.0.2 - yallist: 2.1.2 - dev: true - /lru-cache@5.1.1: resolution: {integrity: sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==} dependencies: @@ -11199,6 +11057,7 @@ packages: resolution: {integrity: sha512-RmF0AsMzgt25qzqqLc1+MbHmhdx0ojF2Fvs4XnOqz2ZOBXzzkEwc/dJQZCYHAn7v1jbVOjAZfK8msRn4BxO4VQ==} dependencies: sourcemap-codec: 1.4.8 + dev: false /magic-string@0.29.0: resolution: {integrity: sha512-WcfidHrDjMY+eLjlU+8OvwREqHwpgCeKVBUpQ3OhYYuvfaYCUgcbuBzappNzZvg/v8onU3oQj+BYpkOJe9Iw4Q==} @@ -11211,7 +11070,6 @@ packages: resolution: {integrity: sha512-iIRwTIf0QKV3UAnYK4PU8uiEc4SRh5jX0mwpIwETPpHdhVM4f53RSwS/vXvN1JhGX+Cs7B8qIq3d6AH49O5fAQ==} dependencies: '@jridgewell/sourcemap-codec': 1.4.15 - dev: false /magic-string@0.30.5: resolution: {integrity: sha512-7xlpfBaQaP/T6Vh8MO/EqXSW5En6INHEvEXQiuff7Gku0PWjU3uf6w/j9o7O+SpB5fOAkrI5HeoNgwjEO0pFsA==} @@ -11935,6 +11793,13 @@ packages: brace-expansion: 2.0.1 dev: true + /minimatch@9.0.1: + resolution: {integrity: sha512-0jWhJpD/MdhPXwPuiRkCbfYfSKp2qnn2eOc279qI7f+osl/l+prKSrvhg157zSYvx/1nmgn2NqdT6k2Z7zSH9w==} + engines: {node: '>=16 || 14 >=14.17'} + dependencies: + brace-expansion: 2.0.1 + dev: true + /minimatch@9.0.3: resolution: {integrity: sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==} engines: {node: '>=16 || 14 >=14.17'} @@ -12280,6 +12145,14 @@ packages: abbrev: 1.1.1 dev: true + /nopt@7.2.1: + resolution: {integrity: sha512-taM24ViiimT/XntxbPyJQzCG+p4EKOpgD3mxFwW38mGjVUrfERQOeY4EDHjdnptttfHuHQXFx+lTP08Q+mLa/w==} + engines: {node: ^14.17.0 || ^16.13.0 || >=18.0.0} + hasBin: true + dependencies: + abbrev: 2.0.0 + dev: true + /normalize-package-data@2.5.0: resolution: {integrity: sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==} dependencies: @@ -13228,6 +13101,7 @@ packages: nanoid: 3.3.7 picocolors: 1.0.0 source-map-js: 1.0.2 + dev: true /postcss@8.4.39: resolution: {integrity: sha512-0vzE+lAiG7hZl1/9I8yzKLx3aR9Xbof3fBHKunvMfOCYAtMhrsnccJY2iTURb9EZd5+pLuiNV9/c/GZJOHsgIw==} @@ -13360,10 +13234,6 @@ packages: resolution: {integrity: sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==} dev: true - /pseudomap@1.0.2: - resolution: {integrity: sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ==} - dev: true - /psl@1.9.0: resolution: {integrity: sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==} dev: true @@ -13586,7 +13456,7 @@ packages: '@redux-saga/core': 1.2.3 dev: false - /redux-vuex@3.0.0(redux@4.2.0)(vue@3.2.41): + /redux-vuex@3.0.0(redux@4.2.0)(vue@3.4.31): resolution: {integrity: sha512-QjIa0mK32yhfzHBHlR5MJYUkUgV7xJoxIIKMzAlpimGSjupa7gcHMjTuWsG6oqK0Q+X6lK6IpLt3NNuSwSmIxg==} peerDependencies: redux: 4.x @@ -13595,10 +13465,10 @@ packages: get-value: 3.0.1 redux: 4.2.0 set-value: 4.1.0 - vue: 3.2.41 + vue: 3.4.31(typescript@5.0.4) dev: false - /redux-vuex@3.0.2(redux@4.2.1)(vue@3.2.41): + /redux-vuex@3.0.2(redux@4.2.1)(vue@3.4.31): resolution: {integrity: sha512-V4ZYQ23VXgoxM2MJOcuuIqhWjO5eaGlv157fFE2KD6s0IttX1iLbqL2W+rwXdaLR7dfMawmLa7H+s2TLscyQUg==} peerDependencies: redux: 4.x @@ -13607,7 +13477,7 @@ packages: get-value: 3.0.1 redux: 4.2.1 set-value: 4.1.0 - vue: 3.2.41 + vue: 3.4.31(typescript@5.0.4) dev: false /redux-vuex@3.1.2(redux@4.2.1)(vue@3.4.31): @@ -14129,7 +13999,6 @@ packages: resolution: {integrity: sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==} engines: {node: '>=10'} hasBin: true - dev: false /send@0.18.0: resolution: {integrity: sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==} @@ -14296,10 +14165,6 @@ packages: resolution: {integrity: sha512-ybx0WO1/8bSBLEWXZvEd7gMW3Sn3JFlW3TvX1nREbDLRNQNaeNN8WK0meBwPdAaOI7TtRRRJn/Es1zhrrCHu7g==} dev: true - /sigmund@1.0.1: - resolution: {integrity: sha512-fCvEXfh6NWpm+YSuY2bpXb/VIihqWA6hLsgboC+0nl71Q7N7o2eaCW8mJa/NLvQhs6jpd3VZV4UiUQlV6+lc8g==} - dev: true - /signal-exit@3.0.7: resolution: {integrity: sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==} @@ -14457,6 +14322,7 @@ packages: /source-map-js@1.0.2: resolution: {integrity: sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==} engines: {node: '>=0.10.0'} + dev: true /source-map-js@1.2.0: resolution: {integrity: sha512-itJW8lvSA0TXEphiRoawsCksnlf8SyvmFzIhltqAHluXd88pkCd+cXJVHTDwdCr0IzwptSm035IHQktUu1QUMg==} @@ -14497,6 +14363,7 @@ packages: /sourcemap-codec@1.4.8: resolution: {integrity: sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==} deprecated: Please use @jridgewell/sourcemap-codec instead + dev: false /space-separated-tokens@2.0.2: resolution: {integrity: sha512-PEGlAwrG8yXGXRjW32fGbg66JAlOAwbObuqVoJpv/mRgoWDQfgH1wDPvtzWyUSNAXBGSk8h755YDbbcEy3SH2Q==} @@ -15369,7 +15236,6 @@ packages: resolution: {integrity: sha512-cW9T5W9xY37cc+jfEnaUvX91foxtHkza3Nw3wkoF4sSlKn0MONdkdEndig/qPBWXNkmplh3NzayQzCiHM4/hqw==} engines: {node: '>=12.20'} hasBin: true - dev: true /typescript@5.3.2: resolution: {integrity: sha512-6l+RyNy7oAHDfxC4FzSJcz9vnjTKxrLpDG5M2Vu4SHRVNg6xzqZp6LYSR9zjqQTu8DU/f5xwxUdADOkbrIX2gQ==} @@ -16030,7 +15896,7 @@ packages: '@babel/plugin-syntax-import-meta': 7.10.4(@babel/core@7.24.8) '@babel/plugin-transform-typescript': 7.23.5(@babel/core@7.24.8) '@vue/babel-plugin-jsx': 1.1.5(@babel/core@7.24.8) - '@vue/compiler-dom': 3.3.9 + '@vue/compiler-dom': 3.4.31 kolorist: 1.8.0 magic-string: 0.30.10 vite: 5.3.3(@types/node@18.18.14) @@ -16610,6 +16476,10 @@ packages: resolution: {integrity: sha512-AyFQ0EVmsOZOlAnxoFOGOq1SQDWAB7C6aqMGS23svWAllfOaxbuFvcT8D1i8z3Gyn8fraVeZNNmN6e9bxxXkKw==} dev: false + /vue-component-type-helpers@2.0.26: + resolution: {integrity: sha512-sO9qQ8oC520SW6kqlls0iqDak53gsTVSrYylajgjmkt1c0vcgjsGSy1KzlDrbEx8pm02IEYhlUkU5hCYf8rwtg==} + dev: true + /vue-eslint-parser@9.3.2(eslint@8.53.0): resolution: {integrity: sha512-q7tWyCVaV9f8iQyIA5Mkj/S6AoJ9KBN8IeUSf3XEmBrOtxOZnfTg5s4KClbZBCK3GtnT/+RyCLZyDHuZwTuBjg==} engines: {node: ^14.17.0 || >=16.0.0} @@ -16646,37 +16516,24 @@ packages: - supports-color dev: true - /vue-i18n@9.2.2(vue@3.2.41): - resolution: {integrity: sha512-yswpwtj89rTBhegUAv9Mu37LNznyu3NpyLQmozF3i1hYOhwpG8RjcjIFIIfnu+2MDZJGSZPXaKWvnQA71Yv9TQ==} - engines: {node: '>= 14'} - peerDependencies: - vue: ^3.0.0 - dependencies: - '@intlify/core-base': 9.2.2 - '@intlify/shared': 9.2.2 - '@intlify/vue-devtools': 9.2.2 - '@vue/devtools-api': 6.5.1 - vue: 3.2.41 - dev: false - - /vue-i18n@9.8.0(vue@3.4.31): - resolution: {integrity: sha512-Izho+6PYjejsTq2mzjcRdBZ5VLRQoSuuexvR8029h5CpN03FYqiqBrShMyf2I1DKkN6kw/xmujcbvC+4QybpsQ==} + /vue-i18n@9.13.1(vue@3.4.31): + resolution: {integrity: sha512-mh0GIxx0wPtPlcB1q4k277y0iKgo25xmDPWioVVYanjPufDBpvu5ySTjP5wOrSvlYQ2m1xI+CFhGdauv/61uQg==} engines: {node: '>= 16'} peerDependencies: vue: ^3.0.0 dependencies: - '@intlify/core-base': 9.8.0 - '@intlify/shared': 9.8.0 + '@intlify/core-base': 9.13.1 + '@intlify/shared': 9.13.1 '@vue/devtools-api': 6.5.1 vue: 3.4.31(typescript@5.3.2) dev: false - /vue-resize@2.0.0-alpha.1(vue@3.2.41): + /vue-resize@2.0.0-alpha.1(vue@3.4.31): resolution: {integrity: sha512-7+iqOueLU7uc9NrMfrzbG8hwMqchfVfSzpVlCMeJQe4pyibqyoifDNbKTZvwxZKDvGkB+PdFeKvnGZMoEb8esg==} peerDependencies: vue: ^3.0.0 dependencies: - vue: 3.2.41 + vue: 3.4.31(typescript@5.0.4) dev: false /vue-template-compiler@2.7.15: @@ -16710,14 +16567,20 @@ packages: typescript: 5.3.2 dev: true - /vue@3.2.41: - resolution: {integrity: sha512-uuuvnrDXEeZ9VUPljgHkqB5IaVO8SxhPpqF2eWOukVrBnRBx2THPSGQBnVRt0GrIG1gvCmFXMGbd7FqcT1ixNQ==} + /vue@3.4.31(typescript@5.0.4): + resolution: {integrity: sha512-njqRrOy7W3YLAlVqSKpBebtZpDVg21FPoaq1I7f/+qqBThK9ChAIjkRWgeP6Eat+8C+iia4P3OYqpATP21BCoQ==} + peerDependencies: + typescript: '*' + peerDependenciesMeta: + typescript: + optional: true dependencies: - '@vue/compiler-dom': 3.2.41 - '@vue/compiler-sfc': 3.2.41 - '@vue/runtime-dom': 3.2.41 - '@vue/server-renderer': 3.2.41(vue@3.2.41) - '@vue/shared': 3.2.41 + '@vue/compiler-dom': 3.4.31 + '@vue/compiler-sfc': 3.4.31 + '@vue/runtime-dom': 3.4.31 + '@vue/server-renderer': 3.4.31(vue@3.4.31) + '@vue/shared': 3.4.31 + typescript: 5.0.4 /vue@3.4.31(typescript@5.3.2): resolution: {integrity: sha512-njqRrOy7W3YLAlVqSKpBebtZpDVg21FPoaq1I7f/+qqBThK9ChAIjkRWgeP6Eat+8C+iia4P3OYqpATP21BCoQ==} @@ -16733,7 +16596,6 @@ packages: '@vue/server-renderer': 3.4.31(vue@3.4.31) '@vue/shared': 3.4.31 typescript: 5.3.2 - dev: false /w3c-keyname@2.2.8: resolution: {integrity: sha512-dpojBhNsCNN7T82Tm7k26A6G9ML3NkhDsnw9n/eoxSRlVBB4CEtIQ/KTCLI2Fwf3ataSXRhYFkQi3SlnFwPvPQ==} @@ -17045,10 +16907,6 @@ packages: resolution: {integrity: sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==} engines: {node: '>=10'} - /yallist@2.1.2: - resolution: {integrity: sha512-ncTzHV7NvsQZkYe1DW7cbDLm0YpzHmZF5r/iyP3ZnQtMiJ+pjzisCiMNI+Sj+xQF5pXhSHxSB3uDbsBTzY/c2A==} - dev: true - /yallist@3.1.1: resolution: {integrity: sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==} From 41e6d4f8291b5d6f80d9460d13c950f682f7d063 Mon Sep 17 00:00:00 2001 From: Alexander Heimbuch Date: Mon, 15 Jul 2024 16:27:30 +0200 Subject: [PATCH 20/20] fix(tests): update tests --- packages/utils/src/transcripts.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/utils/src/transcripts.ts b/packages/utils/src/transcripts.ts index d99eb0b60..4301d7fbe 100644 --- a/packages/utils/src/transcripts.ts +++ b/packages/utils/src/transcripts.ts @@ -11,7 +11,6 @@ import { secondsToMilliseconds, toPlayerTime } from './time.js'; const mapSpeakers = (speakers: PodloveWebPlayerSpeaker[]) => compose( - filter(prop('speaker')), map( ( transcript: PodloveWebPlayerTimelineTranscriptEntry