Merge branch 'omnivore-app:main' into main

This commit is contained in:
Jivesh Mohan
2024-05-02 23:04:56 +08:00
committed by GitHub
19 changed files with 386 additions and 215 deletions

View File

@ -27,8 +27,8 @@ android {
applicationId = "app.omnivore.omnivore"
minSdk = 26
targetSdk = 34
versionCode = 2020001
versionName = "0.202.1"
versionCode = 2020003
versionName = "0.202.3"
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
vectorDrawables {

View File

@ -1,64 +1,65 @@
query UpdatesSince(
$folder: String
$after: String
$first: Int
$since: Date!
$folder: String
$after: String
$first: Int
$since: Date!
) {
updatesSince(after: $after, first: $first, folder: $folder, since: $since) {
... on UpdatesSinceSuccess {
edges {
cursor
itemID
updateReason
node {
id
title
folder
slug
url
pageType
contentReader
createdAt
isArchived
readingProgressPercent
readingProgressAnchorIndex
author
image
description
publishedAt
ownedByViewer
originalArticleUrl
uploadFileId
labels {
...LabelFields
}
highlights {
...HighlightFields
}
pageId
shortId
quote
annotation
state
siteName
subscription
readAt
savedAt
updatedAt
language
wordsCount
}
}
pageInfo {
hasNextPage
hasPreviousPage
startCursor
endCursor
totalCount
}
}
... on UpdatesSinceError {
errorCodes
updatesSince(after: $after, first: $first, folder: $folder, since: $since) {
... on UpdatesSinceSuccess {
edges {
cursor
itemID
updateReason
node {
id
title
folder
slug
url
pageType
contentReader
createdAt
isArchived
readingProgressPercent
readingProgressAnchorIndex
author
image
description
publishedAt
ownedByViewer
originalArticleUrl
uploadFileId
labels {
...LabelFields
}
highlights {
...HighlightFields
}
pageId
shortId
quote
annotation
state
siteName
subscription
readAt
savedAt
updatedAt
language
wordsCount
content
}
}
pageInfo {
hasNextPage
hasPreviousPage
startCursor
endCursor
totalCount
}
}
... on UpdatesSinceError {
errorCodes
}
}
}

View File

@ -66,7 +66,8 @@ suspend fun DataService.sync(since: String, cursor: String?, limit: Int = 20): S
slug = it.slug,
isArchived = it.isArchived,
contentReader = it.contentReader.rawValue,
wordsCount = it.wordsCount
wordsCount = it.wordsCount,
content = it.content
)
val labels = it.labels?.map { label ->
SavedItemLabel(

View File

@ -255,19 +255,9 @@ class FollowingViewModel @Inject constructor(
since: String,
count: Int,
startTime: String,
isInitialBatch: Boolean = true
) {
libraryRepository.syncOfflineItemsWithServerIfNeeded()
val result = libraryRepository.sync(since = since, cursor = cursor, limit = 20)
// Fetch content for the initial batch only
if (isInitialBatch) {
for (slug in result.savedItemSlugs) {
delay(250)
contentRequestChannel.send(slug)
}
}
val totalCount = count + result.count
if (!result.hasError && result.hasMoreItems && result.cursor != null) {
@ -276,7 +266,6 @@ class FollowingViewModel @Inject constructor(
since = since,
count = totalCount,
startTime = startTime,
isInitialBatch = false
)
} else {
datastoreRepo.putString(libraryLastSyncTimestamp, startTime)

View File

@ -273,20 +273,11 @@ class LibraryViewModel @Inject constructor(
cursor: String?,
since: String,
count: Int,
startTime: String,
isInitialBatch: Boolean = true
startTime: String
) {
libraryRepository.syncOfflineItemsWithServerIfNeeded()
val result = libraryRepository.sync(since = since, cursor = cursor, limit = 20)
// Fetch content for the initial batch only
if (isInitialBatch) {
for (slug in result.savedItemSlugs) {
delay(250)
contentRequestChannel.send(slug)
}
}
val totalCount = count + result.count
if (!result.hasError && result.hasMoreItems && result.cursor != null) {
@ -295,7 +286,6 @@ class LibraryViewModel @Inject constructor(
since = since,
count = totalCount,
startTime = startTime,
isInitialBatch = false
)
} else {
datastoreRepository.putString(libraryLastSyncTimestamp, startTime)

View File

@ -1,5 +1,4 @@
// swiftlint:disable file_length type_body_length
#if os(iOS)
import AVFoundation
@ -39,23 +38,23 @@ public struct DigestAudioItem: AudioItemProperties {
public var language: String?
public var startIndex: Int = 0
public var startOffset: Double = 0.0
public init(digest: DigestResult) {
self.digest = digest
self.itemID = digest.id
self.title = digest.title
self.startIndex = 0
self.startOffset = 0
self.imageURL = nil
if let first = digest.speechFiles.first {
self.language = first.language
self.byline = digest.byline
}
}
}
// swiftlint:disable all
@MainActor
public class AudioController: NSObject, ObservableObject, AVAudioPlayerDelegate {
@ -108,7 +107,7 @@ public struct DigestAudioItem: AudioItemProperties {
playbackError = false
self.itemAudioProperties = itemAudioProperties
startAudio(atIndex: itemAudioProperties.startIndex, andOffset: itemAudioProperties.startOffset)
EventTracker.track(
.audioSessionStart(
linkID: itemAudioProperties.itemID,
@ -319,7 +318,7 @@ public struct DigestAudioItem: AudioItemProperties {
public func seek(toIdx: Int) {
let before = durationBefore(playerIndex: toIdx)
let remainder = 0.0
// if the foundIdx happens to be the current item, we just set the position
if let playerItem = player?.currentItem as? SpeechPlayerItem {
if playerItem.speechItem.audioIdx == toIdx {
@ -666,8 +665,10 @@ public struct DigestAudioItem: AudioItemProperties {
player = AVQueuePlayer(items: [])
if let player = player {
observer = player.observe(\.currentItem, options: [.new]) { _, _ in
self.currentAudioIndex = (player.currentItem as? SpeechPlayerItem)?.speechItem.audioIdx ?? 0
self.updateReadText()
DispatchQueue.main.async {
self.currentAudioIndex = (player.currentItem as? SpeechPlayerItem)?.speechItem.audioIdx ?? 0
self.updateReadText()
}
}
}
@ -683,8 +684,8 @@ public struct DigestAudioItem: AudioItemProperties {
func synthesizeFrom(start: Int, playWhenReady: Bool, atOffset: Double = 0.0) {
if let synthesizer = self.synthesizer, let items = self.synthesizer?.createPlayerItems(from: start) {
let prefetchQueue = OperationQueue()
prefetchQueue.maxConcurrentOperationCount = 5
prefetchQueue.maxConcurrentOperationCount = 1
for speechItem in items {
let isLast = speechItem.audioIdx == synthesizer.document.utterances.count - 1
let playerItem = SpeechPlayerItem(session: self, prefetchQueue: prefetchQueue, speechItem: speechItem) {

View File

@ -40,12 +40,11 @@ class SpeechPlayerItem: AVPlayerItem {
resourceLoaderDelegate.owner = self
self.observer = observe(\.status, options: [.new]) { item, _ in
if item.status == .readyToPlay {
let duration = CMTimeGetSeconds(item.duration)
item.session.updateDuration(forItem: item.speechItem, newDuration: duration)
}
if item.status == .failed {
item.session.stopWithError()
DispatchQueue.main.async {
if item.status == .readyToPlay {
let duration = CMTimeGetSeconds(item.duration)
item.session.updateDuration(forItem: item.speechItem, newDuration: duration)
}
}
}
@ -55,11 +54,29 @@ class SpeechPlayerItem: AVPlayerItem {
) { [weak self] _ in
guard let self = self else { return }
self.completed()
self.checkPrefetchQueue(prefetchQueue: prefetchQueue)
}
self.prefetchOperation = PrefetchSpeechItemOperation(speechItem: speechItem)
if let prefetchOperation = self.prefetchOperation {
prefetchQueue.addOperation(prefetchOperation)
prefetchOperation.completionBlock = {
self.checkPrefetchQueue(prefetchQueue: prefetchQueue)
}
}
}
func checkPrefetchQueue(prefetchQueue: OperationQueue) {
DispatchQueue.main.async {
if self.speechItem.audioIdx > self.session.currentAudioIndex + 5 {
// prefetch has gotten too far ahead of the audio. Pause the prefetch queue
print("PAUSING PREFETCH QUEUE", self.speechItem.audioIdx, self.session.currentAudioIndex + 10, self.speechItem.text)
prefetchQueue.isSuspended = true
}
if self.speechItem.audioIdx < self.session.currentAudioIndex + 5 {
print("RESUMING PREFETCH QUEUE", self.speechItem.audioIdx, self.session.currentAudioIndex + 5)
prefetchQueue.isSuspended = false
}
}
}

View File

@ -222,9 +222,13 @@ struct SpeechSynthesizer {
do {
let jsonData = try decoder.decode(SynthesizeResult.self, from: data) as SynthesizeResult
let audioData = Data(fromHexEncodedString: jsonData.audioData)!
var audioData = Data(fromHexEncodedString: jsonData.audioData)!
if audioData.count < 1 {
throw BasicError.message(messageText: "Audio data is empty")
if let silence = generateSilentAudioBuffer() {
audioData = silence
} else {
throw BasicError.message(messageText: "Audio data is empty")
}
}
try audioData.write(to: tempPath)
@ -244,6 +248,34 @@ struct SpeechSynthesizer {
throw BasicError.message(messageText: errorMessage)
}
}
static func generateSilentAudioBuffer() -> Data? {
let audioFormat = AVAudioFormat(standardFormatWithSampleRate: 44100, channels: 1)!
let frameCount = UInt32(audioFormat.sampleRate * 0.001) // 1 millisecond of frames
guard let buffer = AVAudioPCMBuffer(pcmFormat: audioFormat, frameCapacity: frameCount) else {
return nil
}
buffer.frameLength = buffer.frameCapacity
return bufferToData(buffer: buffer)
}
static func bufferToData(buffer: AVAudioPCMBuffer) -> Data {
let channelCount = Int(buffer.format.channelCount)
let frames = Int(buffer.frameLength)
let channels = UnsafeBufferPointer(start: buffer.floatChannelData, count: channelCount)
var data = Data()
for frame in 0..<frames {
for channel in 0..<channelCount {
let value = channels[channel][frame]
var temp = value
data.append(UnsafeBufferPointer(start: &temp, count: 1))
}
}
return data
}
}
struct SynthesizeResult: Decodable {

View File

@ -172,7 +172,7 @@ extension DataService {
try? data.write(to: localPath)
}
}
public func explain(text: String, libraryItemId: String) async throws -> String {
let encoder = JSONEncoder()
let explainRequest = ExplainRequest(text: text, libraryItemId: libraryItemId)

View File

@ -102,19 +102,6 @@ export const markEmailAsItemResolver = authorized<
}
}
const text = `A recent email marked as a library item
by: ${uid}
from: ${recentEmail.from}
subject: ${recentEmail.subject}`
// email us to let us know that an email failed to parse as an article
await sendEmail({
to: env.sender.feedback,
subject: 'A recent email marked as a library item',
text,
from: env.sender.message,
})
return {
success,
}

View File

@ -27,12 +27,24 @@ export const NotebookHeader = (props: NotebookHeaderProps) => {
const exportHighlights = useCallback(() => {
if (articleData?.article.article.highlights) {
const markdown = highlightsAsMarkdown(
let preamble = ''
if (articleData?.article.article.title) {
preamble += `## ${articleData?.article.article.title}\n`
}
if (
articleData?.article.article.contentReader == 'WEB' &&
articleData?.article.article.originalArticleUrl
) {
preamble += `URL: ${articleData?.article.article.originalArticleUrl}\n`
}
const highlights = highlightsAsMarkdown(
articleData?.article.article.highlights
)
if (markdown.length > 1) {
if (preamble.length + highlights.length > 1) {
;(async () => {
await navigator.clipboard.writeText(markdown)
await navigator.clipboard.writeText(preamble + '\n\n' + highlights)
showSuccessToast('Highlights and notes copied')
})()
} else {

View File

@ -48,6 +48,7 @@ const FONT_FAMILIES = [
'IBMPlexSans',
'Fraunces',
'Literata',
'SuperNotesPro',
]
type SettingsProps = {

View File

@ -4,7 +4,7 @@ import '../styles/articleInnerStyling.css'
import type { AppProps } from 'next/app'
import { IdProvider } from '@radix-ui/react-id'
import { NextRouter, useRouter } from 'next/router'
import { useEffect, useState } from 'react'
import { ReactNode, useEffect, useState } from 'react'
import TopBarProgress from 'react-topbar-progress-indicator'
import {
KBarProvider,
@ -23,7 +23,6 @@ import { updateTheme } from '../lib/themeUpdater'
import { ThemeId } from '../components/tokens/stitches.config'
import { posthog } from 'posthog-js'
import { GoogleReCaptchaProvider } from '@google-recaptcha/react'
import { Recaptcha } from '../components/elements/Recaptcha'
TopBarProgress.config({
barColors: {
@ -67,6 +66,24 @@ const generateActions = (router: NextRouter) => {
return defaultActions
}
const ConditionalCaptchaProvider = (props: {
children: ReactNode
}): JSX.Element => {
if (process.env.NEXT_PUBLIC_RECAPTCHA_CHALLENGE_SITE_KEY) {
return (
<GoogleReCaptchaProvider
type="v2-checkbox"
isEnterprise={true}
host="recaptcha.net"
siteKey={process.env.NEXT_PUBLIC_RECAPTCHA_CHALLENGE_SITE_KEY ?? ''}
>
{props.children}
</GoogleReCaptchaProvider>
)
}
return <>props.children</>
}
export function OmnivoreApp({ Component, pageProps }: AppProps): JSX.Element {
const router = useRouter()
@ -81,12 +98,7 @@ export function OmnivoreApp({ Component, pageProps }: AppProps): JSX.Element {
}, [router.events])
return (
<GoogleReCaptchaProvider
type="v2-checkbox"
isEnterprise={true}
host="recaptcha.net"
siteKey={process.env.NEXT_PUBLIC_RECAPTCHA_CHALLENGE_SITE_KEY ?? ''}
>
<ConditionalCaptchaProvider>
<KBarProvider actions={generateActions(router)}>
<KBarPortal>
<KBarPositioner style={{ zIndex: 100 }}>
@ -100,7 +112,7 @@ export function OmnivoreApp({ Component, pageProps }: AppProps): JSX.Element {
<Component {...pageProps} />
</IdProvider>
</KBarProvider>
</GoogleReCaptchaProvider>
</ConditionalCaptchaProvider>
)
}

Binary file not shown.

View File

@ -418,6 +418,28 @@ div#appleid-signin {
src: url('/static/fonts/Literata/Literata-Italic.ttf');
}
@font-face {
font-family: 'SuperNotesPro';
font-weight: 400;
font-style: normal;
src: url('/static/fonts/SNPro/SNPro-VariableRegular.ttf');
}
@font-face {
font-family: 'SuperNotesPro';
font-weight: 700;
font-style: bold;
src: url('/static/fonts/SNPro/SNPro-Bold.ttf');
}
@font-face {
font-family: 'SuperNotesPro';
font-weight: 400;
font-style: italic;
src: url('/static/fonts/SNPro/SNPro-Italic.ttf');
}
@font-face {
font-family: 'FuturaBold';
src: url('/static/fonts/FuturaBold/FuturaBold.otf');

View File

@ -34,7 +34,7 @@
"adminjs": "5.0.1",
"bcryptjs": "^2.4.3",
"cookie-parser": "^1.4.5",
"express": "^4.17.3",
"express": "^4.19.2",
"express-formidable": "^1.2.0",
"express-session": "^1.17.2",
"pg": "^8.6.0",

View File

@ -1954,21 +1954,23 @@ binary-extensions@^2.0.0:
resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-2.2.0.tgz#75f502eeaf9ffde42fc98829645be4ea76bd9e2d"
integrity sha512-jDctJ/IVQbZoJykoeHbhXpOlNBqGNcwXJKJog42E5HDPUwQTSdjCHdihjj0DlnheQ7blbT6dHOafNAiS8ooQKA==
body-parser@1.19.2:
version "1.19.2"
resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.19.2.tgz#4714ccd9c157d44797b8b5607d72c0b89952f26e"
integrity sha512-SAAwOxgoCKMGs9uUAUFHygfLAyaniaoun6I8mFY9pRAJL9+Kec34aU+oIjDhTycub1jozEfEwx1W1IuOYxVSFw==
body-parser@1.20.2:
version "1.20.2"
resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.20.2.tgz#6feb0e21c4724d06de7ff38da36dad4f57a747fd"
integrity sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==
dependencies:
bytes "3.1.2"
content-type "~1.0.4"
content-type "~1.0.5"
debug "2.6.9"
depd "~1.1.2"
http-errors "1.8.1"
depd "2.0.0"
destroy "1.2.0"
http-errors "2.0.0"
iconv-lite "0.4.24"
on-finished "~2.3.0"
qs "6.9.7"
raw-body "2.4.3"
on-finished "2.4.1"
qs "6.11.0"
raw-body "2.5.2"
type-is "~1.6.18"
unpipe "1.0.0"
boxen@^5.0.0:
version "5.1.2"
@ -2077,6 +2079,17 @@ call-bind@^1.0.0, call-bind@^1.0.2:
function-bind "^1.1.1"
get-intrinsic "^1.0.2"
call-bind@^1.0.7:
version "1.0.7"
resolved "https://registry.yarnpkg.com/call-bind/-/call-bind-1.0.7.tgz#06016599c40c56498c18769d2730be242b6fa3b9"
integrity sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==
dependencies:
es-define-property "^1.0.0"
es-errors "^1.3.0"
function-bind "^1.1.2"
get-intrinsic "^1.2.4"
set-function-length "^1.2.1"
callsites@^3.0.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73"
@ -2334,10 +2347,10 @@ content-disposition@0.5.4:
dependencies:
safe-buffer "5.2.1"
content-type@~1.0.4:
version "1.0.4"
resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b"
integrity sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA==
content-type@~1.0.4, content-type@~1.0.5:
version "1.0.5"
resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.5.tgz#8b773162656d1d1086784c8f23a54ce6d73d7918"
integrity sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==
convert-source-map@^1.5.0, convert-source-map@^1.7.0:
version "1.8.0"
@ -2369,10 +2382,10 @@ cookie@0.4.1:
resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.1.tgz#afd713fe26ebd21ba95ceb61f9a8116e50a537d1"
integrity sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA==
cookie@0.4.2:
version "0.4.2"
resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.2.tgz#0e41f24de5ecf317947c82fc789e06a884824432"
integrity sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==
cookie@0.6.0:
version "0.6.0"
resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.6.0.tgz#2798b04b071b0ecbff0dbb62a505a8efa4e19051"
integrity sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==
core-js-compat@^3.14.0, core-js-compat@^3.15.0:
version "3.15.2"
@ -2528,6 +2541,15 @@ defer-to-connect@^2.0.0:
resolved "https://registry.yarnpkg.com/defer-to-connect/-/defer-to-connect-2.0.1.tgz#8016bdb4143e4632b77a3449c6236277de520587"
integrity sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==
define-data-property@^1.1.4:
version "1.1.4"
resolved "https://registry.yarnpkg.com/define-data-property/-/define-data-property-1.1.4.tgz#894dc141bb7d3060ae4366f6a0107e68fbe48c5e"
integrity sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==
dependencies:
es-define-property "^1.0.0"
es-errors "^1.3.0"
gopd "^1.0.1"
define-properties@^1.1.3:
version "1.1.3"
resolved "https://registry.yarnpkg.com/define-properties/-/define-properties-1.1.3.tgz#cf88da6cbee26fe6db7094f61d870cbd84cee9f1"
@ -2535,20 +2557,15 @@ define-properties@^1.1.3:
dependencies:
object-keys "^1.0.12"
depd@~1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9"
integrity sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak=
depd@~2.0.0:
depd@2.0.0, depd@~2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/depd/-/depd-2.0.0.tgz#b696163cc757560d09cf22cc8fad1571b79e76df"
integrity sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==
destroy@~1.0.4:
version "1.0.4"
resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80"
integrity sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA=
destroy@1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.2.0.tgz#4803735509ad8be552934c67df614f94e66fa015"
integrity sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==
diff@^4.0.1:
version "4.0.2"
@ -2631,6 +2648,18 @@ error-ex@^1.3.1:
dependencies:
is-arrayish "^0.2.1"
es-define-property@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/es-define-property/-/es-define-property-1.0.0.tgz#c7faefbdff8b2696cf5f46921edfb77cc4ba3845"
integrity sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==
dependencies:
get-intrinsic "^1.2.4"
es-errors@^1.3.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/es-errors/-/es-errors-1.3.0.tgz#05f75a25dab98e4fb1dcd5e1472c0546d5057c8f"
integrity sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==
escalade@^3.1.1:
version "3.1.1"
resolved "https://registry.yarnpkg.com/escalade/-/escalade-3.1.1.tgz#d8cfdc7000965c5a0174b4a82eaa5c0552742e40"
@ -2697,38 +2726,39 @@ express-session@^1.17.2:
safe-buffer "5.2.1"
uid-safe "~2.1.5"
express@^4.17.3:
version "4.17.3"
resolved "https://registry.yarnpkg.com/express/-/express-4.17.3.tgz#f6c7302194a4fb54271b73a1fe7a06478c8f85a1"
integrity sha512-yuSQpz5I+Ch7gFrPCk4/c+dIBKlQUxtgwqzph132bsT6qhuzss6I8cLJQz7B3rFblzd6wtcI0ZbGltH/C4LjUg==
express@^4.19.2:
version "4.19.2"
resolved "https://registry.yarnpkg.com/express/-/express-4.19.2.tgz#e25437827a3aa7f2a827bc8171bbbb664a356465"
integrity sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==
dependencies:
accepts "~1.3.8"
array-flatten "1.1.1"
body-parser "1.19.2"
body-parser "1.20.2"
content-disposition "0.5.4"
content-type "~1.0.4"
cookie "0.4.2"
cookie "0.6.0"
cookie-signature "1.0.6"
debug "2.6.9"
depd "~1.1.2"
depd "2.0.0"
encodeurl "~1.0.2"
escape-html "~1.0.3"
etag "~1.8.1"
finalhandler "~1.1.2"
finalhandler "1.2.0"
fresh "0.5.2"
http-errors "2.0.0"
merge-descriptors "1.0.1"
methods "~1.1.2"
on-finished "~2.3.0"
on-finished "2.4.1"
parseurl "~1.3.3"
path-to-regexp "0.1.7"
proxy-addr "~2.0.7"
qs "6.9.7"
qs "6.11.0"
range-parser "~1.2.1"
safe-buffer "5.2.1"
send "0.17.2"
serve-static "1.14.2"
send "0.18.0"
serve-static "1.15.0"
setprototypeof "1.2.0"
statuses "~1.5.0"
statuses "2.0.1"
type-is "~1.6.18"
utils-merge "1.0.1"
vary "~1.1.2"
@ -2783,17 +2813,17 @@ fill-range@^7.0.1:
dependencies:
to-regex-range "^5.0.1"
finalhandler@~1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.2.tgz#b7e7d000ffd11938d0fdb053506f6ebabe9f587d"
integrity sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==
finalhandler@1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.2.0.tgz#7d23fe5731b207b4640e4fcd00aec1f9207a7b32"
integrity sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==
dependencies:
debug "2.6.9"
encodeurl "~1.0.2"
escape-html "~1.0.3"
on-finished "~2.3.0"
on-finished "2.4.1"
parseurl "~1.3.3"
statuses "~1.5.0"
statuses "2.0.1"
unpipe "~1.0.0"
find-cache-dir@^2.0.0:
@ -2874,6 +2904,11 @@ function-bind@^1.1.1:
resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d"
integrity sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==
function-bind@^1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c"
integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==
gensync@^1.0.0-beta.2:
version "1.0.0-beta.2"
resolved "https://registry.yarnpkg.com/gensync/-/gensync-1.0.0-beta.2.tgz#32a6ee76c3d7f52d46b2b1ae5d93fea8580a25e0"
@ -2893,6 +2928,17 @@ get-intrinsic@^1.0.2:
has "^1.0.3"
has-symbols "^1.0.1"
get-intrinsic@^1.1.3, get-intrinsic@^1.2.4:
version "1.2.4"
resolved "https://registry.yarnpkg.com/get-intrinsic/-/get-intrinsic-1.2.4.tgz#e385f5a4b5227d449c3eabbad05494ef0abbeadd"
integrity sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==
dependencies:
es-errors "^1.3.0"
function-bind "^1.1.2"
has-proto "^1.0.1"
has-symbols "^1.0.3"
hasown "^2.0.0"
get-stream@^4.1.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/get-stream/-/get-stream-4.1.0.tgz#c1b255575f3dc21d59bfc79cd3d2b46b1c3a54b5"
@ -2938,6 +2984,13 @@ globals@^11.1.0:
resolved "https://registry.yarnpkg.com/globals/-/globals-11.12.0.tgz#ab8795338868a0babd8525758018c2a7eb95c42e"
integrity sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==
gopd@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.0.1.tgz#29ff76de69dac7489b7c0918a5788e56477c332c"
integrity sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==
dependencies:
get-intrinsic "^1.1.3"
got@^11.8.0:
version "11.8.2"
resolved "https://registry.yarnpkg.com/got/-/got-11.8.2.tgz#7abb3959ea28c31f3576f1576c1effce23f33599"
@ -2999,11 +3052,28 @@ has-flag@^4.0.0:
resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b"
integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==
has-property-descriptors@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz#963ed7d071dc7bf5f084c5bfbe0d1b6222586854"
integrity sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==
dependencies:
es-define-property "^1.0.0"
has-proto@^1.0.1:
version "1.0.3"
resolved "https://registry.yarnpkg.com/has-proto/-/has-proto-1.0.3.tgz#b31ddfe9b0e6e9914536a6ab286426d0214f77fd"
integrity sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==
has-symbols@^1.0.1, has-symbols@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.2.tgz#165d3070c00309752a1236a479331e3ac56f1423"
integrity sha512-chXa79rL/UC2KlX17jo3vRGz0azaWEx5tGqZg5pO3NUyEJVB17dMruQlzCCOfUvElghKcm5194+BCRvi2Rv/Gw==
has-symbols@^1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/has-symbols/-/has-symbols-1.0.3.tgz#bb7b2c4349251dce87b125f7bdf874aa7c8b39f8"
integrity sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==
has-yarn@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/has-yarn/-/has-yarn-2.1.0.tgz#137e11354a7b5bf11aa5cb649cf0c6f3ff2b2e77"
@ -3016,6 +3086,13 @@ has@^1.0.3:
dependencies:
function-bind "^1.1.1"
hasown@^2.0.0:
version "2.0.2"
resolved "https://registry.yarnpkg.com/hasown/-/hasown-2.0.2.tgz#003eaf91be7adc372e84ec59dc37252cedb80003"
integrity sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==
dependencies:
function-bind "^1.1.2"
highlight.js@^10.7.1:
version "10.7.3"
resolved "https://registry.yarnpkg.com/highlight.js/-/highlight.js-10.7.3.tgz#697272e3991356e40c3cac566a74eef681756531"
@ -3052,15 +3129,15 @@ http-cache-semantics@^4.0.0:
resolved "https://registry.yarnpkg.com/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz#abe02fcb2985460bf0323be664436ec3476a6d5a"
integrity sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==
http-errors@1.8.1:
version "1.8.1"
resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.8.1.tgz#7c3f28577cbc8a207388455dbd62295ed07bd68c"
integrity sha512-Kpk9Sm7NmI+RHhnj6OIWDI1d6fIoFAtFt9RLaTMRlg/8w49juAStsrBgp0Dp4OdxdVbRIeKhtCUvoi/RuAhO4g==
http-errors@2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-2.0.0.tgz#b7774a1486ef73cf7667ac9ae0858c012c57b9d3"
integrity sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==
dependencies:
depd "~1.1.2"
depd "2.0.0"
inherits "2.0.4"
setprototypeof "1.2.0"
statuses ">= 1.5.0 < 2"
statuses "2.0.1"
toidentifier "1.0.1"
http2-wrapper@^1.0.0-beta.5.2:
@ -3683,6 +3760,11 @@ object-assign@^4.0.1, object-assign@^4.1.1:
resolved "https://registry.yarnpkg.com/object-assign/-/object-assign-4.1.1.tgz#2109adc7965887cfc05cbbd442cac8bfbb360863"
integrity sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=
object-inspect@^1.13.1:
version "1.13.1"
resolved "https://registry.yarnpkg.com/object-inspect/-/object-inspect-1.13.1.tgz#b96c6109324ccfef6b12216a956ca4dc2ff94bc2"
integrity sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==
object-is@^1.0.1:
version "1.1.5"
resolved "https://registry.yarnpkg.com/object-is/-/object-is-1.1.5.tgz#b9deeaa5fc7f1846a0faecdceec138e5778f53ac"
@ -3706,10 +3788,10 @@ object.assign@^4.1.0:
has-symbols "^1.0.1"
object-keys "^1.1.1"
on-finished@~2.3.0:
version "2.3.0"
resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947"
integrity sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=
on-finished@2.4.1:
version "2.4.1"
resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.4.1.tgz#58c8c44116e54845ad57f14ab10b03533184ac3f"
integrity sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==
dependencies:
ee-first "1.1.1"
@ -4039,10 +4121,12 @@ pupa@^2.1.1:
dependencies:
escape-goat "^2.0.0"
qs@6.9.7:
version "6.9.7"
resolved "https://registry.yarnpkg.com/qs/-/qs-6.9.7.tgz#4610846871485e1e048f44ae3b94033f0e675afe"
integrity sha512-IhMFgUmuNpyRfxA90umL7ByLlgRXu6tIfKPpF5TmcfRLlLCckfP/g3IQmju6jjpu+Hh8rA+2p6A27ZSPOOHdKw==
qs@6.11.0:
version "6.11.0"
resolved "https://registry.yarnpkg.com/qs/-/qs-6.11.0.tgz#fd0d963446f7a65e1367e01abd85429453f0c37a"
integrity sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==
dependencies:
side-channel "^1.0.4"
queue-microtask@^1.2.2:
version "1.2.3"
@ -4097,13 +4181,13 @@ range-parser@~1.2.1:
resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031"
integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==
raw-body@2.4.3:
version "2.4.3"
resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.4.3.tgz#8f80305d11c2a0a545c2d9d89d7a0286fcead43c"
integrity sha512-UlTNLIcu0uzb4D2f4WltY6cVjLi+/jEN4lgEUj3E04tpMDpUlkBo/eSn6zou9hum2VMNpCCUone0O0WeJim07g==
raw-body@2.5.2:
version "2.5.2"
resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.5.2.tgz#99febd83b90e08975087e8f1f9419a149366b68a"
integrity sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==
dependencies:
bytes "3.1.2"
http-errors "1.8.1"
http-errors "2.0.0"
iconv-lite "0.4.24"
unpipe "1.0.0"
@ -4544,24 +4628,24 @@ semver@^7.3.2, semver@^7.3.4:
dependencies:
lru-cache "^6.0.0"
send@0.17.2:
version "0.17.2"
resolved "https://registry.yarnpkg.com/send/-/send-0.17.2.tgz#926622f76601c41808012c8bf1688fe3906f7820"
integrity sha512-UJYB6wFSJE3G00nEivR5rgWp8c2xXvJ3OPWPhmuteU0IKj8nKbG3DrjiOmLwpnHGYWAVwA69zmTm++YG0Hmwww==
send@0.18.0:
version "0.18.0"
resolved "https://registry.yarnpkg.com/send/-/send-0.18.0.tgz#670167cc654b05f5aa4a767f9113bb371bc706be"
integrity sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==
dependencies:
debug "2.6.9"
depd "~1.1.2"
destroy "~1.0.4"
depd "2.0.0"
destroy "1.2.0"
encodeurl "~1.0.2"
escape-html "~1.0.3"
etag "~1.8.1"
fresh "0.5.2"
http-errors "1.8.1"
http-errors "2.0.0"
mime "1.6.0"
ms "2.1.3"
on-finished "~2.3.0"
on-finished "2.4.1"
range-parser "~1.2.1"
statuses "~1.5.0"
statuses "2.0.1"
serialize-javascript@^3.0.0:
version "3.1.0"
@ -4570,15 +4654,27 @@ serialize-javascript@^3.0.0:
dependencies:
randombytes "^2.1.0"
serve-static@1.14.2:
version "1.14.2"
resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.14.2.tgz#722d6294b1d62626d41b43a013ece4598d292bfa"
integrity sha512-+TMNA9AFxUEGuC0z2mevogSnn9MXKb4fa7ngeRMJaaGv8vTwnIEkKi+QGvPt33HSnf8pRS+WGM0EbMtCJLKMBQ==
serve-static@1.15.0:
version "1.15.0"
resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.15.0.tgz#faaef08cffe0a1a62f60cad0c4e513cff0ac9540"
integrity sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==
dependencies:
encodeurl "~1.0.2"
escape-html "~1.0.3"
parseurl "~1.3.3"
send "0.17.2"
send "0.18.0"
set-function-length@^1.2.1:
version "1.2.2"
resolved "https://registry.yarnpkg.com/set-function-length/-/set-function-length-1.2.2.tgz#aac72314198eaed975cf77b2c3b6b880695e5449"
integrity sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==
dependencies:
define-data-property "^1.1.4"
es-errors "^1.3.0"
function-bind "^1.1.2"
get-intrinsic "^1.2.4"
gopd "^1.0.1"
has-property-descriptors "^1.0.2"
setprototypeof@1.2.0:
version "1.2.0"
@ -4605,6 +4701,16 @@ shallowequal@^1.1.0:
resolved "https://registry.yarnpkg.com/shallowequal/-/shallowequal-1.1.0.tgz#188d521de95b9087404fd4dcb68b13df0ae4e7f8"
integrity sha512-y0m1JoUZSlPAjXVtPPW70aZWfIL/dSP7AFkRnniLCrK/8MDKog3TySTBmckD+RObVxH0v4Tox67+F14PdED2oQ==
side-channel@^1.0.4:
version "1.0.6"
resolved "https://registry.yarnpkg.com/side-channel/-/side-channel-1.0.6.tgz#abd25fb7cd24baf45466406b1096b7831c9215f2"
integrity sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==
dependencies:
call-bind "^1.0.7"
es-errors "^1.3.0"
get-intrinsic "^1.2.4"
object-inspect "^1.13.1"
signal-exit@^3.0.2:
version "3.0.3"
resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.3.tgz#a1410c2edd8f077b08b4e253c8eacfcaf057461c"
@ -4657,10 +4763,10 @@ stack-trace@0.0.x:
resolved "https://registry.yarnpkg.com/stack-trace/-/stack-trace-0.0.10.tgz#547c70b347e8d32b4e108ea1a2a159e5fdde19c0"
integrity sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA=
"statuses@>= 1.5.0 < 2", statuses@~1.5.0:
version "1.5.0"
resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c"
integrity sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=
statuses@2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/statuses/-/statuses-2.0.1.tgz#55cb000ccf1d48728bd23c685a063998cf1a1b63"
integrity sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==
string-width@^3.0.0:
version "3.1.0"