Feature flag explain

This commit is contained in:
Jackson Harper 2024-04-22 19:04:10 -07:00
parent f0be6a41a9
commit cd5940b840
13 changed files with 126 additions and 424 deletions

View file

@ -1,290 +0,0 @@
import SwiftUI
import Models
import Services
import Views
public class DigestViewModel: ObservableObject {
@Published var isLoading = false
@Published var digest: DigestResult?
func load(dataService: DataService) async {
isLoading = true
// if digest == nil {
// do {
// digest = try await dataService.getLatestDigest(timeoutInterval: 10)
// } catch {
// print("ERROR WITH DIGEST: ", error)
// }
// }
isLoading = false
}
}
@available(iOS 17.0, *)
@MainActor
struct DigestView: View {
let viewModel: DigestViewModel = DigestViewModel()
let dataService: DataService
// @State private var currentIndex = 0
@State private var items: [DigestItem]
// @State private var preloadedItems: [Int: String] = [:]
@Environment(\.dismiss) private var dismiss
// let itemCount = 10 // Number of items to initially load
// let prefetchCount = 2 // Number of items to prefetch
public init(dataService: DataService) {
self.dataService = dataService
self.items = [
DigestItem(
id: "1468AFAA-88sdfsdfC-4546-BE02-EACF385288FC",
site: "CNBC.com",
siteIcon: URL(string: "https://www.cnbc.com/favicon.ico"),
author: "Kif Leswing",
title: "Apple shares just had their best day since last May",
summaryText: "In a significant political turn, the SOTU response faces unexpected collapse, marking a stark contrast to Trump's latest" +
" downturn, alongside an unprecedented surge in Biden's fundraising efforts as of 3/11/24, according to the TDPS Podcast. " +
"The analysis provides insights into the shifting dynamics of political support and the potential implications for future " +
"electoral strategies. ",
keyPointsText: "Key points from the article:",
highlightsText: "Highlights from the article:"
),
DigestItem(
id: "1468AFAA-8sdfsdffsdf-4546-BE02-EACF385288FC",
site: "CNBC.com",
siteIcon: URL(string: "https://www.cnbc.com/favicon.ico"),
author: "Kif Leswing",
title: "Apple shares just had their best day since last May",
summaryText: "In a significant political turn, the SOTU response faces unexpected collapse, marking a stark contrast to Trump's latest" +
" downturn, alongside an unprecedented surge in Biden's fundraising efforts as of 3/11/24, according to the TDPS Podcast. " +
"The analysis provides insights into the shifting dynamics of political support and the potential implications for future " +
"electoral strategies. ",
keyPointsText: "Key points from the article:",
highlightsText: "Highlights from the article:"
),
DigestItem(
id: "1468AFAA-882C-asdadfsa85288FC",
site: "CNBC.com",
siteIcon: URL(string: "https://www.cnbc.com/favicon.ico"),
author: "Kif Leswing",
title: "Apple shares just had their best day since last May",
summaryText: "In a significant political turn, the SOTU response faces unexpected collapse, marking a stark contrast to Trump's latest" +
" downturn, alongside an unprecedented surge in Biden's fundraising efforts as of 3/11/24, according to the TDPS Podcast. " +
"The analysis provides insights into the shifting dynamics of political support and the potential implications for future " +
"electoral strategies. ",
keyPointsText: "Key points from the article:",
highlightsText: "Highlights from the article:"
)
]
// currentIndex = 0
// _preloadedItems = [Int:String]
}
var body: some View {
if viewModel.isLoading {
ProgressView()
} else {
itemBody
.task {
await viewModel.load(dataService: dataService)
}
}
}
@available(iOS 17.0, *)
var itemBody: some View {
ScrollView(.vertical) {
LazyVStack(spacing: 0) {
ForEach(Array(self.items.enumerated()), id: \.1.id) { idx, item in
PreviewItemView(
viewModel: PreviewItemViewModel(dataService: dataService, item: item, showSwipeHint: idx == 0)
)
.containerRelativeFrame([.horizontal, .vertical])
}
RatingView()
.containerRelativeFrame([.horizontal, .vertical])
}
.scrollTargetLayout()
}
.scrollTargetBehavior(.paging)
.ignoresSafeArea()
}
}
//@MainActor
//public class PreviewItemViewModel: ObservableObject {
// let dataService: DataService
// @Published var item: DigestItem
// let showSwipeHint: Bool
//
// @Published var isLoading = false
// @Published var resultText: String?
// @Published var promptDisplayText: String?
//
// init(dataService: DataService, item: DigestItem, showSwipeHint: Bool) {
// self.dataService = dataService
// self.item = item
// self.showSwipeHint = showSwipeHint
// }
//
// func loadResult() async {
//// isLoading = true
//// let taskId = try? await dataService.createAITask(
//// extraText: extraText,
//// libraryItemId: item?.id ?? "",
//// promptName: "summarize-001"
//// )
////
//// if let taskId = taskId {
//// do {
//// let fetchedText = try await dataService.pollAITask(jobId: taskId, timeoutInterval: 30)
//// resultText = fetchedText
//// } catch {
//// print("ERROR WITH RESULT TEXT: ", error)
//// }
//// } else {
//// print("NO TASK ID: ", taskId)
//// }
//// isLoading = false
// }
//}
//
//@MainActor
//struct PreviewItemView: View {
// @StateObject var viewModel: PreviewItemViewModel
//
// var body: some View {
// VStack(spacing: 10) {
// HStack {
// AsyncImage(url: viewModel.item.siteIcon) { phase in
// if let image = phase.image {
// image
// .resizable()
// .aspectRatio(contentMode: .fill)
// .frame(width: 20, height: 20, alignment: .center)
// } else {
// Color.appButtonBackground
// .frame(width: 20, height: 20, alignment: .center)
// }
// }
// Text(viewModel.item.site)
// .font(Font.system(size: 14))
// .frame(maxWidth: .infinity, alignment: .topLeading)
// }
// .padding(.top, 10)
// Text(viewModel.item.title)
// // .font(.body)
// // .fontWeight(.semibold)
// .font(Font.system(size: 18, weight: .semibold))
// .frame(maxWidth: .infinity, alignment: .topLeading)
//
// Text(viewModel.item.author)
// .font(Font.system(size: 14))
// .foregroundColor(Color(hex: "898989"))
// .frame(maxWidth: .infinity, alignment: .topLeading)
//
// Color(hex: "2A2A2A")
// .frame(height: 1)
// .frame(maxWidth: .infinity, alignment: .center)
// .padding(.vertical, 20)
//
// if viewModel.isLoading {
// ProgressView()
// .task {
// await viewModel.loadResult()
// }
// .frame(maxWidth: .infinity, maxHeight: .infinity)
// } else {
// Text(viewModel.item.summaryText)
// .font(Font.system(size: 16))
// // .font(.body)
// .lineSpacing(12.0)
// .frame(maxWidth: .infinity, alignment: .topLeading)
// HStack {
// Button(action: {}, label: {
// HStack(alignment: .center) {
// Text("Start listening")
// .font(Font.system(size: 14))
// .frame(height: 42, alignment: .center)
// Image(systemName: "play.fill")
// .resizable()
// .frame(width: 10, height: 10)
// }
// .padding(.horizontal, 15)
// .background(Color.blue)
// .foregroundColor(.white)
// .cornerRadius(18)
// })
// Spacer()
// }
// .padding(.top, 20)
// }
// Spacer()
// if viewModel.showSwipeHint {
// VStack {
// Image.doubleChevronUp
// Text("Swipe up for next article")
// .foregroundColor(Color(hex: "898989"))
// }
// .padding(.bottom, 50)
// }
// }.frame(maxWidth: .infinity, maxHeight: .infinity)
// .padding(.top, 100)
// .padding(.horizontal, 15)
//
// }
//}
//
//struct RatingView: View {
// @State private var rating: Int = 0
//
// var body: some View {
// VStack(spacing: 30) {
// Text("Rate today's digest")
// .font(.title)
// .padding(.vertical, 40)
// Text("I liked the stories picked for today's digest")
// RatingWidget()
//
// Text("The stories were interesting")
// RatingWidget()
//
// Text("The voices sounded good")
// RatingWidget()
//
// Text("I liked the music")
// RatingWidget()
// Spacer()
// }.padding(.top, 60)
// }
//}
//
//
//struct StarView: View {
// var isFilled: Bool
// var body: some View {
// Image(systemName: isFilled ? "star.fill" : "star")
// .foregroundColor(isFilled ? Color.yellow : Color.gray)
// }
//}
//
//struct RatingWidget: View {
// @State private var rating: Int = 0
// var body: some View {
// HStack {
// ForEach(1...5, id: \.self) { index in
// StarView(isFilled: index <= rating)
// .onTapGesture {
// rating = index
// }
// }
// }
// .padding()
// .background(Color(hex: "313131"))
// .cornerRadius(8)
// // .shadow(radius: 3)
// }
//}

View file

@ -181,7 +181,7 @@ struct AnimatingCellHeight: AnimatableModifier {
// swiftlint:disable file_length
#if os(iOS)
private let enableGrid = UIDevice.isIPad || FeatureFlag.enableGridCardsOnPhone
private let enableGrid = UIDevice.isIPad
@MainActor
struct HomeFeedContainerView: View {
@ -204,8 +204,6 @@ struct AnimatingCellHeight: AnimatableModifier {
@ObservedObject var viewModel: HomeFeedViewModel
@State private var selection = Set<String>()
@AppStorage("LibraryList::digestEnabled") var digestEnabled = false
init(viewModel: HomeFeedViewModel, isEditMode: Binding<EditMode>) {
_viewModel = ObservedObject(wrappedValue: viewModel)
_isEditMode = isEditMode
@ -354,25 +352,6 @@ struct AnimatingCellHeight: AnimatableModifier {
viewModel.stopUsingFollowingPrimer = true
}
}
.task {
do {
// If the user doesn't have digest enabled, try updating their features
// to see if they have it.
if !digestEnabled {
if let viewer = try await dataService.fetchViewer() {
digestEnabled = viewer.hasFeatureGranted("ai-digest")
}
}
if digestEnabled {
Task {
await viewModel.checkForDigestUpdate(dataService: dataService)
}
}
} catch {
print("ERROR FETCHING VIEWER: ", error)
print("")
}
}
.environment(\.editMode, self.$isEditMode)
.navigationBarTitleDisplayMode(.inline)
}
@ -417,7 +396,7 @@ struct AnimatingCellHeight: AnimatableModifier {
if isEditMode == .active {
Button(action: { isEditMode = .inactive }, label: { Text("Cancel") })
} else {
if #available(iOS 17.0, *), digestEnabled {
if #available(iOS 17.0, *), dataService.featureFlags.digestEnabled {
Button(
action: { showLibraryDigest = true },
label: { viewModel.digestIsUnread ? Image.tabDigestSelected : Image.tabDigest }

View file

@ -23,7 +23,7 @@
var body: some View {
Group {
Form {
if FeatureFlag.enableUltraRealisticVoices, language.key == "en" {
if language.key == "en" {
if viewModel.waitingForRealisticVoices {
HStack {
Text(LocalText.texttospeechBetaSignupInProcess)

View file

@ -37,6 +37,8 @@ public struct RootView: View {
Services.scheduleBackgroundFetch()
#endif
}
}.task {
await viewModel.services.dataService.tryUpdateFeatureFlags()
}
}
}

View file

@ -1,93 +0,0 @@
import Models
import SwiftUI
import Utils
import Views
import WebKit
#if os(iOS)
struct HighlightViewer: PlatformViewRepresentable {
let highlightData: HighlightData
func makeCoordinator() -> WebReaderCoordinator {
WebReaderCoordinator()
}
private func makePlatformView(context: Context) -> WKWebView {
let webView = WebViewManager.shared()
let contentController = WKUserContentController()
webView.navigationDelegate = context.coordinator
webView.configuration.userContentController = contentController
webView.configuration.userContentController.removeAllScriptMessageHandlers()
#if os(iOS)
webView.isOpaque = false
webView.backgroundColor = .clear
webView.scrollView.delegate = context.coordinator
webView.scrollView.contentInset.top = readerViewNavBarHeight
webView.scrollView.verticalScrollIndicatorInsets.top = readerViewNavBarHeight
webView.configuration.userContentController.add(webView, name: "viewerAction")
#else
webView.setValue(false, forKey: "drawsBackground")
#endif
for action in WebViewAction.allCases {
webView.configuration.userContentController.add(context.coordinator, name: action.rawValue)
}
webView.configuration.userContentController.addScriptMessageHandler(
context.coordinator, contentWorld: .page, name: "articleAction"
)
loadContent(webView: webView)
return webView
}
private func updatePlatformView(_: WKWebView, context _: Context) {
// If the webview had been terminated `needsReload` will have been set to true
// Or if the articleContent value has changed then it's id will be different from the coordinator's
// if context.coordinator.needsReload {
// loadContent(webView: webView)
// context.coordinator.needsReload = false
// return
// }
}
private func loadContent(webView: WKWebView) {
// swiftlint:disable line_length
let themeKey = ThemeManager.currentThemeName
let content = """
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name='viewport' content='width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=no' />
<style>
@import url("highlight\(themeKey == "Gray" ? "-dark" : "").css");
</style>
</head>
<body>
<div id="root" />
<div id='_omnivore-highlight' class="highlight">
\(highlightData.highlightHTML)
</div>
</body>
</html>
"""
// swiftlint:enable line_length
webView.loadHTMLString(content, baseURL: ViewsPackage.resourceURL)
}
}
extension HighlightViewer {
func makeUIView(context: Context) -> WKWebView {
makePlatformView(context: context)
}
func updateUIView(_ webView: WKWebView, context: Context) {
updatePlatformView(webView, context: context)
}
}
#endif

View file

@ -400,7 +400,7 @@ struct WebReaderContainerView: View {
#endif
},
tapHandler: tapHandler,
explainHandler: explainHandler,
explainHandler: dataService.featureFlags.explainEnabled ? explainHandler : nil,
scrollPercentHandler: scrollPercentHandler,
webViewActionHandler: webViewActionHandler,
navBarVisibilityUpdater: { visible in

View file

@ -1,3 +1,4 @@
import SwiftUI
public struct FeatureInternal {
public let name: String

View file

@ -33,6 +33,8 @@ public final class DataService: ObservableObject {
persistentContainer.viewContext
}
public var featureFlags = FeatureFlags()
public var lastItemSyncTime: Date {
get {
guard
@ -298,4 +300,11 @@ public final class DataService: ObservableObject {
}
return objectID
}
public func tryUpdateFeatureFlags() async {
if let features = (try? await fetchViewer())?.enabledFeatures {
featureFlags.digestEnabled = features.contains("ai-digest")
featureFlags.explainEnabled = features.contains("ai-explain")
}
}
}

View file

@ -1,4 +1,5 @@
import Foundation
import SwiftUI
#if DEBUG
public let isDebug = true
@ -6,11 +7,13 @@ import Foundation
public let isDebug = false
#endif
public enum FeatureFlag {
public static let enableSnoozeFromShareExtension = false
public static let enableRemindersFromShareExtension = false
public static let enableShareButton = false
public static let enableSnooze = false
public static let enableGridCardsOnPhone = false
public static let enableUltraRealisticVoices = true
public struct FeatureFlags {
@AppStorage("FeatureFlag::digestEnabled")
public var digestEnabled = false
@AppStorage("FeatureFlag::explainEnabled")
public var explainEnabled = false
public init() {
}
}

View file

@ -27,6 +27,8 @@ public final class OmnivoreWebView: WKWebView {
private var currentMenu: ContextMenu = .defaultMenu
private var explainEnabled = false
override init(frame: CGRect, configuration: WKWebViewConfiguration) {
super.init(frame: frame, configuration: configuration)
@ -399,8 +401,12 @@ public final class OmnivoreWebView: WKWebView {
return
}
let highlight = UICommand(title: LocalText.genericHighlight, action: #selector(highlightSelection))
let explain = UICommand(title: "Explain", action: #selector(explainSelection))
items = [highlight, explain, annotate]
if explainHandler != nil {
let explain = UICommand(title: "Explain", action: #selector(explainSelection))
items = [highlight, explain, annotate]
} else {
items = [highlight, annotate]
}
} else {
let remove = UICommand(title: "Remove", action: #selector(removeSelection))
let setLabels = UICommand(title: LocalText.labelsGeneric, action: #selector(setLabels))

View file

@ -27,7 +27,7 @@ export function explainRouter() {
return res.status(400).send('Bad Request')
}
if (!(await findGrantedFeatureByName(FeatureName.Explain, user.id))) {
if (!(await findGrantedFeatureByName(FeatureName.AIExplain, user.id))) {
return res.status(403).send('Not granted')
}

View file

@ -17,7 +17,7 @@ export enum FeatureName {
UltraRealisticVoice = 'ultra-realistic-voice',
Notion = 'notion',
AIDigest = 'ai-digest',
Explain = 'explain',
AIExplain = 'ai-explain',
}
export const getFeatureName = (name: string): FeatureName | undefined => {

View file

@ -6493,6 +6493,11 @@
resolved "https://registry.yarnpkg.com/@sqltools/formatter/-/formatter-1.2.3.tgz#1185726610acc37317ddab11c3c7f9066966bd20"
integrity sha512-O3uyB/JbkAEMZaP3YqyHH7TMnex7tWyCbCI4EfJdOCoN6HIhqdJBWTM6aCCiWQ/5f5wxjgU735QAIpJbjDvmzg==
"@sqltools/formatter@^1.2.5":
version "1.2.5"
resolved "https://registry.yarnpkg.com/@sqltools/formatter/-/formatter-1.2.5.tgz#3abc203c79b8c3e90fd6c156a0c62d5403520e12"
integrity sha512-Uy0+khmZqUrUGm5dmMqVlnvufZRSK0FbYzVgp0UMstm+F5+W2/jnEEQyc9vo1ZR/E5ZI/B1WjjoTqBqwJL6Krw==
"@stitches/react@^1.2.5":
version "1.2.8"
resolved "https://registry.yarnpkg.com/@stitches/react/-/react-1.2.8.tgz#954f8008be8d9c65c4e58efa0937f32388ce3a38"
@ -8348,6 +8353,13 @@
dependencies:
undici-types "~5.26.4"
"@types/node@^20.11.0":
version "20.12.7"
resolved "https://registry.yarnpkg.com/@types/node/-/node-20.12.7.tgz#04080362fa3dd6c5822061aa3124f5c152cff384"
integrity sha512-wq0cICSkRLVaf3UGLMGItu/PtdY7oaXaI/RVU+xliKVOtRna3PRY57ZDfztpDL0n11vfymMUnXv8QwYCO7L1wg==
dependencies:
undici-types "~5.26.4"
"@types/node@^20.8.4":
version "20.11.30"
resolved "https://registry.yarnpkg.com/@types/node/-/node-20.11.30.tgz#9c33467fc23167a347e73834f788f4b9f399d66f"
@ -9916,6 +9928,11 @@ app-root-path@^3.0.0:
resolved "https://registry.yarnpkg.com/app-root-path/-/app-root-path-3.0.0.tgz#210b6f43873227e18a4b810a032283311555d5ad"
integrity sha512-qMcx+Gy2UZynHjOHOIXPNvpf+9cjvk3cWrBBK7zg4gH9+clobJRb9NGzcT7mQTcV/6Gm/1WelUtqxVXnNlrwcw==
app-root-path@^3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/app-root-path/-/app-root-path-3.1.0.tgz#5971a2fc12ba170369a7a1ef018c71e6e47c2e86"
integrity sha512-biN3PwB2gUtjaYy/isrU3aNWI5w+fAfvHkSvCKeQGxhmYpwKFUxudR3Yya+KqVRHBmEDYh+/lTozYCFbmzX4nA==
apparatus@^0.0.10:
version "0.0.10"
resolved "https://registry.yarnpkg.com/apparatus/-/apparatus-0.0.10.tgz#81ea756772ada77863db54ceee8202c109bdca3e"
@ -13380,7 +13397,7 @@ dateformat@^3.0.0, dateformat@^3.0.3:
resolved "https://registry.yarnpkg.com/dateformat/-/dateformat-3.0.3.tgz#a6e37499a4d9a9cf85ef5872044d62901c9889ae"
integrity sha512-jyCETtSl3VMZMWeRo7iY1FL19ges1t55hMo5yaam4Jrsm5EPL89UQkoQRyiI+Yf4k8r2ZpdngkV8hr1lIdjb3Q==
dayjs@1.x, dayjs@^1.10.4, dayjs@^1.11.7:
dayjs@1.x, dayjs@^1.10.4, dayjs@^1.11.7, dayjs@^1.11.9:
version "1.11.10"
resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.11.10.tgz#68acea85317a6e164457d6d6947564029a6a16a0"
integrity sha512-vjAczensTgRcqDERK0SR2XMwsF/tSvnvlv6VcF2GIhg6Sx4yOIt/irsr1RDJsKiIyBzJDpCoXiWWq28MqH2cnQ==
@ -14116,7 +14133,7 @@ dotenv@^16.0.1:
resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.0.1.tgz#8f8f9d94876c35dac989876a5d3a82a267fdce1d"
integrity sha512-1K6hR6wtk2FviQ4kEiSjFiH5rpzEVi8WW0x96aztHVMhEspNpc4DVOUTEHtEva5VThQ8IaBX1Pe4gSzpVVUsKQ==
dotenv@^16.3.1:
dotenv@^16.0.3, dotenv@^16.3.1:
version "16.4.5"
resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.4.5.tgz#cdd3b3b604cb327e286b4762e13502f717cb099f"
integrity sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==
@ -16811,6 +16828,17 @@ glob@^10.2.2:
minipass "^5.0.0 || ^6.0.2 || ^7.0.0"
path-scurry "^1.10.1"
glob@^10.3.10:
version "10.3.12"
resolved "https://registry.yarnpkg.com/glob/-/glob-10.3.12.tgz#3a65c363c2e9998d220338e88a5f6ac97302960b"
integrity sha512-TCNv8vJ+xz4QiqTpfOJA7HvYv+tNIRHKfUWw/q+v2jdgN4ebz+KY9tGx5J4rHP0o84mNP+ApH66HRX8us3Khqg==
dependencies:
foreground-child "^3.1.0"
jackspeak "^2.3.6"
minimatch "^9.0.1"
minipass "^7.0.4"
path-scurry "^1.10.2"
glob@^8.0.0:
version "8.0.3"
resolved "https://registry.yarnpkg.com/glob/-/glob-8.0.3.tgz#415c6eb2deed9e502c68fa44a272e6da6eeca42e"
@ -19264,7 +19292,7 @@ iterator.prototype@^1.1.2:
reflect.getprototypeof "^1.0.4"
set-function-name "^2.0.1"
jackspeak@^2.3.5:
jackspeak@^2.3.5, jackspeak@^2.3.6:
version "2.3.6"
resolved "https://registry.yarnpkg.com/jackspeak/-/jackspeak-2.3.6.tgz#647ecc472238aee4b06ac0e461acc21a8c505ca8"
integrity sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==
@ -21256,6 +21284,11 @@ lowlight@^1.14.0:
fault "^1.0.0"
highlight.js "~10.7.0"
lru-cache@^10.2.0:
version "10.2.0"
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-10.2.0.tgz#0bd445ca57363465900f4d1f9bd8db343a4d95c3"
integrity sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==
lru-cache@^4.1.5:
version "4.1.5"
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.5.tgz#8bbe50ea85bed59bc9e33dcab8235ee9bcf443cd"
@ -22481,7 +22514,7 @@ minipass@^5.0.0:
resolved "https://registry.yarnpkg.com/minipass/-/minipass-5.0.0.tgz#3e9788ffb90b694a5d0ec94479a45b5d8738133d"
integrity sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==
"minipass@^5.0.0 || ^6.0.2 || ^7.0.0", minipass@^7.0.3:
"minipass@^5.0.0 || ^6.0.2 || ^7.0.0", minipass@^7.0.3, minipass@^7.0.4:
version "7.0.4"
resolved "https://registry.yarnpkg.com/minipass/-/minipass-7.0.4.tgz#dbce03740f50a4786ba994c1fb908844d27b038c"
integrity sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==
@ -22569,6 +22602,11 @@ mkdirp@^1.0.3, mkdirp@^1.0.4:
resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-1.0.4.tgz#3eb5ed62622756d79a5f0e2a221dfebad75c2f7e"
integrity sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==
mkdirp@^2.1.3:
version "2.1.6"
resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-2.1.6.tgz#964fbcb12b2d8c5d6fbc62a963ac95a273e2cc19"
integrity sha512-+hEnITedc8LAtIP9u3HJDFIdcLV2vXP33sqLLIzkv1Db1zO/1OxbvYf0Y1OC/S/Qo5dxHXepofhmxL02PsKe+A==
mkdirp@~0.3.5:
version "0.3.5"
resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.3.5.tgz#de3e5f8961c88c787ee1368df849ac4413eca8d7"
@ -24892,6 +24930,14 @@ path-scurry@^1.10.1, path-scurry@^1.6.1:
lru-cache "^9.1.1 || ^10.0.0"
minipass "^5.0.0 || ^6.0.2 || ^7.0.0"
path-scurry@^1.10.2:
version "1.10.2"
resolved "https://registry.yarnpkg.com/path-scurry/-/path-scurry-1.10.2.tgz#8f6357eb1239d5fa1da8b9f70e9c080675458ba7"
integrity sha512-7xTavNy5RQXnsjANvVvMkEjvloOinkAjv/Z6Ildz9v2RinZ4SBKTWFOVRbaF8p0vpHnyjV/UwNDdKuUv6M5qcA==
dependencies:
lru-cache "^10.2.0"
minipass "^5.0.0 || ^6.0.2 || ^7.0.0"
path-to-regexp@0.1.7:
version "0.1.7"
resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c"
@ -26961,6 +27007,14 @@ read-pkg@^7.1.0:
parse-json "^5.2.0"
type-fest "^2.0.0"
read-yaml-file@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/read-yaml-file/-/read-yaml-file-2.1.0.tgz#c5866712db9ef5343b4d02c2413bada53c41c4a9"
integrity sha512-UkRNRIwnhG+y7hpqnycCL/xbTk7+ia9VuVTC0S+zVbwd65DI9eUpRMfsWIGrCWxTU/mi+JW8cHQCrv+zfCbEPQ==
dependencies:
js-yaml "^4.0.0"
strip-bom "^4.0.0"
read@1, read@^1.0.7, read@~1.0.7:
version "1.0.7"
resolved "https://registry.yarnpkg.com/read/-/read-1.0.7.tgz#b3da19bd052431a97671d44a42634adf710b40c4"
@ -27105,6 +27159,11 @@ reflect-metadata@^0.1.13:
resolved "https://registry.yarnpkg.com/reflect-metadata/-/reflect-metadata-0.1.13.tgz#67ae3ca57c972a2aa1642b10fe363fe32d49dc08"
integrity sha512-Ts1Y/anZELhSsjMcU605fU9RE4Oi3p5ORujwbIKXfWa+0Zxs510Qrmrce5/Jowq3cHSZSJqBjypxmHarc+vEWg==
reflect-metadata@^0.2.1:
version "0.2.2"
resolved "https://registry.yarnpkg.com/reflect-metadata/-/reflect-metadata-0.2.2.tgz#400c845b6cba87a21f2c65c4aeb158f4fa4d9c5b"
integrity sha512-urBwgfrvVP/eAyXx4hluJivBKzuEbSQs9rKWCrCkbSxNv8mxPcUZKeuoF3Uy4mJl3Lwprp6yy5/39VWigZ4K6Q==
reflect.getprototypeof@^1.0.4:
version "1.0.4"
resolved "https://registry.yarnpkg.com/reflect.getprototypeof/-/reflect.getprototypeof-1.0.4.tgz#aaccbf41aca3821b87bb71d9dcbc7ad0ba50a3f3"
@ -30171,7 +30230,7 @@ tslib@^1.0.0, tslib@^1.11.1, tslib@^1.8.1, tslib@^1.9.0, tslib@^1.9.3:
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00"
integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==
tslib@^2, tslib@^2.0.0, tslib@^2.0.1, tslib@^2.0.3, tslib@^2.1.0, tslib@^2.3.0, tslib@^2.3.1, tslib@^2.4.0, tslib@^2.6.2:
tslib@^2, tslib@^2.0.0, tslib@^2.0.1, tslib@^2.0.3, tslib@^2.1.0, tslib@^2.3.0, tslib@^2.3.1, tslib@^2.4.0, tslib@^2.5.0, tslib@^2.6.2:
version "2.6.2"
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.2.tgz#703ac29425e7b37cd6fd456e92404d46d1f3e4ae"
integrity sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==
@ -30387,6 +30446,27 @@ typeorm-naming-strategies@^4.1.0:
resolved "https://registry.yarnpkg.com/typeorm-naming-strategies/-/typeorm-naming-strategies-4.1.0.tgz#1ec6eb296c8d7b69bb06764d5b9083ff80e814a9"
integrity sha512-vPekJXzZOTZrdDvTl1YoM+w+sUIfQHG4kZTpbFYoTsufyv9NIBRe4Q+PdzhEAFA2std3D9LZHEb1EjE9zhRpiQ==
typeorm@^0.3.19:
version "0.3.20"
resolved "https://registry.yarnpkg.com/typeorm/-/typeorm-0.3.20.tgz#4b61d737c6fed4e9f63006f88d58a5e54816b7ab"
integrity sha512-sJ0T08dV5eoZroaq9uPKBoNcGslHBR4E4y+EBHs//SiGbblGe7IeduP/IH4ddCcj0qp3PHwDwGnuvqEAnKlq/Q==
dependencies:
"@sqltools/formatter" "^1.2.5"
app-root-path "^3.1.0"
buffer "^6.0.3"
chalk "^4.1.2"
cli-highlight "^2.1.11"
dayjs "^1.11.9"
debug "^4.3.4"
dotenv "^16.0.3"
glob "^10.3.10"
mkdirp "^2.1.3"
reflect-metadata "^0.2.1"
sha.js "^2.4.11"
tslib "^2.5.0"
uuid "^9.0.0"
yargs "^17.6.2"
typeorm@^0.3.4:
version "0.3.7"
resolved "https://registry.yarnpkg.com/typeorm/-/typeorm-0.3.7.tgz#5776ed5058f0acb75d64723b39ff458d21de64c1"
@ -30425,6 +30505,11 @@ typescript@^4.4.4:
resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.9.5.tgz#095979f9bcc0d09da324d58d03ce8f8374cbe65a"
integrity sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==
typescript@^5.3.3:
version "5.4.5"
resolved "https://registry.yarnpkg.com/typescript/-/typescript-5.4.5.tgz#42ccef2c571fdbd0f6718b1d1f5e6e5ef006f611"
integrity sha512-vcI4UpRgg81oIRUFwR0WSIHKt11nJ7SAVlYNIu+QpqeyXP+gpQJy/Z4+F0aGxSE4MqwjyXvW/TzgkLAx2AGHwQ==
ua-parser-js@^0.7.30:
version "0.7.33"
resolved "https://registry.yarnpkg.com/ua-parser-js/-/ua-parser-js-0.7.33.tgz#1d04acb4ccef9293df6f70f2c3d22f3030d8b532"