Compare commits

..

No commits in common. "e86f40c62016aed152d2f342ae50d5c0f6147bb1" and "318a2a24fd62e5896284c9471b1680a9ab03cc34" have entirely different histories.

16 changed files with 672 additions and 2790 deletions

View File

@ -3,4 +3,4 @@ GQL_DIR=$(dirname $(dirname "$(realpath "$BASH_SOURCE")"))
cd $GQL_DIR cd $GQL_DIR
LD_LIBRARY_PATH="" nix develop --impure --command bash "$GQL_DIR/bin/assert-no-changes.sh" nix develop --impure --command bash "$GQL_DIR/bin/assert-no-changes.sh"

View File

@ -3,7 +3,6 @@ git ls-files | xargs md5sum > before.txt
yarn install yarn install
yarn graphql-codegen yarn graphql-codegen
prettier ./src --write
git ls-files | xargs md5sum > after.txt git ls-files | xargs md5sum > after.txt

View File

@ -20,7 +20,9 @@
}, },
"gitignore": { "gitignore": {
"inputs": { "inputs": {
"nixpkgs": ["nixpkgs"] "nixpkgs": [
"nixpkgs"
]
}, },
"locked": { "locked": {
"lastModified": 1703887061, "lastModified": 1703887061,

View File

@ -17,14 +17,7 @@
"@graphql-codegen/typescript": "^4.0.1", "@graphql-codegen/typescript": "^4.0.1",
"@graphql-codegen/typescript-operations": "^4.0.1", "@graphql-codegen/typescript-operations": "^4.0.1",
"@graphql-codegen/typescript-react-apollo": "^4.2.0", "@graphql-codegen/typescript-react-apollo": "^4.2.0",
"graphql": "^16.8.1", "graphql": "^16.8.1"
"prettier": "^3.2.5",
"prettier-plugin-organize-imports": "^3.2.4"
},
"prettier": {
"plugins": [
"prettier-plugin-organize-imports"
]
}, },
"devDependencies": { "devDependencies": {
"typescript": "^4.x" "typescript": "^4.x"

File diff suppressed because it is too large Load Diff

View File

@ -1,12 +0,0 @@
query GetAggregatedShotMetrics($aggregateInput: AggregateInputGQL!) {
getAggregatedShotMetrics(aggregateInput: $aggregateInput) {
aggregationIdentifiers {
featureName
groupName
}
targetMetrics {
count
makePercentage
}
}
}

View File

@ -0,0 +1,17 @@
query GetAggregateShots($bucketSets: [BucketSetInputGQL!]!) {
getAggregateShots(bucketSets: $bucketSets) {
featureBuckets {
rangeKey
lowerBound
}
targetMetrics {
count
makePercentage
floatFeature {
featureName
average
median
}
}
}
}

View File

@ -1,8 +0,0 @@
query getDeployedConfig {
getDeployedConfig {
allowNewUsers
devMode
environment
firebase
}
}

View File

@ -1,33 +1,36 @@
query GetFeed( query GetFeed(
$limit: Int! = 5 $first: Int! = 5,
$after: String = null $after: String = null,
$filters: VideoFilterInput = null
) { ) {
getUserVideos(limit: $limit, after: $after, filters: $filters) { getVideoFeedForUser(first: $first, after: $after) {
videos { videos {
id id
owner {
username
}
name name
screenshotUri
totalShotsMade totalShotsMade
totalShots totalShots
makePercentage makePercentage
medianRun
averageTimeBetweenShots
createdAt createdAt
updatedAt updatedAt
shots {
id
videoId
startFrame
endFrame
createdAt
updatedAt
}
startTime startTime
endTime endTime
elapsedTime elapsedTime
screenshotUri
stream { stream {
id
linksRequested
uploadsCompleted
isCompleted isCompleted
} createdAt
tags { updatedAt
tagClasses {
name
}
name
} }
} }
pageInfo { pageInfo {

View File

@ -1,9 +0,0 @@
query GetVideoMakePercentageIntervals($videoId: ID!, $intervalDuration: Int!) {
getVideoMakePercentageIntervals(
videoId: $videoId
intervalDuration: $intervalDuration
) {
makePercentage
elapsedTime
}
}

View File

@ -1,35 +1,30 @@
query GetShots( query GetShots(
$filterInput: FilterInput! $filterInput: FilterInput
$includeCreatedAt: Boolean! = false $includeCueObjectDistance: Boolean! = false
$includeUpdatedAt: Boolean! = false $includeCueObjectAngle: Boolean! = false
$includeCueObjectFeatures: Boolean! = false $includeCueBallSpeed: Boolean! = false
$includePocketingIntentionFeatures: Boolean! = false $includeShotDirection: Boolean! = false
$includeCueObjectDistance: Boolean! = false $includeTargetPocketDistance: Boolean! = false
$includeCueObjectAngle: Boolean! = false $includeMake: Boolean! = false
$includeCueBallSpeed: Boolean! = false $includeIntendedPocketType: Boolean! = false
$includeShotDirection: Boolean! = false
$includeTargetPocketDistance: Boolean! = false
$includeMake: Boolean! = false
$includeIntendedPocketType: Boolean! = false
) { ) {
getShots(filterInput: $filterInput) { getShots(filterInput: $filterInput) {
id id
videoId videoId
startFrame startFrame
endFrame endFrame
createdAt @include(if: $includeCreatedAt) createdAt
updatedAt @include(if: $includeUpdatedAt) updatedAt
cueObjectFeatures @include(if: $includeCueObjectFeatures) { cueObjectFeatures {
cueObjectDistance @include(if: $includeCueObjectDistance) cueObjectDistance @include(if: $includeCueObjectDistance)
cueObjectAngle @include(if: $includeCueObjectAngle) cueObjectAngle @include(if: $includeCueObjectAngle)
cueBallSpeed @include(if: $includeCueBallSpeed) cueBallSpeed @include(if: $includeCueBallSpeed)
shotDirection @include(if: $includeShotDirection) shotDirection @include(if: $includeShotDirection)
} }
pocketingIntentionFeatures pocketingIntentionFeatures {
@include(if: $includePocketingIntentionFeatures) { targetPocketDistance @include(if: $includeTargetPocketDistance)
targetPocketDistance @include(if: $includeTargetPocketDistance) make @include(if: $includeMake)
make @include(if: $includeMake) intendedPocketType @include(if: $includeIntendedPocketType)
intendedPocketType @include(if: $includeIntendedPocketType) }
} }
}
} }

View File

@ -1,38 +0,0 @@
mutation getProfileImageUploadLink($fileExt: String = ".png") {
getProfileImageUploadLink(fileExt: $fileExt) {
uploadUrl
headers {
key
value
}
}
}
mutation editProfileImageUri($profileImageUri: String!) {
editProfileImageUri(profileImageUri: $profileImageUri) {
id
firebaseUid
username
profileImageUri
createdAt
updatedAt
}
}
query getLoggedInUser {
getLoggedInUser {
id
firebaseUid
username
profileImageUri
activeVideoId
createdAt
updatedAt
}
}
query GetUserPlayTime($userId: Int!) {
getPlayTime(userId: $userId) {
totalSeconds
}
}

View File

@ -1,150 +0,0 @@
query GetStreamMonitoringDetails($videoId: Int!) {
getVideo(videoId: $videoId) {
id
totalShots
makePercentage
elapsedTime
homographyHistory {
crop {
left
top
width
height
}
pockets {
left
top
width
height
}
sourcePoints {
topLeft {
x
y
}
topSide {
x
y
}
topRight {
x
y
}
bottomLeft {
x
y
}
bottomSide {
x
y
}
bottomRight {
x
y
}
}
}
stream {
linksRequested
uploadsCompleted
segmentProcessingCursor
isCompleted
uploadCompletionCursor
lastIntendedSegmentBound
}
currentProcessing {
errors {
message
startSegmentIndex
endSegmentIndex
}
}
}
}
query GetVideoUpdatePageDetails($videoId: Int!) {
getVideo(videoId: $videoId) {
id
name
totalShots
makePercentage
elapsedTime
tags {
tagClasses {
name
}
name
}
}
}
mutation DeleteVideo($videoId: Int!) {
deleteVideo(videoId: $videoId)
}
query GetVideoDetails($videoId: Int!) {
getVideo(videoId: $videoId) {
id
name
screenshotUri
averageTimeBetweenShots
elapsedTime
endTime
makePercentage
makePercentage
medianRun
startTime
totalShots
totalShots
totalShotsMade
createdAt
updatedAt
owner {
id
firebaseUid
username
profileImageUri
}
tags {
tagClasses {
name
}
name
}
}
}
query GetVideos($videoIds: [Int!]!) {
getVideos(videoIds: $videoIds) {
id
playlist {
segmentDurations
}
stream {
id
segments {
uploaded
valid
segmentIndex
endFrameIndex
framesPerSecond
}
}
}
}
query GetVideo($videoId: Int!) {
getVideo(videoId: $videoId) {
id
playlist {
segmentDurations
}
stream {
segments {
segmentIndex
endFrameIndex
framesPerSecond
}
}
}
}

View File

@ -1,5 +1,29 @@
mutation CreateUploadStream($videoMetadataInput: VideoMetadataInput!) { mutation CreateUploadStream(
createUploadStream(videoMetadata: $videoMetadataInput) { $videoName: String!
$deviceType: DeviceTypeEnum
$osVersion: String
$appVersion: String
$browserName: String
$browserVersion: String
$locale: String
$timezone: String
$networkType: String
$ipAddress: String
) {
createUploadStream(
videoName: $videoName
uploadMetadata: {
deviceType: $deviceType
osVersion: $osVersion
appVersion: $appVersion
browserName: $browserName
browserVersion: $browserVersion
locale: $locale
timezone: $timezone
networkType: $networkType
ipAddress: $ipAddress
}
) {
videoId videoId
} }
} }
@ -7,54 +31,19 @@ mutation CreateUploadStream($videoMetadataInput: VideoMetadataInput!) {
mutation GetUploadLink($videoId: Int!, $segmentIndex: Int!) { mutation GetUploadLink($videoId: Int!, $segmentIndex: Int!) {
getUploadLink(videoId: $videoId, segmentIndex: $segmentIndex) { getUploadLink(videoId: $videoId, segmentIndex: $segmentIndex) {
uploadUrl uploadUrl
headers {
key
value
}
} }
} }
mutation EditUploadStream( mutation TerminateUploadStream(
$videoId: Int! $videoId: Int!
$videoMetadataInput: VideoMetadataInput! $videoName: String
$gameType: String
$tableSize: String
) { ) {
editUploadStream(videoId: $videoId, videoMetadata: $videoMetadataInput) terminateUploadStream(
} videoId: $videoId
videoName: $videoName
query GetUploadStreams( gameType: $gameType
$limit: Int! = 5 tableSize: $tableSize
$after: String = null )
$filters: VideoFilterInput = null
) {
getUserVideos(limit: $limit, after: $after, filters: $filters) {
videos {
id
}
pageInfo {
hasNextPage
endCursor
}
}
}
query GetUploadStreamsWithDetails(
$limit: Int! = 5
$after: String = null
$filters: VideoFilterInput = null
) {
getUserVideos(limit: $limit, after: $after, filters: $filters) {
videos {
id
name
startTime
stream {
isCompleted
lastIntendedSegmentBound
uploadCompletionCursor
}
}
pageInfo {
hasNextPage
endCursor
}
}
} }

View File

@ -1,51 +1,33 @@
type Query { type Query {
getAggregatedShotMetrics( getAggregateShots(bucketSets: [BucketSetInputGQL!]!): [AggregateResultGQL!]!
aggregateInput: AggregateInputGQL!
): [AggregateResultGQL!]!
getBucketSet(keyName: String!): BucketSetGQL
getDeployedConfig: DeployedConfigGQL!
getVideoMakePercentageIntervals(
videoId: ID!
intervalDuration: Int! = 300
): [MakePercentageIntervalGQL!]!
getShots(filterInput: FilterInput!): [ShotGQL!]!
getUser(userId: Int!): UserGQL getUser(userId: Int!): UserGQL
getLoggedInUser: UserGQL getLoggedInUser: UserGQL
getPlayTime(userId: Int!): UserPlayTimeGQL!
getUserVideos(
userId: Int = null
limit: Int! = 5
after: String = null
filters: VideoFilterInput = null
): VideoHistoryGQL!
getVideo(videoId: Int!): VideoGQL! getVideo(videoId: Int!): VideoGQL!
getVideos(videoIds: [Int!]!): [VideoGQL!]! getShots(filterInput: FilterInput = null): [ShotGQL!]!
getBucketSet(keyName: String!): BucketSetGQL
getVideoFeedForUser(first: Int! = 5, after: String = null): VideoFeedGQL!
} }
type AggregateResultGQL { type AggregateResultGQL {
aggregationIdentifiers: [AggregationIdentifierGQL!]! featureBuckets: [BucketGQL!]!
targetMetrics: TargetMetricsGQL! targetMetrics: [TargetMetricGQL!]!
} }
type AggregationIdentifierGQL { type BucketGQL {
featureName: String! rangeKey: String!
groupName: String! lowerBound: Float!
} }
type TargetMetricsGQL { type TargetMetricGQL {
count: Int! count: Int
makePercentage: Float makePercentage: Float
averageDifficulty: Float floatFeature: TargetFloatFeatureGQL
} }
input AggregateInputGQL { type TargetFloatFeatureGQL {
aggregations: [AggregationInput!]! featureName: String!
filterInput: FilterInput average: Float
} median: Float
input AggregationInput {
bucketSet: BucketSetInputGQL = null
enum: EnumAggregation = null
} }
input BucketSetInputGQL { input BucketSetInputGQL {
@ -58,37 +40,68 @@ input BucketInputGQL {
lowerBound: Float! lowerBound: Float!
} }
input EnumAggregation { type UserGQL {
feature: String! id: Int!
firebaseUid: String!
username: String!
createdAt: DateTime
updatedAt: DateTime
statistics: UserStatisticsGQL!
} }
input FilterInput { """Date with time (isoformat)"""
andFilters: AndFilter = null scalar DateTime
orFilters: OrFilter = null
cueObjectDistance: RangeFilter = null type UserStatisticsGQL {
targetPocketDistance: RangeFilter = null totalShots: Int!
cueObjectAngle: RangeFilter = null totalShotsMade: Int!
cueBallSpeed: RangeFilter = null makePercentage: Decimal!
difficulty: RangeFilter = null averageTimeBetweenShots: Decimal!
intendedPocketType: [PocketEnum!] = null timeSpentPlaying: Decimal!
shotDirection: [ShotDirectionEnum!] = null medianRun: Decimal
videoId: [Int!] = null
userId: [Int!] = null
make: [Boolean!] = null
tags: [VideoTagInput!] = null
} }
input AndFilter { """Decimal (fixed-point)"""
filters: [FilterInput!]! scalar Decimal
type VideoGQL {
id: Int!
name: String
totalShotsMade: Int!
totalShots: Int!
makePercentage: Float!
medianRun: Float
averageTimeBetweenShots: Float
createdAt: DateTime
updatedAt: DateTime
shots: [ShotGQL!]!
startTime: DateTime
endTime: DateTime
elapsedTime: Float
framesPerSecond: Int!
stream: UploadStreamGQL
} }
input OrFilter { type ShotGQL {
filters: [FilterInput!]! id: Int
videoId: Int
startFrame: Int
endFrame: Int
createdAt: DateTime
updatedAt: DateTime
features: ShotFeaturesGQL
cueObjectFeatures: CueObjectFeaturesGQL
pocketingIntentionFeatures: PocketingIntentionFeaturesGQL
} }
input RangeFilter { type ShotFeaturesGQL {
lessThan: Float = null cueObjectAngle: Float
greaterThanEqualTo: Float = null cueObjectDistance: Float
targetPocketDistance: Float
intendedPocket: PocketEnum
cueBallSpeed: Float
shotDirection: ShotDirectionEnum
bank: BankFeaturesGQL
} }
enum PocketEnum { enum PocketEnum {
@ -102,56 +115,17 @@ enum ShotDirectionEnum {
STRAIGHT STRAIGHT
} }
input VideoTagInput { type BankFeaturesGQL {
tagClasses: [VideoTagClassInput!]! = [] wallsHit: [WallTypeEnum!]!
name: String! bankAngle: Float!
distance: Float!
} }
input VideoTagClassInput { enum WallTypeEnum {
name: String! LONG
SHORT
} }
type BucketSetGQL {
keyName: String!
feature: String!
buckets: [BucketGQL!]!
}
type BucketGQL {
rangeKey: String!
lowerBound: Float!
}
type DeployedConfigGQL {
allowNewUsers: Boolean!
firebase: Boolean!
devMode: Boolean!
environment: String!
}
type MakePercentageIntervalGQL {
makePercentage: Float!
elapsedTime: Float!
}
type ShotGQL {
id: Int!
videoId: Int!
startFrame: Int!
endFrame: Int!
createdAt: DateTime
updatedAt: DateTime
cueObjectFeatures: CueObjectFeaturesGQL
pocketingIntentionFeatures: PocketingIntentionFeaturesGQL
bankFeatures: BankFeaturesGQL
user: UserGQL
}
"""
Date with time (isoformat)
"""
scalar DateTime
type CueObjectFeaturesGQL { type CueObjectFeaturesGQL {
cueObjectDistance: Float cueObjectDistance: Float
cueObjectAngle: Float cueObjectAngle: Float
@ -163,144 +137,97 @@ type PocketingIntentionFeaturesGQL {
targetPocketDistance: Float targetPocketDistance: Float
make: Boolean make: Boolean
intendedPocketType: PocketEnum intendedPocketType: PocketEnum
difficulty: Float
}
type BankFeaturesGQL {
wallsHit: [WallTypeEnum!]!
bankAngle: Float!
distance: Float!
}
enum WallTypeEnum {
LONG
SHORT
}
type UserGQL {
id: Int!
firebaseUid: String!
username: String!
activeVideoId: Int
profileImageUri: String
createdAt: DateTime
updatedAt: DateTime
}
type UserPlayTimeGQL {
totalSeconds: Float!
}
type VideoHistoryGQL {
videos: [VideoGQL!]!
pageInfo: PageInfoGQL!
}
type VideoGQL {
id: Int!
owner: UserGQL
name: String
screenshotUri: String
totalShotsMade: Int!
totalShots: Int!
makePercentage: Float!
medianRun: Float
averageTimeBetweenShots: Float
createdAt: DateTime
updatedAt: DateTime
shots: [ShotGQL!]!
startTime: DateTime
endTime: DateTime
elapsedTime: Float
framesPerSecond: Float!
stream: UploadStreamGQL
playlist: HLSPlaylistGQL
tags: [VideoTag!]!
homographyHistory: [HomographyInfoGQL!]!
currentProcessing: VideoProcessingGQL
} }
type UploadStreamGQL { type UploadStreamGQL {
id: ID! id: ID!
linksRequested: Int! linksRequested: Int!
uploadsCompleted: Int! uploadsCompleted: Int!
segmentProcessingCursor: Int!
lastIntendedSegmentBound: Int
isCompleted: Boolean! isCompleted: Boolean!
lowestUnuploadedSegmentIndex: Int! uploadMetadata: UploadStreamMetadata!
uploadCompletionCursor: Int!
errors: [StreamErrorGQL!]!
createdAt: DateTime! createdAt: DateTime!
updatedAt: DateTime! updatedAt: DateTime!
segments: [UploadSegmentGQL!]!
} }
type StreamErrorGQL { type UploadStreamMetadata {
message: String! deviceType: DeviceTypeEnum
osVersion: String
appVersion: String
browserName: String
browserVersion: String
locale: String
timezone: String
networkType: String
ipAddress: String
} }
type UploadSegmentGQL { enum DeviceTypeEnum {
segmentIndex: Int! IOS
uploaded: Boolean! ANDROID
valid: Boolean! BROWSER
endFrameIndex: Int
framesPerSecond: Float
durationsInSeconds: Float
linksRequested: Int!
} }
type HLSPlaylistGQL { input FilterInput {
videoId: Int! andFilters: AndFilter = null
m3u8Text: String! orFilters: OrFilter = null
segmentDurations: [Float!]! cueObjectDistance: CueObjectDistanceInput = null
targetPocketDistance: TargetPocketDistanceInput = null
cueObjectAngle: CueObjectAngleInput = null
cueBallSpeed: CueBallSpeedInput = null
intendedPocketType: IntendedPocketTypeInput = null
shotDirection: ShotDirectionInput = null
} }
type VideoTag { input AndFilter {
tagClasses: [VideoTagClass!]! filters: [FilterInput!]!
name: String!
} }
type VideoTagClass { input OrFilter {
name: String! filters: [FilterInput!]!
} }
type HomographyInfoGQL { input CueObjectDistanceInput {
frameIndex: Int! value: RangeFilter!
crop: BoundingBoxGQL!
pockets: [BoundingBoxGQL!]!
sourcePoints: PocketPointsGQL!
destPoints: PocketPointsGQL!
} }
type BoundingBoxGQL { input RangeFilter {
left: Float! lessThan: Float = null
top: Float! greaterThanEqualTo: Float = null
width: Float!
height: Float!
} }
type PocketPointsGQL { input TargetPocketDistanceInput {
topLeft: IntPoint2D! value: RangeFilter!
topSide: IntPoint2D!
topRight: IntPoint2D!
bottomLeft: IntPoint2D!
bottomSide: IntPoint2D!
bottomRight: IntPoint2D!
} }
type IntPoint2D { input CueObjectAngleInput {
x: Int! value: RangeFilter!
y: Int!
} }
type VideoProcessingGQL { input CueBallSpeedInput {
errors: [VideoProcessingErrorGQL!]! value: RangeFilter!
} }
type VideoProcessingErrorGQL { input IntendedPocketTypeInput {
message: String! value: EnumFilter!
startSegmentIndex: Int }
endSegmentIndex: Int
input EnumFilter {
equals: String = null
}
input ShotDirectionInput {
value: EnumFilter!
}
type BucketSetGQL {
keyName: String!
feature: String!
buckets: [BucketGQL!]!
}
type VideoFeedGQL {
videos: [VideoGQL!]!
pageInfo: PageInfoGQL!
} }
type PageInfoGQL { type PageInfoGQL {
@ -308,22 +235,11 @@ type PageInfoGQL {
endCursor: String endCursor: String
} }
input VideoFilterInput {
isStreamCompleted: Boolean = null
requireCursorCompletion: Boolean! = true
}
type Mutation { type Mutation {
createBucketSet(params: CreateBucketSetInput!): BucketSetGQL! createBucketSet(params: CreateBucketSetInput!): BucketSetGQL!
setLoggerLevel(path: String!, level: String!): Boolean! createUploadStream(uploadMetadata: UploadMetadataInput, videoName: String = null): CreateUploadStreamReturn!
getProfileImageUploadLink(fileExt: String = ".png"): GetUploadLinkReturn!
editProfileImageUri(profileImageUri: String!): UserGQL!
createUploadStream(
videoMetadata: VideoMetadataInput!
): CreateUploadStreamReturn!
getUploadLink(videoId: Int!, segmentIndex: Int!): GetUploadLinkReturn! getUploadLink(videoId: Int!, segmentIndex: Int!): GetUploadLinkReturn!
editUploadStream(videoId: Int!, videoMetadata: VideoMetadataInput!): Boolean! terminateUploadStream(videoId: Int!, videoName: String = null, gameType: String = null, tableSize: String = null): Boolean!
deleteVideo(videoId: Int!): Boolean!
} }
input CreateBucketSetInput { input CreateBucketSetInput {
@ -332,32 +248,11 @@ input CreateBucketSetInput {
buckets: [BucketInputGQL!]! buckets: [BucketInputGQL!]!
} }
type GetUploadLinkReturn {
uploadUrl: String!
headers: [Header]!
}
type Header {
key: String!
value: String!
}
type CreateUploadStreamReturn { type CreateUploadStreamReturn {
videoId: Int! videoId: Int!
} }
input VideoMetadataInput { input UploadMetadataInput {
videoName: String = null
startTime: DateTime = null
endTime: DateTime = null
gameType: String = null
tableSize: String = null
uploadStreamMetadataInput: UploadStreamMetadataInput = null
lastIntendedSegmentBound: Int = null
endStream: Boolean! = false
}
input UploadStreamMetadataInput {
deviceType: DeviceTypeEnum = null deviceType: DeviceTypeEnum = null
osVersion: String = null osVersion: String = null
appVersion: String = null appVersion: String = null
@ -369,8 +264,6 @@ input UploadStreamMetadataInput {
ipAddress: String = null ipAddress: String = null
} }
enum DeviceTypeEnum { type GetUploadLinkReturn {
IOS uploadUrl: String!
ANDROID
BROWSER
} }

View File

@ -2548,16 +2548,6 @@ picomatch@^2.3.1:
resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42"
integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==
prettier-plugin-organize-imports@^3.2.4:
version "3.2.4"
resolved "https://registry.yarnpkg.com/prettier-plugin-organize-imports/-/prettier-plugin-organize-imports-3.2.4.tgz#77967f69d335e9c8e6e5d224074609309c62845e"
integrity sha512-6m8WBhIp0dfwu0SkgfOxJqh+HpdyfqSSLfKKRZSFbDuEQXDDndb8fTpRWkUrX/uBenkex3MgnVk0J3b3Y5byog==
prettier@^3.2.5:
version "3.2.5"
resolved "https://registry.yarnpkg.com/prettier/-/prettier-3.2.5.tgz#e52bc3090586e824964a8813b09aba6233b28368"
integrity sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==
promise@^7.1.1: promise@^7.1.1:
version "7.3.1" version "7.3.1"
resolved "https://registry.yarnpkg.com/promise/-/promise-7.3.1.tgz#064b72602b18f90f29192b8b1bc418ffd1ebd3bf" resolved "https://registry.yarnpkg.com/promise/-/promise-7.3.1.tgz#064b72602b18f90f29192b8b1bc418ffd1ebd3bf"