Compare commits
6 Commits
918d651638
...
dev
Author | SHA1 | Date | |
---|---|---|---|
123933d459 | |||
f0a722b3fb | |||
dca3987e18 | |||
8f67d0421b | |||
3616592896 | |||
e9c04a7b39 |
@ -1,7 +1,8 @@
|
||||
export default {
|
||||
getDb: jest.fn(() => {
|
||||
return {
|
||||
runAsync: jest.fn((statement: string, value: string) => {}),
|
||||
runAsync: jest.fn((statement: string, ... values: string []) => {}),
|
||||
runSync: jest.fn((statement: string, ... values : string []) => {}),
|
||||
getFirstAsync: jest.fn((statement: string, value: string) => {
|
||||
return [];
|
||||
}),
|
||||
|
@ -3,5 +3,5 @@
|
||||
|
||||
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
|
||||
|
||||
<application android:usesCleartextTraffic="true" tools:targetApi="28" tools:ignore="GoogleAppIndexingWarning" tools:replace="android:usesCleartextTraffic" />
|
||||
<application android:largeHeap="true" android:usesCleartextTraffic="true" tools:targetApi="28" tools:ignore="GoogleAppIndexingWarning" tools:replace="android:usesCleartextTraffic" />
|
||||
</manifest>
|
||||
|
@ -1,7 +1,9 @@
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<uses-permission android:name="android.permission.INTERNET"/>
|
||||
<uses-permission android:name="android.permission.MODIFY_AUDIO_SETTINGS"/>
|
||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
|
||||
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
|
||||
<uses-permission android:name="android.permission.RECORD_AUDIO"/>
|
||||
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
|
||||
<uses-permission android:name="android.permission.VIBRATE"/>
|
||||
<uses-permission android:name="android.permission.WAKE_LOCK"/>
|
||||
@ -13,7 +15,7 @@
|
||||
<data android:scheme="https"/>
|
||||
</intent>
|
||||
</queries>
|
||||
<application android:name=".MainApplication" android:label="@string/app_name" android:icon="@mipmap/ic_launcher" android:roundIcon="@mipmap/ic_launcher_round" android:allowBackup="true" android:theme="@style/AppTheme" android:supportsRtl="true">
|
||||
<application android:name=".MainApplication" android:label="@string/app_name" android:icon="@mipmap/ic_launcher" android:roundIcon="@mipmap/ic_launcher_round" android:allowBackup="true" android:theme="@style/AppTheme" android:supportsRtl="true" android:largeHeap="true">
|
||||
<meta-data android:name="expo.modules.updates.ENABLED" android:value="false"/>
|
||||
<meta-data android:name="expo.modules.updates.EXPO_UPDATES_CHECK_ON_LAUNCH" android:value="ALWAYS"/>
|
||||
<meta-data android:name="expo.modules.updates.EXPO_UPDATES_LAUNCH_WAIT_MS" android:value="0"/>
|
||||
|
3
app.json
3
app.json
@ -57,7 +57,8 @@
|
||||
]
|
||||
}
|
||||
}
|
||||
]
|
||||
],
|
||||
"expo-audio"
|
||||
],
|
||||
"experiments": {
|
||||
"typedRoutes": true
|
||||
|
116
app/i18n/api.ts
116
app/i18n/api.ts
@ -1,6 +1,6 @@
|
||||
import { Cache } from "react-native-cache";
|
||||
import { LIBRETRANSLATE_BASE_URL } from "@/constants/api";
|
||||
import AsyncStorage from '@react-native-async-storage/async-storage';
|
||||
import AsyncStorage from "@react-native-async-storage/async-storage";
|
||||
import { Settings } from "../lib/settings";
|
||||
|
||||
type language_t = string;
|
||||
@ -9,74 +9,91 @@ const cache = new Cache({
|
||||
namespace: "translation_terrace",
|
||||
policy: {
|
||||
maxEntries: 50000, // if unspecified, it can have unlimited entries
|
||||
stdTTL: 0 // the standard ttl as number in seconds, default: 0 (unlimited)
|
||||
stdTTL: 0, // the standard ttl as number in seconds, default: 0 (unlimited)
|
||||
},
|
||||
backend: AsyncStorage
|
||||
backend: AsyncStorage,
|
||||
});
|
||||
|
||||
export type language_matrix_entry = {
|
||||
code: string,
|
||||
name: string,
|
||||
targets: string []
|
||||
}
|
||||
code: string;
|
||||
name: string;
|
||||
targets: string[];
|
||||
};
|
||||
|
||||
export type language_matrix = {
|
||||
[key:string] : language_matrix_entry
|
||||
}
|
||||
[key: string]: language_matrix_entry;
|
||||
};
|
||||
|
||||
export async function fetchWithTimeout(url : string, options : RequestInit, timeout = 5000) : Promise<Response> {
|
||||
export async function fetchWithTimeout(
|
||||
url: string,
|
||||
options: RequestInit,
|
||||
timeout = 5000
|
||||
): Promise<Response> {
|
||||
return Promise.race([
|
||||
fetch(url, options),
|
||||
new Promise((_, reject) => setTimeout(() => reject(new Error('timeout')), timeout))
|
||||
new Promise((_, reject) =>
|
||||
setTimeout(() => reject(new Error("timeout")), timeout)
|
||||
),
|
||||
]);
|
||||
}
|
||||
|
||||
export class LanguageServer {
|
||||
constructor(public baseUrl : string) {}
|
||||
constructor(public baseUrl: string) {}
|
||||
|
||||
async fetchLanguages(timeout = 500) : Promise<language_matrix> {
|
||||
async fetchLanguages(timeout = 500): Promise<language_matrix> {
|
||||
let data = {};
|
||||
const res = await fetchWithTimeout(this.baseUrl + "/languages", {
|
||||
const res = await fetchWithTimeout(
|
||||
this.baseUrl + "/languages",
|
||||
{
|
||||
headers: {
|
||||
"Content-Type": "application/json"
|
||||
}
|
||||
}, timeout);
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
},
|
||||
timeout
|
||||
);
|
||||
try {
|
||||
data = await res.json();
|
||||
} catch (e) {
|
||||
throw new Error(`Parsing data from ${await res.text()}: ${e}`)
|
||||
throw new Error(`Parsing data from ${await res.text()}: ${e}`);
|
||||
}
|
||||
try {
|
||||
return Object.fromEntries(
|
||||
Object.values(data as language_matrix_entry []).map((obj : language_matrix_entry) => {
|
||||
return [
|
||||
obj["code"],
|
||||
obj,
|
||||
]
|
||||
})
|
||||
Object.values(data as language_matrix_entry[]).map(
|
||||
(obj: language_matrix_entry) => {
|
||||
return [obj["code"], obj];
|
||||
}
|
||||
)
|
||||
} catch(e) {
|
||||
throw new Error(`Can't extract values from data: ${JSON.stringify(data)}`)
|
||||
);
|
||||
} catch (e) {
|
||||
throw new Error(
|
||||
`Can't extract values from data: ${JSON.stringify(data)}`
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
static async getDefault() {
|
||||
const settings = await Settings.getDefault();
|
||||
return new LanguageServer(await settings.getLibretranslateBaseUrl() || LIBRETRANSLATE_BASE_URL);
|
||||
return new LanguageServer(
|
||||
(await settings.getLibretranslateBaseUrl()) || LIBRETRANSLATE_BASE_URL
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export class Translator {
|
||||
constructor(public source : language_t, public defaultTarget : string = "en", private _languageServer : LanguageServer) {
|
||||
}
|
||||
constructor(
|
||||
public source: language_t,
|
||||
public defaultTarget: string = "en",
|
||||
private _languageServer: LanguageServer
|
||||
) {}
|
||||
|
||||
get languageServer() {
|
||||
return this._languageServer;
|
||||
}
|
||||
|
||||
async translate(text : string, target : string|undefined = undefined) {
|
||||
async translate(text: string, target: string | undefined = undefined) {
|
||||
const url = this._languageServer.baseUrl + `/translate`;
|
||||
const res = await fetch(url, {
|
||||
console.log(url);
|
||||
const postData = {
|
||||
method: "POST",
|
||||
body: JSON.stringify({
|
||||
q: text,
|
||||
@ -84,40 +101,55 @@ export class Translator {
|
||||
target: target || this.defaultTarget,
|
||||
format: "text",
|
||||
alternatives: 3,
|
||||
api_key: ""
|
||||
api_key: "",
|
||||
}),
|
||||
headers: { "Content-Type": "application/json" }
|
||||
});
|
||||
headers: { "Content-Type": "application/json" },
|
||||
};
|
||||
|
||||
console.debug("Requesting %s with %o", url, postData);
|
||||
|
||||
const res = await fetch(url, postData);
|
||||
|
||||
const data = await res.json();
|
||||
console.log(data)
|
||||
return data.translatedText
|
||||
if (res.status === 200) {
|
||||
console.log(data);
|
||||
return data.translatedText;
|
||||
} else {
|
||||
console.error(data);
|
||||
}
|
||||
}
|
||||
|
||||
static async getDefault(defaultTarget: string | undefined = undefined) {
|
||||
const settings = await Settings.getDefault();
|
||||
const source = await settings.getHostLanguage();
|
||||
return new Translator(source, defaultTarget, await LanguageServer.getDefault())
|
||||
return new Translator(
|
||||
source,
|
||||
defaultTarget,
|
||||
await LanguageServer.getDefault()
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
export class CachedTranslator extends Translator {
|
||||
async translate (text : string, target : string|undefined = undefined) {
|
||||
async translate(text: string, target: string | undefined = undefined) {
|
||||
const targetKey = target || this.defaultTarget;
|
||||
// console.debug(`Translating from ${this.source} -> ${targetKey}`)
|
||||
const key1 = `${this.source}::${targetKey}::${text}`
|
||||
const key1 = `${this.source}::${targetKey}::${text}`;
|
||||
const tr1 = await cache.get(key1);
|
||||
if (tr1) return tr1;
|
||||
const tr2 = await super.translate(text, target);
|
||||
const key2 = `${this.source}::${targetKey}::${text}`
|
||||
const key2 = `${this.source}::${targetKey}::${text}`;
|
||||
await cache.set(key2, tr2);
|
||||
return tr2;
|
||||
}
|
||||
|
||||
static async getDefault(defaultTarget: string | undefined = undefined) {
|
||||
const settings = await Settings.getDefault();
|
||||
const source = await settings.getHostLanguage();
|
||||
return new CachedTranslator(source, defaultTarget, await LanguageServer.getDefault())
|
||||
const source = await settings.getHostLanguage() || "en";
|
||||
return new CachedTranslator(
|
||||
source,
|
||||
defaultTarget,
|
||||
await LanguageServer.getDefault()
|
||||
);
|
||||
}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
import _countries from "@/assets/countries.min.json";
|
||||
import LANG_FLAGS from "@/langs-flags-list/lang-flags.json"
|
||||
import LANG_FLAGS from "./lang-flags.json"
|
||||
import { language_matrix_entry } from "./api";
|
||||
import { lang_a2_a3 } from "./lang";
|
||||
|
||||
|
72
app/i18n/lang-flags.json
Normal file
72
app/i18n/lang-flags.json
Normal file
@ -0,0 +1,72 @@
|
||||
{
|
||||
"af": ["za"],
|
||||
"am": ["et"],
|
||||
"ar": ["eg", "sa", "ae"],
|
||||
"az": ["az"],
|
||||
"be": ["by"],
|
||||
"bg": ["bg"],
|
||||
"bn": ["bd", "in"],
|
||||
"bs": ["ba"],
|
||||
"ca": ["es"],
|
||||
"cs": ["cz"],
|
||||
"cy": ["gb"],
|
||||
"da": ["dk"],
|
||||
"de": ["de", "at", "ch"],
|
||||
"el": ["gr"],
|
||||
"en": ["us", "gb", "au"],
|
||||
"es": ["es", "mx", "ar"],
|
||||
"et": ["ee"],
|
||||
"fa": ["ir"],
|
||||
"fi": ["fi"],
|
||||
"fr": ["fr", "ca", "be"],
|
||||
"ga": ["ie"],
|
||||
"gl": ["es"],
|
||||
"gu": ["in"],
|
||||
"he": ["il"],
|
||||
"hi": ["in"],
|
||||
"hr": ["hr"],
|
||||
"ht": ["ht"],
|
||||
"hu": ["hu"],
|
||||
"hy": ["am"],
|
||||
"id": ["id"],
|
||||
"is": ["is"],
|
||||
"it": ["it", "ch", "sm"],
|
||||
"ja": ["jp"],
|
||||
"ka": ["ge"],
|
||||
"kn": ["in"],
|
||||
"ko": ["kr"],
|
||||
"ku": ["tr"],
|
||||
"lv": ["lv"],
|
||||
"mk": ["mk"],
|
||||
"ml": ["in"],
|
||||
"mn": ["mn"],
|
||||
"mr": ["in"],
|
||||
"ms": ["my"],
|
||||
"mt": ["mt"],
|
||||
"nb": ["no"],
|
||||
"ne": ["np"],
|
||||
"nl": ["nl", "be"],
|
||||
"or": ["in"],
|
||||
"pa": ["in", "pk"],
|
||||
"pl": ["pl"],
|
||||
"pt": ["pt", "br"],
|
||||
"ro": ["ro"],
|
||||
"ru": ["ru", "ua", "by"],
|
||||
"si": ["lk"],
|
||||
"sk": ["sk"],
|
||||
"sl": ["si"],
|
||||
"sq": ["al"],
|
||||
"sr": ["rs"],
|
||||
"sv": ["se", "no", "fi"],
|
||||
"sw": ["tz"],
|
||||
"ta": ["in", "lk", "sg"],
|
||||
"te": ["in"],
|
||||
"th": ["th"],
|
||||
"tr": ["tr"],
|
||||
"uk": ["ua"],
|
||||
"ur": ["pk"],
|
||||
"uz": ["uz"],
|
||||
"vi": ["vn"],
|
||||
"zh": ["cn", "tw", "hk"]
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
import _LANG_FLAGS from "@/langs-flags-list/lang-flags.json"
|
||||
import _LANG_FLAGS from "./lang-flags.json"
|
||||
import _LANGUAGES from "@/assets/languages.min.json"
|
||||
|
||||
export const LANG_FLAGS = _LANG_FLAGS
|
||||
|
@ -1,18 +1,19 @@
|
||||
import { Settings } from '@/app/lib/settings';
|
||||
import { getDb } from '@/app/lib/db';
|
||||
import { Knex } from 'knex';
|
||||
import { getDb, migrateDb } from '@/app/lib/db';
|
||||
import { SQLiteDatabase } from 'expo-sqlite';
|
||||
|
||||
describe('Settings', () => {
|
||||
let settings : Settings;
|
||||
let db : Knex;
|
||||
let settings: Settings;
|
||||
let db: SQLiteDatabase;
|
||||
|
||||
beforeEach(async () => {
|
||||
db = await getDb("development");
|
||||
settings = new Settings(db)
|
||||
await migrateDb("development");
|
||||
settings = new Settings(db);
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
await db.migrate.down();
|
||||
await migrateDb("development", "down");
|
||||
});
|
||||
|
||||
it('should set the host language in the database', async () => {
|
||||
|
@ -1,101 +1,170 @@
|
||||
// components/ui/__tests__/WhisperFile.spec.tsx
|
||||
// app/lib/__tests__/whisper.spec.tsx
|
||||
|
||||
import React from "react";
|
||||
import { render, act } from "@testing-library/react-native";
|
||||
import { WhisperFile } from "@/app/lib/whisper"; // Adjust the import path as necessary
|
||||
import { getDb } from "@/app/lib/db";
|
||||
import { WhisperFile, WhisperModelTag } from "@/app/lib/whisper"; // Corrected to use WhisperFile and WhisperModelTag instead of WhisperDownloader
|
||||
import { Settings } from "@/app/lib/settings";
|
||||
import { File } from "expo-file-system/next";
|
||||
jest.mock('expo-file-system');
|
||||
import * as FileSystem from 'expo-file-system';
|
||||
|
||||
jest.mock("@/app/lib/db", () => ({
|
||||
getDb: jest.fn().mockResolvedValue({
|
||||
runAsync: jest.fn(),
|
||||
upsert: jest.fn(), // Mock the upsert method used in addToDatabase
|
||||
}),
|
||||
}));
|
||||
|
||||
jest.mock("@/app/lib/settings", () => ({
|
||||
Settings: {
|
||||
getDefault: jest.fn(() => ({
|
||||
getValue: jest.fn((key) => {
|
||||
switch (key) {
|
||||
case "whisper_model":
|
||||
return "base";
|
||||
default:
|
||||
throw new Error(`Invalid setting: '${key}'`);
|
||||
}
|
||||
}),
|
||||
})),
|
||||
},
|
||||
}));
|
||||
|
||||
|
||||
jest.mock("expo-file-system/next", () => {
|
||||
const _next = jest.requireActual("expo-file-system/next");
|
||||
return {
|
||||
..._next,
|
||||
File: jest.fn().mockImplementation(() => ({
|
||||
..._next.File,
|
||||
text: jest.fn(() => {
|
||||
return new String("text");
|
||||
}),
|
||||
})),
|
||||
};
|
||||
});
|
||||
|
||||
describe("WhisperFile", () => {
|
||||
// Corrected to use WhisperFile instead of WhisperDownloader
|
||||
let whisperFile: WhisperFile;
|
||||
|
||||
beforeEach(() => {
|
||||
beforeEach(async () => {
|
||||
whisperFile = new WhisperFile("small");
|
||||
});
|
||||
|
||||
it("should initialize correctly", () => {
|
||||
expect(whisperFile).toBeInstanceOf(WhisperFile);
|
||||
});
|
||||
|
||||
describe("getModelFileSize", () => {
|
||||
it("should return the correct model file size", async () => {
|
||||
expect(whisperFile.size).toBeUndefined();
|
||||
await whisperFile.updateMetadata();
|
||||
expect(whisperFile.size).toBeGreaterThan(1000);
|
||||
});
|
||||
});
|
||||
|
||||
describe("getWhisperDownloadStatus", () => {
|
||||
it("should return the correct download status", async () => {
|
||||
const mockStatus = {
|
||||
doesTargetExist: true,
|
||||
isDownloadComplete: false,
|
||||
hasDownloadStarted: true,
|
||||
progress: {
|
||||
current: 100,
|
||||
total: 200,
|
||||
remaining: 100,
|
||||
percentRemaining: 50.0,
|
||||
},
|
||||
};
|
||||
jest
|
||||
.spyOn(whisperFile, "getDownloadStatus")
|
||||
.mockResolvedValue(mockStatus);
|
||||
|
||||
const result = await whisperFile.getDownloadStatus();
|
||||
|
||||
expect(result).toEqual(mockStatus);
|
||||
});
|
||||
});
|
||||
|
||||
describe("initiateWhisperDownload", () => {
|
||||
it("should initiate the download with default options", async () => {
|
||||
const mockModelLabel = "small";
|
||||
jest
|
||||
.spyOn(whisperFile, "createDownloadResumable")
|
||||
.mockResolvedValue(true);
|
||||
|
||||
await whisperFile.initiateWhisperDownload(mockModelLabel);
|
||||
|
||||
expect(whisperFile.createDownloadResumable).toHaveBeenCalledWith(
|
||||
mockModelLabel
|
||||
);
|
||||
});
|
||||
|
||||
it("should initiate the download with custom options", async () => {
|
||||
const mockModelLabel = "small";
|
||||
const mockOptions = { force_redownload: true };
|
||||
jest
|
||||
.spyOn(whisperFile, "createDownloadResumable")
|
||||
.mockResolvedValue(true);
|
||||
|
||||
await whisperFile.initiateWhisperDownload(mockModelLabel, mockOptions);
|
||||
|
||||
expect(whisperFile.createDownloadResumable).toHaveBeenCalledWith(
|
||||
mockModelLabel,
|
||||
mockOptions
|
||||
);
|
||||
});
|
||||
|
||||
it("should return the correct download status when target exists and is complete", async () => {
|
||||
it("should create a download resumable with existing data if available", async () => {
|
||||
const mockExistingData = "mockExistingData";
|
||||
jest.spyOn(whisperFile, "doesTargetExist").mockResolvedValue(true);
|
||||
jest.spyOn(whisperFile, "isDownloadComplete").mockResolvedValue(true);
|
||||
|
||||
expect(await whisperFile.doesTargetExist()).toEqual(true);
|
||||
expect(await whisperFile.isDownloadComplete()).toEqual(true);
|
||||
await whisperFile.createDownloadResumable();
|
||||
// expect(whisperFile.targetFileName).toEqual("small.bin");
|
||||
expect(whisperFile.targetPath).toContain("small.bin");
|
||||
|
||||
expect(FileSystem.createDownloadResumable).toHaveBeenCalledWith(
|
||||
"https://huggingface.co/openai/whisper-small/resolve/main/pytorch_model.bin",
|
||||
"file:///whisper/small.bin",
|
||||
{},
|
||||
expect.any(Function),
|
||||
expect.anything(),
|
||||
);
|
||||
});
|
||||
|
||||
it("should return the correct download status when target does not exist", async () => {
|
||||
jest.spyOn(whisperFile, "doesTargetExist").mockResolvedValue(false);
|
||||
// it("should create a download resumable without existing data if not available", async () => {
|
||||
// jest.spyOn(whisperFile, "doesTargetExist").mockResolvedValue(false);
|
||||
|
||||
const result = await whisperFile.getDownloadStatus();
|
||||
// await whisperFile.createDownloadResumable(); // Updated to use createDownloadResumable instead of download
|
||||
|
||||
expect(result).toEqual({
|
||||
doesTargetExist: false,
|
||||
isDownloadComplete: false,
|
||||
hasDownloadStarted: false,
|
||||
progress: undefined,
|
||||
});
|
||||
});
|
||||
});
|
||||
// expect(FileSystem.createDownloadResumable).toHaveBeenCalledWith(
|
||||
// "http://mock.model.com/model",
|
||||
// "mockTargetPath",
|
||||
// {},
|
||||
// expect.any(Function),
|
||||
// undefined
|
||||
// );
|
||||
// });
|
||||
|
||||
// Add more tests as needed for other methods in WhisperFile
|
||||
// it("should update the download status in the database", async () => {
|
||||
// const mockRunAsync = jest.fn();
|
||||
// (getDb as jest.Mock).mockResolvedValue({ runAsync: mockRunAsync });
|
||||
|
||||
// const downloadable = await whisperFile.createDownloadResumable(); // Updated to use createDownloadResumable instead of download
|
||||
// await downloadable.resumeAsync();
|
||||
|
||||
// jest.advanceTimersByTime(1000);
|
||||
|
||||
// expect(mockRunAsync).toHaveBeenCalled();
|
||||
// });
|
||||
|
||||
// it("should record the latest target hash after downloading", async () => {
|
||||
// const mockRecordLatestTargetHash = jest.spyOn(
|
||||
// whisperFile,
|
||||
// "recordLatestTargetHash"
|
||||
// );
|
||||
|
||||
// await whisperFile.createDownloadResumable(); // Updated to use createDownloadResumable instead of download
|
||||
|
||||
// expect(mockRecordLatestTargetHash).toHaveBeenCalled();
|
||||
// });
|
||||
|
||||
// it("should call the onData callback if provided", async () => {
|
||||
// const mockOnData = jest.fn();
|
||||
// const options = { onData: mockOnData };
|
||||
|
||||
// await whisperFile.createDownloadResumable(options); // Updated to use createDownloadResumable instead of download
|
||||
|
||||
// expect(mockOnData).toHaveBeenCalledWith(expect.any(Object));
|
||||
// });
|
||||
|
||||
// describe("getDownloadStatus", () => {
|
||||
// it("should return the correct download status when model size is known and download has started", async () => {
|
||||
// whisperFile.size = 1024;
|
||||
// jest.spyOn(whisperFile, "doesTargetExist").mockResolvedValue(true);
|
||||
// jest.spyOn(whisperFile, "isDownloadComplete").mockResolvedValue(false);
|
||||
// jest.spyOn(whisperFile, "targetFile").mockReturnValue({
|
||||
// size: 512,
|
||||
// });
|
||||
|
||||
// const status = await whisperFile.getDownloadStatus();
|
||||
|
||||
// expect(status).toEqual({
|
||||
// doesTargetExist: true,
|
||||
// isDownloadComplete: false,
|
||||
// hasDownloadStarted: true,
|
||||
// progress: {
|
||||
// current: 512,
|
||||
// total: 1024,
|
||||
// remaining: 512,
|
||||
// percentRemaining: 50.0,
|
||||
// },
|
||||
// });
|
||||
// });
|
||||
|
||||
// it("should return the correct download status when model size is known and download is complete", async () => {
|
||||
// whisperFile.size = 1024;
|
||||
// jest.spyOn(whisperFile, "doesTargetExist").mockResolvedValue(true);
|
||||
// jest.spyOn(whisperFile, "isDownloadComplete").mockResolvedValue(true);
|
||||
|
||||
// const status = await whisperFile.getDownloadStatus();
|
||||
|
||||
// expect(status).toEqual({
|
||||
// doesTargetExist: true,
|
||||
// isDownloadComplete: true,
|
||||
// hasDownloadStarted: false,
|
||||
// progress: undefined,
|
||||
// });
|
||||
// });
|
||||
|
||||
// it("should return the correct download status when model size is unknown", async () => {
|
||||
// jest.spyOn(whisperFile, "doesTargetExist").mockResolvedValue(false);
|
||||
|
||||
// const status = await whisperFile.getDownloadStatus();
|
||||
|
||||
// expect(status).toEqual({
|
||||
// doesTargetExist: false,
|
||||
// isDownloadComplete: false,
|
||||
// hasDownloadStarted: false,
|
||||
// progress: undefined,
|
||||
// });
|
||||
// });
|
||||
// });
|
||||
});
|
||||
|
@ -1,11 +1,28 @@
|
||||
import config from "@/knexfile";
|
||||
import Knex from "knex";
|
||||
import * as SQLite from "expo-sqlite";
|
||||
import { MIGRATE_UP, MIGRATE_DOWN } from "./migrations";
|
||||
|
||||
export async function getDb(
|
||||
environment: "development" | "staging" | "production" = "production",
|
||||
automigrate = true
|
||||
) {
|
||||
const k = Knex(config[environment]);
|
||||
if (automigrate) await k.migrate.up();
|
||||
return k;
|
||||
export type db_mode = "development" | "staging" | "production";
|
||||
|
||||
export async function getDb(mode : db_mode = "production") {
|
||||
return await SQLite.openDatabaseAsync(`translation_terrace_${mode}`);
|
||||
}
|
||||
|
||||
|
||||
export async function migrateDb(mode : db_mode = "production", direction: "up" | "down" = "up") {
|
||||
|
||||
const db = await getDb(mode);
|
||||
|
||||
const m = direction === "up" ? MIGRATE_UP : MIGRATE_DOWN;
|
||||
|
||||
for (let [migration, statements] of Object.entries(m)) {
|
||||
for (let statement of statements) {
|
||||
console.log(statement);
|
||||
try {
|
||||
const result = await db.runAsync(statement);
|
||||
console.log(result);
|
||||
} catch (err) {
|
||||
console.error(err);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
24
app/lib/migrations.ts
Normal file
24
app/lib/migrations.ts
Normal file
@ -0,0 +1,24 @@
|
||||
|
||||
export const MIGRATE_UP = {
|
||||
1: [
|
||||
`CREATE TABLE IF NOT EXISTS settings (
|
||||
key TEXT PRIMARY KEY,
|
||||
value TEXT
|
||||
)`,
|
||||
],
|
||||
2: [
|
||||
`CREATE TABLE IF NOT EXISTS whisper_models (
|
||||
model TEXT PRIMARY KEY,
|
||||
download_status STRING(255),
|
||||
expected_size INTEGER,
|
||||
last_hash STRING(1024),
|
||||
bytes_done INTEGER,
|
||||
bytes_total INTEGER
|
||||
)`,
|
||||
],
|
||||
};
|
||||
|
||||
export const MIGRATE_DOWN = {
|
||||
1: [`DROP TABLE IF EXISTS settings`],
|
||||
2: [`DROP TABLE IF EXISTS whisper_models`],
|
||||
};
|
61
app/lib/readstream.ts
Normal file
61
app/lib/readstream.ts
Normal file
@ -0,0 +1,61 @@
|
||||
/* eslint-disable unicorn/no-null */
|
||||
import * as fs from 'expo-file-system';
|
||||
import { Readable } from 'readable-stream';
|
||||
|
||||
class ExpoReadStream extends Readable {
|
||||
private readonly fileUri: string;
|
||||
private fileSize: number;
|
||||
private currentPosition: number;
|
||||
private readonly chunkSize: number;
|
||||
|
||||
constructor(fileUri: string, options: fs.ReadingOptions) {
|
||||
super();
|
||||
this.fileUri = fileUri;
|
||||
this.fileSize = 0; // Initialize file size (could be fetched if necessary)
|
||||
this.currentPosition = options.position ?? 0;
|
||||
/**
|
||||
* Default chunk size in bytes. React Native Expo will OOM at 110MB, so we set this to 1/100 of it to balance speed and memory usage and importantly the feedback for user.
|
||||
* If this is too large, the progress bar will be stuck when down stream processing this chunk.
|
||||
*/
|
||||
this.chunkSize = options.length ?? 1024 * 1024;
|
||||
void this._init();
|
||||
}
|
||||
|
||||
async _init() {
|
||||
try {
|
||||
const fileInfo = await fs.getInfoAsync(this.fileUri, { size: true });
|
||||
if (fileInfo.exists) {
|
||||
this.fileSize = fileInfo.size ?? 0;
|
||||
} else {
|
||||
this.fileSize = 0;
|
||||
}
|
||||
} catch (error) {
|
||||
this.emit('error', error);
|
||||
}
|
||||
}
|
||||
|
||||
_read() {
|
||||
const readingOptions = {
|
||||
encoding: fs.EncodingType.Base64,
|
||||
position: this.currentPosition,
|
||||
length: this.chunkSize,
|
||||
} satisfies fs.ReadingOptions;
|
||||
fs.readAsStringAsync(this.fileUri, readingOptions).then(chunk => {
|
||||
if (chunk.length === 0) {
|
||||
// End of the stream
|
||||
this.emit('progress', 1);
|
||||
this.push(null);
|
||||
} else {
|
||||
this.currentPosition = Math.min(this.chunkSize + this.currentPosition, this.fileSize);
|
||||
this.emit('progress', this.fileSize === 0 ? 0.5 : (this.currentPosition / this.fileSize));
|
||||
this.push(Buffer.from(chunk, 'base64'));
|
||||
}
|
||||
}).catch(error => {
|
||||
this.emit('error', error);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export function createReadStream(fileUri: string, options: { encoding?: fs.EncodingType; end?: number; highWaterMark?: number; start?: number } = {}): ExpoReadStream {
|
||||
return new ExpoReadStream(fileUri, options);
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
import { SQLiteDatabase } from "expo-sqlite";
|
||||
import { getDb } from "./db";
|
||||
import { Knex } from "knex";
|
||||
import { WhisperFile, whisper_model_tag_t } from "./whisper";
|
||||
|
||||
export class Settings {
|
||||
|
||||
@ -10,7 +11,7 @@ export class Settings {
|
||||
"whisper_model",
|
||||
]
|
||||
|
||||
constructor(public db: Knex) {
|
||||
constructor(public db: SQLiteDatabase) {
|
||||
|
||||
}
|
||||
|
||||
@ -20,9 +21,9 @@ export class Settings {
|
||||
throw new Error(`Invalid setting: '${key}'`)
|
||||
}
|
||||
|
||||
const row = await this.db("settings").select(key).limit(1).first();
|
||||
if (!(row && row[key])) return undefined;
|
||||
return row[key];
|
||||
const row: { value: string } | null = this.db.getFirstSync(`SELECT value FROM settings WHERE key = ?`, key)
|
||||
|
||||
return row?.value;
|
||||
}
|
||||
|
||||
|
||||
@ -32,17 +33,11 @@ export class Settings {
|
||||
}
|
||||
|
||||
// Check if the key already exists
|
||||
const [exists] = await this.db("settings").select(1).whereNotNull(key).limit(1);
|
||||
|
||||
if (exists) {
|
||||
// Update the existing column
|
||||
await this.db("settings").update({ [key]: value });
|
||||
} else {
|
||||
// Insert a new value into the specified column
|
||||
const insertData: { [key: string]: any } = {};
|
||||
insertData[key] = value;
|
||||
await this.db("settings").insert(insertData);
|
||||
}
|
||||
this.db.runSync(`INSERT OR REPLACE INTO
|
||||
settings
|
||||
(key, value)
|
||||
VALUES
|
||||
(?, ?)`, key, value);
|
||||
}
|
||||
|
||||
async setHostLanguage(value: string) {
|
||||
@ -53,7 +48,7 @@ export class Settings {
|
||||
return await this.getValue("host_language")
|
||||
}
|
||||
|
||||
async setLibretranslateBaseUrl(value : string) {
|
||||
async setLibretranslateBaseUrl(value: string) {
|
||||
await this.setValue("libretranslate_base_url", value)
|
||||
}
|
||||
|
||||
@ -61,16 +56,15 @@ export class Settings {
|
||||
return await this.getValue("libretranslate_base_url")
|
||||
}
|
||||
|
||||
async setWhisperModel(value : string) {
|
||||
async setWhisperModel(value: string) {
|
||||
await this.setValue("whisper_model", value);
|
||||
}
|
||||
|
||||
async getWhisperModel() {
|
||||
return await this.getValue("whisper_model");
|
||||
return await this.getValue("whisper_model") as whisper_model_tag_t;
|
||||
}
|
||||
|
||||
static async getDefault() {
|
||||
return new Settings(await getDb())
|
||||
}
|
||||
|
||||
}
|
9
app/lib/util.ts
Normal file
9
app/lib/util.ts
Normal file
@ -0,0 +1,9 @@
|
||||
import { TextDecoder } from "util";
|
||||
|
||||
export function arrbufToStr(arrayBuffer : ArrayBuffer) {
|
||||
return new TextDecoder().decode(new Uint8Array(arrayBuffer));
|
||||
}
|
||||
|
||||
export function strToArrBuf(input : string) : Uint8Array<ArrayBufferLike> {
|
||||
return new TextEncoder().encode(input)
|
||||
}
|
@ -3,6 +3,8 @@ import * as FileSystem from "expo-file-system";
|
||||
import { File, Paths } from "expo-file-system/next";
|
||||
import { getDb } from "./db";
|
||||
import * as Crypto from "expo-crypto";
|
||||
import { arrbufToStr, strToArrBuf } from "./util";
|
||||
import { createReadStream } from "./readstream";
|
||||
|
||||
export const WHISPER_MODEL_PATH = Paths.join(
|
||||
FileSystem.documentDirectory || "file:///",
|
||||
@ -75,7 +77,7 @@ export const WHISPER_MODELS = {
|
||||
size: 6173629930,
|
||||
},
|
||||
} as {
|
||||
[key:whisper_model_tag_t]: {
|
||||
[key: whisper_model_tag_t]: {
|
||||
source: string;
|
||||
target: string;
|
||||
label: string;
|
||||
@ -114,6 +116,13 @@ export type download_status_t = {
|
||||
};
|
||||
|
||||
export class WhisperFile {
|
||||
hf_metadata: hf_metadata_t | undefined;
|
||||
|
||||
target_hash: string | undefined;
|
||||
does_target_exist: boolean = false;
|
||||
does_part_target_exist: boolean = false;
|
||||
download_data: FileSystem.DownloadProgressData | undefined;
|
||||
|
||||
constructor(
|
||||
public tag: whisper_model_tag_t,
|
||||
private targetFileName?: string,
|
||||
@ -122,11 +131,15 @@ export class WhisperFile {
|
||||
) {
|
||||
this.targetFileName = this.targetFileName || `${tag}.bin`;
|
||||
this.label =
|
||||
this.label || `${tag[0].toUpperCase}${tag.substring(1).toLowerCase()}`;
|
||||
this.label || `${tag[0].toUpperCase()}${tag.substring(1).toLowerCase()}`;
|
||||
}
|
||||
|
||||
get targetPath() {
|
||||
return Paths.join(WHISPER_MODEL_DIR, this.targetFileName as string);
|
||||
return Paths.join(WHISPER_MODEL_PATH, this.targetFileName as string);
|
||||
}
|
||||
|
||||
get targetPartPath () {
|
||||
return this.targetPath + ".part";
|
||||
}
|
||||
|
||||
get targetFile() {
|
||||
@ -137,78 +150,44 @@ export class WhisperFile {
|
||||
return await FileSystem.getInfoAsync(this.targetPath);
|
||||
}
|
||||
|
||||
async doesTargetExist() {
|
||||
return (await this.getTargetInfo()).exists;
|
||||
async getTargetPartInfo() {
|
||||
return await FileSystem.getInfoAsync(this.targetPartPath);
|
||||
}
|
||||
|
||||
public async recordLatestTargetHash() {
|
||||
if (!(await this.doesTargetExist())) {
|
||||
console.debug("%s does not exist", this.targetPath);
|
||||
}
|
||||
const digest1Str = await this.getActualTargetHash();
|
||||
if (!digest1Str) {
|
||||
return;
|
||||
}
|
||||
const db = await getDb();
|
||||
await db("whisper_models")
|
||||
.upsert({
|
||||
model: this.tag,
|
||||
last_hash: digest1Str,
|
||||
})
|
||||
.where({ model: this.tag });
|
||||
async updateTargetExistence() {
|
||||
this.does_target_exist = (await this.getTargetInfo()).exists;
|
||||
this.does_part_target_exist = (await this.getTargetPartInfo()).exists;
|
||||
}
|
||||
|
||||
public async getRecordedTargetHash(): Promise<string> {
|
||||
const db = await getDb();
|
||||
const row = await db("whisper_models").select("last_hash").where({
|
||||
model: this.tag,
|
||||
}).first();
|
||||
return row["last_hash"]
|
||||
}
|
||||
|
||||
public async getActualTargetHash(): Promise<string | undefined> {
|
||||
if (!(await this.doesTargetExist())) {
|
||||
public async getTargetSha() {
|
||||
await this.updateTargetExistence();
|
||||
if (!this.does_target_exist) {
|
||||
console.debug("%s does not exist", this.targetPath);
|
||||
return undefined;
|
||||
}
|
||||
const digest1 = await Crypto.digest(
|
||||
Crypto.CryptoDigestAlgorithm.SHA256,
|
||||
this.targetFile.bytes()
|
||||
);
|
||||
const digest1Str = new TextDecoder().decode(new Uint8Array(digest1));
|
||||
return digest1Str;
|
||||
}
|
||||
|
||||
async isTargetCorrupted() {
|
||||
const recordedTargetHash = await this.getRecordedTargetHash();
|
||||
const actualTargetHash = await this.getActualTargetHash();
|
||||
if (!(actualTargetHash || recordedTargetHash)) return false;
|
||||
return actualTargetHash !== recordedTargetHash;
|
||||
}
|
||||
const strData = await FileSystem.readAsStringAsync(this.targetPath, {
|
||||
encoding: FileSystem.EncodingType.Base64,
|
||||
});
|
||||
const data = strToArrBuf(strData);
|
||||
|
||||
async isDownloadComplete() {
|
||||
if (!(await this.doesTargetExist())) {
|
||||
console.debug("%s does not exist", this.targetPath);
|
||||
return false;
|
||||
}
|
||||
const data = this.targetFile.bytes();
|
||||
const meta = await this.fetchMetadata();
|
||||
const expectedHash = meta.oid;
|
||||
const digest1: ArrayBuffer = await Crypto.digest(
|
||||
|
||||
const digest = await Crypto.digest(
|
||||
Crypto.CryptoDigestAlgorithm.SHA256,
|
||||
data
|
||||
);
|
||||
const digest1Str = new TextDecoder().decode(new Uint8Array(digest1));
|
||||
const doesMatch = digest1Str === expectedHash;
|
||||
if (!doesMatch) {
|
||||
console.debug(
|
||||
"sha256 of '%s' does not match expected '%s'",
|
||||
digest1Str,
|
||||
expectedHash
|
||||
);
|
||||
return false;
|
||||
|
||||
return digest;
|
||||
}
|
||||
return true;
|
||||
|
||||
public async updateTargetHash() {
|
||||
const targetSha = await this.getTargetSha();
|
||||
if (!targetSha) return;
|
||||
this.target_hash = arrbufToStr(targetSha);
|
||||
}
|
||||
|
||||
get isHashValid() {
|
||||
return this.target_hash === this.hf_metadata?.oid;
|
||||
}
|
||||
|
||||
delete(ignoreErrors = true) {
|
||||
@ -231,7 +210,21 @@ export class WhisperFile {
|
||||
return create_hf_url(this.tag, "raw");
|
||||
}
|
||||
|
||||
private async fetchMetadata(): Promise<hf_metadata_t> {
|
||||
get percentDone() {
|
||||
if (!this.download_data) return 0;
|
||||
return (
|
||||
(this.download_data.totalBytesWritten /
|
||||
this.download_data.totalBytesExpectedToWrite) *
|
||||
100
|
||||
);
|
||||
}
|
||||
|
||||
get percentLeft() {
|
||||
if (!this.download_data) return 0;
|
||||
return 100 - this.percentDone;
|
||||
}
|
||||
|
||||
public async syncHfMetadata() {
|
||||
try {
|
||||
const resp = await fetch(this.metadataUrl, {
|
||||
credentials: "include",
|
||||
@ -253,7 +246,7 @@ export class WhisperFile {
|
||||
mode: "cors",
|
||||
});
|
||||
const text = await resp.text();
|
||||
return Object.fromEntries(
|
||||
this.hf_metadata = Object.fromEntries(
|
||||
text.split("\n").map((line) => line.split(" "))
|
||||
) as hf_metadata_t;
|
||||
} catch (err) {
|
||||
@ -262,87 +255,94 @@ export class WhisperFile {
|
||||
}
|
||||
}
|
||||
|
||||
async updateMetadata() {
|
||||
const metadata = await this.fetchMetadata();
|
||||
this.size = Number.parseInt(metadata.size);
|
||||
}
|
||||
|
||||
async addToDatabase() {
|
||||
const db = await getDb();
|
||||
await db("whisper_models").upsert({
|
||||
model: this.tag,
|
||||
expected_size: this.size,
|
||||
}).where({
|
||||
model: this.tag,
|
||||
});
|
||||
}
|
||||
|
||||
async createDownloadResumable(
|
||||
options: {
|
||||
onData?: DownloadCallback | undefined;
|
||||
onComplete?: CompletionCallback | undefined;
|
||||
} = {
|
||||
onData: undefined,
|
||||
onComplete: undefined,
|
||||
}
|
||||
) {
|
||||
const existingData = (await this.doesTargetExist())
|
||||
? this.targetFile.text()
|
||||
: undefined;
|
||||
await this.syncHfMetadata();
|
||||
|
||||
if (await this.doesTargetExist()) {
|
||||
// If the whisper model dir doesn't exist, create it.
|
||||
if (!WHISPER_MODEL_DIR.exists) {
|
||||
FileSystem.makeDirectoryAsync(WHISPER_MODEL_PATH, {
|
||||
intermediates: true,
|
||||
});
|
||||
}
|
||||
|
||||
// Check for the existence of the target file
|
||||
// If it exists, load the existing data.
|
||||
await this.updateTargetExistence();
|
||||
|
||||
if (this.does_part_target_exist) {
|
||||
options.onComplete && options.onComplete(this)
|
||||
}
|
||||
|
||||
try {
|
||||
const existingData = this.does_target_exist
|
||||
? await FileSystem.readAsStringAsync(this.targetPath, {
|
||||
encoding: FileSystem.EncodingType.Base64,
|
||||
})
|
||||
: undefined;
|
||||
|
||||
// Create the resumable.
|
||||
return FileSystem.createDownloadResumable(
|
||||
this.modelUrl,
|
||||
this.targetPath,
|
||||
{},
|
||||
async (data: FileSystem.DownloadProgressData) => {
|
||||
const db = await getDb();
|
||||
await db.upsert({
|
||||
model: this.tag,
|
||||
download_status: "active",
|
||||
})
|
||||
await this.recordLatestTargetHash();
|
||||
if (options.onData) await options.onData(data);
|
||||
// console.debug("yes, I'm still downloading");
|
||||
try {
|
||||
this.download_data = data;
|
||||
} catch (err) {
|
||||
console.error("Failed to set downloadData: %s", err);
|
||||
}
|
||||
|
||||
try {
|
||||
await this.syncHfMetadata();
|
||||
} catch (err) {
|
||||
console.error("Failed to update HuggingFace metadata: %s", err)
|
||||
}
|
||||
|
||||
// try {
|
||||
// await this.updateTargetHash();
|
||||
// } catch (er) {
|
||||
// console.error("Failed to update target hash: %s", er);
|
||||
// }
|
||||
|
||||
try {
|
||||
await this.updateTargetExistence();
|
||||
} catch (err) {
|
||||
console.error("Failed to update target existence: %s", err)
|
||||
}
|
||||
if (options.onData) await options.onData(this);
|
||||
|
||||
if (data.totalBytesExpectedToWrite === 0) {
|
||||
console.debug("Finalizing; copying from %s -> %s", this.targetPartPath, this.targetPath);
|
||||
await FileSystem.copyAsync({
|
||||
from: this.targetPartPath,
|
||||
to: this.targetPath,
|
||||
});
|
||||
await this.updateTargetExistence();
|
||||
options.onComplete && options.onComplete(this);
|
||||
}
|
||||
},
|
||||
existingData ? existingData : undefined
|
||||
);
|
||||
} catch (err) {
|
||||
console.error("Could not read %s: %s", this.targetPath, err);
|
||||
}
|
||||
|
||||
async getDownloadStatus() : Promise<download_status_t> {
|
||||
const doesTargetExist = await this.doesTargetExist();
|
||||
const isDownloadComplete = await this.isDownloadComplete();
|
||||
const hasDownloadStarted = doesTargetExist && !isDownloadComplete;
|
||||
|
||||
if (!this.size) {
|
||||
return {
|
||||
doesTargetExist: false,
|
||||
isDownloadComplete: false,
|
||||
hasDownloadStarted: false,
|
||||
progress: undefined,
|
||||
}
|
||||
}
|
||||
|
||||
const remaining = hasDownloadStarted
|
||||
? this.size - (this.targetFile.size as number)
|
||||
: 0;
|
||||
|
||||
const progress = hasDownloadStarted
|
||||
? {
|
||||
current: this.targetFile.size || 0,
|
||||
total: this.size,
|
||||
remaining: this.size - (this.targetFile.size as number),
|
||||
percentRemaining: (remaining / this.size) * 100.0,
|
||||
}
|
||||
: undefined;
|
||||
|
||||
return {
|
||||
doesTargetExist,
|
||||
isDownloadComplete,
|
||||
hasDownloadStarted,
|
||||
progress,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export type DownloadCallback = (arg0: WhisperFile) => any;
|
||||
export type CompletionCallback = (arg0: WhisperFile) => any;
|
||||
|
||||
export type DownloadCallback = (arg0: FileSystem.DownloadProgressData) => any;
|
||||
export const WHISPER_FILES = {
|
||||
small: new WhisperFile("small"),
|
||||
medium: new WhisperFile("medium"),
|
||||
large: new WhisperFile("large"),
|
||||
};
|
||||
|
@ -1,9 +1,14 @@
|
||||
import React, { useState, useEffect } from "react";
|
||||
import { ScrollView, StyleSheet, Text, TouchableHighlight, View } from "react-native";
|
||||
import { Alert, ScrollView, StyleSheet, Text, TouchableHighlight, View } from "react-native";
|
||||
import { useNavigation, Route } from "@react-navigation/native";
|
||||
import { Conversation, Message } from "@/app/lib/conversation";
|
||||
import MessageBubble from "@/components/ui/MessageBubble";
|
||||
import { CachedTranslator, LanguageServer, language_matrix_entry } from "@/app/i18n/api";
|
||||
import { Settings } from "@/app/lib/settings";
|
||||
import { WHISPER_FILES } from "@/app/lib/whisper";
|
||||
import { initWhisper, WhisperContext } from 'whisper.rn'
|
||||
import { useAudioRecorder, AudioModule, RecordingPresets } from 'expo-audio';
|
||||
|
||||
|
||||
const lasOptions = {
|
||||
sampleRate: 32000, // default is 44100 but 32000 is adequate for accurate voice recognition
|
||||
@ -14,7 +19,7 @@ const lasOptions = {
|
||||
};
|
||||
// LiveAudioStream.init(lasOptions as any);
|
||||
|
||||
const ConversationThread = ({ route } : {route?: Route<"Conversation", {conversation : Conversation}>}) => {
|
||||
const ConversationThread = ({ route }: { route?: Route<"Conversation", { conversation: Conversation }> }) => {
|
||||
const navigation = useNavigation();
|
||||
|
||||
if (!route) {
|
||||
@ -27,6 +32,7 @@ const ConversationThread = ({ route } : {route?: Route<"Conversation", {conversa
|
||||
const [messages, setMessages] = useState<Message[]>([]);
|
||||
const [guestSpeak, setGuestSpeak] = useState<string | undefined>();
|
||||
const [guestSpeakLoaded, setGuestSpeakLoaded] = useState<boolean>(false);
|
||||
const [whisperContext, setWhisperContext] = useState<WhisperContext | undefined>();
|
||||
const [cachedTranslator, setCachedTranslator] = useState<
|
||||
undefined | CachedTranslator
|
||||
>();
|
||||
@ -42,17 +48,50 @@ const ConversationThread = ({ route } : {route?: Route<"Conversation", {conversa
|
||||
}
|
||||
}>()
|
||||
|
||||
// recorder settings
|
||||
const audioRecorder = useAudioRecorder(RecordingPresets.HIGH_QUALITY);
|
||||
|
||||
const record = async () => {
|
||||
await audioRecorder.prepareToRecordAsync();
|
||||
audioRecorder.record();
|
||||
};
|
||||
|
||||
const stopRecording = async () => {
|
||||
// The recording will be available on `audioRecorder.uri`.
|
||||
await audioRecorder.stop();
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
(async () => {
|
||||
(async function () {
|
||||
|
||||
const languageServer = await LanguageServer.getDefault();
|
||||
const languages = await languageServer.fetchLanguages();
|
||||
try {
|
||||
const languages = await languageServer.fetchLanguages(5000);
|
||||
const cc = new CachedTranslator(
|
||||
"en",
|
||||
conversation.guest.language,
|
||||
languageServer,
|
||||
)
|
||||
console.log("Set cached translator from %s", languageServer.baseUrl)
|
||||
setCachedTranslator(cc);
|
||||
} catch (err) {
|
||||
console.error("Could not set translator from %s: %s", languageServer.baseUrl, err)
|
||||
}
|
||||
|
||||
const settings = await Settings.getDefault();
|
||||
const whisperFile = WHISPER_FILES[await settings.getWhisperModel() || "en"];
|
||||
setWhisperContext(await initWhisper({
|
||||
filePath: whisperFile.targetPath,
|
||||
}));
|
||||
|
||||
// recorder settings
|
||||
|
||||
(async () => {
|
||||
const status = await AudioModule.requestRecordingPermissionsAsync();
|
||||
if (!status.granted) {
|
||||
Alert.alert('Permission to access microphone was denied');
|
||||
}
|
||||
})();
|
||||
setGuestSpeak(await cc.translate("Speak"));
|
||||
const hostLang1 = languages[conversation.host.language].name;
|
||||
const guestLang1 = languages[conversation.host.language].name;
|
||||
@ -74,13 +113,17 @@ const ConversationThread = ({ route } : {route?: Route<"Conversation", {conversa
|
||||
setMessages([...c]);
|
||||
};
|
||||
|
||||
conversation.onAddMessage = updateMessages;
|
||||
conversation.onTranslationDone = updateMessages;
|
||||
if (!conversation) {
|
||||
console.warn("Conversation is null or undefined.")
|
||||
}
|
||||
|
||||
return () => {
|
||||
conversation.onAddMessage = undefined;
|
||||
conversation.onTranslationDone = undefined;
|
||||
};
|
||||
conversation.on("add_message", updateMessages);
|
||||
conversation.on("translation_done", updateMessages);
|
||||
|
||||
// return () => {
|
||||
// conversation.on("add_message", undefined);
|
||||
// conversation.on("translation_done", undefined);
|
||||
// };
|
||||
}, [conversation, guestSpeak]);
|
||||
|
||||
const renderMessages = () =>
|
||||
@ -91,8 +134,8 @@ const ConversationThread = ({ route } : {route?: Route<"Conversation", {conversa
|
||||
return cachedTranslator ? (
|
||||
<View style={{ flex: 1, flexDirection: "column" }}>
|
||||
{languageLabels && (<View style={styles.languageLabels}>
|
||||
<Text style={styles.nativeHostLabel}>{ languageLabels.hostNative.host } / { languageLabels.hostNative.guest }</Text>
|
||||
<Text style={styles.nativeGuestLabel}>{ languageLabels.guestNative.host } / { languageLabels.guestNative.guest }</Text>
|
||||
<Text style={styles.nativeHostLabel}>{languageLabels.hostNative.host} / {languageLabels.hostNative.guest}</Text>
|
||||
<Text style={styles.nativeGuestLabel}>{languageLabels.guestNative.host} / {languageLabels.guestNative.guest}</Text>
|
||||
</View>)
|
||||
}
|
||||
<ScrollView
|
||||
|
@ -8,6 +8,7 @@ import { SafeAreaProvider, SafeAreaView } from "react-native-safe-area-context";
|
||||
import { Conversation, Speaker } from "@/app/lib/conversation";
|
||||
import { NavigationProp, ParamListBase } from "@react-navigation/native";
|
||||
import { Link, useNavigation } from "expo-router";
|
||||
import { migrateDb } from "@/app/lib/db";
|
||||
|
||||
|
||||
export function LanguageSelection(props: {
|
||||
@ -17,7 +18,7 @@ export function LanguageSelection(props: {
|
||||
}) {
|
||||
const [languages, setLanguages] = useState<language_matrix | undefined>();
|
||||
const [languagesLoaded, setLanguagesLoaded] = useState<boolean>(false);
|
||||
const [translator, setTranslator] = useState<Translator|undefined>();
|
||||
const [translator, setTranslator] = useState<Translator | undefined>();
|
||||
|
||||
const nav = useNavigation();
|
||||
|
||||
@ -30,6 +31,7 @@ export function LanguageSelection(props: {
|
||||
|
||||
useEffect(() => {
|
||||
(async () => {
|
||||
await migrateDb();
|
||||
try {
|
||||
// Replace with your actual async data fetching logic
|
||||
setTranslator(await CachedTranslator.getDefault());
|
||||
@ -49,8 +51,8 @@ export function LanguageSelection(props: {
|
||||
<Text>Settings</Text>
|
||||
</Pressable>
|
||||
<ScrollView >
|
||||
<SafeAreaProvider >
|
||||
<SafeAreaView>
|
||||
<SafeAreaProvider>
|
||||
<SafeAreaView style={styles.table}>
|
||||
{(languages && languagesLoaded) ? Object.entries(languages).filter((l) => (LANG_FLAGS as any)[l[0]] !== undefined).map(
|
||||
([lang, lang_entry]) => {
|
||||
return (
|
||||
@ -66,11 +68,15 @@ export function LanguageSelection(props: {
|
||||
)
|
||||
}
|
||||
|
||||
const DEBUG_BORDER = {
|
||||
borderWidth: 3,
|
||||
borderStyle: "dotted",
|
||||
borderColor: "blue",
|
||||
}
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
column: {
|
||||
flex: 1,
|
||||
flexDirection: 'row',
|
||||
flexWrap: 'wrap',
|
||||
padding: 8,
|
||||
table: {
|
||||
flexDirection: "row",
|
||||
flexWrap: "wrap",
|
||||
},
|
||||
})
|
@ -1,6 +1,7 @@
|
||||
import React, { useState, useEffect } from "react";
|
||||
import { View, Text, TextInput, Pressable, StyleSheet } from "react-native";
|
||||
import {
|
||||
WHISPER_FILES,
|
||||
WhisperFile,
|
||||
download_status_t,
|
||||
whisper_tag_t,
|
||||
@ -34,31 +35,37 @@ const SettingsComponent = () => {
|
||||
} | null>(null);
|
||||
const [whisperModel, setWhisperModel] =
|
||||
useState<keyof typeof WHISPER_MODELS>("small");
|
||||
const [downloader, setDownloader] = useState<any>(null);
|
||||
const [whisperFile, setWhisperFile] = useState<WhisperFile | undefined>();
|
||||
const [downloadStatus, setDownloadStatus] = useState<
|
||||
undefined | download_status_t
|
||||
>();
|
||||
const [whisperFileExists, setWhisperFileExists] = useState<boolean>(false);
|
||||
const [isWhisperHashValid, setIsWhisperHashValid] = useState<boolean>(false);
|
||||
const [downloader, setDownloader] = useState<any>(null);
|
||||
const [bytesDone, setBytesDone] = useState<number | undefined>();
|
||||
const [bytesRemaining, setBytesRemaining] = useState<number | undefined>();
|
||||
const [statusTimeout, setStatusTimeout] = useState<
|
||||
NodeJS.Timeout | undefined
|
||||
>();
|
||||
|
||||
useEffect(() => {
|
||||
loadSettings();
|
||||
}, []);
|
||||
|
||||
const getLanguageOptions = async () => {
|
||||
const languageServer = await LanguageServer.getDefault();
|
||||
setLanguageOptions(await languageServer.fetchLanguages());
|
||||
};
|
||||
|
||||
const loadSettings = async () => {
|
||||
(async function () {
|
||||
const settings = await Settings.getDefault();
|
||||
setHostLanguage((await settings.getHostLanguage()) || "en");
|
||||
setLibretranslateBaseUrl(
|
||||
(await settings.getLibretranslateBaseUrl()) || LIBRETRANSLATE_BASE_URL
|
||||
);
|
||||
setWhisperModel(await settings.getWhisperModel());
|
||||
setWhisperModel((await settings.getWhisperModel()) || "small");
|
||||
setWhisperFile(WHISPER_FILES[whisperModel]);
|
||||
if (whisperFile) {
|
||||
await whisperFile.syncHfMetadata();
|
||||
await whisperFile.updateTargetExistence();
|
||||
await whisperFile.updateTargetHash();
|
||||
setWhisperFileExists(whisperFile.does_target_exist)
|
||||
}
|
||||
})();
|
||||
}, [whisperFile]);
|
||||
|
||||
const getLanguageOptions = async () => {
|
||||
const languageServer = await LanguageServer.getDefault();
|
||||
setLanguageOptions(await languageServer.fetchLanguages());
|
||||
};
|
||||
|
||||
const handleHostLanguageChange = async (lang: string) => {
|
||||
@ -83,34 +90,47 @@ const SettingsComponent = () => {
|
||||
}
|
||||
};
|
||||
|
||||
const intervalUpdateDownloadStatus = async () => {
|
||||
if (!whisperFile) return;
|
||||
const status = await whisperFile.getDownloadStatus();
|
||||
setDownloadStatus(status);
|
||||
};
|
||||
|
||||
const handleWhisperModelChange = async (model: whisper_tag_t) => {
|
||||
const settings = await Settings.getDefault();
|
||||
await settings.setWhisperModel(model);
|
||||
setWhisperModel(model);
|
||||
setWhisperFile(new WhisperFile(model));
|
||||
const wFile = WHISPER_FILES[whisperModel];
|
||||
await wFile.syncHfMetadata();
|
||||
await wFile.updateTargetExistence();
|
||||
// await wFile.updateTargetHash();
|
||||
// setIsWhisperHashValid(wFile.isHashValid);
|
||||
setWhisperFile(wFile);
|
||||
setWhisperFileExists(wFile.does_target_exist);
|
||||
};
|
||||
|
||||
const doSetDownloadStatus = (arg0: WhisperFile) => {
|
||||
console.log("Downloading ....")
|
||||
setIsWhisperHashValid(arg0.isHashValid);
|
||||
setBytesDone(arg0.download_data?.totalBytesWritten);
|
||||
setBytesRemaining(arg0.download_data?.totalBytesExpectedToWrite);
|
||||
};
|
||||
|
||||
const doOnComplete = (arg0: WhisperFile) => {
|
||||
setWhisperFile(arg0);
|
||||
}
|
||||
|
||||
const doDownload = async () => {
|
||||
if (!whisperModel) {
|
||||
throw new Error("Could not start download because whisperModel not set.");
|
||||
}
|
||||
|
||||
console.log("Starging download of %s", whisperModel)
|
||||
console.log("Starting download of %s", whisperModel);
|
||||
|
||||
const whisperFile = new WhisperFile(whisperModel);
|
||||
if (!whisperFile) throw new Error("No whisper file");
|
||||
|
||||
const resumable = await whisperFile.createDownloadResumable();
|
||||
setDownloader(resumable);
|
||||
try {
|
||||
await resumable.downloadAsync();
|
||||
const statusTimeout = setInterval(intervalUpdateDownloadStatus, 200);
|
||||
setStatusTimeout(statusTimeout);
|
||||
const resumable = await whisperFile.createDownloadResumable({
|
||||
onData: doSetDownloadStatus,
|
||||
onComplete: doOnComplete,
|
||||
});
|
||||
setDownloader(resumable);
|
||||
if (!resumable) throw new Error("Could not construct resumable");
|
||||
await resumable.resumeAsync();
|
||||
} catch (error) {
|
||||
console.error("Failed to download whisper model:", error);
|
||||
}
|
||||
@ -173,29 +193,34 @@ const SettingsComponent = () => {
|
||||
/>
|
||||
))}
|
||||
</Picker>
|
||||
<View>
|
||||
{whisperModel &&
|
||||
(downloadStatus?.isDownloadComplete ? (
|
||||
downloadStatus?.doesTargetExist ? (
|
||||
<Pressable onPress={doDelete}>
|
||||
<Text>DELETE {whisperModel.toUpperCase()}</Text>
|
||||
<View style={styles.downloadButtonWrapper}>
|
||||
{((!downloader) && whisperFile) &&
|
||||
(whisperFile.does_target_exist && (<Pressable onPress={doDelete} style={styles.deleteButton}>
|
||||
<Text style={styles.buttonText}>DELETE {whisperModel.toUpperCase()}</Text>
|
||||
</Pressable>))
|
||||
}
|
||||
<Pressable onPress={doDownload} style={styles.downloadButton}>
|
||||
<Text style={styles.buttonText}>DOWNLOAD {whisperModel.toUpperCase()}</Text>
|
||||
</Pressable>
|
||||
) : (
|
||||
<Pressable onPress={doStopDownload}>
|
||||
<Text>PAUSE</Text>
|
||||
))
|
||||
|
||||
{
|
||||
downloader && (
|
||||
<Pressable onPress={doStopDownload} style={styles.pauseDownloadButton}>
|
||||
<Text style={styles.buttonText}>STOP DOWNLOAD</Text>
|
||||
</Pressable>
|
||||
)
|
||||
) : (
|
||||
<Pressable onPress={doDownload}>
|
||||
<Text>DOWNLOAD {whisperModel.toUpperCase()}</Text>
|
||||
</Pressable>
|
||||
))}
|
||||
{downloadStatus?.progress && (
|
||||
}
|
||||
{bytesDone && bytesRemaining && whisperFile?.does_part_target_exist && (
|
||||
<View>
|
||||
{whisperFile &&
|
||||
(<Text>
|
||||
Downloading to {whisperFile.targetPath}
|
||||
</Text>)}
|
||||
<Text>
|
||||
{downloadStatus.progress.current} of{" "}
|
||||
{downloadStatus.progress.total} (
|
||||
{downloadStatus.progress.percentRemaining} %){" "}
|
||||
{bytesDone} of{" "}
|
||||
{bytesRemaining} (
|
||||
{bytesDone / bytesRemaining * 100} %){" "}
|
||||
</Text>
|
||||
</View>
|
||||
)}
|
||||
|
@ -1,5 +1,5 @@
|
||||
jest.mock("@/app/i18n/api", () => require("../../__mocks__/api.ts"));
|
||||
import { renderRouter} from 'expo-router/testing-library';
|
||||
import { renderRouter } from "expo-router/testing-library";
|
||||
import React from "react";
|
||||
import {
|
||||
act,
|
||||
@ -13,14 +13,21 @@ import {
|
||||
createNavigationContainerRef,
|
||||
} from "@react-navigation/native";
|
||||
import TTNavStack from "../TTNavStack";
|
||||
import { migrateDb } from "@/app/lib/db";
|
||||
|
||||
describe("Navigation", () => {
|
||||
beforeEach(() => {
|
||||
beforeEach(async () => {
|
||||
await migrateDb("development", "up");
|
||||
// Reset the navigation state before each test
|
||||
jest.clearAllMocks();
|
||||
jest.useFakeTimers();
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
await migrateDb("development", "down");
|
||||
jest.clearAllMocks();
|
||||
jest.useRealTimers();
|
||||
});
|
||||
|
||||
it("Navigates to ConversationThread on language selection", async () => {
|
||||
const MockComponent = jest.fn(() => <TTNavStack />);
|
||||
renderRouter(
|
||||
@ -28,7 +35,7 @@ describe("Navigation", () => {
|
||||
index: MockComponent,
|
||||
},
|
||||
{
|
||||
initialUrl: '/',
|
||||
initialUrl: "/",
|
||||
}
|
||||
);
|
||||
const languageSelectionText = await waitFor(() =>
|
||||
@ -47,14 +54,16 @@ describe("Navigation", () => {
|
||||
index: MockComponent,
|
||||
},
|
||||
{
|
||||
initialUrl: '/',
|
||||
initialUrl: "/",
|
||||
}
|
||||
);
|
||||
const settingsButton = await waitFor(() =>
|
||||
screen.getByText(/.*Settings.*/i)
|
||||
);
|
||||
fireEvent.press(settingsButton);
|
||||
expect(await waitFor(() => screen.getByText(/Settings/i))).toBeOnTheScreen();
|
||||
expect(
|
||||
await waitFor(() => screen.getByText(/Settings/i))
|
||||
).toBeOnTheScreen();
|
||||
// expect(waitFor(() => screen.getByText(/Settings/i))).toBeTruthy()
|
||||
expect(screen.getByText("Settings")).toBeOnTheScreen();
|
||||
});
|
||||
|
@ -106,7 +106,9 @@ const ISpeakButton = (props: ISpeakButtonProps) => {
|
||||
<View style={styles.flag}>
|
||||
{countries &&
|
||||
countries.map((c) => {
|
||||
return <CountryFlag isoCode={c} size={25} key={c} />;
|
||||
return (
|
||||
<CountryFlag isoCode={c} size={25} key={c} />
|
||||
);
|
||||
})}
|
||||
</View>
|
||||
<View>
|
||||
@ -121,14 +123,13 @@ const ISpeakButton = (props: ISpeakButtonProps) => {
|
||||
|
||||
const styles = StyleSheet.create({
|
||||
button: {
|
||||
width: "20%",
|
||||
borderRadius: 10,
|
||||
borderColor: "white",
|
||||
borderWidth: 1,
|
||||
borderStyle: "solid",
|
||||
height: 110,
|
||||
alignSelf: "flex-start",
|
||||
margin: 8,
|
||||
width: 170,
|
||||
margin: 10,
|
||||
},
|
||||
flag: {},
|
||||
iSpeak: {
|
||||
|
@ -3,9 +3,10 @@ import { render, screen, fireEvent, act } from "@testing-library/react-native";
|
||||
import SettingsComponent from "@/components/Settings";
|
||||
import { language_matrix } from "@/app/i18n/api";
|
||||
import { Settings } from "@/app/lib/settings";
|
||||
import { getDb } from "@/app/lib/db";
|
||||
import { getDb, migrateDb } from "@/app/lib/db";
|
||||
import { Knex } from "knex";
|
||||
import { WhisperFile } from "@/app/lib/whisper";
|
||||
import { SQLiteDatabase } from "expo-sqlite";
|
||||
|
||||
const RENDER_TIME = 1000;
|
||||
|
||||
@ -77,11 +78,12 @@ jest.mock("@/app/i18n/api", () => {
|
||||
|
||||
|
||||
describe("SettingsComponent", () => {
|
||||
let db: Knex;
|
||||
let db: SQLiteDatabase;
|
||||
let settings: Settings;
|
||||
|
||||
beforeEach(async () => {
|
||||
db = await getDb("development");
|
||||
await migrateDb("development");
|
||||
settings = new Settings(db);
|
||||
jest.spyOn(Settings, 'getDefault').mockResolvedValue(settings);
|
||||
await settings.setHostLanguage("en");
|
||||
@ -90,8 +92,7 @@ describe("SettingsComponent", () => {
|
||||
|
||||
afterEach(async () => {
|
||||
jest.restoreAllMocks();
|
||||
await db.migrate.down();
|
||||
await db.destroy();
|
||||
await migrateDb("development", "down");
|
||||
});
|
||||
|
||||
beforeAll(async () => {
|
||||
|
52
jestSetup.ts
52
jestSetup.ts
@ -9,43 +9,37 @@ jest.mock("expo-sqlite", () => {
|
||||
|
||||
const { MIGRATE_UP } = jest.requireActual("./app/lib/migrations");
|
||||
|
||||
const openDatabaseAsync = async (name: string) => {
|
||||
return {
|
||||
closeAsync: jest.fn(() => db.close()),
|
||||
executeSql: jest.fn((sql: string) => db.exec(sql)),
|
||||
runAsync: jest.fn(async (sql: string, params = []) => {
|
||||
for (let m of Object.values(MIGRATE_UP)) {
|
||||
for (let stmt of m) {
|
||||
const s = db.prepare(stmt);
|
||||
s.run();
|
||||
}
|
||||
}
|
||||
const stmt = db.prepare(sql);
|
||||
const genericRun = (sql: string, ... params : string []) => {
|
||||
// console.log("Running %s with %s", sql, params);
|
||||
try {
|
||||
stmt.run(params);
|
||||
const stmt = db.prepare(sql);
|
||||
stmt.run(...params);
|
||||
} catch (e) {
|
||||
throw new Error(
|
||||
`running ${sql} with params ${JSON.stringify(params)}: ${e}`
|
||||
);
|
||||
}
|
||||
}),
|
||||
getFirstAsync: jest.fn(async (sql: string, params = []) => {
|
||||
for (let m of Object.values(MIGRATE_UP)) {
|
||||
for (let stmt of m) {
|
||||
const s = db.prepare(stmt);
|
||||
s.run();
|
||||
}
|
||||
}
|
||||
|
||||
const genericGetFirst = (sql: string, params = []) => {
|
||||
const stmt = db.prepare(sql);
|
||||
// const result = stmt.run(...params);
|
||||
return stmt.get(params);
|
||||
}),
|
||||
};
|
||||
|
||||
const openDatabaseAsync = async (name: string) => {
|
||||
return {
|
||||
closeAsync: jest.fn(() => db.close()),
|
||||
executeSql: jest.fn((sql: string) => db.exec(sql)),
|
||||
runAsync: jest.fn(genericRun),
|
||||
runSync: jest.fn(genericRun),
|
||||
getFirstAsync: jest.fn(genericGetFirst),
|
||||
getFirstSync: jest.fn(genericGetFirst),
|
||||
};
|
||||
};
|
||||
return {
|
||||
migrateDb: async (direction: "up" | "down" = "up") => {
|
||||
const db = await openDatabaseAsync("translation_terrace");
|
||||
const db = await openDatabaseAsync("translation_terrace_development");
|
||||
for (let m of Object.values(MIGRATE_UP)) {
|
||||
for (let stmt of m) {
|
||||
await db.executeSql(stmt);
|
||||
@ -120,3 +114,17 @@ jest.mock('@/app/lib/settings', () => {
|
||||
default: MockSettings
|
||||
};
|
||||
});
|
||||
|
||||
jest.mock('expo-file-system', () => ({
|
||||
// ... other methods ...
|
||||
createDownloadResumable: jest.fn(() => ({
|
||||
downloadAsync: jest.fn(() => Promise.resolve({ uri: 'mocked-uri' })),
|
||||
pauseAsync: jest.fn(() => Promise.resolve()),
|
||||
resumeAsync: jest.fn(() => Promise.resolve()),
|
||||
cancelAsync: jest.fn(() => Promise.resolve()),
|
||||
})),
|
||||
getInfoAsync: jest.fn(() => ({
|
||||
exists: () => false,
|
||||
}))
|
||||
// ... other methods ...
|
||||
}));
|
||||
|
1057
package-lock.json
generated
1057
package-lock.json
generated
@ -9,6 +9,7 @@
|
||||
"version": "1.0.0",
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.26.7",
|
||||
"@expo/knex-expo-sqlite-dialect": "^0.0.1",
|
||||
"@expo/vector-icons": "^14.0.4",
|
||||
"@mmomtchev/react-native-settings": "^1.1.0",
|
||||
"@react-native-async-storage/async-storage": "^2.1.0",
|
||||
@ -16,6 +17,7 @@
|
||||
"@react-navigation/bottom-tabs": "^7.2.0",
|
||||
"@react-navigation/native-stack": "^7.2.0",
|
||||
"expo": "~52.0.28",
|
||||
"expo-audio": "~0.3.4",
|
||||
"expo-background-fetch": "~13.0.5",
|
||||
"expo-blur": "~14.0.3",
|
||||
"expo-constants": "~17.0.6",
|
||||
@ -48,6 +50,7 @@
|
||||
"react-native-sqlite-storage": "^6.0.1",
|
||||
"react-native-web": "~0.19.13",
|
||||
"react-native-webview": "13.12.5",
|
||||
"readable-stream": "^4.7.0",
|
||||
"sqlite": "^5.1.1",
|
||||
"sqlite3": "^5.1.7",
|
||||
"whisper.rn": "^0.3.9"
|
||||
@ -64,6 +67,7 @@
|
||||
"@types/react-native-sqlite-storage": "^6.0.5",
|
||||
"@types/react-navigation": "^3.0.8",
|
||||
"@types/react-test-renderer": "^18.3.1",
|
||||
"@types/readable-stream": "^4.0.18",
|
||||
"babel-jest": "^29.7.0",
|
||||
"babel-plugin-module-resolver": "^5.0.2",
|
||||
"expo": "~52.0.28",
|
||||
@ -2970,6 +2974,26 @@
|
||||
"signal-exit": "^3.0.2"
|
||||
}
|
||||
},
|
||||
"node_modules/@expo/knex-expo-sqlite-dialect": {
|
||||
"version": "0.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@expo/knex-expo-sqlite-dialect/-/knex-expo-sqlite-dialect-0.0.1.tgz",
|
||||
"integrity": "sha512-nCSBIW3uZqQiK/HyoXTJnuxUGxcM5ayYxppwMECGCQ90ouiTkboGFoS6nRzIIqwhvb41vsdikE0m6C9IWdcTig==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"assert": "^2.1.0",
|
||||
"babel-plugin-module-resolver": "^5.0.0",
|
||||
"crypto-browserify": "^3.12.0",
|
||||
"events": "^3.3.0",
|
||||
"node-libs-browser": "^2.2.1",
|
||||
"stream-browserify": "^3.0.0",
|
||||
"timers-browserify": "^2.0.12",
|
||||
"tty-browserify": "^0.0.1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"expo-sqlite": "*",
|
||||
"knex": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/@expo/metro-config": {
|
||||
"version": "0.19.9",
|
||||
"resolved": "https://registry.npmjs.org/@expo/metro-config/-/metro-config-0.19.9.tgz",
|
||||
@ -5025,6 +5049,24 @@
|
||||
"@types/react": "^18"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/readable-stream": {
|
||||
"version": "4.0.18",
|
||||
"resolved": "https://registry.npmjs.org/@types/readable-stream/-/readable-stream-4.0.18.tgz",
|
||||
"integrity": "sha512-21jK/1j+Wg+7jVw1xnSwy/2Q1VgVjWuFssbYGTREPUBeZ+rqVFl2udq0IkxzPC0ZhOzVceUbyIACFZKLqKEBlA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@types/node": "*",
|
||||
"safe-buffer": "~5.1.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/readable-stream/node_modules/safe-buffer": {
|
||||
"version": "5.1.2",
|
||||
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
|
||||
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@types/stack-utils": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz",
|
||||
@ -5568,6 +5610,21 @@
|
||||
"node": "^12.13.0 || ^14.15.0 || >=16.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/are-we-there-yet/node_modules/readable-stream": {
|
||||
"version": "3.6.2",
|
||||
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
|
||||
"integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"inherits": "^2.0.3",
|
||||
"string_decoder": "^1.1.1",
|
||||
"util-deprecate": "^1.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/arg": {
|
||||
"version": "5.0.2",
|
||||
"resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz",
|
||||
@ -5598,6 +5655,23 @@
|
||||
"integrity": "sha512-BSHWgDSAiKs50o2Re8ppvp3seVHXSRM44cdSsT9FfNEUUZLOGWVCsiWaRPWM1Znn+mqZ1OfVZ3z3DWEzSp7hRA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/asn1.js": {
|
||||
"version": "4.10.1",
|
||||
"resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-4.10.1.tgz",
|
||||
"integrity": "sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"bn.js": "^4.0.0",
|
||||
"inherits": "^2.0.1",
|
||||
"minimalistic-assert": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/asn1.js/node_modules/bn.js": {
|
||||
"version": "4.12.1",
|
||||
"resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.1.tgz",
|
||||
"integrity": "sha512-k8TVBiPkPJT9uHLdOKfFpqcfprwBFOAAXXozRubr7R7PfIuKvQlzcI4M0pALeqXN09vdaMbUdUj+pass+uULAg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/assert": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/assert/-/assert-2.1.0.tgz",
|
||||
@ -5731,7 +5805,6 @@
|
||||
"version": "5.0.2",
|
||||
"resolved": "https://registry.npmjs.org/babel-plugin-module-resolver/-/babel-plugin-module-resolver-5.0.2.tgz",
|
||||
"integrity": "sha512-9KtaCazHee2xc0ibfqsDeamwDps6FZNo5S0Q81dUqEuFzVwPhcT4J5jOqIVvgCA3Q/wO9hKYxN/Ds3tIsp5ygg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"find-babel-config": "^2.1.1",
|
||||
@ -5993,6 +6066,26 @@
|
||||
"readable-stream": "^3.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/bl/node_modules/readable-stream": {
|
||||
"version": "3.6.2",
|
||||
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
|
||||
"integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"inherits": "^2.0.3",
|
||||
"string_decoder": "^1.1.1",
|
||||
"util-deprecate": "^1.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/bn.js": {
|
||||
"version": "5.2.1",
|
||||
"resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz",
|
||||
"integrity": "sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/bplist-creator": {
|
||||
"version": "0.0.7",
|
||||
"resolved": "https://registry.npmjs.org/bplist-creator/-/bplist-creator-0.0.7.tgz",
|
||||
@ -6036,6 +6129,129 @@
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/brorand": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz",
|
||||
"integrity": "sha512-cKV8tMCEpQs4hK/ik71d6LrPOnpkpGBR0wzxqr68g2m/LB2GxVYQroAjMJZRVM1Y4BCjCKc3vAamxSzOY2RP+w==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/browserify-aes": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz",
|
||||
"integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"buffer-xor": "^1.0.3",
|
||||
"cipher-base": "^1.0.0",
|
||||
"create-hash": "^1.1.0",
|
||||
"evp_bytestokey": "^1.0.3",
|
||||
"inherits": "^2.0.1",
|
||||
"safe-buffer": "^5.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/browserify-cipher": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.1.tgz",
|
||||
"integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"browserify-aes": "^1.0.4",
|
||||
"browserify-des": "^1.0.0",
|
||||
"evp_bytestokey": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/browserify-des": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.2.tgz",
|
||||
"integrity": "sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"cipher-base": "^1.0.1",
|
||||
"des.js": "^1.0.0",
|
||||
"inherits": "^2.0.1",
|
||||
"safe-buffer": "^5.1.2"
|
||||
}
|
||||
},
|
||||
"node_modules/browserify-rsa": {
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.1.1.tgz",
|
||||
"integrity": "sha512-YBjSAiTqM04ZVei6sXighu679a3SqWORA3qZTEqZImnlkDIFtKc6pNutpjyZ8RJTjQtuYfeetkxM11GwoYXMIQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"bn.js": "^5.2.1",
|
||||
"randombytes": "^2.1.0",
|
||||
"safe-buffer": "^5.2.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.10"
|
||||
}
|
||||
},
|
||||
"node_modules/browserify-sign": {
|
||||
"version": "4.2.3",
|
||||
"resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.3.tgz",
|
||||
"integrity": "sha512-JWCZW6SKhfhjJxO8Tyiiy+XYB7cqd2S5/+WeYHsKdNKFlCBhKbblba1A/HN/90YwtxKc8tCErjffZl++UNmGiw==",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"bn.js": "^5.2.1",
|
||||
"browserify-rsa": "^4.1.0",
|
||||
"create-hash": "^1.2.0",
|
||||
"create-hmac": "^1.1.7",
|
||||
"elliptic": "^6.5.5",
|
||||
"hash-base": "~3.0",
|
||||
"inherits": "^2.0.4",
|
||||
"parse-asn1": "^5.1.7",
|
||||
"readable-stream": "^2.3.8",
|
||||
"safe-buffer": "^5.2.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.12"
|
||||
}
|
||||
},
|
||||
"node_modules/browserify-sign/node_modules/readable-stream": {
|
||||
"version": "2.3.8",
|
||||
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz",
|
||||
"integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"core-util-is": "~1.0.0",
|
||||
"inherits": "~2.0.3",
|
||||
"isarray": "~1.0.0",
|
||||
"process-nextick-args": "~2.0.0",
|
||||
"safe-buffer": "~5.1.1",
|
||||
"string_decoder": "~1.1.1",
|
||||
"util-deprecate": "~1.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/browserify-sign/node_modules/readable-stream/node_modules/safe-buffer": {
|
||||
"version": "5.1.2",
|
||||
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
|
||||
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/browserify-sign/node_modules/string_decoder": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
|
||||
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"safe-buffer": "~5.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/browserify-sign/node_modules/string_decoder/node_modules/safe-buffer": {
|
||||
"version": "5.1.2",
|
||||
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
|
||||
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/browserify-zlib": {
|
||||
"version": "0.2.0",
|
||||
"resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.2.0.tgz",
|
||||
"integrity": "sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"pako": "~1.0.5"
|
||||
}
|
||||
},
|
||||
"node_modules/browserslist": {
|
||||
"version": "4.24.4",
|
||||
"resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.4.tgz",
|
||||
@ -6142,6 +6358,18 @@
|
||||
"integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/buffer-xor": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz",
|
||||
"integrity": "sha512-571s0T7nZWK6vB67HI5dyUF7wXiNcfaPPPTl6zYCNApANjIvYJTg7hlud/+cJpdAhS7dVzqMLmfhfHR3rAcOjQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/builtin-status-codes": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz",
|
||||
"integrity": "sha512-HpGFw18DgFWlncDfjTa2rcQ4W88O1mC8e8yZ2AvQY5KDaktSTwo+KRf6nHK6FRI5FyRyb/5T6+TSxfP7QyGsmQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/bytes": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
|
||||
@ -6457,6 +6685,19 @@
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/cipher-base": {
|
||||
"version": "1.0.6",
|
||||
"resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.6.tgz",
|
||||
"integrity": "sha512-3Ek9H3X6pj5TgenXYtNWdaBon1tgYCaebd+XPg0keyjEbEfkD4KkmAxkQ/i1vYvxdcT5nscLBfq9VJRmCBcFSw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"inherits": "^2.0.4",
|
||||
"safe-buffer": "^5.2.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.10"
|
||||
}
|
||||
},
|
||||
"node_modules/cjs-module-lexer": {
|
||||
"version": "1.4.3",
|
||||
"resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.4.3.tgz",
|
||||
@ -6613,7 +6854,6 @@
|
||||
"version": "2.0.19",
|
||||
"resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.19.tgz",
|
||||
"integrity": "sha512-3tlv/dIP7FWvj3BsbHrGLJ6l/oKh1O3TcgBqMn+yyCagOxc23fyzDS6HypQbgxWbkpDnf52p1LuR4eWDQ/K9WQ==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/combined-stream": {
|
||||
@ -6748,6 +6988,11 @@
|
||||
"integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/console-browserify": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.2.0.tgz",
|
||||
"integrity": "sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA=="
|
||||
},
|
||||
"node_modules/console-control-strings": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz",
|
||||
@ -6755,6 +7000,12 @@
|
||||
"license": "ISC",
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/constants-browserify": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz",
|
||||
"integrity": "sha512-xFxOwqIzR/e1k1gLiWEophSCMqXcwVHIH7akf7b/vxcUeGunlj3hvZaaqxwHsTgn+IndtkQJgSztIDWeumWJDQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/convert-source-map": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz",
|
||||
@ -6792,6 +7043,12 @@
|
||||
"url": "https://opencollective.com/core-js"
|
||||
}
|
||||
},
|
||||
"node_modules/core-util-is": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.3.tgz",
|
||||
"integrity": "sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/cosmiconfig": {
|
||||
"version": "5.2.1",
|
||||
"resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-5.2.1.tgz",
|
||||
@ -6820,6 +7077,49 @@
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/create-ecdh": {
|
||||
"version": "4.0.4",
|
||||
"resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.4.tgz",
|
||||
"integrity": "sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"bn.js": "^4.1.0",
|
||||
"elliptic": "^6.5.3"
|
||||
}
|
||||
},
|
||||
"node_modules/create-ecdh/node_modules/bn.js": {
|
||||
"version": "4.12.1",
|
||||
"resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.1.tgz",
|
||||
"integrity": "sha512-k8TVBiPkPJT9uHLdOKfFpqcfprwBFOAAXXozRubr7R7PfIuKvQlzcI4M0pALeqXN09vdaMbUdUj+pass+uULAg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/create-hash": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz",
|
||||
"integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"cipher-base": "^1.0.1",
|
||||
"inherits": "^2.0.1",
|
||||
"md5.js": "^1.3.4",
|
||||
"ripemd160": "^2.0.1",
|
||||
"sha.js": "^2.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/create-hmac": {
|
||||
"version": "1.1.7",
|
||||
"resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz",
|
||||
"integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"cipher-base": "^1.0.3",
|
||||
"create-hash": "^1.1.0",
|
||||
"inherits": "^2.0.1",
|
||||
"ripemd160": "^2.0.0",
|
||||
"safe-buffer": "^5.0.1",
|
||||
"sha.js": "^2.4.8"
|
||||
}
|
||||
},
|
||||
"node_modules/create-jest": {
|
||||
"version": "29.7.0",
|
||||
"resolved": "https://registry.npmjs.org/create-jest/-/create-jest-29.7.0.tgz",
|
||||
@ -6874,6 +7174,32 @@
|
||||
"node": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/crypto-browserify": {
|
||||
"version": "3.12.1",
|
||||
"resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.1.tgz",
|
||||
"integrity": "sha512-r4ESw/IlusD17lgQi1O20Fa3qNnsckR126TdUuBgAu7GBYSIPvdNyONd3Zrxh0xCwA4+6w/TDArBPsMvhur+KQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"browserify-cipher": "^1.0.1",
|
||||
"browserify-sign": "^4.2.3",
|
||||
"create-ecdh": "^4.0.4",
|
||||
"create-hash": "^1.2.0",
|
||||
"create-hmac": "^1.1.7",
|
||||
"diffie-hellman": "^5.0.3",
|
||||
"hash-base": "~3.0.4",
|
||||
"inherits": "^2.0.4",
|
||||
"pbkdf2": "^3.1.2",
|
||||
"public-encrypt": "^4.0.3",
|
||||
"randombytes": "^2.1.0",
|
||||
"randomfill": "^1.0.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.10"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/crypto-random-string": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/crypto-random-string/-/crypto-random-string-2.0.0.tgz",
|
||||
@ -7145,6 +7471,16 @@
|
||||
"node": ">= 0.8"
|
||||
}
|
||||
},
|
||||
"node_modules/des.js": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/des.js/-/des.js-1.1.0.tgz",
|
||||
"integrity": "sha512-r17GxjhUCjSRy8aiJpr8/UadFIzMzJGexI3Nmz4ADi9LYSFx4gTBp80+NaX/YsXWWLhpZ7v/v/ubEc/bCNfKwg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"inherits": "^2.0.1",
|
||||
"minimalistic-assert": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/destroy": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz",
|
||||
@ -7187,6 +7523,23 @@
|
||||
"node": "^14.15.0 || ^16.10.0 || >=18.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/diffie-hellman": {
|
||||
"version": "5.0.3",
|
||||
"resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz",
|
||||
"integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"bn.js": "^4.1.0",
|
||||
"miller-rabin": "^4.0.0",
|
||||
"randombytes": "^2.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/diffie-hellman/node_modules/bn.js": {
|
||||
"version": "4.12.1",
|
||||
"resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.1.tgz",
|
||||
"integrity": "sha512-k8TVBiPkPJT9uHLdOKfFpqcfprwBFOAAXXozRubr7R7PfIuKvQlzcI4M0pALeqXN09vdaMbUdUj+pass+uULAg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/dir-glob": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz",
|
||||
@ -7199,6 +7552,16 @@
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/domain-browser": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.2.0.tgz",
|
||||
"integrity": "sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=0.4",
|
||||
"npm": ">=1.2"
|
||||
}
|
||||
},
|
||||
"node_modules/domexception": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/domexception/-/domexception-4.0.0.tgz",
|
||||
@ -7288,6 +7651,27 @@
|
||||
"integrity": "sha512-8AJUW6dh75Fm/ny8+kZKJzI1pgoE8bKLZlzDU2W1ENd+DXKJrx7I7l9hb8UWR4ojlnb5OlixMt00QWiYJoVw1w==",
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/elliptic": {
|
||||
"version": "6.6.1",
|
||||
"resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.6.1.tgz",
|
||||
"integrity": "sha512-RaddvvMatK2LJHqFJ+YA4WysVN5Ita9E35botqIYspQ4TkRAlCicdzKOjlyv/1Za5RyTNn7di//eEV0uTAfe3g==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"bn.js": "^4.11.9",
|
||||
"brorand": "^1.1.0",
|
||||
"hash.js": "^1.0.0",
|
||||
"hmac-drbg": "^1.0.1",
|
||||
"inherits": "^2.0.4",
|
||||
"minimalistic-assert": "^1.0.1",
|
||||
"minimalistic-crypto-utils": "^1.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/elliptic/node_modules/bn.js": {
|
||||
"version": "4.12.1",
|
||||
"resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.1.tgz",
|
||||
"integrity": "sha512-k8TVBiPkPJT9uHLdOKfFpqcfprwBFOAAXXozRubr7R7PfIuKvQlzcI4M0pALeqXN09vdaMbUdUj+pass+uULAg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/emittery": {
|
||||
"version": "0.13.1",
|
||||
"resolved": "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz",
|
||||
@ -7541,7 +7925,6 @@
|
||||
"version": "3.2.25",
|
||||
"resolved": "https://registry.npmjs.org/esm/-/esm-3.2.25.tgz",
|
||||
"integrity": "sha512-U1suiZ2oDVWv4zPO56S0NcR5QriEahGtdN2OR6FiOG4WJvcjBVFB0qI4+eKoWFH483PKGuLuu6V8Z4T5g63UVA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
@ -7615,13 +7998,21 @@
|
||||
"version": "3.3.0",
|
||||
"resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz",
|
||||
"integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"engines": {
|
||||
"node": ">=0.8.x"
|
||||
}
|
||||
},
|
||||
"node_modules/evp_bytestokey": {
|
||||
"version": "1.0.3",
|
||||
"resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz",
|
||||
"integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"md5.js": "^1.3.4",
|
||||
"safe-buffer": "^5.1.1"
|
||||
}
|
||||
},
|
||||
"node_modules/exec-async": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/exec-async/-/exec-async-2.2.0.tgz",
|
||||
@ -7821,6 +8212,17 @@
|
||||
"react-native": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/expo-audio": {
|
||||
"version": "0.3.5",
|
||||
"resolved": "https://registry.npmjs.org/expo-audio/-/expo-audio-0.3.5.tgz",
|
||||
"integrity": "sha512-gzpDH3vZI1FDL1Q8pXryACtNIW+idZ/zIZ8WqdTRzJuzxucazrG2gLXUS2ngcXQBn09Jyz4RUnU10Tu2N7/Hgg==",
|
||||
"license": "MIT",
|
||||
"peerDependencies": {
|
||||
"expo": "*",
|
||||
"react": "*",
|
||||
"react-native": "*"
|
||||
}
|
||||
},
|
||||
"node_modules/expo-background-fetch": {
|
||||
"version": "13.0.5",
|
||||
"resolved": "https://registry.npmjs.org/expo-background-fetch/-/expo-background-fetch-13.0.5.tgz",
|
||||
@ -8477,7 +8879,6 @@
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/find-babel-config/-/find-babel-config-2.1.2.tgz",
|
||||
"integrity": "sha512-ZfZp1rQyp4gyuxqt1ZqjFGVeVBvmpURMqdIWXbPRfB97Bf6BzdK/xSIbylEINzQ0kB5tlDQfn9HkNXXWsqTqLg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"json5": "^2.2.3"
|
||||
@ -8881,7 +9282,6 @@
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/getopts/-/getopts-2.3.0.tgz",
|
||||
"integrity": "sha512-5eDf9fuSXwxBL6q5HX+dhDj+dslFGWzU5thZ9kNKUkcPtaPdatmUFKwHFrLb/uf/WpA4BHET+AX3Scl56cAjpA==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/github-from-package": {
|
||||
@ -8894,7 +9294,6 @@
|
||||
"version": "9.3.5",
|
||||
"resolved": "https://registry.npmjs.org/glob/-/glob-9.3.5.tgz",
|
||||
"integrity": "sha512-e1LleDykUz2Iu+MTYdkSsuWX8lvAjAcs0Xef0lNIu0S2wOAzuTxCJtcd9S3cijlwYF18EsU3rzb8jPVobxDh9Q==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"fs.realpath": "^1.0.0",
|
||||
@ -8933,7 +9332,6 @@
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
|
||||
"integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"balanced-match": "^1.0.0"
|
||||
@ -8943,7 +9341,6 @@
|
||||
"version": "8.0.4",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-8.0.4.tgz",
|
||||
"integrity": "sha512-W0Wvr9HyFXZRGIDgCicunpQ299OKXs9RgZfaukz4qAW/pJhcpUfupc9c+OObPOFueNy8VSrZgEmDtk6Kh4WzDA==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"brace-expansion": "^2.0.1"
|
||||
@ -8959,7 +9356,6 @@
|
||||
"version": "4.2.8",
|
||||
"resolved": "https://registry.npmjs.org/minipass/-/minipass-4.2.8.tgz",
|
||||
"integrity": "sha512-fNzuVyifolSLFL4NzpF+wEF4qrgqaaKX0haXPQEdQ7NKAN+WecoKMHV09YcuL/DHxrUsYQOK3MiuDf7Ip2OXfQ==",
|
||||
"dev": true,
|
||||
"license": "ISC",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
@ -9067,6 +9463,29 @@
|
||||
"license": "ISC",
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/hash-base": {
|
||||
"version": "3.0.5",
|
||||
"resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.0.5.tgz",
|
||||
"integrity": "sha512-vXm0l45VbcHEVlTCzs8M+s0VeYsB2lnlAaThoLKGXr3bE/VWDOelNUnycUPEhKEaXARL2TEFjBOyUiM6+55KBg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"inherits": "^2.0.4",
|
||||
"safe-buffer": "^5.2.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.10"
|
||||
}
|
||||
},
|
||||
"node_modules/hash.js": {
|
||||
"version": "1.1.7",
|
||||
"resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz",
|
||||
"integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"inherits": "^2.0.3",
|
||||
"minimalistic-assert": "^1.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/hasown": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
|
||||
@ -9094,6 +9513,17 @@
|
||||
"hermes-estree": "0.23.1"
|
||||
}
|
||||
},
|
||||
"node_modules/hmac-drbg": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz",
|
||||
"integrity": "sha512-Tti3gMqLdZfhOQY1Mzf/AanLiqh1WTiJgEj26ZuYQ9fbkLomzGchCws4FyrSd4VkpBfiNhaE1On+lOz894jvXg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"hash.js": "^1.0.3",
|
||||
"minimalistic-assert": "^1.0.0",
|
||||
"minimalistic-crypto-utils": "^1.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/hoist-non-react-statics": {
|
||||
"version": "3.3.2",
|
||||
"resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz",
|
||||
@ -9194,6 +9624,12 @@
|
||||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/https-browserify": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz",
|
||||
"integrity": "sha512-J+FkSdyD+0mA0N+81tMotaRMfSL9SGi+xpD3T6YApKsc3bGSXJlfXri3VyFOeYkfLRQisDk1W+jIFFKBeUBbBg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/https-proxy-agent": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-5.0.1.tgz",
|
||||
@ -9407,7 +9843,6 @@
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/interpret/-/interpret-2.2.0.tgz",
|
||||
"integrity": "sha512-Ju0Bz/cEia55xDwUWEa8+olFpCiQoypjnQySseKtmjNrnps3P+xfpUmGr90T7yjlVJmOtybRvPXhKMbHr+fWnw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.10"
|
||||
@ -9730,6 +10165,12 @@
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/isarray": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
|
||||
"integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/isexe": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
|
||||
@ -11130,7 +11571,6 @@
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/knex/-/knex-3.1.0.tgz",
|
||||
"integrity": "sha512-GLoII6hR0c4ti243gMs5/1Rb3B+AjwMOfjYm97pu0FOQa7JH56hgBxYf5WK2525ceSbBY1cjeZ9yk99GPMB6Kw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"colorette": "2.0.19",
|
||||
@ -11182,7 +11622,6 @@
|
||||
"version": "10.0.1",
|
||||
"resolved": "https://registry.npmjs.org/commander/-/commander-10.0.1.tgz",
|
||||
"integrity": "sha512-y4Mg2tXshplEbSGzx7amzPwKKOCGuoSRP/CjEdwwk0FOGlUbq6lKuoyDZTNZkmxHdJtp54hdfY/JUrdL7Xfdug==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=14"
|
||||
@ -11192,7 +11631,6 @@
|
||||
"version": "4.3.4",
|
||||
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
|
||||
"integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"ms": "2.1.2"
|
||||
@ -11210,7 +11648,6 @@
|
||||
"version": "2.1.2",
|
||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
||||
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/leven": {
|
||||
@ -11953,6 +12390,17 @@
|
||||
"node": ">=0.10"
|
||||
}
|
||||
},
|
||||
"node_modules/md5.js": {
|
||||
"version": "1.3.5",
|
||||
"resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz",
|
||||
"integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"hash-base": "^3.0.0",
|
||||
"inherits": "^2.0.1",
|
||||
"safe-buffer": "^5.1.2"
|
||||
}
|
||||
},
|
||||
"node_modules/memoize-one": {
|
||||
"version": "5.2.1",
|
||||
"resolved": "https://registry.npmjs.org/memoize-one/-/memoize-one-5.2.1.tgz",
|
||||
@ -12457,6 +12905,25 @@
|
||||
"url": "https://github.com/sponsors/jonschlinkert"
|
||||
}
|
||||
},
|
||||
"node_modules/miller-rabin": {
|
||||
"version": "4.0.1",
|
||||
"resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz",
|
||||
"integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"bn.js": "^4.0.0",
|
||||
"brorand": "^1.0.1"
|
||||
},
|
||||
"bin": {
|
||||
"miller-rabin": "bin/miller-rabin"
|
||||
}
|
||||
},
|
||||
"node_modules/miller-rabin/node_modules/bn.js": {
|
||||
"version": "4.12.1",
|
||||
"resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.1.tgz",
|
||||
"integrity": "sha512-k8TVBiPkPJT9uHLdOKfFpqcfprwBFOAAXXozRubr7R7PfIuKvQlzcI4M0pALeqXN09vdaMbUdUj+pass+uULAg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/mime": {
|
||||
"version": "1.6.0",
|
||||
"resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz",
|
||||
@ -12530,6 +12997,18 @@
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/minimalistic-assert": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz",
|
||||
"integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==",
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/minimalistic-crypto-utils": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz",
|
||||
"integrity": "sha512-JIYlbt6g8i5jKfJ3xz7rF0LXmv2TkDxBLUkiBeZ7bAx4GnnNMr8xFpGnOxn6GhTEHx3SjRrZEoU+j04prX1ktg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/minimatch": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
|
||||
@ -12995,6 +13474,134 @@
|
||||
"integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/node-libs-browser": {
|
||||
"version": "2.2.1",
|
||||
"resolved": "https://registry.npmjs.org/node-libs-browser/-/node-libs-browser-2.2.1.tgz",
|
||||
"integrity": "sha512-h/zcD8H9kaDZ9ALUWwlBUDo6TKF8a7qBSCSEGfjTVIYeqsioSKaAX+BN7NgiMGp6iSIXZ3PxgCu8KS3b71YK5Q==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"assert": "^1.1.1",
|
||||
"browserify-zlib": "^0.2.0",
|
||||
"buffer": "^4.3.0",
|
||||
"console-browserify": "^1.1.0",
|
||||
"constants-browserify": "^1.0.0",
|
||||
"crypto-browserify": "^3.11.0",
|
||||
"domain-browser": "^1.1.1",
|
||||
"events": "^3.0.0",
|
||||
"https-browserify": "^1.0.0",
|
||||
"os-browserify": "^0.3.0",
|
||||
"path-browserify": "0.0.1",
|
||||
"process": "^0.11.10",
|
||||
"punycode": "^1.2.4",
|
||||
"querystring-es3": "^0.2.0",
|
||||
"readable-stream": "^2.3.3",
|
||||
"stream-browserify": "^2.0.1",
|
||||
"stream-http": "^2.7.2",
|
||||
"string_decoder": "^1.0.0",
|
||||
"timers-browserify": "^2.0.4",
|
||||
"tty-browserify": "0.0.0",
|
||||
"url": "^0.11.0",
|
||||
"util": "^0.11.0",
|
||||
"vm-browserify": "^1.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/node-libs-browser/node_modules/assert": {
|
||||
"version": "1.5.1",
|
||||
"resolved": "https://registry.npmjs.org/assert/-/assert-1.5.1.tgz",
|
||||
"integrity": "sha512-zzw1uCAgLbsKwBfFc8CX78DDg+xZeBksSO3vwVIDDN5i94eOrPsSSyiVhmsSABFDM/OcpE2aagCat9dnWQLG1A==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"object.assign": "^4.1.4",
|
||||
"util": "^0.10.4"
|
||||
}
|
||||
},
|
||||
"node_modules/node-libs-browser/node_modules/assert/node_modules/util": {
|
||||
"version": "0.10.4",
|
||||
"resolved": "https://registry.npmjs.org/util/-/util-0.10.4.tgz",
|
||||
"integrity": "sha512-0Pm9hTQ3se5ll1XihRic3FDIku70C+iHUdT/W926rSgHV5QgXsYbKZN8MSC3tJtSkhuROzvsQjAaFENRXr+19A==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"inherits": "2.0.3"
|
||||
}
|
||||
},
|
||||
"node_modules/node-libs-browser/node_modules/buffer": {
|
||||
"version": "4.9.2",
|
||||
"resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.2.tgz",
|
||||
"integrity": "sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"base64-js": "^1.0.2",
|
||||
"ieee754": "^1.1.4",
|
||||
"isarray": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/node-libs-browser/node_modules/inherits": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
|
||||
"integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==",
|
||||
"license": "ISC"
|
||||
},
|
||||
"node_modules/node-libs-browser/node_modules/punycode": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz",
|
||||
"integrity": "sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/node-libs-browser/node_modules/readable-stream": {
|
||||
"version": "2.3.8",
|
||||
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz",
|
||||
"integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"core-util-is": "~1.0.0",
|
||||
"inherits": "~2.0.3",
|
||||
"isarray": "~1.0.0",
|
||||
"process-nextick-args": "~2.0.0",
|
||||
"safe-buffer": "~5.1.1",
|
||||
"string_decoder": "~1.1.1",
|
||||
"util-deprecate": "~1.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/node-libs-browser/node_modules/safe-buffer": {
|
||||
"version": "5.1.2",
|
||||
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
|
||||
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/node-libs-browser/node_modules/stream-browserify": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.2.tgz",
|
||||
"integrity": "sha512-nX6hmklHs/gr2FuxYDltq8fJA1GDlxKQCz8O/IM4atRqBH8OORmBNgfvW5gG10GT/qQ9u0CzIvr2X5Pkt6ntqg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"inherits": "~2.0.1",
|
||||
"readable-stream": "^2.0.2"
|
||||
}
|
||||
},
|
||||
"node_modules/node-libs-browser/node_modules/string_decoder": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
|
||||
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"safe-buffer": "~5.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/node-libs-browser/node_modules/tty-browserify": {
|
||||
"version": "0.0.0",
|
||||
"resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz",
|
||||
"integrity": "sha512-JVa5ijo+j/sOoHGjw0sxw734b1LhBkQ3bvUGNdxnVXDCX81Yx7TFgnZygxrIIWn23hbfTaMYLwRmAxFyDuFmIw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/node-libs-browser/node_modules/util": {
|
||||
"version": "0.11.1",
|
||||
"resolved": "https://registry.npmjs.org/util/-/util-0.11.1.tgz",
|
||||
"integrity": "sha512-HShAsny+zS2TZfaXxD9tYj4HQGlBezXZMZuM/S5PKLLoZkShZiGk9o5CzukI1LVHZvjdvZ2Sj1aW/Ndn2NB/HQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"inherits": "2.0.3"
|
||||
}
|
||||
},
|
||||
"node_modules/node-releases": {
|
||||
"version": "2.0.19",
|
||||
"resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.19.tgz",
|
||||
@ -13125,6 +13732,18 @@
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/object-inspect": {
|
||||
"version": "1.13.4",
|
||||
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.4.tgz",
|
||||
"integrity": "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/object-is": {
|
||||
"version": "1.1.6",
|
||||
"resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.6.tgz",
|
||||
@ -13337,6 +13956,12 @@
|
||||
"node": ">=4"
|
||||
}
|
||||
},
|
||||
"node_modules/os-browserify": {
|
||||
"version": "0.3.0",
|
||||
"resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz",
|
||||
"integrity": "sha512-gjcpUc3clBf9+210TRaDWbf+rZZZEshZ+DlXMRCeAjp0xhTrnQsKHypIy1J3d5hKdUzj69t708EHtU8P6bUn0A==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/os-tmpdir": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
|
||||
@ -13427,6 +14052,29 @@
|
||||
"integrity": "sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw==",
|
||||
"license": "BlueOak-1.0.0"
|
||||
},
|
||||
"node_modules/pako": {
|
||||
"version": "1.0.11",
|
||||
"resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz",
|
||||
"integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==",
|
||||
"license": "(MIT AND Zlib)"
|
||||
},
|
||||
"node_modules/parse-asn1": {
|
||||
"version": "5.1.7",
|
||||
"resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.7.tgz",
|
||||
"integrity": "sha512-CTM5kuWR3sx9IFamcl5ErfPl6ea/N8IYwiJ+vpeB2g+1iknv7zBl5uPwbMbRVznRVbrNY6lGuDoE5b30grmbqg==",
|
||||
"license": "ISC",
|
||||
"dependencies": {
|
||||
"asn1.js": "^4.10.1",
|
||||
"browserify-aes": "^1.2.0",
|
||||
"evp_bytestokey": "^1.0.3",
|
||||
"hash-base": "~3.0",
|
||||
"pbkdf2": "^3.1.2",
|
||||
"safe-buffer": "^5.2.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.10"
|
||||
}
|
||||
},
|
||||
"node_modules/parse-json": {
|
||||
"version": "5.2.0",
|
||||
"resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz",
|
||||
@ -13490,6 +14138,12 @@
|
||||
"cross-spawn": "^7.0.3"
|
||||
}
|
||||
},
|
||||
"node_modules/path-browserify": {
|
||||
"version": "0.0.1",
|
||||
"resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-0.0.1.tgz",
|
||||
"integrity": "sha512-BapA40NHICOS+USX9SN4tyhq+A2RrN/Ws5F0Z5aMHDp98Fl86lX8Oti8B7uN93L4Ifv4fHOEA+pQw87gmMO/lQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/path-exists": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
|
||||
@ -13554,11 +14208,26 @@
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/pbkdf2": {
|
||||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.2.tgz",
|
||||
"integrity": "sha512-iuh7L6jA7JEGu2WxDwtQP1ddOpaJNC4KlDEFfdQajSGgGPNi4OyDc2R7QnbY2bR9QjBVGwgvTdNJZoE7RaxUMA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"create-hash": "^1.1.2",
|
||||
"create-hmac": "^1.1.4",
|
||||
"ripemd160": "^2.0.1",
|
||||
"safe-buffer": "^5.0.1",
|
||||
"sha.js": "^2.4.8"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.12"
|
||||
}
|
||||
},
|
||||
"node_modules/pg-connection-string": {
|
||||
"version": "2.6.2",
|
||||
"resolved": "https://registry.npmjs.org/pg-connection-string/-/pg-connection-string-2.6.2.tgz",
|
||||
"integrity": "sha512-ch6OwaeaPYcova4kKZ15sbJ2hKb/VP48ZD2gE7i1J+L4MspCtBMAx8nMgz7bksc7IojCIIWuEhHibSMFH8m8oA==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/picocolors": {
|
||||
@ -13614,7 +14283,6 @@
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/pkg-up/-/pkg-up-3.1.0.tgz",
|
||||
"integrity": "sha512-nDywThFk1i4BQK4twPQ6TA4RT8bDY96yeuCVBWL3ePARCiEKDRSrNGbFIgUJpLp+XeIR65v8ra7WuJOFUBtkMA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"find-up": "^3.0.0"
|
||||
@ -13627,7 +14295,6 @@
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz",
|
||||
"integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"locate-path": "^3.0.0"
|
||||
@ -13640,7 +14307,6 @@
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz",
|
||||
"integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"p-locate": "^3.0.0",
|
||||
@ -13654,7 +14320,6 @@
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz",
|
||||
"integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"p-try": "^2.0.0"
|
||||
@ -13670,7 +14335,6 @@
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz",
|
||||
"integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"p-limit": "^2.0.0"
|
||||
@ -13683,7 +14347,6 @@
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz",
|
||||
"integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=4"
|
||||
@ -13855,6 +14518,21 @@
|
||||
"node": "^14.17.0 || ^16.13.0 || >=18.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/process": {
|
||||
"version": "0.11.10",
|
||||
"resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz",
|
||||
"integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 0.6.0"
|
||||
}
|
||||
},
|
||||
"node_modules/process-nextick-args": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
|
||||
"integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/progress": {
|
||||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz",
|
||||
@ -13937,6 +14615,26 @@
|
||||
"url": "https://github.com/sponsors/lupomontero"
|
||||
}
|
||||
},
|
||||
"node_modules/public-encrypt": {
|
||||
"version": "4.0.3",
|
||||
"resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz",
|
||||
"integrity": "sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"bn.js": "^4.1.0",
|
||||
"browserify-rsa": "^4.0.0",
|
||||
"create-hash": "^1.1.0",
|
||||
"parse-asn1": "^5.0.0",
|
||||
"randombytes": "^2.0.1",
|
||||
"safe-buffer": "^5.1.2"
|
||||
}
|
||||
},
|
||||
"node_modules/public-encrypt/node_modules/bn.js": {
|
||||
"version": "4.12.1",
|
||||
"resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.1.tgz",
|
||||
"integrity": "sha512-k8TVBiPkPJT9uHLdOKfFpqcfprwBFOAAXXozRubr7R7PfIuKvQlzcI4M0pALeqXN09vdaMbUdUj+pass+uULAg==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/pump": {
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/pump/-/pump-3.0.2.tgz",
|
||||
@ -13981,6 +14679,21 @@
|
||||
"qrcode-terminal": "bin/qrcode-terminal.js"
|
||||
}
|
||||
},
|
||||
"node_modules/qs": {
|
||||
"version": "6.14.0",
|
||||
"resolved": "https://registry.npmjs.org/qs/-/qs-6.14.0.tgz",
|
||||
"integrity": "sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w==",
|
||||
"license": "BSD-3-Clause",
|
||||
"dependencies": {
|
||||
"side-channel": "^1.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.6"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/query-string": {
|
||||
"version": "7.1.3",
|
||||
"resolved": "https://registry.npmjs.org/query-string/-/query-string-7.1.3.tgz",
|
||||
@ -13999,6 +14712,14 @@
|
||||
"url": "https://github.com/sponsors/sindresorhus"
|
||||
}
|
||||
},
|
||||
"node_modules/querystring-es3": {
|
||||
"version": "0.2.1",
|
||||
"resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz",
|
||||
"integrity": "sha512-773xhDQnZBMFobEiztv8LIl70ch5MSF/jUQVlhwFyBILqq96anmoctVIYz+ZRp0qbCKATTn6ev02M3r7Ga5vqA==",
|
||||
"engines": {
|
||||
"node": ">=0.4.x"
|
||||
}
|
||||
},
|
||||
"node_modules/querystringify": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz",
|
||||
@ -14039,13 +14760,21 @@
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz",
|
||||
"integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"safe-buffer": "^5.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/randomfill": {
|
||||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz",
|
||||
"integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"randombytes": "^2.0.5",
|
||||
"safe-buffer": "^5.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/range-parser": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz",
|
||||
@ -14536,17 +15265,43 @@
|
||||
}
|
||||
},
|
||||
"node_modules/readable-stream": {
|
||||
"version": "3.6.2",
|
||||
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
|
||||
"integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
|
||||
"version": "4.7.0",
|
||||
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.7.0.tgz",
|
||||
"integrity": "sha512-oIGGmcpTLwPga8Bn6/Z75SVaH1z5dUut2ibSyAMVhmUggWpmDn2dapB0n7f8nwaSiRtepAsfJyfXIO5DCVAODg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"inherits": "^2.0.3",
|
||||
"string_decoder": "^1.1.1",
|
||||
"util-deprecate": "^1.0.1"
|
||||
"abort-controller": "^3.0.0",
|
||||
"buffer": "^6.0.3",
|
||||
"events": "^3.3.0",
|
||||
"process": "^0.11.10",
|
||||
"string_decoder": "^1.3.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 6"
|
||||
"node": "^12.22.0 || ^14.17.0 || >=16.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/readable-stream/node_modules/buffer": {
|
||||
"version": "6.0.3",
|
||||
"resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz",
|
||||
"integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "github",
|
||||
"url": "https://github.com/sponsors/feross"
|
||||
},
|
||||
{
|
||||
"type": "patreon",
|
||||
"url": "https://www.patreon.com/feross"
|
||||
},
|
||||
{
|
||||
"type": "consulting",
|
||||
"url": "https://feross.org/support"
|
||||
}
|
||||
],
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"base64-js": "^1.3.1",
|
||||
"ieee754": "^1.2.1"
|
||||
}
|
||||
},
|
||||
"node_modules/readline": {
|
||||
@ -14583,7 +15338,6 @@
|
||||
"version": "0.8.0",
|
||||
"resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.8.0.tgz",
|
||||
"integrity": "sha512-/vxpCXddiX8NGfGO/mTafwjq4aFa/71pvamip0++IQk3zG8cbCj0fifNPrjjF1XMXUne91jL9OoxmdykoEtifQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"resolve": "^1.20.0"
|
||||
@ -14743,7 +15497,6 @@
|
||||
"version": "4.1.8",
|
||||
"resolved": "https://registry.npmjs.org/reselect/-/reselect-4.1.8.tgz",
|
||||
"integrity": "sha512-ab9EmR80F/zQTMNeneUr4cv+jSwPJgIlvEmVwLerwrWVbpLlBuls9XHzIeTFy4cegU2NHBp3va0LKOzU5qFEYQ==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/resolve": {
|
||||
@ -14873,6 +15626,16 @@
|
||||
"url": "https://github.com/sponsors/isaacs"
|
||||
}
|
||||
},
|
||||
"node_modules/ripemd160": {
|
||||
"version": "2.0.2",
|
||||
"resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz",
|
||||
"integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"hash-base": "^3.0.0",
|
||||
"inherits": "^2.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/run-parallel": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz",
|
||||
@ -15248,6 +16011,19 @@
|
||||
"node": ">=10"
|
||||
}
|
||||
},
|
||||
"node_modules/sha.js": {
|
||||
"version": "2.4.11",
|
||||
"resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz",
|
||||
"integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==",
|
||||
"license": "(MIT AND BSD-3-Clause)",
|
||||
"dependencies": {
|
||||
"inherits": "^2.0.1",
|
||||
"safe-buffer": "^5.0.1"
|
||||
},
|
||||
"bin": {
|
||||
"sha.js": "bin.js"
|
||||
}
|
||||
},
|
||||
"node_modules/shallow-clone": {
|
||||
"version": "3.0.1",
|
||||
"resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz",
|
||||
@ -15299,6 +16075,78 @@
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/side-channel": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.1.0.tgz",
|
||||
"integrity": "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"es-errors": "^1.3.0",
|
||||
"object-inspect": "^1.13.3",
|
||||
"side-channel-list": "^1.0.0",
|
||||
"side-channel-map": "^1.0.1",
|
||||
"side-channel-weakmap": "^1.0.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/side-channel-list": {
|
||||
"version": "1.0.0",
|
||||
"resolved": "https://registry.npmjs.org/side-channel-list/-/side-channel-list-1.0.0.tgz",
|
||||
"integrity": "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"es-errors": "^1.3.0",
|
||||
"object-inspect": "^1.13.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/side-channel-map": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/side-channel-map/-/side-channel-map-1.0.1.tgz",
|
||||
"integrity": "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"call-bound": "^1.0.2",
|
||||
"es-errors": "^1.3.0",
|
||||
"get-intrinsic": "^1.2.5",
|
||||
"object-inspect": "^1.13.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/side-channel-weakmap": {
|
||||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/side-channel-weakmap/-/side-channel-weakmap-1.0.2.tgz",
|
||||
"integrity": "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"call-bound": "^1.0.2",
|
||||
"es-errors": "^1.3.0",
|
||||
"get-intrinsic": "^1.2.5",
|
||||
"object-inspect": "^1.13.3",
|
||||
"side-channel-map": "^1.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
},
|
||||
"funding": {
|
||||
"url": "https://github.com/sponsors/ljharb"
|
||||
}
|
||||
},
|
||||
"node_modules/signal-exit": {
|
||||
"version": "3.0.7",
|
||||
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz",
|
||||
@ -15668,6 +16516,30 @@
|
||||
"node": ">= 0.6"
|
||||
}
|
||||
},
|
||||
"node_modules/stream-browserify": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-3.0.0.tgz",
|
||||
"integrity": "sha512-H73RAHsVBapbim0tU2JwwOiXUj+fikfiaoYAKHF3VJfA0pe2BCzkhAHBlLG6REzE+2WNZcxOXjK7lkso+9euLA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"inherits": "~2.0.4",
|
||||
"readable-stream": "^3.5.0"
|
||||
}
|
||||
},
|
||||
"node_modules/stream-browserify/node_modules/readable-stream": {
|
||||
"version": "3.6.2",
|
||||
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
|
||||
"integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"inherits": "^2.0.3",
|
||||
"string_decoder": "^1.1.1",
|
||||
"util-deprecate": "^1.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/stream-buffers": {
|
||||
"version": "2.2.0",
|
||||
"resolved": "https://registry.npmjs.org/stream-buffers/-/stream-buffers-2.2.0.tgz",
|
||||
@ -15677,6 +16549,49 @@
|
||||
"node": ">= 0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/stream-http": {
|
||||
"version": "2.8.3",
|
||||
"resolved": "https://registry.npmjs.org/stream-http/-/stream-http-2.8.3.tgz",
|
||||
"integrity": "sha512-+TSkfINHDo4J+ZobQLWiMouQYB+UVYFttRA94FpEzzJ7ZdqcL4uUUQ7WkdkI4DSozGmgBUE/a47L+38PenXhUw==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"builtin-status-codes": "^3.0.0",
|
||||
"inherits": "^2.0.1",
|
||||
"readable-stream": "^2.3.6",
|
||||
"to-arraybuffer": "^1.0.0",
|
||||
"xtend": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/stream-http/node_modules/readable-stream": {
|
||||
"version": "2.3.8",
|
||||
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz",
|
||||
"integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"core-util-is": "~1.0.0",
|
||||
"inherits": "~2.0.3",
|
||||
"isarray": "~1.0.0",
|
||||
"process-nextick-args": "~2.0.0",
|
||||
"safe-buffer": "~5.1.1",
|
||||
"string_decoder": "~1.1.1",
|
||||
"util-deprecate": "~1.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/stream-http/node_modules/safe-buffer": {
|
||||
"version": "5.1.2",
|
||||
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
|
||||
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/stream-http/node_modules/string_decoder": {
|
||||
"version": "1.1.1",
|
||||
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
|
||||
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"safe-buffer": "~5.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/stream-slice": {
|
||||
"version": "0.1.2",
|
||||
"resolved": "https://registry.npmjs.org/stream-slice/-/stream-slice-0.1.2.tgz",
|
||||
@ -16023,6 +16938,20 @@
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/tar-stream/node_modules/readable-stream": {
|
||||
"version": "3.6.2",
|
||||
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
|
||||
"integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"inherits": "^2.0.3",
|
||||
"string_decoder": "^1.1.1",
|
||||
"util-deprecate": "^1.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 6"
|
||||
}
|
||||
},
|
||||
"node_modules/tar/node_modules/fs-minipass": {
|
||||
"version": "2.1.0",
|
||||
"resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz",
|
||||
@ -16078,7 +17007,6 @@
|
||||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/tarn/-/tarn-3.0.2.tgz",
|
||||
"integrity": "sha512-51LAVKUSZSVfI05vjPESNc5vwqqZpbXCsU+/+wxlOrUjk2SnFTt97v9ZgQrD4YmxYW1Px6w2KjaDitCfkvgxMQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=8.0.0"
|
||||
@ -16363,12 +17291,23 @@
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/tildify/-/tildify-2.0.0.tgz",
|
||||
"integrity": "sha512-Cc+OraorugtXNfs50hU9KS369rFXCfgGLpfCfvlc+Ud5u6VWmUQsOAa9HbTvheQdYnrdJqqv1e5oIqXppMYnSw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=8"
|
||||
}
|
||||
},
|
||||
"node_modules/timers-browserify": {
|
||||
"version": "2.0.12",
|
||||
"resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.12.tgz",
|
||||
"integrity": "sha512-9phl76Cqm6FhSX9Xe1ZUAMLtm1BLkKj2Qd5ApyWkXzsMRaA7dgr81kf4wJmQf/hAvg8EEyJxDo3du/0KlhPiKQ==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"setimmediate": "^1.0.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.6.0"
|
||||
}
|
||||
},
|
||||
"node_modules/tmp": {
|
||||
"version": "0.0.33",
|
||||
"resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz",
|
||||
@ -16387,6 +17326,12 @@
|
||||
"integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==",
|
||||
"license": "BSD-3-Clause"
|
||||
},
|
||||
"node_modules/to-arraybuffer": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz",
|
||||
"integrity": "sha512-okFlQcoGTi4LQBG/PgSYblw9VOyptsz2KJZqc6qtgGdes8VktzUQkj4BI2blit072iS8VODNcMA+tvnS9dnuMA==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/to-regex-range": {
|
||||
"version": "5.0.1",
|
||||
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
|
||||
@ -16521,6 +17466,12 @@
|
||||
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
|
||||
"license": "0BSD"
|
||||
},
|
||||
"node_modules/tty-browserify": {
|
||||
"version": "0.0.1",
|
||||
"resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.1.tgz",
|
||||
"integrity": "sha512-C3TaO7K81YvjCgQH9Q1S3R3P3BtN3RIM8n+OvX4il1K1zgE8ZhI0op7kClgkxtutIE8hQrcrHBXvIheqKUUCxw==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/tunnel-agent": {
|
||||
"version": "0.6.0",
|
||||
"resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
|
||||
@ -16756,6 +17707,19 @@
|
||||
"punycode": "^2.1.0"
|
||||
}
|
||||
},
|
||||
"node_modules/url": {
|
||||
"version": "0.11.4",
|
||||
"resolved": "https://registry.npmjs.org/url/-/url-0.11.4.tgz",
|
||||
"integrity": "sha512-oCwdVC7mTuWiPyjLUz/COz5TLk6wgp0RCsN+wHZ2Ekneac9w8uuV0njcbbie2ME+Vs+d6duwmYuR3HgQXs1fOg==",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"punycode": "^1.4.1",
|
||||
"qs": "^6.12.3"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/url-parse": {
|
||||
"version": "1.5.10",
|
||||
"resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz",
|
||||
@ -16767,6 +17731,12 @@
|
||||
"requires-port": "^1.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/url/node_modules/punycode": {
|
||||
"version": "1.4.1",
|
||||
"resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz",
|
||||
"integrity": "sha512-jmYNElW7yvO7TV33CjSmvSiE2yco3bV2czu/OzDKdMNVZQWfxCblURLhf+47syQRBntjfLdd/H0egrzIG+oaFQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/use-latest-callback": {
|
||||
"version": "0.2.3",
|
||||
"resolved": "https://registry.npmjs.org/use-latest-callback/-/use-latest-callback-0.2.3.tgz",
|
||||
@ -16861,6 +17831,12 @@
|
||||
"integrity": "sha512-gQpnTgkubC6hQgdIcRdYGDSDc+SaujOdyesZQMv6JlfQee/9Mp0Qhnys6WxDWvQnL5WZdT7o2Ul187aSt0Rq+w==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/vm-browserify": {
|
||||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.2.tgz",
|
||||
"integrity": "sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==",
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/w3c-xmlserializer": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/w3c-xmlserializer/-/w3c-xmlserializer-4.0.0.tgz",
|
||||
@ -17335,6 +18311,15 @@
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/xtend": {
|
||||
"version": "4.0.2",
|
||||
"resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz",
|
||||
"integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/y18n": {
|
||||
"version": "5.0.8",
|
||||
"resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
|
||||
|
@ -16,6 +16,7 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"@babel/runtime": "^7.26.7",
|
||||
"@expo/knex-expo-sqlite-dialect": "^0.0.1",
|
||||
"@expo/vector-icons": "^14.0.4",
|
||||
"@mmomtchev/react-native-settings": "^1.1.0",
|
||||
"@react-native-async-storage/async-storage": "^2.1.0",
|
||||
@ -23,6 +24,7 @@
|
||||
"@react-navigation/bottom-tabs": "^7.2.0",
|
||||
"@react-navigation/native-stack": "^7.2.0",
|
||||
"expo": "~52.0.28",
|
||||
"expo-audio": "~0.3.4",
|
||||
"expo-background-fetch": "~13.0.5",
|
||||
"expo-blur": "~14.0.3",
|
||||
"expo-constants": "~17.0.6",
|
||||
@ -55,6 +57,7 @@
|
||||
"react-native-sqlite-storage": "^6.0.1",
|
||||
"react-native-web": "~0.19.13",
|
||||
"react-native-webview": "13.12.5",
|
||||
"readable-stream": "^4.7.0",
|
||||
"sqlite": "^5.1.1",
|
||||
"sqlite3": "^5.1.7",
|
||||
"whisper.rn": "^0.3.9"
|
||||
@ -84,6 +87,7 @@
|
||||
"@types/react-native-sqlite-storage": "^6.0.5",
|
||||
"@types/react-navigation": "^3.0.8",
|
||||
"@types/react-test-renderer": "^18.3.1",
|
||||
"@types/readable-stream": "^4.0.18",
|
||||
"babel-jest": "^29.7.0",
|
||||
"babel-plugin-module-resolver": "^5.0.2",
|
||||
"expo": "~52.0.28",
|
||||
|
Reference in New Issue
Block a user