Merge branch '193-implement-jest-unit-testing' of git@github.com:anultravioletaurora/Jellify.git
11
.github/pull_request_template.md
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
### What is the change
|
||||
|
||||
|
||||
### What does this address
|
||||
|
||||
|
||||
### Issue number / link
|
||||
|
||||
|
||||
### Tag reviewers
|
||||
@anultravioletaurora
|
||||
7
.github/workflows/publish-beta.yml
vendored
@@ -44,11 +44,14 @@ jobs:
|
||||
with:
|
||||
commit_message: "[skip actions]"
|
||||
file_pattern: "ios/Jellify.xcodeproj/project.pbxproj"
|
||||
|
||||
|
||||
- name: 🔢 Set artifact version numbers
|
||||
run: mkdir artifacts && mv ./ios/Jellify.ipa ./artifacts/Jellify-${{ env.VERSION_NUMBER }}.ipa && mv ./android/app/build/outputs/apk/release/app-release.apk ./artifacts/Jellify-${{ env.VERSION_NUMBER }}.apk
|
||||
|
||||
- name: 🎉 Create Github release
|
||||
uses: ncipollo/release-action@v1
|
||||
with:
|
||||
artifacts: "ios/Jellify.ipa,android/app/build/outputs/apk/release/app-release.apk"
|
||||
artifacts: "./artifacts/*"
|
||||
name: ${{ env.VERSION_NUMBER }}
|
||||
prerelease: true
|
||||
tag: ${{ env.VERSION_NUMBER }}
|
||||
|
||||
69
README.md
@@ -42,7 +42,7 @@ This app was designed with me and my dad in mind, since I wanted to give him a s
|
||||
- [Shared, Public, and Collaborative Playlists](https://github.com/anultravioletaurora/Jellify/issues/175)
|
||||
- [Web / Desktop support](https://github.com/anultravioletaurora/Jellify/issues/71)
|
||||
- [Watch (Apple Watch / WearOS) Support](https://github.com/anultravioletaurora/Jellify/issues/61)
|
||||
- [TV (Android, Samsung) Support](https://github.com/anultravioletaurora/Jellify/issues/85)
|
||||
- [TV (Android, Apple, Samsung) Support](https://github.com/anultravioletaurora/Jellify/issues/85)
|
||||
|
||||
## 👀 Lemme see!
|
||||
### Home
|
||||
@@ -99,23 +99,27 @@ Playlist
|
||||
### On the Server
|
||||
<img src="https://github.com/user-attachments/assets/741884a2-b9b7-4081-b3a0-6655d08071dc" alt="Playback Tracking" width="300" height="200">
|
||||
|
||||
## 🏗 Built with:
|
||||
## 🏗 Built with good stuff
|
||||
[](https://reactjs.org “Go to React homepage”) [](https://typescriptlang.org “Go to TypeScript homepage”)
|
||||
### 🎨 Frontend
|
||||
[Tamagui](https://tamagui.dev/)\
|
||||
[React Navigation](https://reactnavigation.org/)\
|
||||
[Burnt](https://github.com/nandorojo/burnt)\
|
||||
[React Navigation](https://reactnavigation.org/)\
|
||||
[React Native CarPlay](https://github.com/birkir/react-native-carplay)\
|
||||
[React Native Draggable Flatlist](https://github.com/computerjazz/react-native-draggable-flatlist)\
|
||||
[React Native Reanimated](https://docs.swmansion.com/react-native-reanimated/)\
|
||||
[React Native Vector Icons](https://github.com/oblador/react-native-vector-icons)
|
||||
- Specifically Material Community Icons
|
||||
- Specifically using [Material Community Icons](https://oblador.github.io/react-native-vector-icons/#MaterialCommunityIcons)
|
||||
|
||||
### 🎛️ Backend
|
||||
[Jellyfin SDK](https://typescript-sdk.jellyfin.org/)\
|
||||
[Expo SDK](https://expo.dev/)\
|
||||
[Jellyfin SDK](https://typescript-sdk.jellyfin.org/)\
|
||||
[Tanstack Query](https://tanstack.com/query/latest/docs/framework/react/react-native)\
|
||||
[React Native Track Player](https://github.com/doublesymmetry/react-native-track-player)\
|
||||
[React Native MMKV](https://github.com/mrousavy/react-native-mmkv)\
|
||||
[React Native Boost](https://github.com/kuatsu/react-native-boost)\
|
||||
[React Native File Access](https://github.com/alpha0010/react-native-file-access)\
|
||||
[React Native Boost](https://github.com/kuatsu/react-native-boost)
|
||||
[React Native MMKV](https://github.com/mrousavy/react-native-mmkv)\
|
||||
[React Native Track Player](https://github.com/doublesymmetry/react-native-track-player)\
|
||||
[React Native URL Polyfill](https://github.com/charpeni/react-native-url-polyfill)
|
||||
|
||||
### 👩💻 Monitoring
|
||||
[GlitchTip](https://glitchtip.com/)
|
||||
@@ -125,33 +129,62 @@ This is undoubtedly a passion project of [mine](https://github.com/anultraviolet
|
||||
|
||||
## 🏃♀️Running Locally
|
||||
|
||||
#### Universal Dependencies
|
||||
- Ruby
|
||||
- NodeJS
|
||||
### ⚛️ Universal Dependencies
|
||||
- [Ruby](https://www.ruby-lang.org/en/documentation/installation/) for Fastlane
|
||||
- [NodeJS v22](https://nodejs.org/en/download) for React Native
|
||||
|
||||
#### iOS Instructions
|
||||
### 🍎 iOS
|
||||
#### Dependencies
|
||||
- [Xcode](https://developer.apple.com/xcode/) for building
|
||||
|
||||
#### Instructions
|
||||
##### Setup
|
||||
- Clone this repository
|
||||
- Run `npm run init` to initialize the project
|
||||
- This will install `npm` packages, install `bundler` and required gems, and installs CocoaPods
|
||||
- In the `ios` directory, run `fastlane match development --readonly` to fetch the development signing certificates
|
||||
- You will need access to the *Jellify Signing* private repository
|
||||
- To run locally, run `npm run start` then run the app on your device or in the simulator
|
||||
- Make sure you open the `Jellify.xcodeworkspace`, *not* the `Jellify.xcodeproject`
|
||||
- *You will need access to the *Jellify Signing* private repository*
|
||||
|
||||
##### Running
|
||||
- Run `npm run start` to start the dev server
|
||||
- Open the `Jellify.xcodeworkspace` with Xcode, *not* the `Jellify.xcodeproject`
|
||||
- Run either on a device or in the simulator
|
||||
- *You will need to wait for Xcode to finish it's "Indexing" step*
|
||||
|
||||
##### Building
|
||||
- To create a build, run `npm run fastlane:ios:build` to use fastlane to compile an `.ipa` for you
|
||||
|
||||
#### Android Instructions
|
||||
### 🤖 Android
|
||||
#### Dependencies
|
||||
- [Android Studio](https://developer.android.com/studio)
|
||||
- [Java Development Kit](https://www.oracle.com/th/java/technologies/downloads/)
|
||||
|
||||
#### Instructions
|
||||
##### Setup
|
||||
- Clone this repository
|
||||
- Run `npm i` to install `npm` packages
|
||||
- To run locally, run `npm run start`, then run the app on your devvice or in the emulator
|
||||
|
||||
##### Running
|
||||
- Run `npm run start` to start the dev server
|
||||
- Open the `android` folder with Android Studio
|
||||
- *Android Studio should automatically grab the "Run Configurations" and initialize Gradle*
|
||||
- Run either on a device or in the simulator
|
||||
|
||||
##### Building
|
||||
- To create a build, run `npm run fastlane:android:build` to use fastlane to compile an `.apk` for you
|
||||
|
||||
#### References
|
||||
- [Setting up Android SDK](https://developer.android.com/about/versions/14/setup-sdk)
|
||||
- [ANDROID_HOME not being set](https://stackoverflow.com/questions/26356359/error-android-home-is-not-set-and-android-command-not-in-your-path-you-must/54888107#54888107)
|
||||
|
||||
## 🙏 Special Thanks To
|
||||
- The [Jellyfin Team](https://jellyfin.org/) for making this possible with their software, SDKs, and unequivocal helpfulness.
|
||||
- Extra thanks to [Niels](https://github.com/nielsvanvelzen) and [Bill](https://github.com/thornbill)
|
||||
- [James](https://github.com/jmshrv) and all other contributors of [Finamp](https://github.com/jmshrv/finamp). *Jellify* draws inspiration and wisdom from it, and is another fantastic music app for Jellyfin.
|
||||
- James’ [API Blog Post](https://jmshrv.com/posts/jellyfin-api/) proved to be exceptionally valuable during development
|
||||
- The folks in the [Margelo Community Discord](https://discord.com/invite/6CSHz2qAvA) for their assistance
|
||||
- Extra thanks to [Ritesh](https://github.com/riteshshukla04) for your help, knowledge, and guidance
|
||||
- Extra thanks to [Ritesh](https://github.com/riteshshukla04) for your help, knowledge, and guidance
|
||||
- [Nicolas Charpentier](https://github.com/charpeni) for his [React Native URL Polyfill](https://github.com/charpeni/react-native-url-polyfill) module and for his assistance with getting Jest working
|
||||
- My fellow [contributors](https://github.com/anultravioletaurora/Jellify/graphs/contributors) who have poured so much heart and a lot of sweat into making *Jellify* a great experience
|
||||
- Extra thanks to [John Grant](https://github.com/johngrantdev) for shaping and designing the user experience in many places
|
||||
- My dear friends that have heard me talk about *Jellify* for literally **eons**. Thank you for testing *Jellify* during it's infancy and for supporting me all the way back at the beginning of this project
|
||||
|
||||
@@ -9,17 +9,19 @@ GEM
|
||||
public_suffix (>= 2.0.2, < 7.0)
|
||||
artifactory (3.0.17)
|
||||
atomos (0.1.3)
|
||||
aws-eventstream (1.3.0)
|
||||
aws-partitions (1.1046.0)
|
||||
aws-sdk-core (3.217.1)
|
||||
aws-eventstream (1.3.2)
|
||||
aws-partitions (1.1082.0)
|
||||
aws-sdk-core (3.222.1)
|
||||
aws-eventstream (~> 1, >= 1.3.0)
|
||||
aws-partitions (~> 1, >= 1.992.0)
|
||||
aws-sigv4 (~> 1.9)
|
||||
base64
|
||||
jmespath (~> 1, >= 1.6.1)
|
||||
aws-sdk-kms (1.97.0)
|
||||
logger
|
||||
aws-sdk-kms (1.99.0)
|
||||
aws-sdk-core (~> 3, >= 3.216.0)
|
||||
aws-sigv4 (~> 1.5)
|
||||
aws-sdk-s3 (1.179.0)
|
||||
aws-sdk-s3 (1.183.0)
|
||||
aws-sdk-core (~> 3, >= 3.216.0)
|
||||
aws-sdk-kms (~> 1)
|
||||
aws-sigv4 (~> 1.5)
|
||||
@@ -68,7 +70,7 @@ GEM
|
||||
faraday_middleware (1.2.1)
|
||||
faraday (~> 1.0)
|
||||
fastimage (2.4.0)
|
||||
fastlane (2.226.0)
|
||||
fastlane (2.227.0)
|
||||
CFPropertyList (>= 2.3, < 4.0.0)
|
||||
addressable (>= 2.8, < 3.0.0)
|
||||
artifactory (~> 3.0)
|
||||
@@ -129,12 +131,12 @@ GEM
|
||||
google-apis-core (>= 0.11.0, < 2.a)
|
||||
google-apis-storage_v1 (0.31.0)
|
||||
google-apis-core (>= 0.11.0, < 2.a)
|
||||
google-cloud-core (1.7.1)
|
||||
google-cloud-core (1.8.0)
|
||||
google-cloud-env (>= 1.0, < 3.a)
|
||||
google-cloud-errors (~> 1.0)
|
||||
google-cloud-env (1.6.0)
|
||||
faraday (>= 0.17.3, < 3.0)
|
||||
google-cloud-errors (1.4.0)
|
||||
google-cloud-errors (1.5.0)
|
||||
google-cloud-storage (1.47.0)
|
||||
addressable (~> 2.8)
|
||||
digest-crc (~> 0.4)
|
||||
@@ -152,15 +154,18 @@ GEM
|
||||
highline (2.0.3)
|
||||
http-cookie (1.0.8)
|
||||
domain_name (~> 0.5)
|
||||
httpclient (2.8.3)
|
||||
httpclient (2.9.0)
|
||||
mutex_m
|
||||
jmespath (1.6.2)
|
||||
json (2.9.1)
|
||||
json (2.10.2)
|
||||
jwt (2.10.1)
|
||||
base64
|
||||
logger (1.7.0)
|
||||
mini_magick (4.13.2)
|
||||
mini_mime (1.1.5)
|
||||
multi_json (1.15.0)
|
||||
multipart-post (2.4.1)
|
||||
mutex_m (0.3.0)
|
||||
nanaimo (0.4.0)
|
||||
naturally (2.2.1)
|
||||
nkf (0.2.0)
|
||||
@@ -174,7 +179,7 @@ GEM
|
||||
trailblazer-option (>= 0.1.1, < 0.2.0)
|
||||
uber (< 0.2.0)
|
||||
retriable (3.1.2)
|
||||
rexml (3.4.0)
|
||||
rexml (3.4.1)
|
||||
rouge (3.28.0)
|
||||
ruby2_keywords (0.0.5)
|
||||
rubyzip (2.4.1)
|
||||
@@ -206,14 +211,14 @@ GEM
|
||||
colored2 (~> 3.1)
|
||||
nanaimo (~> 0.4.0)
|
||||
rexml (>= 3.3.6, < 4.0)
|
||||
xcpretty (0.4.0)
|
||||
xcpretty (0.4.1)
|
||||
rouge (~> 3.28.0)
|
||||
xcpretty-travis-formatter (1.0.1)
|
||||
xcpretty (~> 0.2, >= 0.0.7)
|
||||
|
||||
PLATFORMS
|
||||
ruby
|
||||
x86_64-darwin-23
|
||||
x64-mingw-ucrt
|
||||
x86_64-linux
|
||||
|
||||
DEPENDENCIES
|
||||
fastlane
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
|
||||
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
|
||||
<uses-permission android:name="android.permission.INTERNET" />
|
||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||
|
||||
<application
|
||||
android:name=".MainApplication"
|
||||
android:label="@string/app_name"
|
||||
android:networkSecurityConfig="@xml/network_security_config"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:roundIcon="@mipmap/ic_launcher_round"
|
||||
android:allowBackup="false"
|
||||
|
||||
|
Before Width: | Height: | Size: 3.0 KiB After Width: | Height: | Size: 4.0 KiB |
|
Before Width: | Height: | Size: 4.9 KiB After Width: | Height: | Size: 5.5 KiB |
|
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 2.3 KiB |
|
Before Width: | Height: | Size: 2.8 KiB After Width: | Height: | Size: 3.0 KiB |
|
Before Width: | Height: | Size: 4.5 KiB After Width: | Height: | Size: 6.3 KiB |
|
Before Width: | Height: | Size: 6.9 KiB After Width: | Height: | Size: 8.4 KiB |
|
Before Width: | Height: | Size: 6.3 KiB After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 16 KiB |
|
Before Width: | Height: | Size: 9.0 KiB After Width: | Height: | Size: 19 KiB |
|
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 24 KiB |
8
android/app/src/main/res/xml/network_security_config.xml
Normal file
@@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<network-security-config xmlns:tools="http://schemas.android.com/tools">
|
||||
<!-- Allow cleartext network traffic -->
|
||||
<base-config
|
||||
cleartextTrafficPermitted="true"
|
||||
tools:ignore="InsecureBaseConfiguration">
|
||||
</base-config>
|
||||
</network-security-config>
|
||||
@@ -23,12 +23,18 @@ export async function fetchSearchResults(searchString: string | undefined) : Pro
|
||||
searchTerm: trim(searchString),
|
||||
recursive: true,
|
||||
includeItemTypes: [
|
||||
'MusicArtist',
|
||||
'Audio',
|
||||
'MusicAlbum',
|
||||
'MusicArtist',
|
||||
'Playlist'
|
||||
],
|
||||
limit: QueryConfig.limits.search
|
||||
limit: QueryConfig.limits.search,
|
||||
sortBy: [
|
||||
'IsFolder'
|
||||
],
|
||||
sortOrder: [
|
||||
'Descending'
|
||||
]
|
||||
})
|
||||
.then((response) => {
|
||||
if (response.data.Items)
|
||||
|
||||
@@ -1,31 +1,40 @@
|
||||
import { getItemsApi, getSuggestionsApi } from "@jellyfin/sdk/lib/utils/api";
|
||||
import Client from "../../../api/client";
|
||||
import { BaseItemDto } from "@jellyfin/sdk/lib/generated-client/models";
|
||||
import { getSuggestionsApi } from "@jellyfin/sdk/lib/utils/api";
|
||||
import { BaseItemDto, BaseItemKind } from "@jellyfin/sdk/lib/generated-client/models";
|
||||
|
||||
export async function fetchSearchSuggestions() : Promise<BaseItemDto[]> {
|
||||
return new Promise((resolve, reject) => {
|
||||
getSuggestionsApi(Client.api!)
|
||||
.getSuggestions({
|
||||
userId: Client.user!.id,
|
||||
type: [
|
||||
'MusicArtist',
|
||||
'MusicAlbum',
|
||||
'Audio',
|
||||
'Playlist'
|
||||
getItemsApi(Client.api!)
|
||||
.getItems({
|
||||
recursive: true,
|
||||
limit: 10,
|
||||
includeItemTypes: [
|
||||
BaseItemKind.MusicArtist,
|
||||
BaseItemKind.Playlist,
|
||||
BaseItemKind.Audio,
|
||||
BaseItemKind.MusicAlbum
|
||||
],
|
||||
sortBy: [
|
||||
"IsFavoriteOrLiked",
|
||||
"Random"
|
||||
]
|
||||
})
|
||||
.then((response) => {
|
||||
if (response.data.Items)
|
||||
resolve(response.data.Items)
|
||||
.then(({ data }) => {
|
||||
if (data.Items)
|
||||
resolve(data.Items);
|
||||
else
|
||||
resolve([]);
|
||||
})
|
||||
.catch((error) => {
|
||||
reject(error);
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use Items API based functions instead of Suggestions API
|
||||
* @returns
|
||||
*/
|
||||
export async function fetchSuggestedArtists() : Promise<BaseItemDto[]> {
|
||||
return new Promise((resolve, reject) => {
|
||||
getSuggestionsApi(Client.api!)
|
||||
@@ -47,6 +56,10 @@ export async function fetchSuggestedArtists() : Promise<BaseItemDto[]> {
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use Items API based functions instead of Suggestions API
|
||||
* @returns
|
||||
*/
|
||||
export async function fetchSuggestedAlbums() : Promise<BaseItemDto[]> {
|
||||
return new Promise((resolve, reject) => {
|
||||
getSuggestionsApi(Client.api!)
|
||||
@@ -68,6 +81,10 @@ export async function fetchSuggestedAlbums() : Promise<BaseItemDto[]> {
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use Items API based functions instead of Suggestions API
|
||||
* @returns
|
||||
*/
|
||||
export async function fetchSuggestedTracks() : Promise<BaseItemDto[]> {
|
||||
return new Promise((resolve, reject) => {
|
||||
getSuggestionsApi(Client.api!)
|
||||
|
||||
@@ -85,7 +85,7 @@ export function ArtistScreen({
|
||||
<FlatList
|
||||
contentContainerStyle={{
|
||||
flexGrow: 1,
|
||||
alignContent: 'center'
|
||||
alignItems: "center"
|
||||
}}
|
||||
data={albums}
|
||||
numColumns={columns} // TODO: Make this adjustable
|
||||
@@ -93,7 +93,7 @@ export function ArtistScreen({
|
||||
<ItemCard
|
||||
caption={album.Name}
|
||||
subCaption={album.ProductionYear?.toString()}
|
||||
width={(width / 1.1) / columns}
|
||||
size={"$14"}
|
||||
squared
|
||||
item={album}
|
||||
onPress={() => {
|
||||
|
||||
@@ -27,7 +27,7 @@ export default function RecentlyAdded({
|
||||
caption={item.Name}
|
||||
subCaption={`${item.Artists?.join(", ")}`}
|
||||
squared
|
||||
width={150}
|
||||
size={"$12"}
|
||||
item={item}
|
||||
onPress={() => {
|
||||
navigation.navigate("Album", {
|
||||
|
||||
@@ -10,7 +10,7 @@ interface HorizontalCardListProps extends FlatListProps<BaseItemDto> {
|
||||
* we cut it off and display a "Show More" card
|
||||
*/
|
||||
cutoff?: number | undefined;
|
||||
onSeeMore: () => void;
|
||||
onSeeMore?: () => void | undefined;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -31,17 +31,17 @@ export default function HorizontalCardList({
|
||||
data={props.data}
|
||||
renderItem={props.renderItem}
|
||||
ListFooterComponent={() => {
|
||||
return props.data ? (
|
||||
<IconCard
|
||||
name={
|
||||
squared
|
||||
? "arrow-right-box"
|
||||
: "arrow-right-circle"
|
||||
}
|
||||
circular={!squared}
|
||||
caption="See More"
|
||||
onPress={onSeeMore}
|
||||
/>
|
||||
return props.data && onSeeMore ? (
|
||||
<IconCard
|
||||
name={
|
||||
squared
|
||||
? "arrow-right-box"
|
||||
: "arrow-right-circle"
|
||||
}
|
||||
circular={!squared}
|
||||
caption="See More"
|
||||
onPress={onSeeMore}
|
||||
/>
|
||||
) : undefined}
|
||||
}
|
||||
removeClippedSubviews
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import React from "react";
|
||||
import type { CardProps as TamaguiCardProps } from "tamagui"
|
||||
import { getToken, Card as TamaguiCard, View } from "tamagui";
|
||||
import { getToken, Card as TamaguiCard, View, YStack } from "tamagui";
|
||||
import { BaseItemDto } from "@jellyfin/sdk/lib/generated-client/models";
|
||||
import { Text } from "../helpers/text";
|
||||
import { Image } from "expo-image";
|
||||
@@ -16,24 +16,21 @@ interface CardProps extends TamaguiCardProps {
|
||||
|
||||
export function ItemCard(props: CardProps) {
|
||||
|
||||
const dimensions = props.width && typeof(props.width) === "number" ? { width: props.width, height: props.width } : { width: 150, height: 150 };
|
||||
|
||||
const logoDimensions = props.width && typeof(props.width) === "number" ? { width: props.width / 2, height: props.width / 6 }: { width: 100, height: 75 };
|
||||
|
||||
return (
|
||||
<View
|
||||
alignItems="center"
|
||||
margin={5}
|
||||
>
|
||||
<TamaguiCard
|
||||
size="$4"
|
||||
size={"$12"}
|
||||
height={props.size}
|
||||
width={props.size}
|
||||
backgroundColor={getToken("$color.amethyst")}
|
||||
borderRadius={props.squared ? 5 : dimensions.width}
|
||||
circular={!props.squared}
|
||||
borderRadius={props.squared ? 5 : 'unset'}
|
||||
animation="bouncy"
|
||||
hoverStyle={props.onPress ? { scale: 0.925 } : {}}
|
||||
pressStyle={props.onPress ? { scale: 0.875 } : {}}
|
||||
width={props.width ?? 150}
|
||||
height={props.width ?? 150}
|
||||
{...props}
|
||||
>
|
||||
<TamaguiCard.Header>
|
||||
@@ -59,18 +56,18 @@ export function ItemCard(props: CardProps) {
|
||||
)}
|
||||
placeholder={props.item.ImageBlurHashes && props.item.ImageBlurHashes["Primary"] ? props.item.ImageBlurHashes["Primary"][0] : undefined}
|
||||
style={{
|
||||
width: dimensions.width,
|
||||
height: dimensions.height,
|
||||
borderRadius: props.squared ? 5 : dimensions.width
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
borderRadius: props.squared ? 2 : 100
|
||||
}}
|
||||
/>
|
||||
</TamaguiCard.Background>
|
||||
</TamaguiCard>
|
||||
{ props.caption && (
|
||||
<View
|
||||
<YStack
|
||||
alignContent="center"
|
||||
alignItems="center"
|
||||
width={dimensions.width}
|
||||
maxWidth={props.size}
|
||||
>
|
||||
<Text
|
||||
bold
|
||||
@@ -89,7 +86,7 @@ export function ItemCard(props: CardProps) {
|
||||
{ props.subCaption }
|
||||
</Text>
|
||||
)}
|
||||
</View>
|
||||
</YStack>
|
||||
)}
|
||||
</View>
|
||||
)
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { Card, getTokens, View } from "tamagui";
|
||||
import { H2, H4 } from "./text";
|
||||
import { H2, H4, H5 } from "./text";
|
||||
import Icon from "./icon";
|
||||
|
||||
interface IconCardProps {
|
||||
@@ -30,12 +30,12 @@ export default function IconCard({
|
||||
borderRadius={circular ? 300 : 5}
|
||||
hoverStyle={{ scale: 0.925 }}
|
||||
pressStyle={{ scale: 0.875 }}
|
||||
width={width ? width : 150}
|
||||
height={width ? width : 150}
|
||||
width={width ? width : "$12"}
|
||||
height={width ? width : "$12"}
|
||||
onPress={onPress}
|
||||
>
|
||||
<Card.Header>
|
||||
<H4 color={getTokens().color.purpleDark}>{ caption ?? "" }</H4>
|
||||
<H5 color={getTokens().color.purpleDark}>{ caption ?? "" }</H5>
|
||||
<Icon
|
||||
color={getTokens().color.purpleDark.val}
|
||||
name={name}
|
||||
|
||||
@@ -26,6 +26,7 @@ export default function Playlists({ navigation }: { navigation: NativeStackNavig
|
||||
renderItem={({ item: playlist }) =>
|
||||
<ItemCard
|
||||
item={playlist}
|
||||
size={"$11"}
|
||||
squared
|
||||
caption={playlist.Name ?? "Untitled Playlist"}
|
||||
onPress={() => {
|
||||
|
||||
@@ -36,10 +36,10 @@ export default function RecentlyPlayed({
|
||||
}}
|
||||
renderItem={({ index, item: recentlyPlayedTrack }) =>
|
||||
<ItemCard
|
||||
size={"$12"}
|
||||
caption={recentlyPlayedTrack.Name}
|
||||
subCaption={`${recentlyPlayedTrack.Artists?.join(", ")}`}
|
||||
squared
|
||||
width={150}
|
||||
item={recentlyPlayedTrack}
|
||||
onPress={() => {
|
||||
usePlayNewQueue.mutate({
|
||||
|
||||
@@ -14,6 +14,7 @@ import { Image } from "expo-image";
|
||||
import { getImageApi } from "@jellyfin/sdk/lib/utils/api";
|
||||
import Client from "../../api/client";
|
||||
import Icon from "../Global/helpers/icon";
|
||||
import { Platform } from "react-native";
|
||||
|
||||
export default function ItemDetail({
|
||||
item,
|
||||
@@ -78,13 +79,21 @@ export default function ItemDetail({
|
||||
minHeight={width / 1.5}
|
||||
minWidth={width / 1.5}
|
||||
>
|
||||
<Icon
|
||||
name="chevron-down"
|
||||
onPress={() => {
|
||||
navigation.goBack();
|
||||
}}
|
||||
small
|
||||
/>
|
||||
{/**
|
||||
* Android needs a dismiss chevron here
|
||||
*/}
|
||||
{ Platform.OS === 'android' ? (
|
||||
<Icon
|
||||
name="chevron-down"
|
||||
onPress={() => {
|
||||
navigation.goBack();
|
||||
}}
|
||||
small
|
||||
/>
|
||||
|
||||
) : (
|
||||
<Spacer />
|
||||
)}
|
||||
|
||||
<Spacer />
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ export default function ServerAuthentication({
|
||||
|
||||
const useApiMutation = useMutation({
|
||||
mutationFn: async (credentials: JellyfinCredentials) => {
|
||||
return await Client.api!.authenticateUserByName(credentials.username, credentials.password!);
|
||||
return await Client.api!.authenticateUserByName(credentials.username, credentials.password);
|
||||
},
|
||||
onSuccess: async (authResult) => {
|
||||
|
||||
@@ -107,7 +107,7 @@ export default function ServerAuthentication({
|
||||
)}
|
||||
|
||||
<Button
|
||||
disabled={_.isEmpty(username) || _.isEmpty(password) || useApiMutation.isPending}
|
||||
disabled={_.isEmpty(username) || useApiMutation.isPending}
|
||||
onPress={() => {
|
||||
|
||||
if (!_.isUndefined(username)) {
|
||||
|
||||
@@ -7,8 +7,13 @@ import { QueryKeys } from "../../enums/query-keys";
|
||||
import { fetchSearchResults } from "../../api/queries/functions/search";
|
||||
import { useQuery } from "@tanstack/react-query";
|
||||
import { FlatList } from "react-native";
|
||||
import { Text } from "../Global/helpers/text";
|
||||
import { H3 } from "../Global/helpers/text";
|
||||
import { fetchSearchSuggestions } from "../../api/queries/functions/suggestions";
|
||||
import { Spinner, YStack } from "tamagui";
|
||||
import Suggestions from "./suggestions";
|
||||
import { isEmpty } from "lodash";
|
||||
import HorizontalCardList from "../Global/components/horizontal-list";
|
||||
import { ItemCard } from "../Global/components/item-card";
|
||||
|
||||
export default function Search({
|
||||
navigation
|
||||
@@ -18,12 +23,12 @@ export default function Search({
|
||||
|
||||
const [searchString, setSearchString] = useState<string | undefined>(undefined);
|
||||
|
||||
const { data: items, refetch, isFetching } = useQuery({
|
||||
const { data: items, refetch, isFetching: fetchingResults } = useQuery({
|
||||
queryKey: [QueryKeys.Search, searchString],
|
||||
queryFn: () => fetchSearchResults(searchString)
|
||||
});
|
||||
|
||||
const { data } = useQuery({
|
||||
const { data: suggestions, isFetching: fetchingSuggestions, refetch: refetchSuggestions } = useQuery({
|
||||
queryKey: [QueryKeys.SearchSuggestions],
|
||||
queryFn: () => fetchSearchSuggestions()
|
||||
});
|
||||
@@ -34,7 +39,10 @@ export default function Search({
|
||||
|
||||
return () => {
|
||||
clearTimeout(timeout);
|
||||
timeout = setTimeout(() => refetch, 1000)
|
||||
timeout = setTimeout(() => {
|
||||
refetch();
|
||||
refetchSuggestions();
|
||||
}, 1000)
|
||||
}
|
||||
}, []);
|
||||
|
||||
@@ -48,17 +56,56 @@ export default function Search({
|
||||
contentInsetAdjustmentBehavior="automatic"
|
||||
progressViewOffset={10}
|
||||
ListHeaderComponent={(
|
||||
<Input
|
||||
placeholder="Seek and ye shall find..."
|
||||
onChangeText={(value) => handleSearchStringUpdate(value)}
|
||||
value={searchString}
|
||||
/>
|
||||
<YStack>
|
||||
<Input
|
||||
placeholder="Seek and ye shall find"
|
||||
onChangeText={(value) => handleSearchStringUpdate(value)}
|
||||
value={searchString}
|
||||
/>
|
||||
|
||||
{ !isEmpty(items) && (
|
||||
<YStack>
|
||||
<H3>Results</H3>
|
||||
|
||||
<HorizontalCardList
|
||||
data={items?.filter(result => result.Type === 'MusicArtist')}
|
||||
renderItem={({ item: artistResult }) => {
|
||||
return (
|
||||
<ItemCard
|
||||
item={artistResult}
|
||||
onPress={() => {
|
||||
navigation.push('Artist', {
|
||||
artist: artistResult
|
||||
})
|
||||
}}
|
||||
size={"$8"}
|
||||
caption={artistResult.Name ?? "Untitled Artist"}
|
||||
/>
|
||||
)
|
||||
}}
|
||||
/>
|
||||
</YStack>
|
||||
)}
|
||||
</YStack>
|
||||
)}
|
||||
ListEmptyComponent={(
|
||||
<Text>No results found</Text>
|
||||
)}
|
||||
data={items}
|
||||
refreshing={isFetching}
|
||||
ListEmptyComponent={() => {
|
||||
return (
|
||||
<YStack
|
||||
alignContent="center"
|
||||
justifyContent="flex-end"
|
||||
marginTop={"$4"}
|
||||
>
|
||||
{ fetchingResults ? (
|
||||
<Spinner />
|
||||
) : (
|
||||
<Suggestions suggestions={suggestions} navigation={navigation} />
|
||||
)}
|
||||
</YStack>
|
||||
)
|
||||
}}
|
||||
// We're displaying artists separately so we're going to filter them out here
|
||||
data={items?.filter((result) => result.Type !== 'MusicArtist')}
|
||||
refreshing={fetchingResults}
|
||||
renderItem={({ item }) =>
|
||||
<Item item={item} queueName={searchString ?? "Search"} navigation={navigation} />
|
||||
}
|
||||
|
||||
55
components/Search/suggestions.tsx
Normal file
@@ -0,0 +1,55 @@
|
||||
import { NativeStackNavigationProp } from "@react-navigation/native-stack";
|
||||
import { FlatList, RefreshControl } from "react-native";
|
||||
import { StackParamList } from "../types";
|
||||
import { BaseItemDto } from "@jellyfin/sdk/lib/generated-client/models";
|
||||
import Item from "../Global/components/item";
|
||||
import { H3, Text } from "../Global/helpers/text";
|
||||
import { YStack } from "tamagui";
|
||||
import { ItemCard } from "../Global/components/item-card";
|
||||
import HorizontalCardList from "../Global/components/horizontal-list";
|
||||
|
||||
interface SuggestionsProps {
|
||||
suggestions: BaseItemDto[] | undefined;
|
||||
navigation: NativeStackNavigationProp<StackParamList>;
|
||||
}
|
||||
|
||||
export default function Suggestions(
|
||||
props: SuggestionsProps
|
||||
) : React.JSX.Element {
|
||||
|
||||
return (
|
||||
<FlatList
|
||||
// Artists are displayed in the header, so we'll filter them out here
|
||||
data={props.suggestions?.filter(suggestion => suggestion.Type !== 'MusicArtist')}
|
||||
ListHeaderComponent={(
|
||||
<YStack>
|
||||
<H3>Suggestions</H3>
|
||||
|
||||
<HorizontalCardList
|
||||
data={props.suggestions?.filter(suggestion => suggestion.Type === 'MusicArtist')}
|
||||
renderItem={({ item: suggestedArtist }) => {
|
||||
return (
|
||||
<ItemCard
|
||||
item={suggestedArtist}
|
||||
onPress={() => {
|
||||
props.navigation.push('Artist', {
|
||||
artist: suggestedArtist
|
||||
})
|
||||
}}
|
||||
size={"$8"}
|
||||
caption={suggestedArtist.Name ?? "Untitled Artist"}
|
||||
/>
|
||||
)
|
||||
}}
|
||||
/>
|
||||
</YStack>
|
||||
)}
|
||||
ListEmptyComponent={(
|
||||
<Text textAlign="center">Wake now, discover that you are the eyes of the world...</Text>
|
||||
)}
|
||||
renderItem={({ item }) => {
|
||||
return <Item item={item} queueName={"Suggestions"} navigation={props.navigation} />
|
||||
}}
|
||||
/>
|
||||
)
|
||||
}
|
||||
@@ -2,19 +2,23 @@ import { createNativeStackNavigator } from "@react-navigation/native-stack";
|
||||
import Player from "./Player/stack";
|
||||
import { Tabs } from "./tabs";
|
||||
import { StackParamList } from "./types";
|
||||
import { useTheme } from 'tamagui'
|
||||
import DetailsScreen from "./ItemDetail/screen";
|
||||
|
||||
export default function Navigation(): React.JSX.Element {
|
||||
|
||||
const RootStack = createNativeStackNavigator<StackParamList>()
|
||||
|
||||
|
||||
const theme = useTheme()
|
||||
|
||||
return (
|
||||
<RootStack.Navigator>
|
||||
<RootStack.Screen
|
||||
name="Tabs"
|
||||
component={Tabs}
|
||||
options={{
|
||||
headerShown: false
|
||||
headerShown: false,
|
||||
navigationBarColor: theme.background.val,
|
||||
}}
|
||||
/>
|
||||
<RootStack.Screen
|
||||
|
||||
@@ -718,7 +718,7 @@
|
||||
CODE_SIGN_IDENTITY = "Apple Development: Jack Caulfield (66Z9J9NX2X)";
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "Apple Development: Jack Caulfield (66Z9J9NX2X)";
|
||||
CODE_SIGN_STYLE = Manual;
|
||||
CURRENT_PROJECT_VERSION = 98;
|
||||
CURRENT_PROJECT_VERSION = 107;
|
||||
DEVELOPMENT_TEAM = WAH9CZ8BPG;
|
||||
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = WAH9CZ8BPG;
|
||||
ENABLE_BITCODE = NO;
|
||||
@@ -759,7 +759,7 @@
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
|
||||
CODE_SIGN_STYLE = Manual;
|
||||
CURRENT_PROJECT_VERSION = 98;
|
||||
CURRENT_PROJECT_VERSION = 107;
|
||||
DEVELOPMENT_TEAM = WAH9CZ8BPG;
|
||||
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = WAH9CZ8BPG;
|
||||
INFOPLIST_FILE = Jellify/Info.plist;
|
||||
|
||||
@@ -56,7 +56,7 @@ platform :ios do
|
||||
api_key_path: "fastlane/appstore_connect_api_key.json",
|
||||
beta_app_feedback_email: "violet@cosmonautical.cloud",
|
||||
beta_app_description: "A music app for Jellyfin",
|
||||
expire_previous_builds: true,
|
||||
expire_previous_builds: false,
|
||||
distribute_external: true,
|
||||
changelog: "Updated Sign In components, Player Optimizations, 'See More' buttons",
|
||||
groups: [
|
||||
|
||||
367
package-lock.json
generated
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "jellify",
|
||||
"version": "0.10.74",
|
||||
"version": "0.10.80",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "jellify",
|
||||
"version": "0.10.74",
|
||||
"version": "0.10.80",
|
||||
"dependencies": {
|
||||
"@jellyfin/sdk": "^0.11.0",
|
||||
"@react-native-community/blur": "^4.4.1",
|
||||
@@ -22,12 +22,16 @@
|
||||
"@tanstack/react-query": "^5.66.0",
|
||||
"@tanstack/react-query-persist-client": "^5.66.0",
|
||||
"axios": "^1.7.9",
|
||||
"bundle": "^2.1.0",
|
||||
"bundler": "^0.8.0",
|
||||
"burnt": "^0.12.2",
|
||||
"expo": "^52.0.0",
|
||||
"expo-image": "^2.0.7",
|
||||
"gem": "^2.4.3",
|
||||
"invert-color": "^2.0.0",
|
||||
"jest-expo": "^52.0.6",
|
||||
"lodash": "^4.17.21",
|
||||
"npm-bundle": "^3.0.3",
|
||||
"react": "18.3.1",
|
||||
"react-freeze": "^1.0.4",
|
||||
"react-native": "0.77.0",
|
||||
@@ -50,6 +54,7 @@
|
||||
"react-native-url-polyfill": "^2.0.0",
|
||||
"react-native-uuid": "^2.0.3",
|
||||
"react-native-vector-icons": "^10.2.0",
|
||||
"ruby": "^0.6.1",
|
||||
"tamagui": "^1.124.17"
|
||||
},
|
||||
"devDependencies": {
|
||||
@@ -457,13 +462,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/helpers": {
|
||||
"version": "7.25.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.25.7.tgz",
|
||||
"integrity": "sha512-Sv6pASx7Esm38KQpF/U/OXLwPPrdGHNKoeblRxgZRLXnAtnkEe4ptJPDtAZM7fBLadbc1Q07kQpSiGQ0Jg6tRA==",
|
||||
"version": "7.27.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.27.0.tgz",
|
||||
"integrity": "sha512-U5eyP/CTFPuNE3qk+WZMxFkp/4zUzdceQlfzf7DdGdhp+Fezd7HD+i8Y24ZuTMKX3wQBld449jijbGq6OdGNQg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/template": "^7.25.7",
|
||||
"@babel/types": "^7.25.7"
|
||||
"@babel/template": "^7.27.0",
|
||||
"@babel/types": "^7.27.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
@@ -556,12 +561,12 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/parser": {
|
||||
"version": "7.26.8",
|
||||
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.26.8.tgz",
|
||||
"integrity": "sha512-TZIQ25pkSoaKEYYaHbbxkfL36GNsQ6iFiBbeuzAkLnXayKR1yP1zFe+NxuZWWsUyvt8icPU9CCq0sgWGXR1GEw==",
|
||||
"version": "7.27.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.27.0.tgz",
|
||||
"integrity": "sha512-iaepho73/2Pz7w2eMS0Q5f83+0RKI7i4xmiYeBmDzfRVbQtTOG7Ts0S4HzJVsTMGI9keU8rNfuZr8DKfSt7Yyg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/types": "^7.26.8"
|
||||
"@babel/types": "^7.27.0"
|
||||
},
|
||||
"bin": {
|
||||
"parser": "bin/babel-parser.js"
|
||||
@@ -2212,9 +2217,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/runtime": {
|
||||
"version": "7.25.7",
|
||||
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.25.7.tgz",
|
||||
"integrity": "sha512-FjoyLe754PMiYsFaN5C94ttGiOmBNYTf6pLr4xXHAT5uctHb092PBszndLDR5XA/jghQvn4n7JMHl7dmTgbm9w==",
|
||||
"version": "7.27.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.27.0.tgz",
|
||||
"integrity": "sha512-VtPOkrdPHZsKc/clNqyi9WUA8TINkZ4cGk63UUE3u4pmB2k+ZMQRDuIOagv8UVd6j7k0T3+RRIb7beKTebNbcw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"regenerator-runtime": "^0.14.0"
|
||||
@@ -2224,14 +2229,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/template": {
|
||||
"version": "7.26.8",
|
||||
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.26.8.tgz",
|
||||
"integrity": "sha512-iNKaX3ZebKIsCvJ+0jd6embf+Aulaa3vNBqZ41kM7iTWjx5qzWKXGHiJUW3+nTpQ18SG11hdF8OAzKrpXkb96Q==",
|
||||
"version": "7.27.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.27.0.tgz",
|
||||
"integrity": "sha512-2ncevenBqXI6qRMukPlXwHKHchC7RyMuu4xv5JBXRfOGVcTy1mXCD12qrp7Jsoxll1EV3+9sE4GugBVRjT2jFA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/code-frame": "^7.26.2",
|
||||
"@babel/parser": "^7.26.8",
|
||||
"@babel/types": "^7.26.8"
|
||||
"@babel/parser": "^7.27.0",
|
||||
"@babel/types": "^7.27.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=6.9.0"
|
||||
@@ -2275,9 +2280,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@babel/types": {
|
||||
"version": "7.26.8",
|
||||
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.26.8.tgz",
|
||||
"integrity": "sha512-eUuWapzEGWFEpHFxgEaBG8e3n6S8L3MSu0oda755rOfabWPnh0Our1AozNFVUxGFIhbKgd1ksprsoDGMinTOTA==",
|
||||
"version": "7.27.0",
|
||||
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.27.0.tgz",
|
||||
"integrity": "sha512-H45s8fVLYjbhFH62dIJ3WtmJ6RSPt/3DRO0ZcT2SUiYiQyz3BLVb9ADEnLl91m74aQPS3AzzeajZHYOalWe3bg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@babel/helper-string-parser": "^7.25.9",
|
||||
@@ -7350,6 +7355,12 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/q": {
|
||||
"version": "1.5.8",
|
||||
"resolved": "https://registry.npmjs.org/@types/q/-/q-1.5.8.tgz",
|
||||
"integrity": "sha512-hroOstUScF6zhIi+5+x0dzqrHA1EJi+Irri6b1fxolMTqqHIV/Cg77EtnQcZqZCu8hR3mX2BzIxN4/GzI68Kfw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/react": {
|
||||
"version": "18.3.18",
|
||||
"resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.18.tgz",
|
||||
@@ -8161,9 +8172,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/axios": {
|
||||
"version": "1.7.9",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-1.7.9.tgz",
|
||||
"integrity": "sha512-LhLcE7Hbiryz8oMDdDptSrWowmB4Bl6RCt6sIJKpRB4XtVf0iEgewX3au/pJqm+Py1kCASkb/FFKjxQaLtxJvw==",
|
||||
"version": "1.8.4",
|
||||
"resolved": "https://registry.npmjs.org/axios/-/axios-1.8.4.tgz",
|
||||
"integrity": "sha512-eBSYY4Y68NNlHbHBMdeDmKNtDgXWhQsJcGqzO3iLUM0GraQFSS9cVgPX5I9b3lbdFKyYoAEGAZF1DwhTaljNAw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"follow-redirects": "^1.15.6",
|
||||
@@ -8826,6 +8837,26 @@
|
||||
"integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/bundle": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/bundle/-/bundle-2.1.0.tgz",
|
||||
"integrity": "sha512-d7TeT8m2HuymDjSEmMppWe/h5SSPPUZkaWKrAofx6gNXDdZ3FL/81oOTGPG+LIaZbNr9m4rtUi98Yw0Q1vHIIw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/bundler": {
|
||||
"version": "0.8.0",
|
||||
"resolved": "https://registry.npmjs.org/bundler/-/bundler-0.8.0.tgz",
|
||||
"integrity": "sha512-vHl3CsqgXtfJnEe61oOYRoevN0Tl3P/Z6e6Z9Sr3xif8oaV6L4bV7m4cYCiOWT1oPvOyl3j9Lten4/GrIeIupA==",
|
||||
"engines": [
|
||||
"node ~0.4.0"
|
||||
],
|
||||
"dependencies": {
|
||||
"coa": ">= 0.1.1"
|
||||
},
|
||||
"bin": {
|
||||
"bundler": "bin/bundler"
|
||||
}
|
||||
},
|
||||
"node_modules/burnt": {
|
||||
"version": "0.12.2",
|
||||
"resolved": "https://registry.npmjs.org/burnt/-/burnt-0.12.2.tgz",
|
||||
@@ -9168,6 +9199,91 @@
|
||||
"node": ">= 0.12.0"
|
||||
}
|
||||
},
|
||||
"node_modules/coa": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/coa/-/coa-2.0.2.tgz",
|
||||
"integrity": "sha512-q5/jG+YQnSy4nRTV4F7lPepBJZ8qBNJJDBuJdoejDyLXgmL7IEo+Le2JDZudFTFt7mrCqIRaSjws4ygRCTCAXA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/q": "^1.5.1",
|
||||
"chalk": "^2.4.1",
|
||||
"q": "^1.1.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/coa/node_modules/ansi-styles": {
|
||||
"version": "3.2.1",
|
||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
|
||||
"integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"color-convert": "^1.9.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/coa/node_modules/chalk": {
|
||||
"version": "2.4.2",
|
||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
|
||||
"integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"ansi-styles": "^3.2.1",
|
||||
"escape-string-regexp": "^1.0.5",
|
||||
"supports-color": "^5.3.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/coa/node_modules/color-convert": {
|
||||
"version": "1.9.3",
|
||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
|
||||
"integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"color-name": "1.1.3"
|
||||
}
|
||||
},
|
||||
"node_modules/coa/node_modules/color-name": {
|
||||
"version": "1.1.3",
|
||||
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
|
||||
"integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/coa/node_modules/escape-string-regexp": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
|
||||
"integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=0.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/coa/node_modules/has-flag": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
|
||||
"integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/coa/node_modules/supports-color": {
|
||||
"version": "5.5.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
|
||||
"integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"has-flag": "^3.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/collect-v8-coverage": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.2.tgz",
|
||||
@@ -10078,6 +10194,18 @@
|
||||
"integrity": "sha512-HYTX8tKge/VNp6FGO+f/uVDmUkq+cEfcxYhKf15Akc4M5yxt5YmorwlAitKWjWhWQnKcDRBAQKXkhqqXMqcrjw==",
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/emitter-b": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/emitter-b/-/emitter-b-1.0.0.tgz",
|
||||
"integrity": "sha512-Ug5yFHs+cj511x0hsP8TO2nbXiJ+c8Adol9xiob/qXD8ptihxZ1mr1z3D5Cph2TJoQgUNH9fXwrBNhHxL6KJ+w==",
|
||||
"dependencies": {
|
||||
"proto": ">=1.0.17"
|
||||
},
|
||||
"license": {
|
||||
"name": "MIT",
|
||||
"url": "http://www.opensource.org/licenses/mit-license.php"
|
||||
}
|
||||
},
|
||||
"node_modules/emittery": {
|
||||
"version": "0.13.1",
|
||||
"resolved": "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz",
|
||||
@@ -11975,6 +12103,22 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/gem": {
|
||||
"version": "2.4.3",
|
||||
"resolved": "https://registry.npmjs.org/gem/-/gem-2.4.3.tgz",
|
||||
"integrity": "sha512-PkXm35oFCg9/Sb7RvYar3JlYuPBkBBgiH5G3Z97Xy9gIU8Zy5hBA/K9rk3AxeCiQRNm/n4koItA7zb/irbcvlA==",
|
||||
"dependencies": {
|
||||
"emitter-b": "*",
|
||||
"hashmap": "https://github.com/Tixit/hashmap/archive/c666bbe32a8d23bbafc96c5d8f18e385b1b00f27.tar.gz",
|
||||
"observe": "1",
|
||||
"proto": ">=1.0.17",
|
||||
"trimArguments": "https://github.com/fresheneesz/trimArguments/archive/c9c023c9ff1e0aec4b67370a80a92dacadcf8b11.tar.gz"
|
||||
},
|
||||
"license": {
|
||||
"name": "MIT",
|
||||
"url": "http://www.opensource.org/licenses/mit-license.php"
|
||||
}
|
||||
},
|
||||
"node_modules/gensync": {
|
||||
"version": "1.0.0-beta.2",
|
||||
"resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz",
|
||||
@@ -12281,6 +12425,15 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/hashmap": {
|
||||
"version": "2.0.5-minfiedBugFix",
|
||||
"resolved": "https://github.com/Tixit/hashmap/archive/c666bbe32a8d23bbafc96c5d8f18e385b1b00f27.tar.gz",
|
||||
"integrity": "sha512-VYmmBJ/KuQgX7flE0edHE7ke0PXIi/wbpcv+s7mrMkOJSoE/L/BNCWyODSWSznT5spxwInc4iymCa8VGisC3Ew==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/hasown": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
|
||||
@@ -12463,9 +12616,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/image-size": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/image-size/-/image-size-1.2.0.tgz",
|
||||
"integrity": "sha512-4S8fwbO6w3GeCVN6OPtA9I5IGKkcDMPcKndtUlpJuCwu7JLjtj7JZpwqLuyY2nrmQT3AWsCJLSKPsc2mPBSl3w==",
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/image-size/-/image-size-1.2.1.tgz",
|
||||
"integrity": "sha512-rH+46sQJ2dlwfjfhCyNx5thzrv+dtmBIhPHk0zgRUukHzZ/kRueTJXoYYsclBaKcSMBWuGbOFXtioLpzTb5euw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"queue": "6.0.2"
|
||||
@@ -12563,6 +12716,12 @@
|
||||
"integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==",
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/insync": {
|
||||
"version": "2.1.1",
|
||||
"resolved": "https://registry.npmjs.org/insync/-/insync-2.1.1.tgz",
|
||||
"integrity": "sha512-UzUhOZFpCMM22Xlig9iUPqalf8n7c4eYScamce1C+jN3ad8FtmVm42ryMwVq0hAxHbwUhWFhPvTFQQpFdDUKkw==",
|
||||
"license": "BSD-3-Clause"
|
||||
},
|
||||
"node_modules/internal-ip": {
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/internal-ip/-/internal-ip-4.3.0.tgz",
|
||||
@@ -15482,6 +15641,15 @@
|
||||
"integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/ncp": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/ncp/-/ncp-2.0.0.tgz",
|
||||
"integrity": "sha512-zIdGUrPRFTUELUvr3Gmc7KZ2Sw/h1PiVM0Af/oHB6zgnV1ikqSfRk+TOufi79aHYCW3NiOXmr1BP5nWbzojLaA==",
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"ncp": "bin/ncp"
|
||||
}
|
||||
},
|
||||
"node_modules/negotiator": {
|
||||
"version": "0.6.3",
|
||||
"resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz",
|
||||
@@ -15615,6 +15783,107 @@
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/npm-bundle": {
|
||||
"version": "3.0.3",
|
||||
"resolved": "https://registry.npmjs.org/npm-bundle/-/npm-bundle-3.0.3.tgz",
|
||||
"integrity": "sha512-fHF7FR32YNgjqi0MQMLnE78Ff9/wYd4/7/Cke3dLLi2QzETKotIiWGCxwDoXAZDWVoTuVRYQa2ZdiZPuBL7QnA==",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"glob": "^6.0.1",
|
||||
"insync": "^2.1.1",
|
||||
"mkdirp": "^0.5.1",
|
||||
"ncp": "^2.0.0",
|
||||
"rimraf": "^2.4.4"
|
||||
},
|
||||
"bin": {
|
||||
"npm-bundle": "bin/cli.js"
|
||||
}
|
||||
},
|
||||
"node_modules/npm-bundle/node_modules/brace-expansion": {
|
||||
"version": "1.1.11",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
|
||||
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"balanced-match": "^1.0.0",
|
||||
"concat-map": "0.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/npm-bundle/node_modules/glob": {
|
||||
"version": "6.0.4",
|
||||
"resolved": "https://registry.npmjs.org/glob/-/glob-6.0.4.tgz",
|
||||
"integrity": "sha512-MKZeRNyYZAVVVG1oZeLaWie1uweH40m9AZwIwxyPbTSX4hHrVYSzLg0Ro5Z5R7XKkIX+Cc6oD1rqeDJnwsB8/A==",
|
||||
"deprecated": "Glob versions prior to v9 are no longer supported",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"inflight": "^1.0.4",
|
||||
"inherits": "2",
|
||||
"minimatch": "2 || 3",
|
||||
"once": "^1.3.0",
|
||||
"path-is-absolute": "^1.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/npm-bundle/node_modules/minimatch": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
|
||||
"integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"brace-expansion": "^1.1.7"
|
||||
},
|
||||
"engines": {
|
||||
"node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/npm-bundle/node_modules/mkdirp": {
|
||||
"version": "0.5.6",
|
||||
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz",
|
||||
"integrity": "sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"minimist": "^1.2.6"
|
||||
},
|
||||
"bin": {
|
||||
"mkdirp": "bin/cmd.js"
|
||||
}
|
||||
},
|
||||
"node_modules/npm-bundle/node_modules/rimraf": {
|
||||
"version": "2.7.1",
|
||||
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz",
|
||||
"integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==",
|
||||
"deprecated": "Rimraf versions prior to v4 are no longer supported",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"glob": "^7.1.3"
|
||||
},
|
||||
"bin": {
|
||||
"rimraf": "bin.js"
|
||||
}
|
||||
},
|
||||
"node_modules/npm-bundle/node_modules/rimraf/node_modules/glob": {
|
||||
"version": "7.2.3",
|
||||
"resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
|
||||
"integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
|
||||
"deprecated": "Glob versions prior to v9 are no longer supported",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"fs.realpath": "^1.0.0",
|
||||
"inflight": "^1.0.4",
|
||||
"inherits": "2",
|
||||
"minimatch": "^3.1.1",
|
||||
"once": "^1.3.0",
|
||||
"path-is-absolute": "^1.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": "*"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/isaacs"
|
||||
}
|
||||
},
|
||||
"node_modules/npm-package-arg": {
|
||||
"version": "11.0.3",
|
||||
"resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-11.0.3.tgz",
|
||||
@@ -15781,6 +16050,18 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/observe": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/observe/-/observe-1.4.1.tgz",
|
||||
"integrity": "sha512-xq1XHEwjJm5Vqpvpy0/RknqF+rDsg8o6CApoWxfGizHEjFCruOU4HnScM2wQesoug4hMg07nLinTCBaZK6aAPA==",
|
||||
"dependencies": {
|
||||
"proto": "*"
|
||||
},
|
||||
"license": {
|
||||
"name": "MIT",
|
||||
"url": "http://www.opensource.org/licenses/mit-license.php"
|
||||
}
|
||||
},
|
||||
"node_modules/on-finished": {
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz",
|
||||
@@ -16450,6 +16731,11 @@
|
||||
"react-is": "^16.13.1"
|
||||
}
|
||||
},
|
||||
"node_modules/proto": {
|
||||
"version": "1.0.19",
|
||||
"resolved": "https://registry.npmjs.org/proto/-/proto-1.0.19.tgz",
|
||||
"integrity": "sha512-NNRn4T3FAcMbiRZAr6HlAP3PyqSv79bcYdfiZbY1nognRTVeGAd5Ncg4yHZdM2ey9ovP/sOg/0lfalvaj3ZpHA=="
|
||||
},
|
||||
"node_modules/proxy-from-env": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz",
|
||||
@@ -16504,6 +16790,17 @@
|
||||
],
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/q": {
|
||||
"version": "1.5.1",
|
||||
"resolved": "https://registry.npmjs.org/q/-/q-1.5.1.tgz",
|
||||
"integrity": "sha512-kV/CThkXo6xyFEZUugw/+pIOywXcDbFYgSct5cT3gqlbkBE1SJdwy6UQoZvodiWF/ckQLZyDE/Bu1M6gVu5lVw==",
|
||||
"deprecated": "You or someone you depend on is using Q, the JavaScript Promise library that gave JavaScript developers strong feelings about promises. They can almost certainly migrate to the native JavaScript promise now. Thank you literally everyone for joining me in this bet against the odds. Be excellent to each other.\n\n(For a CapTP with native promises, see @endo/eventual-send and @endo/captp)",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=0.6.0",
|
||||
"teleport": ">=0.2.0"
|
||||
}
|
||||
},
|
||||
"node_modules/qrcode-terminal": {
|
||||
"version": "0.11.0",
|
||||
"resolved": "https://registry.npmjs.org/qrcode-terminal/-/qrcode-terminal-0.11.0.tgz",
|
||||
@@ -17489,6 +17786,15 @@
|
||||
"url": "https://github.com/sponsors/isaacs"
|
||||
}
|
||||
},
|
||||
"node_modules/ruby": {
|
||||
"version": "0.6.1",
|
||||
"resolved": "https://registry.npmjs.org/ruby/-/ruby-0.6.1.tgz",
|
||||
"integrity": "sha512-TjMB+HyxathhcgvtQ3jkYWWjW3t9q+3VPLe0jpsm1x8tryXJ3626rO6gQ+0S12Oyac+Glp6KDuy1JBdKND+eSQ==",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"lodash": "^4.13.0"
|
||||
}
|
||||
},
|
||||
"node_modules/run-parallel": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
|
||||
@@ -18897,6 +19203,11 @@
|
||||
"integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/trimArguments": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://github.com/fresheneesz/trimArguments/archive/c9c023c9ff1e0aec4b67370a80a92dacadcf8b11.tar.gz",
|
||||
"integrity": "sha512-SC6VIl5Lbma02frRD70cQg/IFW2czQrTiyhUqzCWUWxm80VxCR9i9HD0GkSe8gaGUlyc7YVhdMa6wccli1j/TA=="
|
||||
},
|
||||
"node_modules/ts-api-utils": {
|
||||
"version": "1.3.0",
|
||||
"resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "jellify",
|
||||
"version": "0.10.74",
|
||||
"version": "0.10.80",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"init": "npm i && npm run pod:install",
|
||||
@@ -32,12 +32,16 @@
|
||||
"@tanstack/react-query": "^5.66.0",
|
||||
"@tanstack/react-query-persist-client": "^5.66.0",
|
||||
"axios": "^1.7.9",
|
||||
"bundle": "^2.1.0",
|
||||
"bundler": "^0.8.0",
|
||||
"burnt": "^0.12.2",
|
||||
"expo": "^52.0.0",
|
||||
"expo-image": "^2.0.7",
|
||||
"gem": "^2.4.3",
|
||||
"invert-color": "^2.0.0",
|
||||
"jest-expo": "^52.0.6",
|
||||
"lodash": "^4.17.21",
|
||||
"npm-bundle": "^3.0.3",
|
||||
"react": "18.3.1",
|
||||
"react-freeze": "^1.0.4",
|
||||
"react-native": "0.77.0",
|
||||
@@ -60,6 +64,7 @@
|
||||
"react-native-url-polyfill": "^2.0.0",
|
||||
"react-native-uuid": "^2.0.3",
|
||||
"react-native-vector-icons": "^10.2.0",
|
||||
"ruby": "^0.6.1",
|
||||
"tamagui": "^1.124.17"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
||||