From c4181c6011ca7470ea7624f02f82442741d0fd33 Mon Sep 17 00:00:00 2001 From: Simon Binder Date: Mon, 31 Mar 2025 16:11:11 +0200 Subject: [PATCH 01/16] Add sync progress APIs --- .../src/client/AbstractPowerSyncDatabase.ts | 6 +- packages/common/src/db/crud/SyncProgress.ts | 81 +++++++++++++++++++ packages/common/src/db/crud/SyncStatus.ts | 23 ++++++ packages/common/src/index.ts | 1 + 4 files changed, 106 insertions(+), 5 deletions(-) create mode 100644 packages/common/src/db/crud/SyncProgress.ts diff --git a/packages/common/src/client/AbstractPowerSyncDatabase.ts b/packages/common/src/client/AbstractPowerSyncDatabase.ts index 843deb4c8..712d65584 100644 --- a/packages/common/src/client/AbstractPowerSyncDatabase.ts +++ b/packages/common/src/client/AbstractPowerSyncDatabase.ts @@ -32,6 +32,7 @@ import { type PowerSyncConnectionOptions, type RequiredAdditionalConnectionOptions } from './sync/stream/AbstractStreamingSyncImplementation.js'; +import { FULL_SYNC_PRIORITY } from 'src/db/crud/SyncProgress.js'; export interface DisconnectAndClearOptions { /** When set to false, data in local-only tables is preserved. */ @@ -146,11 +147,6 @@ export const isPowerSyncDatabaseOptionsWithSettings = (test: any): test is Power return typeof test == 'object' && isSQLOpenOptions(test.database); }; -/** - * The priority used by the core extension to indicate that a full sync was completed. - */ -const FULL_SYNC_PRIORITY = 2147483647; - export abstract class AbstractPowerSyncDatabase extends BaseObserver { /** * Transactions should be queued in the DBAdapter, but we also want to prevent diff --git a/packages/common/src/db/crud/SyncProgress.ts b/packages/common/src/db/crud/SyncProgress.ts new file mode 100644 index 000000000..d48e1a0aa --- /dev/null +++ b/packages/common/src/db/crud/SyncProgress.ts @@ -0,0 +1,81 @@ +import type { SyncStatus } from "./SyncStatus.js"; + +// (bucket, progress) pairs +export type InternalProgressInformation = Record; + +/** + * The priority used by the core extension to indicate that a full sync was completed. + */ +export const FULL_SYNC_PRIORITY = 2147483647; + +/** + * Information about a progressing download made by the PowerSync SDK. + * + * To obtain these values, use {@link SyncProgress}, available through + * {@link SyncStatus#downloadProgress}. + */ +export interface ProgressWithOperations { + /** + * The total amount of operations to download for the current sync iteration + * to complete. + */ + total: number; + /** + * The amount of operations that have already been downloaded. + */ + completed: number; + + /** + * Relative progress, as {@link completed} of {@link total}. This will be a number + * between `0.0` and `1.0`. + */ + fraction: number; +}; + +/** + * Provides realtime progress on how PowerSync is downloading rows. + * + * The reported progress always reflects the status towards th end of a sync iteration (after + * which a consistent snapshot of all buckets is available locally). + * + * In rare cases (in particular, when a [compacting](https://docs.powersync.com/usage/lifecycle-maintenance/compacting-buckets) + * operation takes place between syncs), it's possible for the returned numbers to be slightly + * inaccurate. For this reason, {@link SyncProgress} should be seen as an approximation of progress. + * The information returned is good enough to build progress bars, but not exact enough to track + * individual download counts. + * + * Also note that data is downloaded in bulk, which means that individual counters are unlikely + * to be updated one-by-one. + */ +export class SyncProgress { + constructor(protected internal: InternalProgressInformation) {} + + get untilCompletion(): ProgressWithOperations { + return this.untilPriority(FULL_SYNC_PRIORITY); + } + + untilPriority(priority: number): ProgressWithOperations { + let total = 0; + let downloaded = 0; + + for (const progress of Object.values(this.internal)) { + // Include higher-priority buckets, which are represented by lower numbers. + if (progress.priority <= priority) { + downloaded += progress.sinceLast; + total += progress.targetCount - progress.atLast; + } + } + + let progress = total == 0 ? 0.0 : downloaded / total; + return { + total, + completed: downloaded, + fraction: progress, + } + } +} diff --git a/packages/common/src/db/crud/SyncStatus.ts b/packages/common/src/db/crud/SyncStatus.ts index 1356ab51d..446643f9f 100644 --- a/packages/common/src/db/crud/SyncStatus.ts +++ b/packages/common/src/db/crud/SyncStatus.ts @@ -1,3 +1,5 @@ +import { InternalProgressInformation, SyncProgress } from "./SyncProgress.js"; + export type SyncDataFlowStatus = Partial<{ downloading: boolean; uploading: boolean; @@ -12,6 +14,12 @@ export type SyncDataFlowStatus = Partial<{ * Cleared on the next successful upload. */ uploadError?: Error; + /** + * Internal information about how far we are downloading operations in buckets. + * + * Please use the {@link SyncStatus#downloadProgress} property to track sync progress. + */ + downloadProgress: InternalProgressInformation, }>; export interface SyncPriorityStatus { @@ -85,6 +93,21 @@ export class SyncStatus { return (this.options.priorityStatusEntries ?? []).slice().sort(SyncStatus.comparePriorities); } + /** + * A realtime progress report on how many operations have been downloaded and + * how many are necessary in total to complete the next sync iteration. + * + * This field is only set when {@link SyncDataFlowStatus#downloading} is also true. + */ + get downloadProgress(): SyncProgress | null { + const internalProgress = this.options.dataFlow?.downloadProgress; + if (internalProgress == null) { + return null; + } + + return new SyncProgress(internalProgress); + } + /** * Reports a pair of {@link SyncStatus#hasSynced} and {@link SyncStatus#lastSyncedAt} fields that apply * to a specific bucket priority instead of the entire sync operation. diff --git a/packages/common/src/index.ts b/packages/common/src/index.ts index 99497d151..b90fac71b 100644 --- a/packages/common/src/index.ts +++ b/packages/common/src/index.ts @@ -19,6 +19,7 @@ export * from './client/sync/stream/AbstractStreamingSyncImplementation.js'; export * from './client/sync/stream/streaming-sync-types.js'; export { MAX_OP_ID } from './client/constants.js'; +export { ProgressWithOperations, SyncProgress } from './db/crud/SyncProgress.js'; export * from './db/crud/SyncStatus.js'; export * from './db/crud/UploadQueueStatus.js'; export * from './db/schema/Schema.js'; From 51541c912b28a99997d3f251aba5a0522b904afb Mon Sep 17 00:00:00 2001 From: Simon Binder Date: Mon, 31 Mar 2025 16:45:37 +0200 Subject: [PATCH 02/16] Track progress for sync lines --- .../sync/bucket/BucketStorageAdapter.ts | 6 ++ .../client/sync/bucket/SqliteBucketStorage.ts | 17 +++++- .../AbstractStreamingSyncImplementation.ts | 55 +++++++++++++++++-- packages/common/src/db/crud/SyncProgress.ts | 3 +- packages/common/src/db/crud/SyncStatus.ts | 2 +- 5 files changed, 76 insertions(+), 7 deletions(-) diff --git a/packages/common/src/client/sync/bucket/BucketStorageAdapter.ts b/packages/common/src/client/sync/bucket/BucketStorageAdapter.ts index df31253e2..1cfcc603c 100644 --- a/packages/common/src/client/sync/bucket/BucketStorageAdapter.ts +++ b/packages/common/src/client/sync/bucket/BucketStorageAdapter.ts @@ -30,6 +30,11 @@ export interface SyncLocalDatabaseResult { checkpointFailures?: string[]; } +export type BucketOperationProgress = Record; + export interface BucketChecksum { bucket: string; priority?: number; @@ -65,6 +70,7 @@ export interface BucketStorageAdapter extends BaseObserver; + getBucketOperationProgress(): Promise; syncLocalDatabase( checkpoint: Checkpoint, diff --git a/packages/common/src/client/sync/bucket/SqliteBucketStorage.ts b/packages/common/src/client/sync/bucket/SqliteBucketStorage.ts index 2dab15fd5..7acb24cf1 100644 --- a/packages/common/src/client/sync/bucket/SqliteBucketStorage.ts +++ b/packages/common/src/client/sync/bucket/SqliteBucketStorage.ts @@ -5,6 +5,7 @@ import { BaseObserver } from '../../../utils/BaseObserver.js'; import { MAX_OP_ID } from '../../constants.js'; import { BucketChecksum, + BucketOperationProgress, BucketState, BucketStorageAdapter, BucketStorageListener, @@ -91,6 +92,11 @@ export class SqliteBucketStorage extends BaseObserver imp return result; } + async getBucketOperationProgress(): Promise { + const rows = await this.db.getAll<{name: string, count_at_last: number, count_since_last: number}>("SELECT name, count_at_last, count_since_last FROM ps_buckets"); + return Object.fromEntries(rows.map((r) => [r.name, {atLast: r.count_at_last, sinceLast: r.count_since_last}])); + } + async saveSyncData(batch: SyncDataBatch) { await this.writeTransaction(async (tx) => { let count = 0; @@ -199,7 +205,16 @@ export class SqliteBucketStorage extends BaseObserver imp 'sync_local', arg ]); - return result == 1; + if (result == 1) { + if (priority == null) { + const bucketToCount = Object.fromEntries(checkpoint.buckets.map((b) => [b.bucket, b.count])); + await tx.execute('UPDATE ps_buckets SET count_since_last = 0, count_at_last = ?1->name WHERE ?1->name IS NOT NULL', [JSON.stringify(bucketToCount)]); + } + + return true; + } else { + return false; + } }); } diff --git a/packages/common/src/client/sync/stream/AbstractStreamingSyncImplementation.ts b/packages/common/src/client/sync/stream/AbstractStreamingSyncImplementation.ts index 808ebc2c3..94488ac7b 100644 --- a/packages/common/src/client/sync/stream/AbstractStreamingSyncImplementation.ts +++ b/packages/common/src/client/sync/stream/AbstractStreamingSyncImplementation.ts @@ -20,6 +20,7 @@ import { isStreamingSyncData } from './streaming-sync-types.js'; import { DataStream } from 'src/utils/DataStream.js'; +import { InternalProgressInformation } from 'src/db/crud/SyncProgress.js'; export enum LockType { CRUD = 'crud', @@ -163,13 +164,14 @@ export abstract class AbstractStreamingSyncImplementation protected streamingSyncPromise?: Promise; syncStatus: SyncStatus; + private syncStatusOptions: SyncStatusOptions; triggerCrudUpload: () => void; constructor(options: AbstractStreamingSyncImplementationOptions) { super(); this.options = { ...DEFAULT_STREAMING_SYNC_OPTIONS, ...options }; - this.syncStatus = new SyncStatus({ + this.syncStatusOptions = { connected: false, connecting: false, lastSyncedAt: undefined, @@ -177,7 +179,8 @@ export abstract class AbstractStreamingSyncImplementation uploading: false, downloading: false } - }); + }; + this.syncStatus = new SyncStatus(this.syncStatusOptions); this.abortController = null; this.triggerCrudUpload = throttleLeadingTrailing(() => { @@ -417,7 +420,8 @@ The next upload iteration will be delayed.`); connected: false, connecting: false, dataFlow: { - downloading: false + downloading: false, + downloadProgress: null, } }); }); @@ -581,6 +585,7 @@ The next upload iteration will be delayed.`); bucketMap = newBuckets; await this.options.adapter.removeBuckets([...bucketsToDelete]); await this.options.adapter.setTargetCheckpoint(targetCheckpoint); + await this.updateSyncStatusForStartingCheckpoint(targetCheckpoint); } else if (isStreamingSyncCheckpointComplete(line)) { this.logger.debug('Checkpoint complete', targetCheckpoint); const result = await this.options.adapter.syncLocalDatabase(targetCheckpoint!); @@ -601,6 +606,7 @@ The next upload iteration will be delayed.`); lastSyncedAt: new Date(), dataFlow: { downloading: false, + downloadProgress: null, downloadError: undefined } }); @@ -658,6 +664,7 @@ The next upload iteration will be delayed.`); write_checkpoint: diff.write_checkpoint }; targetCheckpoint = newCheckpoint; + await this.updateSyncStatusForStartingCheckpoint(targetCheckpoint); bucketMap = new Map(); newBuckets.forEach((checksum, name) => @@ -675,9 +682,23 @@ The next upload iteration will be delayed.`); await this.options.adapter.setTargetCheckpoint(targetCheckpoint); } else if (isStreamingSyncData(line)) { const { data } = line; + const previousProgress = this.syncStatusOptions.dataFlow?.downloadProgress; + let updatedProgress: InternalProgressInformation | null = null; + if (previousProgress) { + updatedProgress = {...previousProgress}; + const progressForBucket = updatedProgress[data.bucket]; + if (progressForBucket) { + updatedProgress[data.bucket] = { + ...progressForBucket, + sinceLast: progressForBucket.sinceLast + data.data.length, + }; + } + } + this.updateSyncStatus({ dataFlow: { - downloading: true + downloading: true, + downloadProgress: updatedProgress, } }); await this.options.adapter.saveSyncData({ buckets: [SyncDataBucket.fromRow(data)] }); @@ -724,6 +745,7 @@ The next upload iteration will be delayed.`); priorityStatusEntries: [], dataFlow: { downloading: false, + downloadProgress: null, downloadError: undefined } }); @@ -738,6 +760,30 @@ The next upload iteration will be delayed.`); }); } + private async updateSyncStatusForStartingCheckpoint(checkpoint: Checkpoint) { + const localProgress = await this.options.adapter.getBucketOperationProgress(); + const progress: InternalProgressInformation = {}; + + for (const bucket of checkpoint.buckets) { + const savedProgress = localProgress[bucket.bucket]; + progress[bucket.bucket] = { + // The fallback priority doesn't matter here, but 3 is the one newer versions of the sync service + // will use by default. + priority: bucket.priority ?? 3, + atLast: savedProgress?.atLast ?? 0, + sinceLast: savedProgress.sinceLast ?? 0, + targetCount: bucket.count ?? 0, + }; + } + + this.updateSyncStatus({ + dataFlow: { + downloading: true, + downloadProgress: progress, + } + }); + } + protected updateSyncStatus(options: SyncStatusOptions) { const updatedStatus = new SyncStatus({ connected: options.connected ?? this.syncStatus.connected, @@ -751,6 +797,7 @@ The next upload iteration will be delayed.`); }); if (!this.syncStatus.isEqual(updatedStatus)) { + this.syncStatusOptions = options; this.syncStatus = updatedStatus; // Only trigger this is there was a change this.iterateListeners((cb) => cb.statusChanged?.(updatedStatus)); diff --git a/packages/common/src/db/crud/SyncProgress.ts b/packages/common/src/db/crud/SyncProgress.ts index d48e1a0aa..b6a3f1266 100644 --- a/packages/common/src/db/crud/SyncProgress.ts +++ b/packages/common/src/db/crud/SyncProgress.ts @@ -1,6 +1,7 @@ import type { SyncStatus } from "./SyncStatus.js"; // (bucket, progress) pairs +/** @internal */ export type InternalProgressInformation = Record; /** - * The priority used by the core extension to indicate that a full sync was completed. + * @internal The priority used by the core extension to indicate that a full sync was completed. */ export const FULL_SYNC_PRIORITY = 2147483647; diff --git a/packages/common/src/db/crud/SyncStatus.ts b/packages/common/src/db/crud/SyncStatus.ts index 446643f9f..520ac74d5 100644 --- a/packages/common/src/db/crud/SyncStatus.ts +++ b/packages/common/src/db/crud/SyncStatus.ts @@ -19,7 +19,7 @@ export type SyncDataFlowStatus = Partial<{ * * Please use the {@link SyncStatus#downloadProgress} property to track sync progress. */ - downloadProgress: InternalProgressInformation, + downloadProgress: InternalProgressInformation | null, }>; export interface SyncPriorityStatus { From 49bf3bffb3e9c6de5fafabe79fc5178d853c12ec Mon Sep 17 00:00:00 2001 From: Simon Binder Date: Tue, 1 Apr 2025 13:26:37 +0200 Subject: [PATCH 03/16] Try testing sync with mock fetch --- .../src/client/AbstractPowerSyncDatabase.ts | 2 +- packages/node/package.json | 3 +- packages/node/src/db/PowerSyncDatabase.ts | 14 +- packages/node/src/sync/stream/NodeRemote.ts | 2 +- packages/node/tests/PowerSyncDatabase.test.ts | 1 - packages/node/tests/sync.test.ts | 102 ++ packages/node/tests/utils.ts | 109 +- pnpm-lock.yaml | 1171 +++++++++-------- 8 files changed, 848 insertions(+), 556 deletions(-) create mode 100644 packages/node/tests/sync.test.ts diff --git a/packages/common/src/client/AbstractPowerSyncDatabase.ts b/packages/common/src/client/AbstractPowerSyncDatabase.ts index 712d65584..cba08536c 100644 --- a/packages/common/src/client/AbstractPowerSyncDatabase.ts +++ b/packages/common/src/client/AbstractPowerSyncDatabase.ts @@ -32,7 +32,7 @@ import { type PowerSyncConnectionOptions, type RequiredAdditionalConnectionOptions } from './sync/stream/AbstractStreamingSyncImplementation.js'; -import { FULL_SYNC_PRIORITY } from 'src/db/crud/SyncProgress.js'; +import { FULL_SYNC_PRIORITY } from '../db/crud/SyncProgress.js'; export interface DisconnectAndClearOptions { /** When set to false, data in local-only tables is preserved. */ diff --git a/packages/node/package.json b/packages/node/package.json index 2dce56b8d..683379bfe 100644 --- a/packages/node/package.json +++ b/packages/node/package.json @@ -54,9 +54,10 @@ "comlink": "^4.4.2" }, "devDependencies": { + "@powersync/drizzle-driver": "workspace:*", "@types/async-lock": "^1.4.0", "drizzle-orm": "^0.35.2", - "@powersync/drizzle-driver": "workspace:*", + "fetch-mock": "^12.5.2", "rollup": "4.14.3", "typescript": "^5.5.3", "vitest": "^3.0.5" diff --git a/packages/node/src/db/PowerSyncDatabase.ts b/packages/node/src/db/PowerSyncDatabase.ts index 48c5b5fcb..3dd0f90d1 100644 --- a/packages/node/src/db/PowerSyncDatabase.ts +++ b/packages/node/src/db/PowerSyncDatabase.ts @@ -1,8 +1,10 @@ import { AbstractPowerSyncDatabase, + AbstractRemoteOptions, AbstractStreamingSyncImplementation, BucketStorageAdapter, DBAdapter, + DEFAULT_REMOTE_LOGGER, PowerSyncBackendConnector, PowerSyncDatabaseOptions, PowerSyncDatabaseOptionsWithSettings, @@ -18,6 +20,12 @@ import { NodeSQLOpenOptions } from './options.js'; export type NodePowerSyncDatabaseOptions = PowerSyncDatabaseOptions & { database: DBAdapter | SQLOpenFactory | NodeSQLOpenOptions; + /** + * Options to override how the SDK will connect to the sync service. + * + * This option is intended to be used for internal tests. + */ + remoteOptions?: Partial, }; /** @@ -57,7 +65,11 @@ export class PowerSyncDatabase extends AbstractPowerSyncDatabase { protected generateSyncStreamImplementation( connector: PowerSyncBackendConnector ): AbstractStreamingSyncImplementation { - const remote = new NodeRemote(connector); + const remote = new NodeRemote( + connector, + DEFAULT_REMOTE_LOGGER, + (this.options as NodePowerSyncDatabaseOptions).remoteOptions, + ); return new NodeStreamingSyncImplementation({ adapter: this.bucketStorageAdapter, diff --git a/packages/node/src/sync/stream/NodeRemote.ts b/packages/node/src/sync/stream/NodeRemote.ts index b0c147484..54af8c5b0 100644 --- a/packages/node/src/sync/stream/NodeRemote.ts +++ b/packages/node/src/sync/stream/NodeRemote.ts @@ -28,8 +28,8 @@ export class NodeRemote extends AbstractRemote { options?: Partial ) { super(connector, logger, { + fetchImplementation: options?.fetchImplementation ?? new NodeFetchProvider(), ...(options ?? {}), - fetchImplementation: options?.fetchImplementation ?? new NodeFetchProvider() }); } diff --git a/packages/node/tests/PowerSyncDatabase.test.ts b/packages/node/tests/PowerSyncDatabase.test.ts index 992864f26..4f7f71a2f 100644 --- a/packages/node/tests/PowerSyncDatabase.test.ts +++ b/packages/node/tests/PowerSyncDatabase.test.ts @@ -1,5 +1,4 @@ import * as path from 'node:path'; -import * as fs from 'node:fs/promises'; import { Worker } from 'node:worker_threads'; import { vi, expect, test } from 'vitest'; diff --git a/packages/node/tests/sync.test.ts b/packages/node/tests/sync.test.ts new file mode 100644 index 000000000..a03be8b58 --- /dev/null +++ b/packages/node/tests/sync.test.ts @@ -0,0 +1,102 @@ +import { describe, vi, expect, beforeEach } from 'vitest'; + +import { connectedDatabaseTest, MockSyncService, TestConnector, waitForSyncStatus } from "./utils"; +import { AbstractPowerSyncDatabase, BucketChecksum, OplogEntryJSON } from '@powersync/common'; + +describe('Sync', () => { + describe('reports progress', () => { + let lastOpId = 0; + + beforeEach(() => { + lastOpId = 0; + }); + + function pushDataLine(service: MockSyncService, bucket: string, amount: number) { + const data: OplogEntryJSON[] = []; + for (let i = 0; i < amount; i++) { + data.push({ + op_id: `${++lastOpId}`, + op: 'PUT', + object_type: bucket, + object_id: `${lastOpId}`, + checksum: 0, + data: '{}', + }); + } + + service.pushLine({data: { + bucket, + data, + }}); + } + + function pushCheckpointComplete(service: MockSyncService, priority?: number) { + if (priority != null) { + service.pushLine({ + partial_checkpoint_complete: { + last_op_id: `${lastOpId}`, + priority, + }, + }); + } else { + service.pushLine({ + checkpoint_complete: { + last_op_id: `${lastOpId}`, + }, + }); + } + } + + connectedDatabaseTest('without priorities', async ({database, syncService}) => { + await database.connect(new TestConnector()); + await vi.waitFor(() => expect(syncService.connectedListeners).toBe(1)); + + syncService.pushLine({checkpoint: { + last_op_id: '10', + buckets: [bucket('a', 10)] + }}); + + await waitForProgress(database, [0, 10]); + + pushDataLine(syncService, 'a', 10); + await waitForProgress(database, [10, 10]); + + pushCheckpointComplete(syncService); + await waitForSyncStatus(database, (s) => s.downloadProgress == null); + + // Emit new data, progress should be 0/2 instead of 10/12 + syncService.pushLine({checkpoint_diff: { + last_op_id: '12', + updated_buckets: [bucket('a', 12)], + removed_buckets: [], + write_checkpoint: '', + }}); + await waitForProgress(database, [0, 2]); + pushDataLine(syncService, 'a', 2); + await waitForProgress(database, [2, 2]); + pushCheckpointComplete(syncService); + await waitForSyncStatus(database, (s) => s.downloadProgress == null); + }); + }); +}); + +function bucket(name: string, count: number, priority: number = 3): BucketChecksum { + return { + bucket: name, + count, + checksum: 0, + priority, + }; +} + +async function waitForProgress(database: AbstractPowerSyncDatabase, total: [number, number]) { + await waitForSyncStatus(database, (status) => { + const progress = status.downloadProgress; + if (!progress) { + return false; + } + + const untilCompletion = progress.untilCompletion; + return untilCompletion.completed == total[0] && untilCompletion.total == total[1]; + }); +} diff --git a/packages/node/tests/utils.ts b/packages/node/tests/utils.ts index bd4eb1951..adf6b95df 100644 --- a/packages/node/tests/utils.ts +++ b/packages/node/tests/utils.ts @@ -1,8 +1,9 @@ import os from 'node:os'; import fs from 'node:fs/promises'; import path from 'node:path'; +import { defaultFetchMockConfig, FetchMock } from 'fetch-mock'; import { test } from 'vitest'; -import { column, PowerSyncDatabase, Schema, Table } from '../lib'; +import { AbstractPowerSyncDatabase, AbstractRemoteOptions, column, NodePowerSyncDatabaseOptions, PowerSyncBackendConnector, PowerSyncCredentials, PowerSyncDatabase, Schema, StreamingSyncLine, SyncStatus, Table } from '../lib'; export async function createTempDir() { const ostmpdir = os.tmpdir(); @@ -37,9 +38,10 @@ export const tempDirectoryTest = test.extend<{ tmpdir: string }>({ } }); -export const databaseTest = tempDirectoryTest.extend<{ database: PowerSyncDatabase }>({ - database: async ({ tmpdir }, use) => { +function createDatabaseFixture(options: Partial = {}) { + return async ({ tmpdir }, use) => { const database = new PowerSyncDatabase({ + ...options, schema: AppSchema, database: { dbFilename: 'test.db', @@ -47,5 +49,104 @@ export const databaseTest = tempDirectoryTest.extend<{ database: PowerSyncDataba } }); await use(database); - } + await database.close(); + }; +} + +export const databaseTest = tempDirectoryTest.extend<{ database: PowerSyncDatabase }>({ + database: async ({tmpdir}, use) => { + await createDatabaseFixture()({tmpdir}, use); + }, +}); + +// TODO: Unify this with the test setup for the web SDK. +export const mockSyncServiceTest = tempDirectoryTest.extend<{syncService: MockSyncService}>({ + syncService: async ({}, use) => { + // Don't install global fetch mocks, we want tests to be isolated! + const fetchMock = new FetchMock(defaultFetchMockConfig); + const listeners: ReadableStreamDefaultController[] = []; + + fetchMock.route('path:/sync/stream', async () => { + let thisController: ReadableStreamDefaultController | null = null; + + const syncLines = new ReadableStream({ + start(controller) { + thisController = controller; + listeners.push(controller); + }, + cancel() { + listeners.splice(listeners.indexOf(thisController!), 1); + }, + }); + + + const encoder = new TextEncoder(); + const asLines = new TransformStream({ + transform: (chunk, controller) => { + const line = `${JSON.stringify(chunk)}\n`; + controller.enqueue(encoder.encode(line)); + }, + }); + + return new Response(syncLines.pipeThrough(asLines), {status: 200}); + }); + fetchMock.catch(404); + + await use({ + clientOptions: { + fetchImplementation: fetchMock.fetchHandler.bind(fetchMock), + }, + get connectedListeners() { + return listeners.length; + }, + pushLine(line) { + for (const listener of listeners) { + listener.enqueue(line); + } + }, + }); + }, +}); + +export const connectedDatabaseTest = mockSyncServiceTest.extend<{ database: PowerSyncDatabase }>({ + database: async ({ tmpdir, syncService }, use) => { + const fixture = createDatabaseFixture({remoteOptions: syncService.clientOptions}); + await fixture({ tmpdir }, use); + }, }); + +export interface MockSyncService { + clientOptions: Partial, + pushLine: (line: StreamingSyncLine) => void, + connectedListeners: number, +} + +export class TestConnector implements PowerSyncBackendConnector { + async fetchCredentials(): Promise { + return { + endpoint: '', + token: '' + }; + } + async uploadData(database: AbstractPowerSyncDatabase): Promise { + const tx = await database.getNextCrudTransaction(); + await tx?.complete(); + } +} + +export function waitForSyncStatus(database: AbstractPowerSyncDatabase, matcher: (status: SyncStatus) => boolean): Promise { + return new Promise((resolve) => { + if (matcher(database.currentStatus)) { + return resolve(); + } + + const dispose = database.registerListener({ + statusChanged: (status) => { + if (matcher(status)) { + dispose(); + resolve(); + } + } + }); + }); +} diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index e58f73733..77dde2a7a 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -19,7 +19,7 @@ importers: version: 4.0.11(@pnpm/logger@5.2.0) '@vitest/browser': specifier: ^3.0.8 - version: 3.0.8(@testing-library/dom@10.4.0)(@types/node@22.7.4)(playwright@1.51.0)(typescript@5.7.2)(vite@6.2.3(@types/node@22.7.4)(less@4.2.2)(lightningcss@1.28.2)(sass@1.85.0)(terser@5.39.0))(vitest@3.0.8)(webdriverio@9.8.0) + version: 3.0.8(@testing-library/dom@10.4.0)(@types/node@22.7.4)(playwright@1.51.0)(typescript@5.7.2)(vite@6.2.3(@types/node@22.7.4)(jiti@1.21.6)(less@4.2.2)(lightningcss@1.28.2)(sass@1.85.0)(terser@5.39.0)(tsx@4.19.3)(yaml@2.6.1))(vitest@3.0.8)(webdriverio@9.8.0) husky: specifier: ^9.0.11 version: 9.1.6 @@ -89,10 +89,10 @@ importers: devDependencies: '@angular-builders/custom-webpack': specifier: ^19.0.0 - version: 19.0.0(@angular/compiler-cli@19.2.4(@angular/compiler@19.2.4)(typescript@5.5.4))(@angular/compiler@19.2.4)(@angular/service-worker@19.2.4(@angular/core@19.2.4(rxjs@7.8.1)(zone.js@0.15.0))(rxjs@7.8.1))(@rspack/core@1.1.8)(@swc/core@1.10.1)(@types/node@22.7.4)(chokidar@4.0.1)(html-webpack-plugin@5.6.0(@rspack/core@1.1.8)(webpack@5.98.0(@swc/core@1.10.1)))(jiti@1.21.6)(lightningcss@1.28.2)(tailwindcss@3.4.13)(tsx@4.19.3)(typescript@5.5.4)(vite@6.2.3(@types/node@22.7.4)(jiti@1.21.6)(less@4.2.2)(lightningcss@1.28.2)(sass@1.85.0)(terser@5.39.0)(tsx@4.19.3)(yaml@2.6.1))(yaml@2.6.1) + version: 19.0.0(@angular/compiler-cli@19.2.4(@angular/compiler@19.2.4)(typescript@5.5.4))(@angular/compiler@19.2.4)(@angular/service-worker@19.2.4(@angular/core@19.2.4(rxjs@7.8.1)(zone.js@0.15.0))(rxjs@7.8.1))(@rspack/core@1.1.8(@swc/helpers@0.5.5))(@swc/core@1.10.1(@swc/helpers@0.5.5))(@types/node@22.7.4)(chokidar@4.0.1)(html-webpack-plugin@5.6.0(@rspack/core@1.1.8(@swc/helpers@0.5.5))(webpack@5.98.0(@swc/core@1.10.1(@swc/helpers@0.5.5))))(jiti@1.21.6)(lightningcss@1.28.2)(tailwindcss@3.4.13(ts-node@10.9.2(@swc/core@1.10.1(@swc/helpers@0.5.5))(@types/node@22.7.4)(typescript@5.5.4)))(tsx@4.19.3)(typescript@5.5.4)(vite@6.2.3(@types/node@22.7.4)(jiti@1.21.6)(less@4.2.2)(lightningcss@1.28.2)(sass@1.85.0)(terser@5.39.0)(tsx@4.19.3)(yaml@2.6.1))(yaml@2.6.1) '@angular-devkit/build-angular': specifier: ^19.2.5 - version: 19.2.5(@angular/compiler-cli@19.2.4(@angular/compiler@19.2.4)(typescript@5.5.4))(@angular/compiler@19.2.4)(@angular/service-worker@19.2.4(@angular/core@19.2.4(rxjs@7.8.1)(zone.js@0.15.0))(rxjs@7.8.1))(@rspack/core@1.1.8)(@swc/core@1.10.1)(@types/node@22.7.4)(chokidar@4.0.1)(html-webpack-plugin@5.6.0(@rspack/core@1.1.8)(webpack@5.98.0(@swc/core@1.10.1)))(jiti@1.21.6)(lightningcss@1.28.2)(tailwindcss@3.4.13)(tsx@4.19.3)(typescript@5.5.4)(vite@6.2.3(@types/node@22.7.4)(jiti@1.21.6)(less@4.2.2)(lightningcss@1.28.2)(sass@1.85.0)(terser@5.39.0)(tsx@4.19.3)(yaml@2.6.1))(yaml@2.6.1) + version: 19.2.5(@angular/compiler-cli@19.2.4(@angular/compiler@19.2.4)(typescript@5.5.4))(@angular/compiler@19.2.4)(@angular/service-worker@19.2.4(@angular/core@19.2.4(rxjs@7.8.1)(zone.js@0.15.0))(rxjs@7.8.1))(@rspack/core@1.1.8(@swc/helpers@0.5.5))(@swc/core@1.10.1(@swc/helpers@0.5.5))(@types/node@22.7.4)(chokidar@4.0.1)(html-webpack-plugin@5.6.0(@rspack/core@1.1.8(@swc/helpers@0.5.5))(webpack@5.98.0(@swc/core@1.10.1(@swc/helpers@0.5.5))))(jiti@1.21.6)(lightningcss@1.28.2)(tailwindcss@3.4.13(ts-node@10.9.2(@swc/core@1.10.1(@swc/helpers@0.5.5))(@types/node@22.7.4)(typescript@5.5.4)))(tsx@4.19.3)(typescript@5.5.4)(vite@6.2.3(@types/node@22.7.4)(jiti@1.21.6)(less@4.2.2)(lightningcss@1.28.2)(sass@1.85.0)(terser@5.39.0)(tsx@4.19.3)(yaml@2.6.1))(yaml@2.6.1) '@angular/cli': specifier: ^19.2.5 version: 19.2.5(@types/node@22.7.4)(chokidar@4.0.1) @@ -137,7 +137,7 @@ importers: version: 0.1.11(react-native@0.74.5(@babel/core@7.26.10)(@babel/preset-env@7.25.7(@babel/core@7.26.10))(@types/react@18.2.79)(encoding@0.1.13)(react@18.2.0))(react@18.2.0) '@react-navigation/drawer': specifier: ^6.6.15 - version: 6.7.2(l2wxk4fvyl3ebgrlaryoia2mpm) + version: 6.7.2(8a892ff6c949d4273486936ff7d0b326) '@react-navigation/native': specifier: ^6.1.17 version: 6.1.18(react-native@0.74.5(@babel/core@7.26.10)(@babel/preset-env@7.25.7(@babel/core@7.26.10))(@types/react@18.2.79)(encoding@0.1.13)(react@18.2.0))(react@18.2.0) @@ -161,7 +161,7 @@ importers: version: 1.11.3 expo-router: specifier: 3.5.21 - version: 3.5.21(itxjk4e5lx4jky57qutbl2llka) + version: 3.5.21(861b7493f2d52858e88dcfa7bffd38c4) expo-splash-screen: specifier: ~0.27.4 version: 0.27.6(encoding@0.1.13)(expo-modules-autolinking@1.11.3)(expo@51.0.27(@babel/core@7.26.10)(@babel/preset-env@7.25.7(@babel/core@7.26.10))(encoding@0.1.13)) @@ -215,7 +215,7 @@ importers: version: 10.2.0 react-navigation-stack: specifier: ^2.10.4 - version: 2.10.4(qmdtutm2q5vv2bqwrj2rmb5zum) + version: 2.10.4(723df46775cc6e8dbfaef5bf48d4f911) typed-async-storage: specifier: ^3.1.2 version: 3.1.2 @@ -450,16 +450,16 @@ importers: version: 7.7.0 '@electron-forge/plugin-webpack': specifier: ^7.7.0 - version: 7.7.0(@rspack/core@1.1.8)(@swc/core@1.10.1) + version: 7.7.0(@rspack/core@1.1.8(@swc/helpers@0.5.5))(@swc/core@1.10.1(@swc/helpers@0.5.5)) '@vercel/webpack-asset-relocator-loader': specifier: 1.7.3 version: 1.7.3 copy-webpack-plugin: specifier: ^13.0.0 - version: 13.0.0(webpack@5.95.0(@swc/core@1.10.1)) + version: 13.0.0(webpack@5.95.0(@swc/core@1.10.1(@swc/helpers@0.5.5))) css-loader: specifier: ^6.11.0 - version: 6.11.0(@rspack/core@1.1.8)(webpack@5.95.0(@swc/core@1.10.1)) + version: 6.11.0(@rspack/core@1.1.8(@swc/helpers@0.5.5))(webpack@5.95.0(@swc/core@1.10.1(@swc/helpers@0.5.5))) dotenv: specifier: ^16.4.7 version: 16.4.7 @@ -471,19 +471,19 @@ importers: version: 3.2.9 fork-ts-checker-webpack-plugin: specifier: ^9.0.2 - version: 9.0.2(typescript@5.8.2)(webpack@5.95.0(@swc/core@1.10.1)) + version: 9.0.2(typescript@5.8.2)(webpack@5.95.0(@swc/core@1.10.1(@swc/helpers@0.5.5))) node-loader: specifier: ^2.1.0 - version: 2.1.0(webpack@5.95.0(@swc/core@1.10.1)) + version: 2.1.0(webpack@5.95.0(@swc/core@1.10.1(@swc/helpers@0.5.5))) style-loader: specifier: ^3.3.4 - version: 3.3.4(webpack@5.95.0(@swc/core@1.10.1)) + version: 3.3.4(webpack@5.95.0(@swc/core@1.10.1(@swc/helpers@0.5.5))) ts-loader: specifier: ^9.5.2 - version: 9.5.2(typescript@5.8.2)(webpack@5.95.0(@swc/core@1.10.1)) + version: 9.5.2(typescript@5.8.2)(webpack@5.95.0(@swc/core@1.10.1(@swc/helpers@0.5.5))) ts-node: specifier: ^10.9.2 - version: 10.9.2(@swc/core@1.10.1)(@types/node@22.7.4)(typescript@5.8.2) + version: 10.9.2(@swc/core@1.10.1(@swc/helpers@0.5.5))(@types/node@22.7.4)(typescript@5.8.2) tsx: specifier: ^4.19.3 version: 4.19.3 @@ -492,7 +492,7 @@ importers: version: 5.8.2 webpack: specifier: ^5.90.1 - version: 5.95.0(@swc/core@1.10.1) + version: 5.95.0(@swc/core@1.10.1(@swc/helpers@0.5.5)) demos/example-nextjs: dependencies: @@ -556,10 +556,10 @@ importers: version: 10.4.20(postcss@8.4.47) babel-loader: specifier: ^9.1.3 - version: 9.2.1(@babel/core@7.26.10)(webpack@5.98.0) + version: 9.2.1(@babel/core@7.26.10)(webpack@5.98.0(@swc/core@1.10.1(@swc/helpers@0.5.5))) css-loader: specifier: ^6.11.0 - version: 6.11.0(@rspack/core@1.1.8)(webpack@5.98.0) + version: 6.11.0(@rspack/core@1.1.8(@swc/helpers@0.5.5))(webpack@5.98.0(@swc/core@1.10.1(@swc/helpers@0.5.5))) eslint: specifier: ^8.57.0 version: 8.57.1 @@ -574,13 +574,13 @@ importers: version: 1.79.4 sass-loader: specifier: ^13.3.3 - version: 13.3.3(sass@1.79.4)(webpack@5.98.0) + version: 13.3.3(sass@1.79.4)(webpack@5.98.0(@swc/core@1.10.1(@swc/helpers@0.5.5))) style-loader: specifier: ^3.3.4 - version: 3.3.4(webpack@5.98.0) + version: 3.3.4(webpack@5.98.0(@swc/core@1.10.1(@swc/helpers@0.5.5))) tailwindcss: specifier: ^3.4.3 - version: 3.4.13(ts-node@10.9.2(@types/node@20.16.10)(typescript@5.8.2)) + version: 3.4.13(ts-node@10.9.2(@swc/core@1.10.1(@swc/helpers@0.5.5))(@types/node@20.16.10)(typescript@5.8.2)) demos/example-node: dependencies: @@ -593,7 +593,7 @@ importers: devDependencies: ts-node: specifier: ^10.9.2 - version: 10.9.2(@swc/core@1.10.1)(@types/node@22.7.4)(typescript@5.8.2) + version: 10.9.2(@swc/core@1.10.1(@swc/helpers@0.5.5))(@types/node@22.7.4)(typescript@5.8.2) typescript: specifier: ^5.8.2 version: 5.8.2 @@ -644,10 +644,10 @@ importers: devDependencies: '@types/webpack': specifier: ^5.28.5 - version: 5.28.5(webpack-cli@5.1.4(webpack@5.95.0)) + version: 5.28.5(webpack-cli@5.1.4) html-webpack-plugin: specifier: ^5.6.0 - version: 5.6.0(@rspack/core@1.1.8)(webpack@5.95.0(webpack-cli@5.1.4)) + version: 5.6.0(@rspack/core@1.1.8(@swc/helpers@0.5.5))(webpack@5.95.0) serve: specifier: ^14.2.1 version: 14.2.3 @@ -874,7 +874,7 @@ importers: version: 6.3.1(expo@51.0.27(@babel/core@7.24.5)(@babel/preset-env@7.26.9(@babel/core@7.24.5))(encoding@0.1.13)) expo-router: specifier: ^3.5.15 - version: 3.5.21(gc6ebsds2rxeucccxhmqtwmlpi) + version: 3.5.21(c189db6b79bdaefc0f767c4cd94a478a) expo-splash-screen: specifier: ~0.27.4 version: 0.27.6(encoding@0.1.13)(expo-modules-autolinking@1.11.1)(expo@51.0.27(@babel/core@7.24.5)(@babel/preset-env@7.26.9(@babel/core@7.24.5))(encoding@0.1.13)) @@ -929,7 +929,7 @@ importers: version: 18.3.11 eas-cli: specifier: ^7.2.0 - version: 7.8.5(@swc/core@1.10.1)(@types/node@22.7.4)(encoding@0.1.13)(expo-modules-autolinking@1.11.1)(typescript@5.3.3) + version: 7.8.5(@swc/core@1.10.1(@swc/helpers@0.5.5))(@types/node@22.7.4)(encoding@0.1.13)(expo-modules-autolinking@1.11.1)(typescript@5.3.3) eslint: specifier: 8.55.0 version: 8.55.0 @@ -971,7 +971,7 @@ importers: version: 0.1.11(react-native@0.74.5(@babel/core@7.24.5)(@babel/preset-env@7.25.7(@babel/core@7.24.5))(@types/react@18.2.79)(encoding@0.1.13)(react@18.2.0))(react@18.2.0) '@react-navigation/drawer': specifier: ^6.6.3 - version: 6.7.2(f5uupuoecme7pb3346nlwm73my) + version: 6.7.2(fe8cd8328c484d4e3eaed8eea351852b) '@react-navigation/native': specifier: ^6.0.0 version: 6.1.18(react-native@0.74.5(@babel/core@7.24.5)(@babel/preset-env@7.25.7(@babel/core@7.24.5))(@types/react@18.2.79)(encoding@0.1.13)(react@18.2.0))(react@18.2.0) @@ -1010,7 +1010,7 @@ importers: version: 6.3.1(expo@51.0.37(@babel/core@7.24.5)(@babel/preset-env@7.25.7(@babel/core@7.24.5))(encoding@0.1.13)) expo-router: specifier: 3.5.23 - version: 3.5.23(x45f6tg66eoafhyrv4brrngbdm) + version: 3.5.23(2f86f7434a59b644ba234fab7be01c9e) expo-secure-store: specifier: ~13.0.1 version: 13.0.2(expo@51.0.37(@babel/core@7.24.5)(@babel/preset-env@7.25.7(@babel/core@7.24.5))(encoding@0.1.13)) @@ -1058,7 +1058,7 @@ importers: version: 3.31.1(react-native@0.74.5(@babel/core@7.24.5)(@babel/preset-env@7.25.7(@babel/core@7.24.5))(@types/react@18.2.79)(encoding@0.1.13)(react@18.2.0))(react@18.2.0) react-navigation-stack: specifier: ^2.10.4 - version: 2.10.4(b23yjknfeew5kcy4o5zrlfz5ae) + version: 2.10.4(cf0911ea264205029347060226fe0d29) devDependencies: '@babel/core': specifier: ^7.24.5 @@ -1122,7 +1122,7 @@ importers: version: 0.1.11(react-native@0.74.5(@babel/core@7.24.5)(@babel/preset-env@7.25.7(@babel/core@7.24.5))(@types/react@18.2.79)(encoding@0.1.13)(react@18.2.0))(react@18.2.0) '@react-navigation/drawer': specifier: ^6.6.3 - version: 6.7.2(f5uupuoecme7pb3346nlwm73my) + version: 6.7.2(fe8cd8328c484d4e3eaed8eea351852b) '@react-navigation/native': specifier: ^6.0.0 version: 6.1.18(react-native@0.74.5(@babel/core@7.24.5)(@babel/preset-env@7.25.7(@babel/core@7.24.5))(@types/react@18.2.79)(encoding@0.1.13)(react@18.2.0))(react@18.2.0) @@ -1155,7 +1155,7 @@ importers: version: 6.3.1(expo@51.0.27(@babel/core@7.24.5)(@babel/preset-env@7.25.7(@babel/core@7.24.5))(encoding@0.1.13)) expo-router: specifier: 3.5.21 - version: 3.5.21(qrxjjyxvihi5xb6jovt7bb6fjy) + version: 3.5.21(43cc03a7fb538f7aef105856925492f6) expo-secure-store: specifier: ~13.0.1 version: 13.0.2(expo@51.0.27(@babel/core@7.24.5)(@babel/preset-env@7.25.7(@babel/core@7.24.5))(encoding@0.1.13)) @@ -1215,7 +1215,7 @@ importers: version: 0.19.12(encoding@0.1.13)(react-dom@18.2.0(react@18.2.0))(react@18.2.0) react-navigation-stack: specifier: ^2.10.4 - version: 2.10.4(b23yjknfeew5kcy4o5zrlfz5ae) + version: 2.10.4(cf0911ea264205029347060226fe0d29) devDependencies: '@babel/core': specifier: ^7.24.5 @@ -1751,7 +1751,7 @@ importers: version: 20.17.6 drizzle-orm: specifier: ^0.35.2 - version: 0.35.2(@op-engineering/op-sqlite@11.4.8(react@18.3.1))(@types/better-sqlite3@7.6.12)(@types/react@18.3.18)(better-sqlite3@11.7.2)(kysely@0.27.4)(react@18.3.1) + version: 0.35.2(@op-engineering/op-sqlite@11.4.8(react-native@0.77.0(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@react-native-community/cli-server-api@15.1.3)(@types/react@18.3.18)(react@18.3.1))(react@18.3.1))(@types/better-sqlite3@7.6.12)(@types/react@18.3.18)(better-sqlite3@11.7.2)(kysely@0.27.4)(react@18.3.1) vite: specifier: ^6.1.0 version: 6.1.0(@types/node@20.17.6)(jiti@1.21.6)(less@4.2.2)(lightningcss@1.28.2)(sass@1.85.0)(terser@5.39.0)(tsx@4.19.3)(yaml@2.6.1) @@ -1816,7 +1816,10 @@ importers: version: 1.4.2 drizzle-orm: specifier: ^0.35.2 - version: 0.35.2(@op-engineering/op-sqlite@11.4.8(react@18.3.1))(@types/better-sqlite3@7.6.12)(@types/react@18.3.18)(better-sqlite3@11.7.2)(kysely@0.27.4)(react@18.3.1) + version: 0.35.2(@op-engineering/op-sqlite@11.4.8(react-native@0.77.0(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@react-native-community/cli-server-api@15.1.3)(@types/react@18.3.18)(react@18.3.1))(react@18.3.1))(@types/better-sqlite3@7.6.12)(@types/react@18.3.18)(better-sqlite3@11.7.2)(kysely@0.27.4)(react@18.3.1) + fetch-mock: + specifier: ^12.5.2 + version: 12.5.2 rollup: specifier: 4.14.3 version: 4.14.3 @@ -2036,13 +2039,13 @@ importers: version: 4.0.1 source-map-loader: specifier: ^5.0.0 - version: 5.0.0(webpack@5.95.0(webpack-cli@5.1.4)) + version: 5.0.0(webpack@5.95.0) stream-browserify: specifier: ^3.0.0 version: 3.0.0 terser-webpack-plugin: specifier: ^5.3.9 - version: 5.3.10(webpack@5.95.0(webpack-cli@5.1.4)) + version: 5.3.10(webpack@5.95.0) uuid: specifier: ^9.0.1 version: 9.0.1 @@ -9023,6 +9026,9 @@ packages: '@types/fs-extra@9.0.13': resolution: {integrity: sha512-nEnwB++1u5lVDM2UI4c1+5R+FYaKfaAzS4OococimjVm3nQw3TuzH5UNsocrcTBbhnerblyHj4A49qXbIiZdpA==} + '@types/glob-to-regexp@0.4.4': + resolution: {integrity: sha512-nDKoaKJYbnn1MZxUY0cA1bPmmgZbg0cTq7Rh13d0KWYNOiKbqoR+2d89SnRPszGh7ROzSwZ/GOjZ4jPbmmZ6Eg==} + '@types/glob@7.2.0': resolution: {integrity: sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==} @@ -12718,6 +12724,10 @@ packages: resolution: {integrity: sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==} engines: {node: ^12.20 || >= 14.13} + fetch-mock@12.5.2: + resolution: {integrity: sha512-b5KGDFmdmado2MPQjZl6ix3dAG3iwCitb0XQwN72y2s9VnWZ3ObaGNy+bkpm1390foiLDybdJ7yjRGKD36kATw==} + engines: {node: '>=18.11.0'} + fetch-retry@4.1.1: resolution: {integrity: sha512-e6eB7zN6UBSwGVwrbWVH+gdLnkW9WwHhmq2YDK1Sh30pzx1onRVGBvogTlUeWxwTa+L86NYdo4hFkh7O8ZjSnA==} @@ -17686,6 +17696,10 @@ packages: resolution: {integrity: sha512-vqlC04+RQoFalODCbCumG2xIOvapzVMHwsyIGM/SIE8fRhFFsXeH8/QQ+s0T0kDAhKc4k30s73/0ydkHQz6HlQ==} engines: {node: '>= 0.4'} + regexparam@3.0.0: + resolution: {integrity: sha512-RSYAtP31mvYLkAHrOlh25pCNQ5hWnT106VukGaaFfuJrZFkGRX5GhUAdPqpSDXxOhA2c4akmRuplv1mRqnBn6Q==} + engines: {node: '>=8'} + regexpp@3.2.0: resolution: {integrity: sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==} engines: {node: '>=8'} @@ -20679,10 +20693,10 @@ snapshots: '@jridgewell/gen-mapping': 0.3.5 '@jridgewell/trace-mapping': 0.3.25 - '@angular-builders/common@3.0.0(@swc/core@1.10.1)(@types/node@22.7.4)(chokidar@4.0.1)(typescript@5.5.4)': + '@angular-builders/common@3.0.0(@swc/core@1.10.1(@swc/helpers@0.5.5))(@types/node@22.7.4)(chokidar@4.0.1)(typescript@5.5.4)': dependencies: '@angular-devkit/core': 19.2.5(chokidar@4.0.1) - ts-node: 10.9.2(@swc/core@1.10.1)(@types/node@22.7.4)(typescript@5.5.4) + ts-node: 10.9.2(@swc/core@1.10.1(@swc/helpers@0.5.5))(@types/node@22.7.4)(typescript@5.5.4) tsconfig-paths: 4.2.0 transitivePeerDependencies: - '@swc/core' @@ -20691,11 +20705,11 @@ snapshots: - chokidar - typescript - '@angular-builders/custom-webpack@19.0.0(@angular/compiler-cli@19.2.4(@angular/compiler@19.2.4)(typescript@5.5.4))(@angular/compiler@19.2.4)(@angular/service-worker@19.2.4(@angular/core@19.2.4(rxjs@7.8.1)(zone.js@0.15.0))(rxjs@7.8.1))(@rspack/core@1.1.8)(@swc/core@1.10.1)(@types/node@22.7.4)(chokidar@4.0.1)(html-webpack-plugin@5.6.0(@rspack/core@1.1.8)(webpack@5.98.0(@swc/core@1.10.1)))(jiti@1.21.6)(lightningcss@1.28.2)(tailwindcss@3.4.13)(tsx@4.19.3)(typescript@5.5.4)(vite@6.2.3(@types/node@22.7.4)(jiti@1.21.6)(less@4.2.2)(lightningcss@1.28.2)(sass@1.85.0)(terser@5.39.0)(tsx@4.19.3)(yaml@2.6.1))(yaml@2.6.1)': + '@angular-builders/custom-webpack@19.0.0(@angular/compiler-cli@19.2.4(@angular/compiler@19.2.4)(typescript@5.5.4))(@angular/compiler@19.2.4)(@angular/service-worker@19.2.4(@angular/core@19.2.4(rxjs@7.8.1)(zone.js@0.15.0))(rxjs@7.8.1))(@rspack/core@1.1.8(@swc/helpers@0.5.5))(@swc/core@1.10.1(@swc/helpers@0.5.5))(@types/node@22.7.4)(chokidar@4.0.1)(html-webpack-plugin@5.6.0(@rspack/core@1.1.8(@swc/helpers@0.5.5))(webpack@5.98.0(@swc/core@1.10.1(@swc/helpers@0.5.5))))(jiti@1.21.6)(lightningcss@1.28.2)(tailwindcss@3.4.13(ts-node@10.9.2(@swc/core@1.10.1(@swc/helpers@0.5.5))(@types/node@22.7.4)(typescript@5.5.4)))(tsx@4.19.3)(typescript@5.5.4)(vite@6.2.3(@types/node@22.7.4)(jiti@1.21.6)(less@4.2.2)(lightningcss@1.28.2)(sass@1.85.0)(terser@5.39.0)(tsx@4.19.3)(yaml@2.6.1))(yaml@2.6.1)': dependencies: - '@angular-builders/common': 3.0.0(@swc/core@1.10.1)(@types/node@22.7.4)(chokidar@4.0.1)(typescript@5.5.4) + '@angular-builders/common': 3.0.0(@swc/core@1.10.1(@swc/helpers@0.5.5))(@types/node@22.7.4)(chokidar@4.0.1)(typescript@5.5.4) '@angular-devkit/architect': 0.1902.5(chokidar@4.0.1) - '@angular-devkit/build-angular': 19.2.5(@angular/compiler-cli@19.2.4(@angular/compiler@19.2.4)(typescript@5.5.4))(@angular/compiler@19.2.4)(@angular/service-worker@19.2.4(@angular/core@19.2.4(rxjs@7.8.1)(zone.js@0.15.0))(rxjs@7.8.1))(@rspack/core@1.1.8)(@swc/core@1.10.1)(@types/node@22.7.4)(chokidar@4.0.1)(html-webpack-plugin@5.6.0(@rspack/core@1.1.8)(webpack@5.98.0(@swc/core@1.10.1)))(jiti@1.21.6)(lightningcss@1.28.2)(tailwindcss@3.4.13)(tsx@4.19.3)(typescript@5.5.4)(vite@6.2.3(@types/node@22.7.4)(jiti@1.21.6)(less@4.2.2)(lightningcss@1.28.2)(sass@1.85.0)(terser@5.39.0)(tsx@4.19.3)(yaml@2.6.1))(yaml@2.6.1) + '@angular-devkit/build-angular': 19.2.5(@angular/compiler-cli@19.2.4(@angular/compiler@19.2.4)(typescript@5.5.4))(@angular/compiler@19.2.4)(@angular/service-worker@19.2.4(@angular/core@19.2.4(rxjs@7.8.1)(zone.js@0.15.0))(rxjs@7.8.1))(@rspack/core@1.1.8(@swc/helpers@0.5.5))(@swc/core@1.10.1(@swc/helpers@0.5.5))(@types/node@22.7.4)(chokidar@4.0.1)(html-webpack-plugin@5.6.0(@rspack/core@1.1.8(@swc/helpers@0.5.5))(webpack@5.98.0(@swc/core@1.10.1(@swc/helpers@0.5.5))))(jiti@1.21.6)(lightningcss@1.28.2)(tailwindcss@3.4.13(ts-node@10.9.2(@swc/core@1.10.1(@swc/helpers@0.5.5))(@types/node@22.7.4)(typescript@5.5.4)))(tsx@4.19.3)(typescript@5.5.4)(vite@6.2.3(@types/node@22.7.4)(jiti@1.21.6)(less@4.2.2)(lightningcss@1.28.2)(sass@1.85.0)(terser@5.39.0)(tsx@4.19.3)(yaml@2.6.1))(yaml@2.6.1) '@angular-devkit/core': 19.2.5(chokidar@4.0.1) '@angular/compiler-cli': 19.2.4(@angular/compiler@19.2.4)(typescript@5.5.4) lodash: 4.17.21 @@ -20744,13 +20758,13 @@ snapshots: transitivePeerDependencies: - chokidar - '@angular-devkit/build-angular@19.2.5(@angular/compiler-cli@19.2.4(@angular/compiler@19.2.4)(typescript@5.5.4))(@angular/compiler@19.2.4)(@angular/service-worker@19.2.4(@angular/core@19.2.4(rxjs@7.8.1)(zone.js@0.15.0))(rxjs@7.8.1))(@rspack/core@1.1.8)(@swc/core@1.10.1)(@types/node@22.7.4)(chokidar@4.0.1)(html-webpack-plugin@5.6.0(@rspack/core@1.1.8)(webpack@5.98.0(@swc/core@1.10.1)))(jiti@1.21.6)(lightningcss@1.28.2)(tailwindcss@3.4.13)(tsx@4.19.3)(typescript@5.5.4)(vite@6.2.3(@types/node@22.7.4)(jiti@1.21.6)(less@4.2.2)(lightningcss@1.28.2)(sass@1.85.0)(terser@5.39.0)(tsx@4.19.3)(yaml@2.6.1))(yaml@2.6.1)': + '@angular-devkit/build-angular@19.2.5(@angular/compiler-cli@19.2.4(@angular/compiler@19.2.4)(typescript@5.5.4))(@angular/compiler@19.2.4)(@angular/service-worker@19.2.4(@angular/core@19.2.4(rxjs@7.8.1)(zone.js@0.15.0))(rxjs@7.8.1))(@rspack/core@1.1.8(@swc/helpers@0.5.5))(@swc/core@1.10.1(@swc/helpers@0.5.5))(@types/node@22.7.4)(chokidar@4.0.1)(html-webpack-plugin@5.6.0(@rspack/core@1.1.8(@swc/helpers@0.5.5))(webpack@5.98.0(@swc/core@1.10.1(@swc/helpers@0.5.5))))(jiti@1.21.6)(lightningcss@1.28.2)(tailwindcss@3.4.13(ts-node@10.9.2(@swc/core@1.10.1(@swc/helpers@0.5.5))(@types/node@22.7.4)(typescript@5.5.4)))(tsx@4.19.3)(typescript@5.5.4)(vite@6.2.3(@types/node@22.7.4)(jiti@1.21.6)(less@4.2.2)(lightningcss@1.28.2)(sass@1.85.0)(terser@5.39.0)(tsx@4.19.3)(yaml@2.6.1))(yaml@2.6.1)': dependencies: '@ampproject/remapping': 2.3.0 '@angular-devkit/architect': 0.1902.5(chokidar@4.0.1) - '@angular-devkit/build-webpack': 0.1902.5(chokidar@4.0.1)(webpack-dev-server@5.2.0(webpack@5.98.0(@swc/core@1.10.1)(esbuild@0.25.1)))(webpack@5.98.0(@swc/core@1.10.1)(esbuild@0.25.1)) + '@angular-devkit/build-webpack': 0.1902.5(chokidar@4.0.1)(webpack-dev-server@5.2.0(webpack@5.98.0(@swc/core@1.10.1(@swc/helpers@0.5.5))))(webpack@5.98.0(@swc/core@1.10.1(@swc/helpers@0.5.5))) '@angular-devkit/core': 19.2.5(chokidar@4.0.1) - '@angular/build': 19.2.5(@angular/compiler-cli@19.2.4(@angular/compiler@19.2.4)(typescript@5.5.4))(@angular/compiler@19.2.4)(@angular/service-worker@19.2.4(@angular/core@19.2.4(rxjs@7.8.1)(zone.js@0.15.0))(rxjs@7.8.1))(@types/node@22.7.4)(chokidar@4.0.1)(jiti@1.21.6)(less@4.2.2)(lightningcss@1.28.2)(postcss@8.5.2)(tailwindcss@3.4.13)(terser@5.39.0)(tsx@4.19.3)(typescript@5.5.4)(yaml@2.6.1) + '@angular/build': 19.2.5(@angular/compiler-cli@19.2.4(@angular/compiler@19.2.4)(typescript@5.5.4))(@angular/compiler@19.2.4)(@angular/service-worker@19.2.4(@angular/core@19.2.4(rxjs@7.8.1)(zone.js@0.15.0))(rxjs@7.8.1))(@types/node@22.7.4)(chokidar@4.0.1)(jiti@1.21.6)(less@4.2.2)(lightningcss@1.28.2)(postcss@8.5.2)(tailwindcss@3.4.13(ts-node@10.9.2(@swc/core@1.10.1(@swc/helpers@0.5.5))(@types/node@22.7.4)(typescript@5.5.4)))(terser@5.39.0)(tsx@4.19.3)(typescript@5.5.4)(yaml@2.6.1) '@angular/compiler-cli': 19.2.4(@angular/compiler@19.2.4)(typescript@5.5.4) '@babel/core': 7.26.10 '@babel/generator': 7.26.10 @@ -20762,14 +20776,14 @@ snapshots: '@babel/preset-env': 7.26.9(@babel/core@7.26.10) '@babel/runtime': 7.26.10 '@discoveryjs/json-ext': 0.6.3 - '@ngtools/webpack': 19.2.5(@angular/compiler-cli@19.2.4(@angular/compiler@19.2.4)(typescript@5.5.4))(typescript@5.5.4)(webpack@5.98.0(@swc/core@1.10.1)(esbuild@0.25.1)) + '@ngtools/webpack': 19.2.5(@angular/compiler-cli@19.2.4(@angular/compiler@19.2.4)(typescript@5.5.4))(typescript@5.5.4)(webpack@5.98.0(@swc/core@1.10.1(@swc/helpers@0.5.5))) '@vitejs/plugin-basic-ssl': 1.2.0(vite@6.2.3(@types/node@22.7.4)(jiti@1.21.6)(less@4.2.2)(lightningcss@1.28.2)(sass@1.85.0)(terser@5.39.0)(tsx@4.19.3)(yaml@2.6.1)) ansi-colors: 4.1.3 autoprefixer: 10.4.20(postcss@8.5.2) - babel-loader: 9.2.1(@babel/core@7.26.10)(webpack@5.98.0(@swc/core@1.10.1)(esbuild@0.25.1)) + babel-loader: 9.2.1(@babel/core@7.26.10)(webpack@5.98.0(@swc/core@1.10.1(@swc/helpers@0.5.5))) browserslist: 4.24.4 - copy-webpack-plugin: 12.0.2(webpack@5.98.0(@swc/core@1.10.1)(esbuild@0.25.1)) - css-loader: 7.1.2(@rspack/core@1.1.8)(webpack@5.98.0(@swc/core@1.10.1)(esbuild@0.25.1)) + copy-webpack-plugin: 12.0.2(webpack@5.98.0(@swc/core@1.10.1(@swc/helpers@0.5.5))) + css-loader: 7.1.2(@rspack/core@1.1.8(@swc/helpers@0.5.5))(webpack@5.98.0(@swc/core@1.10.1(@swc/helpers@0.5.5))) esbuild-wasm: 0.25.1 fast-glob: 3.3.3 http-proxy-middleware: 3.0.3 @@ -20777,36 +20791,36 @@ snapshots: jsonc-parser: 3.3.1 karma-source-map-support: 1.4.0 less: 4.2.2 - less-loader: 12.2.0(@rspack/core@1.1.8)(less@4.2.2)(webpack@5.98.0(@swc/core@1.10.1)(esbuild@0.25.1)) - license-webpack-plugin: 4.0.2(webpack@5.98.0(@swc/core@1.10.1)(esbuild@0.25.1)) + less-loader: 12.2.0(@rspack/core@1.1.8(@swc/helpers@0.5.5))(less@4.2.2)(webpack@5.98.0(@swc/core@1.10.1(@swc/helpers@0.5.5))) + license-webpack-plugin: 4.0.2(webpack@5.98.0(@swc/core@1.10.1(@swc/helpers@0.5.5))) loader-utils: 3.3.1 - mini-css-extract-plugin: 2.9.2(webpack@5.98.0(@swc/core@1.10.1)(esbuild@0.25.1)) + mini-css-extract-plugin: 2.9.2(webpack@5.98.0(@swc/core@1.10.1(@swc/helpers@0.5.5))) open: 10.1.0 ora: 5.4.1 picomatch: 4.0.2 piscina: 4.8.0 postcss: 8.5.2 - postcss-loader: 8.1.1(@rspack/core@1.1.8)(postcss@8.5.2)(typescript@5.5.4)(webpack@5.98.0(@swc/core@1.10.1)(esbuild@0.25.1)) + postcss-loader: 8.1.1(@rspack/core@1.1.8(@swc/helpers@0.5.5))(postcss@8.5.2)(typescript@5.5.4)(webpack@5.98.0(@swc/core@1.10.1(@swc/helpers@0.5.5))) resolve-url-loader: 5.0.0 rxjs: 7.8.1 sass: 1.85.0 - sass-loader: 16.0.5(@rspack/core@1.1.8)(sass@1.85.0)(webpack@5.98.0(@swc/core@1.10.1)(esbuild@0.25.1)) + sass-loader: 16.0.5(@rspack/core@1.1.8(@swc/helpers@0.5.5))(sass@1.85.0)(webpack@5.98.0(@swc/core@1.10.1(@swc/helpers@0.5.5))) semver: 7.7.1 - source-map-loader: 5.0.0(webpack@5.98.0(@swc/core@1.10.1)(esbuild@0.25.1)) + source-map-loader: 5.0.0(webpack@5.98.0(@swc/core@1.10.1(@swc/helpers@0.5.5))) source-map-support: 0.5.21 terser: 5.39.0 tree-kill: 1.2.2 tslib: 2.8.1 typescript: 5.5.4 - webpack: 5.98.0(@swc/core@1.10.1)(esbuild@0.25.1) - webpack-dev-middleware: 7.4.2(webpack@5.98.0(@swc/core@1.10.1)(esbuild@0.25.1)) - webpack-dev-server: 5.2.0(webpack@5.98.0(@swc/core@1.10.1)(esbuild@0.25.1)) + webpack: 5.98.0(@swc/core@1.10.1(@swc/helpers@0.5.5))(esbuild@0.25.1) + webpack-dev-middleware: 7.4.2(webpack@5.98.0(@swc/core@1.10.1(@swc/helpers@0.5.5))) + webpack-dev-server: 5.2.0(webpack@5.98.0(@swc/core@1.10.1(@swc/helpers@0.5.5))) webpack-merge: 6.0.1 - webpack-subresource-integrity: 5.1.0(html-webpack-plugin@5.6.0(@rspack/core@1.1.8)(webpack@5.98.0(@swc/core@1.10.1)))(webpack@5.98.0(@swc/core@1.10.1)(esbuild@0.25.1)) + webpack-subresource-integrity: 5.1.0(html-webpack-plugin@5.6.0(@rspack/core@1.1.8(@swc/helpers@0.5.5))(webpack@5.98.0(@swc/core@1.10.1(@swc/helpers@0.5.5))))(webpack@5.98.0(@swc/core@1.10.1(@swc/helpers@0.5.5))) optionalDependencies: '@angular/service-worker': 19.2.4(@angular/core@19.2.4(rxjs@7.8.1)(zone.js@0.15.0))(rxjs@7.8.1) esbuild: 0.25.1 - tailwindcss: 3.4.13(ts-node@10.9.2(@types/node@20.16.10)(typescript@5.8.2)) + tailwindcss: 3.4.13(ts-node@10.9.2(@swc/core@1.10.1(@swc/helpers@0.5.5))(@types/node@22.7.4)(typescript@5.5.4)) transitivePeerDependencies: - '@angular/compiler' - '@rspack/core' @@ -20830,12 +20844,12 @@ snapshots: - webpack-cli - yaml - '@angular-devkit/build-webpack@0.1902.5(chokidar@4.0.1)(webpack-dev-server@5.2.0(webpack@5.98.0(@swc/core@1.10.1)(esbuild@0.25.1)))(webpack@5.98.0(@swc/core@1.10.1)(esbuild@0.25.1))': + '@angular-devkit/build-webpack@0.1902.5(chokidar@4.0.1)(webpack-dev-server@5.2.0(webpack@5.98.0(@swc/core@1.10.1(@swc/helpers@0.5.5))))(webpack@5.98.0(@swc/core@1.10.1(@swc/helpers@0.5.5)))': dependencies: '@angular-devkit/architect': 0.1902.5(chokidar@4.0.1) rxjs: 7.8.1 - webpack: 5.98.0(@swc/core@1.10.1)(esbuild@0.25.1) - webpack-dev-server: 5.2.0(webpack@5.98.0(@swc/core@1.10.1)(esbuild@0.25.1)) + webpack: 5.98.0(@swc/core@1.10.1(@swc/helpers@0.5.5))(esbuild@0.25.1) + webpack-dev-server: 5.2.0(webpack@5.98.0(@swc/core@1.10.1(@swc/helpers@0.5.5))) transitivePeerDependencies: - chokidar @@ -20865,7 +20879,7 @@ snapshots: '@angular/core': 19.2.4(rxjs@7.8.1)(zone.js@0.15.0) tslib: 2.7.0 - '@angular/build@19.2.5(@angular/compiler-cli@19.2.4(@angular/compiler@19.2.4)(typescript@5.5.4))(@angular/compiler@19.2.4)(@angular/service-worker@19.2.4(@angular/core@19.2.4(rxjs@7.8.1)(zone.js@0.15.0))(rxjs@7.8.1))(@types/node@22.7.4)(chokidar@4.0.1)(jiti@1.21.6)(less@4.2.2)(lightningcss@1.28.2)(postcss@8.5.2)(tailwindcss@3.4.13)(terser@5.39.0)(tsx@4.19.3)(typescript@5.5.4)(yaml@2.6.1)': + '@angular/build@19.2.5(@angular/compiler-cli@19.2.4(@angular/compiler@19.2.4)(typescript@5.5.4))(@angular/compiler@19.2.4)(@angular/service-worker@19.2.4(@angular/core@19.2.4(rxjs@7.8.1)(zone.js@0.15.0))(rxjs@7.8.1))(@types/node@22.7.4)(chokidar@4.0.1)(jiti@1.21.6)(less@4.2.2)(lightningcss@1.28.2)(postcss@8.5.2)(tailwindcss@3.4.13(ts-node@10.9.2(@swc/core@1.10.1(@swc/helpers@0.5.5))(@types/node@22.7.4)(typescript@5.5.4)))(terser@5.39.0)(tsx@4.19.3)(typescript@5.5.4)(yaml@2.6.1)': dependencies: '@ampproject/remapping': 2.3.0 '@angular-devkit/architect': 0.1902.5(chokidar@4.0.1) @@ -20901,7 +20915,7 @@ snapshots: less: 4.2.2 lmdb: 3.2.6 postcss: 8.5.2 - tailwindcss: 3.4.13(ts-node@10.9.2(@types/node@20.16.10)(typescript@5.8.2)) + tailwindcss: 3.4.13(ts-node@10.9.2(@swc/core@1.10.1(@swc/helpers@0.5.5))(@types/node@22.7.4)(typescript@5.5.4)) transitivePeerDependencies: - '@types/node' - chokidar @@ -23391,6 +23405,18 @@ snapshots: transitivePeerDependencies: - supports-color + '@babel/plugin-transform-runtime@7.26.10(@babel/core@7.24.5)': + dependencies: + '@babel/core': 7.24.5 + '@babel/helper-module-imports': 7.25.9 + '@babel/helper-plugin-utils': 7.26.5 + babel-plugin-polyfill-corejs2: 0.4.11(@babel/core@7.24.5) + babel-plugin-polyfill-corejs3: 0.11.1(@babel/core@7.24.5) + babel-plugin-polyfill-regenerator: 0.6.2(@babel/core@7.24.5) + semver: 6.3.1 + transitivePeerDependencies: + - supports-color + '@babel/plugin-transform-runtime@7.26.10(@babel/core@7.26.10)': dependencies: '@babel/core': 7.26.10 @@ -24751,7 +24777,7 @@ snapshots: update-notifier: 6.0.2 webpack: 5.95.0(@swc/core@1.10.1(@swc/helpers@0.5.5)) webpack-bundle-analyzer: 4.10.2 - webpack-dev-server: 4.15.2(webpack@5.95.0(@swc/core@1.10.1(@swc/helpers@0.5.5))) + webpack-dev-server: 4.15.2(debug@4.4.0)(webpack@5.95.0(@swc/core@1.10.1(@swc/helpers@0.5.5))) webpack-merge: 6.0.1 transitivePeerDependencies: - '@docusaurus/faster' @@ -24774,10 +24800,10 @@ snapshots: '@docusaurus/cssnano-preset@3.7.0': dependencies: - cssnano-preset-advanced: 6.1.2(postcss@8.5.1) - postcss: 8.5.1 - postcss-sort-media-queries: 5.2.0(postcss@8.5.1) - tslib: 2.7.0 + cssnano-preset-advanced: 6.1.2(postcss@8.5.3) + postcss: 8.5.3 + postcss-sort-media-queries: 5.2.0(postcss@8.5.3) + tslib: 2.8.1 '@docusaurus/faster@3.7.0(@docusaurus/types@3.7.0(@swc/core@1.10.1(@swc/helpers@0.5.5))(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(@swc/helpers@0.5.5)': dependencies: @@ -25601,7 +25627,7 @@ snapshots: - supports-color - utf-8-validate - '@electron-forge/plugin-webpack@7.7.0(@rspack/core@1.1.8)(@swc/core@1.10.1)': + '@electron-forge/plugin-webpack@7.7.0(@rspack/core@1.1.8(@swc/helpers@0.5.5))(@swc/core@1.10.1(@swc/helpers@0.5.5))': dependencies: '@electron-forge/core-utils': 7.7.0 '@electron-forge/plugin-base': 7.7.0 @@ -25611,10 +25637,10 @@ snapshots: debug: 4.4.0(supports-color@8.1.1) fast-glob: 3.3.2 fs-extra: 10.1.0 - html-webpack-plugin: 5.6.0(@rspack/core@1.1.8)(webpack@5.95.0(@swc/core@1.10.1)) + html-webpack-plugin: 5.6.0(@rspack/core@1.1.8(@swc/helpers@0.5.5))(webpack@5.95.0(@swc/core@1.10.1(@swc/helpers@0.5.5))) listr2: 7.0.2 - webpack: 5.95.0(@swc/core@1.10.1) - webpack-dev-server: 4.15.2(debug@4.4.0)(webpack@5.95.0(@swc/core@1.10.1)) + webpack: 5.95.0(@swc/core@1.10.1(@swc/helpers@0.5.5)) + webpack-dev-server: 4.15.2(debug@4.4.0)(webpack@5.95.0(@swc/core@1.10.1(@swc/helpers@0.5.5))) webpack-merge: 5.10.0 transitivePeerDependencies: - '@rspack/core' @@ -26628,7 +26654,7 @@ snapshots: password-prompt: 1.1.3 sudo-prompt: 8.2.5 tmp: 0.0.33 - tslib: 2.7.0 + tslib: 2.8.1 transitivePeerDependencies: - supports-color @@ -26822,18 +26848,18 @@ snapshots: base64-js: 1.5.1 xmlbuilder: 14.0.0 - '@expo/plugin-help@5.1.23(@swc/core@1.10.1)(@types/node@22.7.4)(typescript@5.3.3)': + '@expo/plugin-help@5.1.23(@swc/core@1.10.1(@swc/helpers@0.5.5))(@types/node@22.7.4)(typescript@5.3.3)': dependencies: - '@oclif/core': 2.16.0(@swc/core@1.10.1)(@types/node@22.7.4)(typescript@5.3.3) + '@oclif/core': 2.16.0(@swc/core@1.10.1(@swc/helpers@0.5.5))(@types/node@22.7.4)(typescript@5.3.3) transitivePeerDependencies: - '@swc/core' - '@swc/wasm' - '@types/node' - typescript - '@expo/plugin-warn-if-update-available@2.5.1(@swc/core@1.10.1)(@types/node@22.7.4)(typescript@5.3.3)': + '@expo/plugin-warn-if-update-available@2.5.1(@swc/core@1.10.1(@swc/helpers@0.5.5))(@types/node@22.7.4)(typescript@5.3.3)': dependencies: - '@oclif/core': 2.16.0(@swc/core@1.10.1)(@types/node@22.7.4)(typescript@5.3.3) + '@oclif/core': 2.16.0(@swc/core@1.10.1(@swc/helpers@0.5.5))(@types/node@22.7.4)(typescript@5.3.3) chalk: 4.1.2 debug: 4.4.0(supports-color@8.1.1) ejs: 3.1.10 @@ -27297,7 +27323,7 @@ snapshots: '@ionic/utils-object@2.1.5': dependencies: debug: 4.4.0(supports-color@8.1.1) - tslib: 2.7.0 + tslib: 2.8.1 transitivePeerDependencies: - supports-color @@ -27822,7 +27848,7 @@ snapshots: '@motionone/easing': 10.18.0 '@motionone/types': 10.17.1 '@motionone/utils': 10.18.0 - tslib: 2.7.0 + tslib: 2.8.1 '@motionone/dom@10.12.0': dependencies: @@ -27831,18 +27857,18 @@ snapshots: '@motionone/types': 10.17.1 '@motionone/utils': 10.18.0 hey-listen: 1.0.8 - tslib: 2.7.0 + tslib: 2.8.1 '@motionone/easing@10.18.0': dependencies: '@motionone/utils': 10.18.0 - tslib: 2.7.0 + tslib: 2.8.1 '@motionone/generators@10.18.0': dependencies: '@motionone/types': 10.17.1 '@motionone/utils': 10.18.0 - tslib: 2.7.0 + tslib: 2.8.1 '@motionone/types@10.17.1': {} @@ -27850,7 +27876,7 @@ snapshots: dependencies: '@motionone/types': 10.17.1 hey-listen: 1.0.8 - tslib: 2.7.0 + tslib: 2.8.1 '@msgpackr-extract/msgpackr-extract-darwin-arm64@3.0.3': optional: true @@ -28147,11 +28173,11 @@ snapshots: '@next/swc-win32-x64-msvc@14.2.3': optional: true - '@ngtools/webpack@19.2.5(@angular/compiler-cli@19.2.4(@angular/compiler@19.2.4)(typescript@5.5.4))(typescript@5.5.4)(webpack@5.98.0(@swc/core@1.10.1)(esbuild@0.25.1))': + '@ngtools/webpack@19.2.5(@angular/compiler-cli@19.2.4(@angular/compiler@19.2.4)(typescript@5.5.4))(typescript@5.5.4)(webpack@5.98.0(@swc/core@1.10.1(@swc/helpers@0.5.5)))': dependencies: '@angular/compiler-cli': 19.2.4(@angular/compiler@19.2.4)(typescript@5.5.4) typescript: 5.5.4 - webpack: 5.98.0(@swc/core@1.10.1)(esbuild@0.25.1) + webpack: 5.98.0(@swc/core@1.10.1(@swc/helpers@0.5.5))(esbuild@0.25.1) '@nicolo-ribaudo/eslint-scope-5-internals@5.1.1-v1': dependencies: @@ -28173,9 +28199,9 @@ snapshots: '@npmcli/agent@3.0.0': dependencies: - agent-base: 7.1.1 + agent-base: 7.1.3 http-proxy-agent: 7.0.2 - https-proxy-agent: 7.0.5 + https-proxy-agent: 7.0.6 lru-cache: 10.4.3 socks-proxy-agent: 8.0.4 transitivePeerDependencies: @@ -28275,7 +28301,7 @@ snapshots: widest-line: 3.1.0 wrap-ansi: 7.0.0 - '@oclif/core@2.16.0(@swc/core@1.10.1)(@types/node@22.7.4)(typescript@5.3.3)': + '@oclif/core@2.16.0(@swc/core@1.10.1(@swc/helpers@0.5.5))(@types/node@22.7.4)(typescript@5.3.3)': dependencies: '@types/cli-progress': 3.11.6 ansi-escapes: 4.3.2 @@ -28300,8 +28326,8 @@ snapshots: strip-ansi: 6.0.1 supports-color: 8.1.1 supports-hyperlinks: 2.3.0 - ts-node: 10.9.2(@swc/core@1.10.1)(@types/node@22.7.4)(typescript@5.3.3) - tslib: 2.7.0 + ts-node: 10.9.2(@swc/core@1.10.1(@swc/helpers@0.5.5))(@types/node@22.7.4)(typescript@5.3.3) + tslib: 2.8.1 widest-line: 3.1.0 wordwrap: 1.0.0 wrap-ansi: 7.0.0 @@ -28313,9 +28339,9 @@ snapshots: '@oclif/linewrap@1.0.0': {} - '@oclif/plugin-autocomplete@2.3.10(@swc/core@1.10.1)(@types/node@22.7.4)(typescript@5.3.3)': + '@oclif/plugin-autocomplete@2.3.10(@swc/core@1.10.1(@swc/helpers@0.5.5))(@types/node@22.7.4)(typescript@5.3.3)': dependencies: - '@oclif/core': 2.16.0(@swc/core@1.10.1)(@types/node@22.7.4)(typescript@5.3.3) + '@oclif/core': 2.16.0(@swc/core@1.10.1(@swc/helpers@0.5.5))(@types/node@22.7.4)(typescript@5.3.3) chalk: 4.1.2 debug: 4.4.0(supports-color@8.1.1) transitivePeerDependencies: @@ -28764,7 +28790,7 @@ snapshots: '@react-native-community/cli-tools': 13.6.6(encoding@0.1.13) chalk: 4.1.2 execa: 5.1.1 - fast-glob: 3.3.2 + fast-glob: 3.3.3 transitivePeerDependencies: - encoding @@ -28773,7 +28799,7 @@ snapshots: '@react-native-community/cli-tools': 13.6.9(encoding@0.1.13) chalk: 4.1.2 execa: 5.1.1 - fast-glob: 3.3.2 + fast-glob: 3.3.3 transitivePeerDependencies: - encoding @@ -28782,7 +28808,7 @@ snapshots: '@react-native-community/cli-tools': 14.1.0 chalk: 4.1.2 execa: 5.1.1 - fast-glob: 3.3.2 + fast-glob: 3.3.3 '@react-native-community/cli-clean@15.1.3': dependencies: @@ -28803,7 +28829,7 @@ snapshots: '@react-native-community/cli-tools': 15.1.3 chalk: 4.1.2 execa: 5.1.1 - fast-glob: 3.3.2 + fast-glob: 3.3.3 '@react-native-community/cli-config@11.3.6(encoding@0.1.13)': dependencies: @@ -28822,7 +28848,7 @@ snapshots: chalk: 4.1.2 cosmiconfig: 5.2.1 deepmerge: 4.3.1 - fast-glob: 3.3.2 + fast-glob: 3.3.3 joi: 17.13.3 transitivePeerDependencies: - encoding @@ -28833,7 +28859,7 @@ snapshots: chalk: 4.1.2 cosmiconfig: 5.2.1 deepmerge: 4.3.1 - fast-glob: 3.3.2 + fast-glob: 3.3.3 joi: 17.13.3 transitivePeerDependencies: - encoding @@ -28844,7 +28870,7 @@ snapshots: chalk: 4.1.2 cosmiconfig: 9.0.0(typescript@5.8.2) deepmerge: 4.3.1 - fast-glob: 3.3.2 + fast-glob: 3.3.3 joi: 17.13.3 transitivePeerDependencies: - typescript @@ -29081,7 +29107,7 @@ snapshots: '@react-native-community/cli-tools': 13.6.6(encoding@0.1.13) chalk: 4.1.2 execa: 5.1.1 - fast-glob: 3.3.2 + fast-glob: 3.3.3 fast-xml-parser: 4.5.0 ora: 5.4.1 transitivePeerDependencies: @@ -29092,7 +29118,7 @@ snapshots: '@react-native-community/cli-tools': 13.6.9(encoding@0.1.13) chalk: 4.1.2 execa: 5.1.1 - fast-glob: 3.3.2 + fast-glob: 3.3.3 fast-xml-parser: 4.5.0 ora: 5.4.1 transitivePeerDependencies: @@ -29103,7 +29129,7 @@ snapshots: '@react-native-community/cli-tools': 14.1.0 chalk: 4.1.2 execa: 5.1.1 - fast-glob: 3.3.2 + fast-glob: 3.3.3 fast-xml-parser: 4.5.0 ora: 5.4.1 @@ -29572,7 +29598,7 @@ snapshots: '@babel/plugin-transform-react-jsx': 7.25.9(@babel/core@7.24.5) '@babel/plugin-transform-react-jsx-self': 7.25.7(@babel/core@7.24.5) '@babel/plugin-transform-react-jsx-source': 7.25.7(@babel/core@7.24.5) - '@babel/plugin-transform-runtime': 7.25.9(@babel/core@7.24.5) + '@babel/plugin-transform-runtime': 7.26.10(@babel/core@7.24.5) '@babel/plugin-transform-shorthand-properties': 7.25.9(@babel/core@7.24.5) '@babel/plugin-transform-spread': 7.25.9(@babel/core@7.24.5) '@babel/plugin-transform-sticky-regex': 7.25.9(@babel/core@7.24.5) @@ -29770,7 +29796,7 @@ snapshots: '@babel/plugin-transform-react-jsx-self': 7.25.7(@babel/core@7.26.10) '@babel/plugin-transform-react-jsx-source': 7.25.7(@babel/core@7.26.10) '@babel/plugin-transform-regenerator': 7.25.9(@babel/core@7.26.10) - '@babel/plugin-transform-runtime': 7.25.9(@babel/core@7.26.10) + '@babel/plugin-transform-runtime': 7.26.10(@babel/core@7.26.10) '@babel/plugin-transform-shorthand-properties': 7.25.9(@babel/core@7.26.10) '@babel/plugin-transform-spread': 7.25.9(@babel/core@7.26.10) '@babel/plugin-transform-sticky-regex': 7.25.9(@babel/core@7.26.10) @@ -30498,20 +30524,7 @@ snapshots: react-is: 16.13.1 use-latest-callback: 0.2.1(react@18.2.0) - '@react-navigation/drawer@6.7.2(f5uupuoecme7pb3346nlwm73my)': - dependencies: - '@react-navigation/elements': 1.3.31(@react-navigation/native@6.1.18(react-native@0.74.5(@babel/core@7.24.5)(@babel/preset-env@7.25.7(@babel/core@7.24.5))(@types/react@18.2.79)(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native-safe-area-context@4.10.5(react-native@0.74.5(@babel/core@7.24.5)(@babel/preset-env@7.25.7(@babel/core@7.24.5))(@types/react@18.2.79)(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native@0.74.5(@babel/core@7.24.5)(@babel/preset-env@7.25.7(@babel/core@7.24.5))(@types/react@18.2.79)(encoding@0.1.13)(react@18.2.0))(react@18.2.0) - '@react-navigation/native': 6.1.18(react-native@0.74.5(@babel/core@7.24.5)(@babel/preset-env@7.25.7(@babel/core@7.24.5))(@types/react@18.2.79)(encoding@0.1.13)(react@18.2.0))(react@18.2.0) - color: 4.2.3 - react: 18.2.0 - react-native: 0.74.5(@babel/core@7.24.5)(@babel/preset-env@7.25.7(@babel/core@7.24.5))(@types/react@18.2.79)(encoding@0.1.13)(react@18.2.0) - react-native-gesture-handler: 2.16.2(react-native@0.74.5(@babel/core@7.24.5)(@babel/preset-env@7.25.7(@babel/core@7.24.5))(@types/react@18.2.79)(encoding@0.1.13)(react@18.2.0))(react@18.2.0) - react-native-reanimated: 3.10.1(@babel/core@7.24.5)(react-native@0.74.5(@babel/core@7.24.5)(@babel/preset-env@7.25.7(@babel/core@7.24.5))(@types/react@18.2.79)(encoding@0.1.13)(react@18.2.0))(react@18.2.0) - react-native-safe-area-context: 4.10.5(react-native@0.74.5(@babel/core@7.24.5)(@babel/preset-env@7.25.7(@babel/core@7.24.5))(@types/react@18.2.79)(encoding@0.1.13)(react@18.2.0))(react@18.2.0) - react-native-screens: 3.31.1(react-native@0.74.5(@babel/core@7.24.5)(@babel/preset-env@7.25.7(@babel/core@7.24.5))(@types/react@18.2.79)(encoding@0.1.13)(react@18.2.0))(react@18.2.0) - warn-once: 0.1.1 - - '@react-navigation/drawer@6.7.2(ghvgknxqxtkf2snjzmu2bwsmre)': + '@react-navigation/drawer@6.7.2(3f3d461ed9a1c5b87bb0ca8ce18d5723)': dependencies: '@react-navigation/elements': 1.3.31(@react-navigation/native@6.1.18(react-native@0.74.1(@babel/core@7.24.5)(@babel/preset-env@7.26.9(@babel/core@7.24.5))(@types/react@18.3.11)(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native-safe-area-context@4.10.1(react-native@0.74.1(@babel/core@7.24.5)(@babel/preset-env@7.26.9(@babel/core@7.24.5))(@types/react@18.3.11)(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native@0.74.1(@babel/core@7.24.5)(@babel/preset-env@7.26.9(@babel/core@7.24.5))(@types/react@18.3.11)(encoding@0.1.13)(react@18.2.0))(react@18.2.0) '@react-navigation/native': 6.1.18(react-native@0.74.1(@babel/core@7.24.5)(@babel/preset-env@7.26.9(@babel/core@7.24.5))(@types/react@18.3.11)(encoding@0.1.13)(react@18.2.0))(react@18.2.0) @@ -30525,7 +30538,7 @@ snapshots: warn-once: 0.1.1 optional: true - '@react-navigation/drawer@6.7.2(l2wxk4fvyl3ebgrlaryoia2mpm)': + '@react-navigation/drawer@6.7.2(8a892ff6c949d4273486936ff7d0b326)': dependencies: '@react-navigation/elements': 1.3.31(@react-navigation/native@6.1.18(react-native@0.74.5(@babel/core@7.26.10)(@babel/preset-env@7.25.7(@babel/core@7.26.10))(@types/react@18.2.79)(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native-safe-area-context@4.10.5(react-native@0.74.5(@babel/core@7.26.10)(@babel/preset-env@7.25.7(@babel/core@7.26.10))(@types/react@18.2.79)(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native@0.74.5(@babel/core@7.26.10)(@babel/preset-env@7.25.7(@babel/core@7.26.10))(@types/react@18.2.79)(encoding@0.1.13)(react@18.2.0))(react@18.2.0) '@react-navigation/native': 6.1.18(react-native@0.74.5(@babel/core@7.26.10)(@babel/preset-env@7.25.7(@babel/core@7.26.10))(@types/react@18.2.79)(encoding@0.1.13)(react@18.2.0))(react@18.2.0) @@ -30538,6 +30551,19 @@ snapshots: react-native-screens: 3.31.1(react-native@0.74.5(@babel/core@7.26.10)(@babel/preset-env@7.25.7(@babel/core@7.26.10))(@types/react@18.2.79)(encoding@0.1.13)(react@18.2.0))(react@18.2.0) warn-once: 0.1.1 + '@react-navigation/drawer@6.7.2(fe8cd8328c484d4e3eaed8eea351852b)': + dependencies: + '@react-navigation/elements': 1.3.31(@react-navigation/native@6.1.18(react-native@0.74.5(@babel/core@7.24.5)(@babel/preset-env@7.25.7(@babel/core@7.24.5))(@types/react@18.2.79)(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native-safe-area-context@4.10.5(react-native@0.74.5(@babel/core@7.24.5)(@babel/preset-env@7.25.7(@babel/core@7.24.5))(@types/react@18.2.79)(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native@0.74.5(@babel/core@7.24.5)(@babel/preset-env@7.25.7(@babel/core@7.24.5))(@types/react@18.2.79)(encoding@0.1.13)(react@18.2.0))(react@18.2.0) + '@react-navigation/native': 6.1.18(react-native@0.74.5(@babel/core@7.24.5)(@babel/preset-env@7.25.7(@babel/core@7.24.5))(@types/react@18.2.79)(encoding@0.1.13)(react@18.2.0))(react@18.2.0) + color: 4.2.3 + react: 18.2.0 + react-native: 0.74.5(@babel/core@7.24.5)(@babel/preset-env@7.25.7(@babel/core@7.24.5))(@types/react@18.2.79)(encoding@0.1.13)(react@18.2.0) + react-native-gesture-handler: 2.16.2(react-native@0.74.5(@babel/core@7.24.5)(@babel/preset-env@7.25.7(@babel/core@7.24.5))(@types/react@18.2.79)(encoding@0.1.13)(react@18.2.0))(react@18.2.0) + react-native-reanimated: 3.10.1(@babel/core@7.24.5)(react-native@0.74.5(@babel/core@7.24.5)(@babel/preset-env@7.25.7(@babel/core@7.24.5))(@types/react@18.2.79)(encoding@0.1.13)(react@18.2.0))(react@18.2.0) + react-native-safe-area-context: 4.10.5(react-native@0.74.5(@babel/core@7.24.5)(@babel/preset-env@7.25.7(@babel/core@7.24.5))(@types/react@18.2.79)(encoding@0.1.13)(react@18.2.0))(react@18.2.0) + react-native-screens: 3.31.1(react-native@0.74.5(@babel/core@7.24.5)(@babel/preset-env@7.25.7(@babel/core@7.24.5))(@types/react@18.2.79)(encoding@0.1.13)(react@18.2.0))(react@18.2.0) + warn-once: 0.1.1 + '@react-navigation/elements@1.3.31(@react-navigation/native@6.1.18(react-native@0.74.1(@babel/core@7.24.5)(@babel/preset-env@7.26.9(@babel/core@7.24.5))(@types/react@18.3.11)(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native-safe-area-context@4.10.1(react-native@0.74.1(@babel/core@7.24.5)(@babel/preset-env@7.26.9(@babel/core@7.24.5))(@types/react@18.3.11)(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native@0.74.1(@babel/core@7.24.5)(@babel/preset-env@7.26.9(@babel/core@7.24.5))(@types/react@18.3.11)(encoding@0.1.13)(react@18.2.0))(react@18.2.0)': dependencies: '@react-navigation/native': 6.1.18(react-native@0.74.1(@babel/core@7.24.5)(@babel/preset-env@7.26.9(@babel/core@7.24.5))(@types/react@18.3.11)(encoding@0.1.13)(react@18.2.0))(react@18.2.0) @@ -31716,7 +31742,7 @@ snapshots: chokidar: 3.6.0 esbuild: 0.19.12 execa: 5.1.1 - fast-glob: 3.3.2 + fast-glob: 3.3.3 fs-extra: 11.2.0 get-tsconfig: 4.8.1 lodash.debounce: 4.0.8 @@ -32850,6 +32876,8 @@ snapshots: dependencies: '@types/node': 20.17.12 + '@types/glob-to-regexp@0.4.4': {} + '@types/glob@7.2.0': dependencies: '@types/minimatch': 5.1.2 @@ -33103,7 +33131,7 @@ snapshots: dependencies: vue: 2.7.16 - '@types/webpack@5.28.5(webpack-cli@5.1.4(webpack@5.95.0))': + '@types/webpack@5.28.5(webpack-cli@5.1.4)': dependencies: '@types/node': 20.16.10 tapable: 2.2.1 @@ -33361,7 +33389,7 @@ snapshots: globby: 11.1.0 is-glob: 4.0.3 minimatch: 9.0.5 - semver: 7.6.3 + semver: 7.7.1 ts-api-utils: 1.3.0(typescript@5.8.2) optionalDependencies: typescript: 5.8.2 @@ -33378,7 +33406,7 @@ snapshots: '@typescript-eslint/typescript-estree': 5.62.0(typescript@5.8.2) eslint: 8.57.1 eslint-scope: 5.1.1 - semver: 7.6.3 + semver: 7.7.1 transitivePeerDependencies: - supports-color - typescript @@ -33505,10 +33533,10 @@ snapshots: - vite optional: true - '@vitest/browser@3.0.8(@testing-library/dom@10.4.0)(@types/node@22.7.4)(playwright@1.51.0)(typescript@5.7.2)(vite@6.2.3(@types/node@22.7.4)(less@4.2.2)(lightningcss@1.28.2)(sass@1.85.0)(terser@5.39.0))(vitest@3.0.8)(webdriverio@9.8.0)': + '@vitest/browser@3.0.8(@testing-library/dom@10.4.0)(@types/node@22.7.4)(playwright@1.51.0)(typescript@5.7.2)(vite@6.2.3(@types/node@22.7.4)(jiti@1.21.6)(less@4.2.2)(lightningcss@1.28.2)(sass@1.85.0)(terser@5.39.0)(tsx@4.19.3)(yaml@2.6.1))(vitest@3.0.8)(webdriverio@9.8.0)': dependencies: '@testing-library/user-event': 14.6.1(@testing-library/dom@10.4.0) - '@vitest/mocker': 3.0.8(msw@2.7.3(@types/node@22.7.4)(typescript@5.7.2))(vite@6.2.3(@types/node@22.7.4)(less@4.2.2)(lightningcss@1.28.2)(sass@1.85.0)(terser@5.39.0)) + '@vitest/mocker': 3.0.8(msw@2.7.3(@types/node@22.7.4)(typescript@5.7.2))(vite@6.2.3(@types/node@22.7.4)(jiti@1.21.6)(less@4.2.2)(lightningcss@1.28.2)(sass@1.85.0)(terser@5.39.0)(tsx@4.19.3)(yaml@2.6.1)) '@vitest/utils': 3.0.8 magic-string: 0.30.17 msw: 2.7.3(@types/node@22.7.4)(typescript@5.7.2) @@ -33543,7 +33571,7 @@ snapshots: msw: 2.7.3(@types/node@22.7.4)(typescript@5.7.2) vite: 5.4.11(@types/node@22.7.4)(less@4.2.2)(lightningcss@1.28.2)(sass@1.85.0)(terser@5.39.0) - '@vitest/mocker@3.0.8(msw@2.7.3(@types/node@22.7.4)(typescript@5.7.2))(vite@6.2.3(@types/node@22.7.4)(less@4.2.2)(lightningcss@1.28.2)(sass@1.85.0)(terser@5.39.0))': + '@vitest/mocker@3.0.8(msw@2.7.3(@types/node@22.7.4)(typescript@5.7.2))(vite@6.2.3(@types/node@22.7.4)(jiti@1.21.6)(less@4.2.2)(lightningcss@1.28.2)(sass@1.85.0)(terser@5.39.0)(tsx@4.19.3)(yaml@2.6.1))': dependencies: '@vitest/spy': 3.0.8 estree-walker: 3.0.3 @@ -33619,7 +33647,7 @@ snapshots: '@vue/compiler-sfc@2.7.16': dependencies: '@babel/parser': 7.26.3 - postcss: 8.5.1 + postcss: 8.5.3 source-map: 0.6.1 optionalDependencies: prettier: 2.8.8 @@ -33713,7 +33741,7 @@ snapshots: vue: 3.4.21(typescript@5.5.4) vue-demi: 0.13.11(vue@3.4.21(typescript@5.5.4)) - '@vuetify/loader-shared@2.0.3(vue@3.4.21(typescript@5.5.4))(vuetify@3.6.8(typescript@5.5.4)(vite-plugin-vuetify@2.0.4)(vue@3.4.21(typescript@5.5.4)))': + '@vuetify/loader-shared@2.0.3(vue@3.4.21(typescript@5.5.4))(vuetify@3.6.8)': dependencies: upath: 2.0.1 vue: 3.4.21(typescript@5.5.4) @@ -33929,17 +33957,17 @@ snapshots: dependencies: commander: 10.0.1 - '@webpack-cli/configtest@2.1.1(webpack-cli@5.1.4(webpack@5.95.0))(webpack@5.95.0(webpack-cli@5.1.4))': + '@webpack-cli/configtest@2.1.1(webpack-cli@5.1.4)(webpack@5.95.0)': dependencies: webpack: 5.95.0(webpack-cli@5.1.4) webpack-cli: 5.1.4(webpack@5.95.0) - '@webpack-cli/info@2.0.2(webpack-cli@5.1.4(webpack@5.95.0))(webpack@5.95.0(webpack-cli@5.1.4))': + '@webpack-cli/info@2.0.2(webpack-cli@5.1.4)(webpack@5.95.0)': dependencies: webpack: 5.95.0(webpack-cli@5.1.4) webpack-cli: 5.1.4(webpack@5.95.0) - '@webpack-cli/serve@2.0.5(webpack-cli@5.1.4(webpack@5.95.0))(webpack@5.95.0(webpack-cli@5.1.4))': + '@webpack-cli/serve@2.0.5(webpack-cli@5.1.4)(webpack@5.95.0)': dependencies: webpack: 5.95.0(webpack-cli@5.1.4) webpack-cli: 5.1.4(webpack@5.95.0) @@ -33987,6 +34015,10 @@ snapshots: dependencies: acorn: 8.12.1 + acorn-jsx@5.3.2(acorn@8.14.1): + dependencies: + acorn: 8.14.1 + acorn-walk@8.3.4: dependencies: acorn: 8.12.1 @@ -34215,7 +34247,7 @@ snapshots: aria-hidden@1.2.4: dependencies: - tslib: 2.7.0 + tslib: 2.8.1 aria-query@5.1.3: dependencies: @@ -34336,11 +34368,11 @@ snapshots: ast-types@0.15.2: dependencies: - tslib: 2.7.0 + tslib: 2.8.1 ast-types@0.16.1: dependencies: - tslib: 2.7.0 + tslib: 2.8.1 astral-regex@1.0.0: {} @@ -34473,12 +34505,12 @@ snapshots: schema-utils: 4.2.0 webpack: 5.95.0(@swc/core@1.10.1(@swc/helpers@0.5.5)) - babel-loader@9.2.1(@babel/core@7.26.10)(webpack@5.98.0(@swc/core@1.10.1)(esbuild@0.25.1)): + babel-loader@9.2.1(@babel/core@7.26.10)(webpack@5.98.0(@swc/core@1.10.1(@swc/helpers@0.5.5))): dependencies: '@babel/core': 7.26.10 find-cache-dir: 4.0.0 schema-utils: 4.2.0 - webpack: 5.98.0(@swc/core@1.10.1)(esbuild@0.25.1) + webpack: 5.98.0(@swc/core@1.10.1(@swc/helpers@0.5.5))(esbuild@0.25.1) babel-loader@9.2.1(@babel/core@7.26.10)(webpack@5.98.0(@swc/core@1.6.13(@swc/helpers@0.5.5))): dependencies: @@ -34487,13 +34519,6 @@ snapshots: schema-utils: 4.2.0 webpack: 5.98.0(@swc/core@1.6.13(@swc/helpers@0.5.5)) - babel-loader@9.2.1(@babel/core@7.26.10)(webpack@5.98.0): - dependencies: - '@babel/core': 7.26.10 - find-cache-dir: 4.0.0 - schema-utils: 4.2.0 - webpack: 5.98.0 - babel-plugin-dynamic-import-node@2.3.3: dependencies: object.assign: 4.1.5 @@ -34808,7 +34833,7 @@ snapshots: domhandler: 5.0.3 htmlparser2: 9.1.0 picocolors: 1.1.1 - postcss: 8.5.2 + postcss: 8.5.3 postcss-media-query-parser: 0.2.3 better-opn@3.0.2: @@ -35192,7 +35217,7 @@ snapshots: camel-case@4.1.2: dependencies: pascal-case: 3.1.2 - tslib: 2.7.0 + tslib: 2.8.1 camelcase-css@2.0.1: {} @@ -35642,32 +35667,32 @@ snapshots: copy-webpack-plugin@11.0.0(webpack@5.95.0(@swc/core@1.10.1(@swc/helpers@0.5.5))): dependencies: - fast-glob: 3.3.2 + fast-glob: 3.3.3 glob-parent: 6.0.2 globby: 13.2.2 normalize-path: 3.0.0 - schema-utils: 4.2.0 + schema-utils: 4.3.0 serialize-javascript: 6.0.2 webpack: 5.95.0(@swc/core@1.10.1(@swc/helpers@0.5.5)) - copy-webpack-plugin@12.0.2(webpack@5.98.0(@swc/core@1.10.1)(esbuild@0.25.1)): + copy-webpack-plugin@12.0.2(webpack@5.98.0(@swc/core@1.10.1(@swc/helpers@0.5.5))): dependencies: fast-glob: 3.3.3 glob-parent: 6.0.2 globby: 14.0.2 normalize-path: 3.0.0 - schema-utils: 4.2.0 + schema-utils: 4.3.0 serialize-javascript: 6.0.2 - webpack: 5.98.0(@swc/core@1.10.1)(esbuild@0.25.1) + webpack: 5.98.0(@swc/core@1.10.1(@swc/helpers@0.5.5))(esbuild@0.25.1) - copy-webpack-plugin@13.0.0(webpack@5.95.0(@swc/core@1.10.1)): + copy-webpack-plugin@13.0.0(webpack@5.95.0(@swc/core@1.10.1(@swc/helpers@0.5.5))): dependencies: glob-parent: 6.0.2 normalize-path: 3.0.0 schema-utils: 4.2.0 serialize-javascript: 6.0.2 tinyglobby: 0.2.12 - webpack: 5.95.0(@swc/core@1.10.1) + webpack: 5.95.0(@swc/core@1.10.1(@swc/helpers@0.5.5)) core-js-compat@3.38.1: dependencies: @@ -35848,6 +35873,10 @@ snapshots: dependencies: postcss: 8.5.1 + css-declaration-sorter@7.2.0(postcss@8.5.3): + dependencies: + postcss: 8.5.3 + css-has-pseudo@7.0.2(postcss@8.5.1): dependencies: '@csstools/selector-specificity': 5.0.0(postcss-selector-parser@7.0.0) @@ -35873,7 +35902,7 @@ snapshots: '@rspack/core': 1.1.8(@swc/helpers@0.5.5) webpack: 5.95.0(@swc/core@1.10.1(@swc/helpers@0.5.5)) - css-loader@6.11.0(@rspack/core@1.1.8)(webpack@5.95.0(@swc/core@1.10.1)): + css-loader@6.11.0(@rspack/core@1.1.8(@swc/helpers@0.5.5))(webpack@5.98.0(@swc/core@1.10.1(@swc/helpers@0.5.5))): dependencies: icss-utils: 5.1.0(postcss@8.5.1) postcss: 8.5.1 @@ -35885,43 +35914,29 @@ snapshots: semver: 7.6.3 optionalDependencies: '@rspack/core': 1.1.8(@swc/helpers@0.5.5) - webpack: 5.95.0(@swc/core@1.10.1) + webpack: 5.98.0(@swc/core@1.10.1(@swc/helpers@0.5.5))(esbuild@0.25.1) - css-loader@6.11.0(@rspack/core@1.1.8)(webpack@5.98.0): + css-loader@7.1.2(@rspack/core@1.1.8(@swc/helpers@0.5.5))(webpack@5.98.0(@swc/core@1.10.1(@swc/helpers@0.5.5))): dependencies: - icss-utils: 5.1.0(postcss@8.5.1) - postcss: 8.5.1 - postcss-modules-extract-imports: 3.1.0(postcss@8.5.1) - postcss-modules-local-by-default: 4.0.5(postcss@8.5.1) - postcss-modules-scope: 3.2.0(postcss@8.5.1) - postcss-modules-values: 4.0.0(postcss@8.5.1) - postcss-value-parser: 4.2.0 - semver: 7.6.3 - optionalDependencies: - '@rspack/core': 1.1.8(@swc/helpers@0.5.5) - webpack: 5.98.0 - - css-loader@7.1.2(@rspack/core@1.1.8)(webpack@5.98.0(@swc/core@1.10.1)(esbuild@0.25.1)): - dependencies: - icss-utils: 5.1.0(postcss@8.5.2) - postcss: 8.5.2 - postcss-modules-extract-imports: 3.1.0(postcss@8.5.2) - postcss-modules-local-by-default: 4.0.5(postcss@8.5.2) - postcss-modules-scope: 3.2.0(postcss@8.5.2) - postcss-modules-values: 4.0.0(postcss@8.5.2) + icss-utils: 5.1.0(postcss@8.5.3) + postcss: 8.5.3 + postcss-modules-extract-imports: 3.1.0(postcss@8.5.3) + postcss-modules-local-by-default: 4.0.5(postcss@8.5.3) + postcss-modules-scope: 3.2.0(postcss@8.5.3) + postcss-modules-values: 4.0.0(postcss@8.5.3) postcss-value-parser: 4.2.0 semver: 7.7.1 optionalDependencies: '@rspack/core': 1.1.8(@swc/helpers@0.5.5) - webpack: 5.98.0(@swc/core@1.10.1)(esbuild@0.25.1) + webpack: 5.98.0(@swc/core@1.10.1(@swc/helpers@0.5.5))(esbuild@0.25.1) css-minimizer-webpack-plugin@5.0.1(clean-css@5.3.3)(lightningcss@1.28.2)(webpack@5.95.0(@swc/core@1.10.1(@swc/helpers@0.5.5))): dependencies: '@jridgewell/trace-mapping': 0.3.25 - cssnano: 6.1.2(postcss@8.5.1) + cssnano: 6.1.2(postcss@8.5.3) jest-worker: 29.7.0 - postcss: 8.5.1 - schema-utils: 4.2.0 + postcss: 8.5.3 + schema-utils: 4.3.0 serialize-javascript: 6.0.2 webpack: 5.95.0(@swc/core@1.10.1(@swc/helpers@0.5.5)) optionalDependencies: @@ -35975,16 +35990,16 @@ snapshots: cssesc@3.0.0: {} - cssnano-preset-advanced@6.1.2(postcss@8.5.1): + cssnano-preset-advanced@6.1.2(postcss@8.5.3): dependencies: - autoprefixer: 10.4.20(postcss@8.5.1) + autoprefixer: 10.4.20(postcss@8.5.3) browserslist: 4.24.4 - cssnano-preset-default: 6.1.2(postcss@8.5.1) - postcss: 8.5.1 - postcss-discard-unused: 6.0.5(postcss@8.5.1) - postcss-merge-idents: 6.0.3(postcss@8.5.1) - postcss-reduce-idents: 6.0.3(postcss@8.5.1) - postcss-zindex: 6.0.2(postcss@8.5.1) + cssnano-preset-default: 6.1.2(postcss@8.5.3) + postcss: 8.5.3 + postcss-discard-unused: 6.0.5(postcss@8.5.3) + postcss-merge-idents: 6.0.3(postcss@8.5.3) + postcss-reduce-idents: 6.0.3(postcss@8.5.3) + postcss-zindex: 6.0.2(postcss@8.5.3) cssnano-preset-default@6.1.2(postcss@8.5.1): dependencies: @@ -36020,16 +36035,60 @@ snapshots: postcss-svgo: 6.0.3(postcss@8.5.1) postcss-unique-selectors: 6.0.4(postcss@8.5.1) + cssnano-preset-default@6.1.2(postcss@8.5.3): + dependencies: + browserslist: 4.24.4 + css-declaration-sorter: 7.2.0(postcss@8.5.3) + cssnano-utils: 4.0.2(postcss@8.5.3) + postcss: 8.5.3 + postcss-calc: 9.0.1(postcss@8.5.3) + postcss-colormin: 6.1.0(postcss@8.5.3) + postcss-convert-values: 6.1.0(postcss@8.5.3) + postcss-discard-comments: 6.0.2(postcss@8.5.3) + postcss-discard-duplicates: 6.0.3(postcss@8.5.3) + postcss-discard-empty: 6.0.3(postcss@8.5.3) + postcss-discard-overridden: 6.0.2(postcss@8.5.3) + postcss-merge-longhand: 6.0.5(postcss@8.5.3) + postcss-merge-rules: 6.1.1(postcss@8.5.3) + postcss-minify-font-values: 6.1.0(postcss@8.5.3) + postcss-minify-gradients: 6.0.3(postcss@8.5.3) + postcss-minify-params: 6.1.0(postcss@8.5.3) + postcss-minify-selectors: 6.0.4(postcss@8.5.3) + postcss-normalize-charset: 6.0.2(postcss@8.5.3) + postcss-normalize-display-values: 6.0.2(postcss@8.5.3) + postcss-normalize-positions: 6.0.2(postcss@8.5.3) + postcss-normalize-repeat-style: 6.0.2(postcss@8.5.3) + postcss-normalize-string: 6.0.2(postcss@8.5.3) + postcss-normalize-timing-functions: 6.0.2(postcss@8.5.3) + postcss-normalize-unicode: 6.1.0(postcss@8.5.3) + postcss-normalize-url: 6.0.2(postcss@8.5.3) + postcss-normalize-whitespace: 6.0.2(postcss@8.5.3) + postcss-ordered-values: 6.0.2(postcss@8.5.3) + postcss-reduce-initial: 6.1.0(postcss@8.5.3) + postcss-reduce-transforms: 6.0.2(postcss@8.5.3) + postcss-svgo: 6.0.3(postcss@8.5.3) + postcss-unique-selectors: 6.0.4(postcss@8.5.3) + cssnano-utils@4.0.2(postcss@8.5.1): dependencies: postcss: 8.5.1 + cssnano-utils@4.0.2(postcss@8.5.3): + dependencies: + postcss: 8.5.3 + cssnano@6.1.2(postcss@8.5.1): dependencies: cssnano-preset-default: 6.1.2(postcss@8.5.1) lilconfig: 3.1.2 postcss: 8.5.1 + cssnano@6.1.2(postcss@8.5.3): + dependencies: + cssnano-preset-default: 6.1.2(postcss@8.5.3) + lilconfig: 3.1.2 + postcss: 8.5.3 + csso@5.0.5: dependencies: css-tree: 2.2.1 @@ -36399,7 +36458,7 @@ snapshots: dot-case@3.0.4: dependencies: no-case: 3.0.4 - tslib: 2.7.0 + tslib: 2.8.1 dot-prop@6.0.1: dependencies: @@ -36415,7 +36474,7 @@ snapshots: dotenv@16.4.7: {} - drizzle-orm@0.35.2(@op-engineering/op-sqlite@11.4.8(react@18.3.1))(@types/better-sqlite3@7.6.12)(@types/react@18.3.18)(better-sqlite3@11.7.2)(kysely@0.27.4)(react@18.3.1): + drizzle-orm@0.35.2(@op-engineering/op-sqlite@11.4.8(react-native@0.77.0(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@react-native-community/cli-server-api@15.1.3)(@types/react@18.3.18)(react@18.3.1))(react@18.3.1))(@types/better-sqlite3@7.6.12)(@types/react@18.3.18)(better-sqlite3@11.7.2)(kysely@0.27.4)(react@18.3.1): optionalDependencies: '@op-engineering/op-sqlite': 11.4.8(react-native@0.77.0(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@react-native-community/cli-server-api@15.1.3)(@types/react@18.3.18)(react@18.3.1))(react@18.3.1) '@types/better-sqlite3': 7.6.12 @@ -36431,7 +36490,7 @@ snapshots: duplexer@0.1.2: {} - eas-cli@7.8.5(@swc/core@1.10.1)(@types/node@22.7.4)(encoding@0.1.13)(expo-modules-autolinking@1.11.1)(typescript@5.3.3): + eas-cli@7.8.5(@swc/core@1.10.1(@swc/helpers@0.5.5))(@types/node@22.7.4)(encoding@0.1.13)(expo-modules-autolinking@1.11.1)(typescript@5.3.3): dependencies: '@expo/apple-utils': 1.7.0 '@expo/code-signing-certificates': 0.0.5 @@ -36447,8 +36506,8 @@ snapshots: '@expo/package-manager': 1.1.2 '@expo/pkcs12': 0.0.8 '@expo/plist': 0.0.20 - '@expo/plugin-help': 5.1.23(@swc/core@1.10.1)(@types/node@22.7.4)(typescript@5.3.3) - '@expo/plugin-warn-if-update-available': 2.5.1(@swc/core@1.10.1)(@types/node@22.7.4)(typescript@5.3.3) + '@expo/plugin-help': 5.1.23(@swc/core@1.10.1(@swc/helpers@0.5.5))(@types/node@22.7.4)(typescript@5.3.3) + '@expo/plugin-warn-if-update-available': 2.5.1(@swc/core@1.10.1(@swc/helpers@0.5.5))(@types/node@22.7.4)(typescript@5.3.3) '@expo/prebuild-config': 6.7.3(encoding@0.1.13)(expo-modules-autolinking@1.11.1) '@expo/results': 1.0.0 '@expo/rudder-sdk-node': 1.1.1(encoding@0.1.13) @@ -36456,7 +36515,7 @@ snapshots: '@expo/steps': 1.0.95 '@expo/timeago.js': 1.0.0 '@oclif/core': 1.26.2 - '@oclif/plugin-autocomplete': 2.3.10(@swc/core@1.10.1)(@types/node@22.7.4)(typescript@5.3.3) + '@oclif/plugin-autocomplete': 2.3.10(@swc/core@1.10.1(@swc/helpers@0.5.5))(@types/node@22.7.4)(typescript@5.3.3) '@segment/ajv-human-errors': 2.13.0(ajv@8.11.0) '@urql/core': 4.0.11(graphql@16.8.1) '@urql/exchange-retry': 1.2.0(graphql@16.8.1) @@ -37051,7 +37110,7 @@ snapshots: debug: 4.4.0(supports-color@8.1.1) enhanced-resolve: 5.17.1 eslint: 8.57.1 - eslint-module-utils: 2.12.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.8.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.8.2))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1) + eslint-module-utils: 2.12.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.8.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1) fast-glob: 3.3.2 get-tsconfig: 4.8.1 is-bun-module: 1.2.1 @@ -37074,7 +37133,7 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-module-utils@2.12.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.8.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.8.2))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1): + eslint-module-utils@2.12.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.8.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1): dependencies: debug: 3.2.7 optionalDependencies: @@ -37144,7 +37203,7 @@ snapshots: doctrine: 2.1.0 eslint: 8.57.1 eslint-import-resolver-node: 0.3.9 - eslint-module-utils: 2.12.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.8.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.8.2))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0(eslint@8.57.1))(eslint@8.57.1))(eslint@8.57.1) + eslint-module-utils: 2.12.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.8.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1) hasown: 2.0.2 is-core-module: 2.15.1 is-glob: 4.0.3 @@ -37809,26 +37868,26 @@ snapshots: dependencies: invariant: 2.2.4 - expo-router@3.5.21(gc6ebsds2rxeucccxhmqtwmlpi): + expo-router@3.5.21(43cc03a7fb538f7aef105856925492f6): dependencies: - '@expo/metro-runtime': 3.2.1(react-native@0.74.1(@babel/core@7.24.5)(@babel/preset-env@7.26.9(@babel/core@7.24.5))(@types/react@18.3.11)(encoding@0.1.13)(react@18.2.0)) - '@expo/server': 0.4.4(typescript@5.3.3) + '@expo/metro-runtime': 3.2.1(react-native@0.74.5(@babel/core@7.24.5)(@babel/preset-env@7.25.7(@babel/core@7.24.5))(@types/react@18.2.79)(encoding@0.1.13)(react@18.2.0)) + '@expo/server': 0.4.4(typescript@5.5.4) '@radix-ui/react-slot': 1.0.1(react@18.2.0) - '@react-navigation/bottom-tabs': 6.5.20(@react-navigation/native@6.1.18(react-native@0.74.1(@babel/core@7.24.5)(@babel/preset-env@7.26.9(@babel/core@7.24.5))(@types/react@18.3.11)(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native-safe-area-context@4.10.1(react-native@0.74.1(@babel/core@7.24.5)(@babel/preset-env@7.26.9(@babel/core@7.24.5))(@types/react@18.3.11)(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native-screens@3.31.1(react-native@0.74.1(@babel/core@7.24.5)(@babel/preset-env@7.26.9(@babel/core@7.24.5))(@types/react@18.3.11)(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native@0.74.1(@babel/core@7.24.5)(@babel/preset-env@7.26.9(@babel/core@7.24.5))(@types/react@18.3.11)(encoding@0.1.13)(react@18.2.0))(react@18.2.0) - '@react-navigation/native': 6.1.18(react-native@0.74.1(@babel/core@7.24.5)(@babel/preset-env@7.26.9(@babel/core@7.24.5))(@types/react@18.3.11)(encoding@0.1.13)(react@18.2.0))(react@18.2.0) - '@react-navigation/native-stack': 6.9.26(@react-navigation/native@6.1.18(react-native@0.74.1(@babel/core@7.24.5)(@babel/preset-env@7.26.9(@babel/core@7.24.5))(@types/react@18.3.11)(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native-safe-area-context@4.10.1(react-native@0.74.1(@babel/core@7.24.5)(@babel/preset-env@7.26.9(@babel/core@7.24.5))(@types/react@18.3.11)(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native-screens@3.31.1(react-native@0.74.1(@babel/core@7.24.5)(@babel/preset-env@7.26.9(@babel/core@7.24.5))(@types/react@18.3.11)(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native@0.74.1(@babel/core@7.24.5)(@babel/preset-env@7.26.9(@babel/core@7.24.5))(@types/react@18.3.11)(encoding@0.1.13)(react@18.2.0))(react@18.2.0) - expo: 51.0.27(@babel/core@7.24.5)(@babel/preset-env@7.26.9(@babel/core@7.24.5))(encoding@0.1.13) - expo-constants: 16.0.2(expo@51.0.27(@babel/core@7.24.5)(@babel/preset-env@7.26.9(@babel/core@7.24.5))(encoding@0.1.13)) - expo-linking: 6.3.1(expo@51.0.27(@babel/core@7.24.5)(@babel/preset-env@7.26.9(@babel/core@7.24.5))(encoding@0.1.13)) - expo-splash-screen: 0.27.5(encoding@0.1.13)(expo-modules-autolinking@1.11.1)(expo@51.0.27(@babel/core@7.24.5)(@babel/preset-env@7.26.9(@babel/core@7.24.5))(encoding@0.1.13)) + '@react-navigation/bottom-tabs': 6.5.20(@react-navigation/native@6.1.18(react-native@0.74.5(@babel/core@7.24.5)(@babel/preset-env@7.25.7(@babel/core@7.24.5))(@types/react@18.2.79)(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native-safe-area-context@4.10.5(react-native@0.74.5(@babel/core@7.24.5)(@babel/preset-env@7.25.7(@babel/core@7.24.5))(@types/react@18.2.79)(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native-screens@3.31.1(react-native@0.74.5(@babel/core@7.24.5)(@babel/preset-env@7.25.7(@babel/core@7.24.5))(@types/react@18.2.79)(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native@0.74.5(@babel/core@7.24.5)(@babel/preset-env@7.25.7(@babel/core@7.24.5))(@types/react@18.2.79)(encoding@0.1.13)(react@18.2.0))(react@18.2.0) + '@react-navigation/native': 6.1.18(react-native@0.74.5(@babel/core@7.24.5)(@babel/preset-env@7.25.7(@babel/core@7.24.5))(@types/react@18.2.79)(encoding@0.1.13)(react@18.2.0))(react@18.2.0) + '@react-navigation/native-stack': 6.9.26(@react-navigation/native@6.1.18(react-native@0.74.5(@babel/core@7.24.5)(@babel/preset-env@7.25.7(@babel/core@7.24.5))(@types/react@18.2.79)(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native-safe-area-context@4.10.5(react-native@0.74.5(@babel/core@7.24.5)(@babel/preset-env@7.25.7(@babel/core@7.24.5))(@types/react@18.2.79)(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native-screens@3.31.1(react-native@0.74.5(@babel/core@7.24.5)(@babel/preset-env@7.25.7(@babel/core@7.24.5))(@types/react@18.2.79)(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native@0.74.5(@babel/core@7.24.5)(@babel/preset-env@7.25.7(@babel/core@7.24.5))(@types/react@18.2.79)(encoding@0.1.13)(react@18.2.0))(react@18.2.0) + expo: 51.0.27(@babel/core@7.24.5)(@babel/preset-env@7.25.7(@babel/core@7.24.5))(encoding@0.1.13) + expo-constants: 16.0.2(expo@51.0.27(@babel/core@7.24.5)(@babel/preset-env@7.25.7(@babel/core@7.24.5))(encoding@0.1.13)) + expo-linking: 6.3.1(expo@51.0.27(@babel/core@7.24.5)(@babel/preset-env@7.25.7(@babel/core@7.24.5))(encoding@0.1.13)) + expo-splash-screen: 0.27.5(encoding@0.1.13)(expo-modules-autolinking@1.11.3)(expo@51.0.27(@babel/core@7.24.5)(@babel/preset-env@7.25.7(@babel/core@7.24.5))(encoding@0.1.13)) expo-status-bar: 1.12.1 react-native-helmet-async: 2.0.4(react@18.2.0) - react-native-safe-area-context: 4.10.1(react-native@0.74.1(@babel/core@7.24.5)(@babel/preset-env@7.26.9(@babel/core@7.24.5))(@types/react@18.3.11)(encoding@0.1.13)(react@18.2.0))(react@18.2.0) - react-native-screens: 3.31.1(react-native@0.74.1(@babel/core@7.24.5)(@babel/preset-env@7.26.9(@babel/core@7.24.5))(@types/react@18.3.11)(encoding@0.1.13)(react@18.2.0))(react@18.2.0) + react-native-safe-area-context: 4.10.5(react-native@0.74.5(@babel/core@7.24.5)(@babel/preset-env@7.25.7(@babel/core@7.24.5))(@types/react@18.2.79)(encoding@0.1.13)(react@18.2.0))(react@18.2.0) + react-native-screens: 3.31.1(react-native@0.74.5(@babel/core@7.24.5)(@babel/preset-env@7.25.7(@babel/core@7.24.5))(@types/react@18.2.79)(encoding@0.1.13)(react@18.2.0))(react@18.2.0) schema-utils: 4.2.0 optionalDependencies: - '@react-navigation/drawer': 6.7.2(ghvgknxqxtkf2snjzmu2bwsmre) - react-native-reanimated: 3.10.1(@babel/core@7.24.5)(react-native@0.74.1(@babel/core@7.24.5)(@babel/preset-env@7.26.9(@babel/core@7.24.5))(@types/react@18.3.11)(encoding@0.1.13)(react@18.2.0))(react@18.2.0) + '@react-navigation/drawer': 6.7.2(fe8cd8328c484d4e3eaed8eea351852b) + react-native-reanimated: 3.10.1(@babel/core@7.24.5)(react-native@0.74.5(@babel/core@7.24.5)(@babel/preset-env@7.25.7(@babel/core@7.24.5))(@types/react@18.2.79)(encoding@0.1.13)(react@18.2.0))(react@18.2.0) transitivePeerDependencies: - encoding - expo-modules-autolinking @@ -37837,7 +37896,7 @@ snapshots: - supports-color - typescript - expo-router@3.5.21(itxjk4e5lx4jky57qutbl2llka): + expo-router@3.5.21(861b7493f2d52858e88dcfa7bffd38c4): dependencies: '@expo/metro-runtime': 3.2.1(react-native@0.74.5(@babel/core@7.26.10)(@babel/preset-env@7.25.7(@babel/core@7.26.10))(@types/react@18.2.79)(encoding@0.1.13)(react@18.2.0)) '@expo/server': 0.4.4(typescript@5.5.4) @@ -37855,7 +37914,7 @@ snapshots: react-native-screens: 3.31.1(react-native@0.74.5(@babel/core@7.26.10)(@babel/preset-env@7.25.7(@babel/core@7.26.10))(@types/react@18.2.79)(encoding@0.1.13)(react@18.2.0))(react@18.2.0) schema-utils: 4.2.0 optionalDependencies: - '@react-navigation/drawer': 6.7.2(l2wxk4fvyl3ebgrlaryoia2mpm) + '@react-navigation/drawer': 6.7.2(8a892ff6c949d4273486936ff7d0b326) react-native-reanimated: 3.10.1(@babel/core@7.26.10)(react-native@0.74.5(@babel/core@7.26.10)(@babel/preset-env@7.25.7(@babel/core@7.26.10))(@types/react@18.2.79)(encoding@0.1.13)(react@18.2.0))(react@18.2.0) transitivePeerDependencies: - encoding @@ -37865,26 +37924,26 @@ snapshots: - supports-color - typescript - expo-router@3.5.21(qrxjjyxvihi5xb6jovt7bb6fjy): + expo-router@3.5.21(c189db6b79bdaefc0f767c4cd94a478a): dependencies: - '@expo/metro-runtime': 3.2.1(react-native@0.74.5(@babel/core@7.24.5)(@babel/preset-env@7.25.7(@babel/core@7.24.5))(@types/react@18.2.79)(encoding@0.1.13)(react@18.2.0)) - '@expo/server': 0.4.4(typescript@5.5.4) + '@expo/metro-runtime': 3.2.1(react-native@0.74.1(@babel/core@7.24.5)(@babel/preset-env@7.26.9(@babel/core@7.24.5))(@types/react@18.3.11)(encoding@0.1.13)(react@18.2.0)) + '@expo/server': 0.4.4(typescript@5.3.3) '@radix-ui/react-slot': 1.0.1(react@18.2.0) - '@react-navigation/bottom-tabs': 6.5.20(@react-navigation/native@6.1.18(react-native@0.74.5(@babel/core@7.24.5)(@babel/preset-env@7.25.7(@babel/core@7.24.5))(@types/react@18.2.79)(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native-safe-area-context@4.10.5(react-native@0.74.5(@babel/core@7.24.5)(@babel/preset-env@7.25.7(@babel/core@7.24.5))(@types/react@18.2.79)(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native-screens@3.31.1(react-native@0.74.5(@babel/core@7.24.5)(@babel/preset-env@7.25.7(@babel/core@7.24.5))(@types/react@18.2.79)(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native@0.74.5(@babel/core@7.24.5)(@babel/preset-env@7.25.7(@babel/core@7.24.5))(@types/react@18.2.79)(encoding@0.1.13)(react@18.2.0))(react@18.2.0) - '@react-navigation/native': 6.1.18(react-native@0.74.5(@babel/core@7.24.5)(@babel/preset-env@7.25.7(@babel/core@7.24.5))(@types/react@18.2.79)(encoding@0.1.13)(react@18.2.0))(react@18.2.0) - '@react-navigation/native-stack': 6.9.26(@react-navigation/native@6.1.18(react-native@0.74.5(@babel/core@7.24.5)(@babel/preset-env@7.25.7(@babel/core@7.24.5))(@types/react@18.2.79)(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native-safe-area-context@4.10.5(react-native@0.74.5(@babel/core@7.24.5)(@babel/preset-env@7.25.7(@babel/core@7.24.5))(@types/react@18.2.79)(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native-screens@3.31.1(react-native@0.74.5(@babel/core@7.24.5)(@babel/preset-env@7.25.7(@babel/core@7.24.5))(@types/react@18.2.79)(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native@0.74.5(@babel/core@7.24.5)(@babel/preset-env@7.25.7(@babel/core@7.24.5))(@types/react@18.2.79)(encoding@0.1.13)(react@18.2.0))(react@18.2.0) - expo: 51.0.27(@babel/core@7.24.5)(@babel/preset-env@7.25.7(@babel/core@7.24.5))(encoding@0.1.13) - expo-constants: 16.0.2(expo@51.0.27(@babel/core@7.24.5)(@babel/preset-env@7.25.7(@babel/core@7.24.5))(encoding@0.1.13)) - expo-linking: 6.3.1(expo@51.0.27(@babel/core@7.24.5)(@babel/preset-env@7.25.7(@babel/core@7.24.5))(encoding@0.1.13)) - expo-splash-screen: 0.27.5(encoding@0.1.13)(expo-modules-autolinking@1.11.3)(expo@51.0.27(@babel/core@7.24.5)(@babel/preset-env@7.25.7(@babel/core@7.24.5))(encoding@0.1.13)) + '@react-navigation/bottom-tabs': 6.5.20(@react-navigation/native@6.1.18(react-native@0.74.1(@babel/core@7.24.5)(@babel/preset-env@7.26.9(@babel/core@7.24.5))(@types/react@18.3.11)(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native-safe-area-context@4.10.1(react-native@0.74.1(@babel/core@7.24.5)(@babel/preset-env@7.26.9(@babel/core@7.24.5))(@types/react@18.3.11)(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native-screens@3.31.1(react-native@0.74.1(@babel/core@7.24.5)(@babel/preset-env@7.26.9(@babel/core@7.24.5))(@types/react@18.3.11)(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native@0.74.1(@babel/core@7.24.5)(@babel/preset-env@7.26.9(@babel/core@7.24.5))(@types/react@18.3.11)(encoding@0.1.13)(react@18.2.0))(react@18.2.0) + '@react-navigation/native': 6.1.18(react-native@0.74.1(@babel/core@7.24.5)(@babel/preset-env@7.26.9(@babel/core@7.24.5))(@types/react@18.3.11)(encoding@0.1.13)(react@18.2.0))(react@18.2.0) + '@react-navigation/native-stack': 6.9.26(@react-navigation/native@6.1.18(react-native@0.74.1(@babel/core@7.24.5)(@babel/preset-env@7.26.9(@babel/core@7.24.5))(@types/react@18.3.11)(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native-safe-area-context@4.10.1(react-native@0.74.1(@babel/core@7.24.5)(@babel/preset-env@7.26.9(@babel/core@7.24.5))(@types/react@18.3.11)(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native-screens@3.31.1(react-native@0.74.1(@babel/core@7.24.5)(@babel/preset-env@7.26.9(@babel/core@7.24.5))(@types/react@18.3.11)(encoding@0.1.13)(react@18.2.0))(react@18.2.0))(react-native@0.74.1(@babel/core@7.24.5)(@babel/preset-env@7.26.9(@babel/core@7.24.5))(@types/react@18.3.11)(encoding@0.1.13)(react@18.2.0))(react@18.2.0) + expo: 51.0.27(@babel/core@7.24.5)(@babel/preset-env@7.26.9(@babel/core@7.24.5))(encoding@0.1.13) + expo-constants: 16.0.2(expo@51.0.27(@babel/core@7.24.5)(@babel/preset-env@7.26.9(@babel/core@7.24.5))(encoding@0.1.13)) + expo-linking: 6.3.1(expo@51.0.27(@babel/core@7.24.5)(@babel/preset-env@7.26.9(@babel/core@7.24.5))(encoding@0.1.13)) + expo-splash-screen: 0.27.5(encoding@0.1.13)(expo-modules-autolinking@1.11.1)(expo@51.0.27(@babel/core@7.24.5)(@babel/preset-env@7.26.9(@babel/core@7.24.5))(encoding@0.1.13)) expo-status-bar: 1.12.1 react-native-helmet-async: 2.0.4(react@18.2.0) - react-native-safe-area-context: 4.10.5(react-native@0.74.5(@babel/core@7.24.5)(@babel/preset-env@7.25.7(@babel/core@7.24.5))(@types/react@18.2.79)(encoding@0.1.13)(react@18.2.0))(react@18.2.0) - react-native-screens: 3.31.1(react-native@0.74.5(@babel/core@7.24.5)(@babel/preset-env@7.25.7(@babel/core@7.24.5))(@types/react@18.2.79)(encoding@0.1.13)(react@18.2.0))(react@18.2.0) + react-native-safe-area-context: 4.10.1(react-native@0.74.1(@babel/core@7.24.5)(@babel/preset-env@7.26.9(@babel/core@7.24.5))(@types/react@18.3.11)(encoding@0.1.13)(react@18.2.0))(react@18.2.0) + react-native-screens: 3.31.1(react-native@0.74.1(@babel/core@7.24.5)(@babel/preset-env@7.26.9(@babel/core@7.24.5))(@types/react@18.3.11)(encoding@0.1.13)(react@18.2.0))(react@18.2.0) schema-utils: 4.2.0 optionalDependencies: - '@react-navigation/drawer': 6.7.2(f5uupuoecme7pb3346nlwm73my) - react-native-reanimated: 3.10.1(@babel/core@7.24.5)(react-native@0.74.5(@babel/core@7.24.5)(@babel/preset-env@7.25.7(@babel/core@7.24.5))(@types/react@18.2.79)(encoding@0.1.13)(react@18.2.0))(react@18.2.0) + '@react-navigation/drawer': 6.7.2(3f3d461ed9a1c5b87bb0ca8ce18d5723) + react-native-reanimated: 3.10.1(@babel/core@7.24.5)(react-native@0.74.1(@babel/core@7.24.5)(@babel/preset-env@7.26.9(@babel/core@7.24.5))(@types/react@18.3.11)(encoding@0.1.13)(react@18.2.0))(react@18.2.0) transitivePeerDependencies: - encoding - expo-modules-autolinking @@ -37893,7 +37952,7 @@ snapshots: - supports-color - typescript - expo-router@3.5.23(x45f6tg66eoafhyrv4brrngbdm): + expo-router@3.5.23(2f86f7434a59b644ba234fab7be01c9e): dependencies: '@expo/metro-runtime': 3.2.3(react-native@0.74.5(@babel/core@7.24.5)(@babel/preset-env@7.25.7(@babel/core@7.24.5))(@types/react@18.2.79)(encoding@0.1.13)(react@18.2.0)) '@expo/server': 0.4.4(typescript@5.5.4) @@ -37911,7 +37970,7 @@ snapshots: react-native-screens: 3.31.1(react-native@0.74.5(@babel/core@7.24.5)(@babel/preset-env@7.25.7(@babel/core@7.24.5))(@types/react@18.2.79)(encoding@0.1.13)(react@18.2.0))(react@18.2.0) schema-utils: 4.2.0 optionalDependencies: - '@react-navigation/drawer': 6.7.2(f5uupuoecme7pb3346nlwm73my) + '@react-navigation/drawer': 6.7.2(fe8cd8328c484d4e3eaed8eea351852b) react-native-reanimated: 3.10.1(@babel/core@7.24.5)(react-native@0.74.5(@babel/core@7.24.5)(@babel/preset-env@7.25.7(@babel/core@7.24.5))(@types/react@18.2.79)(encoding@0.1.13)(react@18.2.0))(react@18.2.0) transitivePeerDependencies: - encoding @@ -38320,6 +38379,13 @@ snapshots: node-domexception: 1.0.0 web-streams-polyfill: 3.2.1 + fetch-mock@12.5.2: + dependencies: + '@types/glob-to-regexp': 0.4.4 + dequal: 2.0.3 + glob-to-regexp: 0.4.1 + regexparam: 3.0.0 + fetch-retry@4.1.1: {} figures@3.2.0: @@ -38500,7 +38566,7 @@ snapshots: eslint: 8.57.1 vue-template-compiler: 2.7.16 - fork-ts-checker-webpack-plugin@9.0.2(typescript@5.8.2)(webpack@5.95.0(@swc/core@1.10.1)): + fork-ts-checker-webpack-plugin@9.0.2(typescript@5.8.2)(webpack@5.95.0(@swc/core@1.10.1(@swc/helpers@0.5.5))): dependencies: '@babel/code-frame': 7.26.2 chalk: 4.1.2 @@ -38515,7 +38581,7 @@ snapshots: semver: 7.6.3 tapable: 2.2.1 typescript: 5.8.2 - webpack: 5.95.0(@swc/core@1.10.1) + webpack: 5.95.0(@swc/core@1.10.1(@swc/helpers@0.5.5)) form-data-encoder@2.1.4: {} @@ -38562,13 +38628,13 @@ snapshots: react: 18.2.0 react-dom: 18.2.0(react@18.2.0) style-value-types: 5.0.0 - tslib: 2.7.0 + tslib: 2.8.1 optionalDependencies: '@emotion/is-prop-valid': 0.8.8 framesync@6.0.1: dependencies: - tslib: 2.7.0 + tslib: 2.8.1 freeport-async@2.0.0: {} @@ -38873,7 +38939,7 @@ snapshots: dependencies: array-union: 2.1.0 dir-glob: 3.0.1 - fast-glob: 3.3.2 + fast-glob: 3.3.3 ignore: 5.3.2 merge2: 1.4.1 slash: 3.0.0 @@ -38881,7 +38947,7 @@ snapshots: globby@13.2.2: dependencies: dir-glob: 3.0.1 - fast-glob: 3.3.2 + fast-glob: 3.3.3 ignore: 5.3.2 merge2: 1.4.1 slash: 4.0.0 @@ -39220,7 +39286,7 @@ snapshots: entities: 4.5.0 param-case: 3.0.4 relateurl: 0.2.7 - terser: 5.34.1 + terser: 5.39.0 html-tags@3.3.1: {} @@ -39237,18 +39303,7 @@ snapshots: '@rspack/core': 1.1.8(@swc/helpers@0.5.5) webpack: 5.95.0(@swc/core@1.10.1(@swc/helpers@0.5.5)) - html-webpack-plugin@5.6.0(@rspack/core@1.1.8)(webpack@5.95.0(@swc/core@1.10.1)): - dependencies: - '@types/html-minifier-terser': 6.1.0 - html-minifier-terser: 6.1.0 - lodash: 4.17.21 - pretty-error: 4.0.0 - tapable: 2.2.1 - optionalDependencies: - '@rspack/core': 1.1.8(@swc/helpers@0.5.5) - webpack: 5.95.0(@swc/core@1.10.1) - - html-webpack-plugin@5.6.0(@rspack/core@1.1.8)(webpack@5.95.0(webpack-cli@5.1.4)): + html-webpack-plugin@5.6.0(@rspack/core@1.1.8(@swc/helpers@0.5.5))(webpack@5.95.0): dependencies: '@types/html-minifier-terser': 6.1.0 html-minifier-terser: 6.1.0 @@ -39259,7 +39314,7 @@ snapshots: '@rspack/core': 1.1.8(@swc/helpers@0.5.5) webpack: 5.95.0(webpack-cli@5.1.4) - html-webpack-plugin@5.6.0(@rspack/core@1.1.8)(webpack@5.98.0(@swc/core@1.10.1)): + html-webpack-plugin@5.6.0(@rspack/core@1.1.8(@swc/helpers@0.5.5))(webpack@5.98.0(@swc/core@1.10.1(@swc/helpers@0.5.5))): dependencies: '@types/html-minifier-terser': 6.1.0 html-minifier-terser: 6.1.0 @@ -39268,7 +39323,7 @@ snapshots: tapable: 2.2.1 optionalDependencies: '@rspack/core': 1.1.8(@swc/helpers@0.5.5) - webpack: 5.98.0(@swc/core@1.10.1) + webpack: 5.98.0(@swc/core@1.10.1(@swc/helpers@0.5.5))(esbuild@0.25.1) optional: true htmlfy@0.6.0: @@ -39455,9 +39510,9 @@ snapshots: dependencies: postcss: 8.5.1 - icss-utils@5.1.0(postcss@8.5.2): + icss-utils@5.1.0(postcss@8.5.3): dependencies: - postcss: 8.5.2 + postcss: 8.5.3 idb@7.1.1: {} @@ -40368,12 +40423,12 @@ snapshots: readable-stream: 2.3.8 optional: true - less-loader@12.2.0(@rspack/core@1.1.8)(less@4.2.2)(webpack@5.98.0(@swc/core@1.10.1)(esbuild@0.25.1)): + less-loader@12.2.0(@rspack/core@1.1.8(@swc/helpers@0.5.5))(less@4.2.2)(webpack@5.98.0(@swc/core@1.10.1(@swc/helpers@0.5.5))): dependencies: less: 4.2.2 optionalDependencies: '@rspack/core': 1.1.8(@swc/helpers@0.5.5) - webpack: 5.98.0(@swc/core@1.10.1)(esbuild@0.25.1) + webpack: 5.98.0(@swc/core@1.10.1(@swc/helpers@0.5.5))(esbuild@0.25.1) less@4.2.2: dependencies: @@ -40402,11 +40457,11 @@ snapshots: dependencies: isomorphic.js: 0.2.5 - license-webpack-plugin@4.0.2(webpack@5.98.0(@swc/core@1.10.1)(esbuild@0.25.1)): + license-webpack-plugin@4.0.2(webpack@5.98.0(@swc/core@1.10.1(@swc/helpers@0.5.5))): dependencies: webpack-sources: 3.2.3 optionalDependencies: - webpack: 5.98.0(@swc/core@1.10.1)(esbuild@0.25.1) + webpack: 5.98.0(@swc/core@1.10.1(@swc/helpers@0.5.5))(esbuild@0.25.1) lie@3.3.0: dependencies: @@ -40699,7 +40754,7 @@ snapshots: lower-case@2.0.2: dependencies: - tslib: 2.7.0 + tslib: 2.8.1 lowercase-keys@2.0.0: {} @@ -41299,17 +41354,17 @@ snapshots: metro-minify-terser@0.76.7: dependencies: - terser: 5.34.1 + terser: 5.39.0 metro-minify-terser@0.80.12: dependencies: flow-enums-runtime: 0.0.6 - terser: 5.34.1 + terser: 5.39.0 metro-minify-terser@0.81.3: dependencies: flow-enums-runtime: 0.0.6 - terser: 5.34.1 + terser: 5.39.0 metro-minify-uglify@0.76.7: dependencies: @@ -41347,7 +41402,7 @@ snapshots: '@babel/plugin-transform-react-jsx': 7.25.9(@babel/core@7.26.10) '@babel/plugin-transform-react-jsx-self': 7.25.7(@babel/core@7.26.10) '@babel/plugin-transform-react-jsx-source': 7.25.7(@babel/core@7.26.10) - '@babel/plugin-transform-runtime': 7.25.9(@babel/core@7.26.10) + '@babel/plugin-transform-runtime': 7.26.10(@babel/core@7.26.10) '@babel/plugin-transform-shorthand-properties': 7.25.9(@babel/core@7.26.10) '@babel/plugin-transform-spread': 7.25.9(@babel/core@7.26.10) '@babel/plugin-transform-sticky-regex': 7.25.9(@babel/core@7.26.10) @@ -41880,8 +41935,8 @@ snapshots: micromark-extension-mdxjs@3.0.0: dependencies: - acorn: 8.12.1 - acorn-jsx: 5.3.2(acorn@8.12.1) + acorn: 8.14.1 + acorn-jsx: 5.3.2(acorn@8.14.1) micromark-extension-mdx-expression: 3.0.0 micromark-extension-mdx-jsx: 3.0.1 micromark-extension-mdx-md: 2.0.0 @@ -42090,15 +42145,15 @@ snapshots: mini-css-extract-plugin@2.9.1(webpack@5.95.0(@swc/core@1.10.1(@swc/helpers@0.5.5))): dependencies: - schema-utils: 4.2.0 + schema-utils: 4.3.0 tapable: 2.2.1 webpack: 5.95.0(@swc/core@1.10.1(@swc/helpers@0.5.5)) - mini-css-extract-plugin@2.9.2(webpack@5.98.0(@swc/core@1.10.1)(esbuild@0.25.1)): + mini-css-extract-plugin@2.9.2(webpack@5.98.0(@swc/core@1.10.1(@swc/helpers@0.5.5))): dependencies: - schema-utils: 4.2.0 + schema-utils: 4.3.0 tapable: 2.2.1 - webpack: 5.98.0(@swc/core@1.10.1)(esbuild@0.25.1) + webpack: 5.98.0(@swc/core@1.10.1(@swc/helpers@0.5.5))(esbuild@0.25.1) minimalistic-assert@1.0.1: {} @@ -42387,7 +42442,7 @@ snapshots: no-case@3.0.4: dependencies: lower-case: 2.0.2 - tslib: 2.7.0 + tslib: 2.8.1 nocache@3.0.4: {} @@ -42487,10 +42542,10 @@ snapshots: node-int64@0.4.0: {} - node-loader@2.1.0(webpack@5.95.0(@swc/core@1.10.1)): + node-loader@2.1.0(webpack@5.95.0(@swc/core@1.10.1(@swc/helpers@0.5.5))): dependencies: loader-utils: 2.0.4 - webpack: 5.95.0(@swc/core@1.10.1) + webpack: 5.95.0(@swc/core@1.10.1(@swc/helpers@0.5.5)) node-releases@2.0.18: {} @@ -42933,7 +42988,7 @@ snapshots: param-case@3.0.4: dependencies: dot-case: 3.0.4 - tslib: 2.7.0 + tslib: 2.8.1 parent-module@1.0.1: dependencies: @@ -43013,7 +43068,7 @@ snapshots: pascal-case@3.1.2: dependencies: no-case: 3.0.4 - tslib: 2.7.0 + tslib: 2.8.1 password-prompt@1.1.3: dependencies: @@ -43160,7 +43215,7 @@ snapshots: framesync: 6.0.1 hey-listen: 1.0.8 style-value-types: 5.0.0 - tslib: 2.7.0 + tslib: 2.8.1 portfinder@1.0.32: dependencies: @@ -43183,6 +43238,12 @@ snapshots: postcss-selector-parser: 6.1.2 postcss-value-parser: 4.2.0 + postcss-calc@9.0.1(postcss@8.5.3): + dependencies: + postcss: 8.5.3 + postcss-selector-parser: 6.1.2 + postcss-value-parser: 4.2.0 + postcss-clamp@4.1.0(postcss@8.5.1): dependencies: postcss: 8.5.1 @@ -43217,12 +43278,26 @@ snapshots: postcss: 8.5.1 postcss-value-parser: 4.2.0 + postcss-colormin@6.1.0(postcss@8.5.3): + dependencies: + browserslist: 4.24.4 + caniuse-api: 3.0.0 + colord: 2.9.3 + postcss: 8.5.3 + postcss-value-parser: 4.2.0 + postcss-convert-values@6.1.0(postcss@8.5.1): dependencies: browserslist: 4.24.4 postcss: 8.5.1 postcss-value-parser: 4.2.0 + postcss-convert-values@6.1.0(postcss@8.5.3): + dependencies: + browserslist: 4.24.4 + postcss: 8.5.3 + postcss-value-parser: 4.2.0 + postcss-custom-media@11.0.5(postcss@8.5.1): dependencies: '@csstools/cascade-layer-name-parser': 2.0.4(@csstools/css-parser-algorithms@3.0.4(@csstools/css-tokenizer@3.0.3))(@csstools/css-tokenizer@3.0.3) @@ -43257,21 +43332,37 @@ snapshots: dependencies: postcss: 8.5.1 + postcss-discard-comments@6.0.2(postcss@8.5.3): + dependencies: + postcss: 8.5.3 + postcss-discard-duplicates@6.0.3(postcss@8.5.1): dependencies: postcss: 8.5.1 + postcss-discard-duplicates@6.0.3(postcss@8.5.3): + dependencies: + postcss: 8.5.3 + postcss-discard-empty@6.0.3(postcss@8.5.1): dependencies: postcss: 8.5.1 + postcss-discard-empty@6.0.3(postcss@8.5.3): + dependencies: + postcss: 8.5.3 + postcss-discard-overridden@6.0.2(postcss@8.5.1): dependencies: postcss: 8.5.1 - postcss-discard-unused@6.0.5(postcss@8.5.1): + postcss-discard-overridden@6.0.2(postcss@8.5.3): dependencies: - postcss: 8.5.1 + postcss: 8.5.3 + + postcss-discard-unused@6.0.5(postcss@8.5.3): + dependencies: + postcss: 8.5.3 postcss-selector-parser: 6.1.2 postcss-double-position-gradients@6.0.0(postcss@8.5.1): @@ -43326,13 +43417,22 @@ snapshots: '@csstools/utilities': 2.0.0(postcss@8.5.1) postcss: 8.5.1 - postcss-load-config@4.0.2(postcss@8.4.47)(ts-node@10.9.2(@types/node@20.16.10)(typescript@5.8.2)): + postcss-load-config@4.0.2(postcss@8.4.47)(ts-node@10.9.2(@swc/core@1.10.1(@swc/helpers@0.5.5))(@types/node@20.16.10)(typescript@5.8.2)): + dependencies: + lilconfig: 3.1.2 + yaml: 2.6.1 + optionalDependencies: + postcss: 8.4.47 + ts-node: 10.9.2(@swc/core@1.10.1(@swc/helpers@0.5.5))(@types/node@20.16.10)(typescript@5.8.2) + + postcss-load-config@4.0.2(postcss@8.4.47)(ts-node@10.9.2(@swc/core@1.10.1(@swc/helpers@0.5.5))(@types/node@22.7.4)(typescript@5.5.4)): dependencies: lilconfig: 3.1.2 yaml: 2.6.1 optionalDependencies: postcss: 8.4.47 - ts-node: 10.9.2(@types/node@20.16.10)(typescript@5.8.2) + ts-node: 10.9.2(@swc/core@1.10.1(@swc/helpers@0.5.5))(@types/node@22.7.4)(typescript@5.5.4) + optional: true postcss-loader@7.3.4(postcss@8.5.1)(typescript@5.5.4)(webpack@5.95.0(@swc/core@1.10.1(@swc/helpers@0.5.5))): dependencies: @@ -43344,7 +43444,7 @@ snapshots: transitivePeerDependencies: - typescript - postcss-loader@8.1.1(@rspack/core@1.1.8)(postcss@8.5.2)(typescript@5.5.4)(webpack@5.98.0(@swc/core@1.10.1)(esbuild@0.25.1)): + postcss-loader@8.1.1(@rspack/core@1.1.8(@swc/helpers@0.5.5))(postcss@8.5.2)(typescript@5.5.4)(webpack@5.98.0(@swc/core@1.10.1(@swc/helpers@0.5.5))): dependencies: cosmiconfig: 9.0.0(typescript@5.5.4) jiti: 1.21.6 @@ -43352,7 +43452,7 @@ snapshots: semver: 7.7.1 optionalDependencies: '@rspack/core': 1.1.8(@swc/helpers@0.5.5) - webpack: 5.98.0(@swc/core@1.10.1)(esbuild@0.25.1) + webpack: 5.98.0(@swc/core@1.10.1(@swc/helpers@0.5.5))(esbuild@0.25.1) transitivePeerDependencies: - typescript @@ -43363,10 +43463,10 @@ snapshots: postcss-media-query-parser@0.2.3: {} - postcss-merge-idents@6.0.3(postcss@8.5.1): + postcss-merge-idents@6.0.3(postcss@8.5.3): dependencies: - cssnano-utils: 4.0.2(postcss@8.5.1) - postcss: 8.5.1 + cssnano-utils: 4.0.2(postcss@8.5.3) + postcss: 8.5.3 postcss-value-parser: 4.2.0 postcss-merge-longhand@6.0.5(postcss@8.5.1): @@ -43375,6 +43475,12 @@ snapshots: postcss-value-parser: 4.2.0 stylehacks: 6.1.1(postcss@8.5.1) + postcss-merge-longhand@6.0.5(postcss@8.5.3): + dependencies: + postcss: 8.5.3 + postcss-value-parser: 4.2.0 + stylehacks: 6.1.1(postcss@8.5.3) + postcss-merge-rules@6.1.1(postcss@8.5.1): dependencies: browserslist: 4.24.4 @@ -43383,11 +43489,24 @@ snapshots: postcss: 8.5.1 postcss-selector-parser: 6.1.2 + postcss-merge-rules@6.1.1(postcss@8.5.3): + dependencies: + browserslist: 4.24.4 + caniuse-api: 3.0.0 + cssnano-utils: 4.0.2(postcss@8.5.3) + postcss: 8.5.3 + postcss-selector-parser: 6.1.2 + postcss-minify-font-values@6.1.0(postcss@8.5.1): dependencies: postcss: 8.5.1 postcss-value-parser: 4.2.0 + postcss-minify-font-values@6.1.0(postcss@8.5.3): + dependencies: + postcss: 8.5.3 + postcss-value-parser: 4.2.0 + postcss-minify-gradients@6.0.3(postcss@8.5.1): dependencies: colord: 2.9.3 @@ -43395,6 +43514,13 @@ snapshots: postcss: 8.5.1 postcss-value-parser: 4.2.0 + postcss-minify-gradients@6.0.3(postcss@8.5.3): + dependencies: + colord: 2.9.3 + cssnano-utils: 4.0.2(postcss@8.5.3) + postcss: 8.5.3 + postcss-value-parser: 4.2.0 + postcss-minify-params@6.1.0(postcss@8.5.1): dependencies: browserslist: 4.24.4 @@ -43402,18 +43528,30 @@ snapshots: postcss: 8.5.1 postcss-value-parser: 4.2.0 + postcss-minify-params@6.1.0(postcss@8.5.3): + dependencies: + browserslist: 4.24.4 + cssnano-utils: 4.0.2(postcss@8.5.3) + postcss: 8.5.3 + postcss-value-parser: 4.2.0 + postcss-minify-selectors@6.0.4(postcss@8.5.1): dependencies: postcss: 8.5.1 postcss-selector-parser: 6.1.2 + postcss-minify-selectors@6.0.4(postcss@8.5.3): + dependencies: + postcss: 8.5.3 + postcss-selector-parser: 6.1.2 + postcss-modules-extract-imports@3.1.0(postcss@8.5.1): dependencies: postcss: 8.5.1 - postcss-modules-extract-imports@3.1.0(postcss@8.5.2): + postcss-modules-extract-imports@3.1.0(postcss@8.5.3): dependencies: - postcss: 8.5.2 + postcss: 8.5.3 postcss-modules-local-by-default@4.0.5(postcss@8.5.1): dependencies: @@ -43422,10 +43560,10 @@ snapshots: postcss-selector-parser: 6.1.2 postcss-value-parser: 4.2.0 - postcss-modules-local-by-default@4.0.5(postcss@8.5.2): + postcss-modules-local-by-default@4.0.5(postcss@8.5.3): dependencies: - icss-utils: 5.1.0(postcss@8.5.2) - postcss: 8.5.2 + icss-utils: 5.1.0(postcss@8.5.3) + postcss: 8.5.3 postcss-selector-parser: 6.1.2 postcss-value-parser: 4.2.0 @@ -43434,9 +43572,9 @@ snapshots: postcss: 8.5.1 postcss-selector-parser: 6.1.2 - postcss-modules-scope@3.2.0(postcss@8.5.2): + postcss-modules-scope@3.2.0(postcss@8.5.3): dependencies: - postcss: 8.5.2 + postcss: 8.5.3 postcss-selector-parser: 6.1.2 postcss-modules-values@4.0.0(postcss@8.5.1): @@ -43444,10 +43582,10 @@ snapshots: icss-utils: 5.1.0(postcss@8.5.1) postcss: 8.5.1 - postcss-modules-values@4.0.0(postcss@8.5.2): + postcss-modules-values@4.0.0(postcss@8.5.3): dependencies: - icss-utils: 5.1.0(postcss@8.5.2) - postcss: 8.5.2 + icss-utils: 5.1.0(postcss@8.5.3) + postcss: 8.5.3 postcss-nested@6.2.0(postcss@8.4.47): dependencies: @@ -43465,47 +43603,92 @@ snapshots: dependencies: postcss: 8.5.1 + postcss-normalize-charset@6.0.2(postcss@8.5.3): + dependencies: + postcss: 8.5.3 + postcss-normalize-display-values@6.0.2(postcss@8.5.1): dependencies: postcss: 8.5.1 postcss-value-parser: 4.2.0 + postcss-normalize-display-values@6.0.2(postcss@8.5.3): + dependencies: + postcss: 8.5.3 + postcss-value-parser: 4.2.0 + postcss-normalize-positions@6.0.2(postcss@8.5.1): dependencies: postcss: 8.5.1 postcss-value-parser: 4.2.0 + postcss-normalize-positions@6.0.2(postcss@8.5.3): + dependencies: + postcss: 8.5.3 + postcss-value-parser: 4.2.0 + postcss-normalize-repeat-style@6.0.2(postcss@8.5.1): dependencies: postcss: 8.5.1 postcss-value-parser: 4.2.0 + postcss-normalize-repeat-style@6.0.2(postcss@8.5.3): + dependencies: + postcss: 8.5.3 + postcss-value-parser: 4.2.0 + postcss-normalize-string@6.0.2(postcss@8.5.1): dependencies: postcss: 8.5.1 postcss-value-parser: 4.2.0 + postcss-normalize-string@6.0.2(postcss@8.5.3): + dependencies: + postcss: 8.5.3 + postcss-value-parser: 4.2.0 + postcss-normalize-timing-functions@6.0.2(postcss@8.5.1): dependencies: postcss: 8.5.1 postcss-value-parser: 4.2.0 + postcss-normalize-timing-functions@6.0.2(postcss@8.5.3): + dependencies: + postcss: 8.5.3 + postcss-value-parser: 4.2.0 + postcss-normalize-unicode@6.1.0(postcss@8.5.1): dependencies: browserslist: 4.24.4 postcss: 8.5.1 postcss-value-parser: 4.2.0 + postcss-normalize-unicode@6.1.0(postcss@8.5.3): + dependencies: + browserslist: 4.24.4 + postcss: 8.5.3 + postcss-value-parser: 4.2.0 + postcss-normalize-url@6.0.2(postcss@8.5.1): dependencies: postcss: 8.5.1 postcss-value-parser: 4.2.0 + postcss-normalize-url@6.0.2(postcss@8.5.3): + dependencies: + postcss: 8.5.3 + postcss-value-parser: 4.2.0 + postcss-normalize-whitespace@6.0.2(postcss@8.5.1): dependencies: postcss: 8.5.1 postcss-value-parser: 4.2.0 + postcss-normalize-whitespace@6.0.2(postcss@8.5.3): + dependencies: + postcss: 8.5.3 + postcss-value-parser: 4.2.0 + postcss-opacity-percentage@3.0.0(postcss@8.5.1): dependencies: postcss: 8.5.1 @@ -43516,6 +43699,12 @@ snapshots: postcss: 8.5.1 postcss-value-parser: 4.2.0 + postcss-ordered-values@6.0.2(postcss@8.5.3): + dependencies: + cssnano-utils: 4.0.2(postcss@8.5.3) + postcss: 8.5.3 + postcss-value-parser: 4.2.0 + postcss-overflow-shorthand@6.0.0(postcss@8.5.1): dependencies: postcss: 8.5.1 @@ -43602,9 +43791,9 @@ snapshots: postcss: 8.5.1 postcss-selector-parser: 7.0.0 - postcss-reduce-idents@6.0.3(postcss@8.5.1): + postcss-reduce-idents@6.0.3(postcss@8.5.3): dependencies: - postcss: 8.5.1 + postcss: 8.5.3 postcss-value-parser: 4.2.0 postcss-reduce-initial@6.1.0(postcss@8.5.1): @@ -43613,11 +43802,22 @@ snapshots: caniuse-api: 3.0.0 postcss: 8.5.1 + postcss-reduce-initial@6.1.0(postcss@8.5.3): + dependencies: + browserslist: 4.24.4 + caniuse-api: 3.0.0 + postcss: 8.5.3 + postcss-reduce-transforms@6.0.2(postcss@8.5.1): dependencies: postcss: 8.5.1 postcss-value-parser: 4.2.0 + postcss-reduce-transforms@6.0.2(postcss@8.5.3): + dependencies: + postcss: 8.5.3 + postcss-value-parser: 4.2.0 + postcss-replace-overflow-wrap@4.0.0(postcss@8.5.1): dependencies: postcss: 8.5.1 @@ -43637,9 +43837,9 @@ snapshots: cssesc: 3.0.0 util-deprecate: 1.0.2 - postcss-sort-media-queries@5.2.0(postcss@8.5.1): + postcss-sort-media-queries@5.2.0(postcss@8.5.3): dependencies: - postcss: 8.5.1 + postcss: 8.5.3 sort-css-media-queries: 2.2.0 postcss-svgo@6.0.3(postcss@8.5.1): @@ -43648,16 +43848,27 @@ snapshots: postcss-value-parser: 4.2.0 svgo: 3.3.2 + postcss-svgo@6.0.3(postcss@8.5.3): + dependencies: + postcss: 8.5.3 + postcss-value-parser: 4.2.0 + svgo: 3.3.2 + postcss-unique-selectors@6.0.4(postcss@8.5.1): dependencies: postcss: 8.5.1 postcss-selector-parser: 6.1.2 + postcss-unique-selectors@6.0.4(postcss@8.5.3): + dependencies: + postcss: 8.5.3 + postcss-selector-parser: 6.1.2 + postcss-value-parser@4.2.0: {} - postcss-zindex@6.0.2(postcss@8.5.1): + postcss-zindex@6.0.2(postcss@8.5.3): dependencies: - postcss: 8.5.1 + postcss: 8.5.3 postcss@8.4.27: dependencies: @@ -44840,19 +45051,7 @@ snapshots: - supports-color - utf-8-validate - react-navigation-stack@2.10.4(b23yjknfeew5kcy4o5zrlfz5ae): - dependencies: - '@react-native-community/masked-view': 0.1.11(react-native@0.74.5(@babel/core@7.24.5)(@babel/preset-env@7.25.7(@babel/core@7.24.5))(@types/react@18.2.79)(encoding@0.1.13)(react@18.2.0))(react@18.2.0) - color: 3.2.1 - react: 18.2.0 - react-native: 0.74.5(@babel/core@7.24.5)(@babel/preset-env@7.25.7(@babel/core@7.24.5))(@types/react@18.2.79)(encoding@0.1.13)(react@18.2.0) - react-native-gesture-handler: 2.16.2(react-native@0.74.5(@babel/core@7.24.5)(@babel/preset-env@7.25.7(@babel/core@7.24.5))(@types/react@18.2.79)(encoding@0.1.13)(react@18.2.0))(react@18.2.0) - react-native-iphone-x-helper: 1.3.1(react-native@0.74.5(@babel/core@7.24.5)(@babel/preset-env@7.25.7(@babel/core@7.24.5))(@types/react@18.2.79)(encoding@0.1.13)(react@18.2.0)) - react-native-safe-area-context: 4.10.5(react-native@0.74.5(@babel/core@7.24.5)(@babel/preset-env@7.25.7(@babel/core@7.24.5))(@types/react@18.2.79)(encoding@0.1.13)(react@18.2.0))(react@18.2.0) - react-native-screens: 3.31.1(react-native@0.74.5(@babel/core@7.24.5)(@babel/preset-env@7.25.7(@babel/core@7.24.5))(@types/react@18.2.79)(encoding@0.1.13)(react@18.2.0))(react@18.2.0) - react-navigation: 4.4.4(react-native@0.74.5(@babel/core@7.24.5)(@babel/preset-env@7.25.7(@babel/core@7.24.5))(@types/react@18.2.79)(encoding@0.1.13)(react@18.2.0))(react@18.2.0) - - react-navigation-stack@2.10.4(qmdtutm2q5vv2bqwrj2rmb5zum): + react-navigation-stack@2.10.4(723df46775cc6e8dbfaef5bf48d4f911): dependencies: '@react-native-community/masked-view': 0.1.11(react-native@0.74.5(@babel/core@7.26.10)(@babel/preset-env@7.25.7(@babel/core@7.26.10))(@types/react@18.2.79)(encoding@0.1.13)(react@18.2.0))(react@18.2.0) color: 3.2.1 @@ -44864,6 +45063,18 @@ snapshots: react-native-screens: 3.31.1(react-native@0.74.5(@babel/core@7.26.10)(@babel/preset-env@7.25.7(@babel/core@7.26.10))(@types/react@18.2.79)(encoding@0.1.13)(react@18.2.0))(react@18.2.0) react-navigation: 4.4.4(react-native@0.74.5(@babel/core@7.26.10)(@babel/preset-env@7.25.7(@babel/core@7.26.10))(@types/react@18.2.79)(encoding@0.1.13)(react@18.2.0))(react@18.2.0) + react-navigation-stack@2.10.4(cf0911ea264205029347060226fe0d29): + dependencies: + '@react-native-community/masked-view': 0.1.11(react-native@0.74.5(@babel/core@7.24.5)(@babel/preset-env@7.25.7(@babel/core@7.24.5))(@types/react@18.2.79)(encoding@0.1.13)(react@18.2.0))(react@18.2.0) + color: 3.2.1 + react: 18.2.0 + react-native: 0.74.5(@babel/core@7.24.5)(@babel/preset-env@7.25.7(@babel/core@7.24.5))(@types/react@18.2.79)(encoding@0.1.13)(react@18.2.0) + react-native-gesture-handler: 2.16.2(react-native@0.74.5(@babel/core@7.24.5)(@babel/preset-env@7.25.7(@babel/core@7.24.5))(@types/react@18.2.79)(encoding@0.1.13)(react@18.2.0))(react@18.2.0) + react-native-iphone-x-helper: 1.3.1(react-native@0.74.5(@babel/core@7.24.5)(@babel/preset-env@7.25.7(@babel/core@7.24.5))(@types/react@18.2.79)(encoding@0.1.13)(react@18.2.0)) + react-native-safe-area-context: 4.10.5(react-native@0.74.5(@babel/core@7.24.5)(@babel/preset-env@7.25.7(@babel/core@7.24.5))(@types/react@18.2.79)(encoding@0.1.13)(react@18.2.0))(react@18.2.0) + react-native-screens: 3.31.1(react-native@0.74.5(@babel/core@7.24.5)(@babel/preset-env@7.25.7(@babel/core@7.24.5))(@types/react@18.2.79)(encoding@0.1.13)(react@18.2.0))(react@18.2.0) + react-navigation: 4.4.4(react-native@0.74.5(@babel/core@7.24.5)(@babel/preset-env@7.25.7(@babel/core@7.24.5))(@types/react@18.2.79)(encoding@0.1.13)(react@18.2.0))(react@18.2.0) + react-navigation@4.4.4(react-native@0.74.5(@babel/core@7.24.5)(@babel/preset-env@7.25.7(@babel/core@7.24.5))(@types/react@18.2.79)(encoding@0.1.13)(react@18.2.0))(react@18.2.0): dependencies: '@react-navigation/core': 3.7.9(react@18.2.0) @@ -44886,7 +45097,7 @@ snapshots: dependencies: react: 18.2.0 react-style-singleton: 2.2.1(@types/react@18.3.11)(react@18.2.0) - tslib: 2.7.0 + tslib: 2.8.1 optionalDependencies: '@types/react': 18.3.11 @@ -44895,7 +45106,7 @@ snapshots: react: 18.2.0 react-remove-scroll-bar: 2.3.6(@types/react@18.3.11)(react@18.2.0) react-style-singleton: 2.2.1(@types/react@18.3.11)(react@18.2.0) - tslib: 2.7.0 + tslib: 2.8.1 use-callback-ref: 1.3.2(@types/react@18.3.11)(react@18.2.0) use-sidecar: 1.1.2(@types/react@18.3.11)(react@18.2.0) optionalDependencies: @@ -44954,7 +45165,7 @@ snapshots: get-nonce: 1.0.1 invariant: 2.2.4 react: 18.2.0 - tslib: 2.7.0 + tslib: 2.8.1 optionalDependencies: '@types/react': 18.3.11 @@ -45088,7 +45299,7 @@ snapshots: ast-types: 0.15.2 esprima: 4.0.1 source-map: 0.6.1 - tslib: 2.7.0 + tslib: 2.8.1 recast@0.23.11: dependencies: @@ -45096,7 +45307,7 @@ snapshots: esprima: 4.0.1 source-map: 0.6.1 tiny-invariant: 1.3.3 - tslib: 2.7.0 + tslib: 2.8.1 rechoir@0.6.2: dependencies: @@ -45176,6 +45387,8 @@ snapshots: es-errors: 1.3.0 set-function-name: 2.0.2 + regexparam@3.0.0: {} + regexpp@3.2.0: {} regexpu-core@6.1.1: @@ -45355,7 +45568,7 @@ snapshots: adjust-sourcemap-loader: 4.0.0 convert-source-map: 1.9.0 loader-utils: 2.0.4 - postcss: 8.5.2 + postcss: 8.5.3 source-map: 0.6.1 resolve.exports@2.0.2: {} @@ -45598,20 +45811,20 @@ snapshots: safer-buffer@2.1.2: {} - sass-loader@13.3.3(sass@1.79.4)(webpack@5.98.0): + sass-loader@13.3.3(sass@1.79.4)(webpack@5.98.0(@swc/core@1.10.1(@swc/helpers@0.5.5))): dependencies: neo-async: 2.6.2 - webpack: 5.98.0 + webpack: 5.98.0(@swc/core@1.10.1(@swc/helpers@0.5.5))(esbuild@0.25.1) optionalDependencies: sass: 1.79.4 - sass-loader@16.0.5(@rspack/core@1.1.8)(sass@1.85.0)(webpack@5.98.0(@swc/core@1.10.1)(esbuild@0.25.1)): + sass-loader@16.0.5(@rspack/core@1.1.8(@swc/helpers@0.5.5))(sass@1.85.0)(webpack@5.98.0(@swc/core@1.10.1(@swc/helpers@0.5.5))): dependencies: neo-async: 2.6.2 optionalDependencies: '@rspack/core': 1.1.8(@swc/helpers@0.5.5) sass: 1.85.0 - webpack: 5.98.0(@swc/core@1.10.1)(esbuild@0.25.1) + webpack: 5.98.0(@swc/core@1.10.1(@swc/helpers@0.5.5))(esbuild@0.25.1) sass@1.79.4: dependencies: @@ -46002,7 +46215,7 @@ snapshots: snake-case@3.0.4: dependencies: dot-case: 3.0.4 - tslib: 2.7.0 + tslib: 2.8.1 sockjs@0.3.24: dependencies: @@ -46020,7 +46233,7 @@ snapshots: socks-proxy-agent@8.0.4: dependencies: - agent-base: 7.1.1 + agent-base: 7.1.3 debug: 4.4.0(supports-color@8.1.1) socks: 2.8.3 transitivePeerDependencies: @@ -46039,17 +46252,17 @@ snapshots: source-map-js@1.2.1: {} - source-map-loader@5.0.0(webpack@5.95.0(webpack-cli@5.1.4)): + source-map-loader@5.0.0(webpack@5.95.0): dependencies: iconv-lite: 0.6.3 source-map-js: 1.2.1 webpack: 5.95.0(webpack-cli@5.1.4) - source-map-loader@5.0.0(webpack@5.98.0(@swc/core@1.10.1)(esbuild@0.25.1)): + source-map-loader@5.0.0(webpack@5.98.0(@swc/core@1.10.1(@swc/helpers@0.5.5))): dependencies: iconv-lite: 0.6.3 source-map-js: 1.2.1 - webpack: 5.98.0(@swc/core@1.10.1)(esbuild@0.25.1) + webpack: 5.98.0(@swc/core@1.10.1(@swc/helpers@0.5.5))(esbuild@0.25.1) source-map-support@0.5.21: dependencies: @@ -46336,17 +46549,17 @@ snapshots: structured-headers@0.4.1: {} - style-loader@3.3.4(webpack@5.95.0(@swc/core@1.10.1)): + style-loader@3.3.4(webpack@5.95.0(@swc/core@1.10.1(@swc/helpers@0.5.5))): dependencies: - webpack: 5.95.0(@swc/core@1.10.1) + webpack: 5.95.0(@swc/core@1.10.1(@swc/helpers@0.5.5)) - style-loader@3.3.4(webpack@5.98.0(@swc/core@1.6.13(@swc/helpers@0.5.5))): + style-loader@3.3.4(webpack@5.98.0(@swc/core@1.10.1(@swc/helpers@0.5.5))): dependencies: - webpack: 5.98.0(@swc/core@1.6.13(@swc/helpers@0.5.5)) + webpack: 5.98.0(@swc/core@1.10.1(@swc/helpers@0.5.5))(esbuild@0.25.1) - style-loader@3.3.4(webpack@5.98.0): + style-loader@3.3.4(webpack@5.98.0(@swc/core@1.6.13(@swc/helpers@0.5.5))): dependencies: - webpack: 5.98.0 + webpack: 5.98.0(@swc/core@1.6.13(@swc/helpers@0.5.5)) style-to-object@0.4.4: dependencies: @@ -46359,7 +46572,7 @@ snapshots: style-value-types@5.0.0: dependencies: hey-listen: 1.0.8 - tslib: 2.7.0 + tslib: 2.8.1 styled-jsx@5.1.1(@babel/core@7.26.10)(react@18.2.0): dependencies: @@ -46374,6 +46587,12 @@ snapshots: postcss: 8.5.1 postcss-selector-parser: 6.1.2 + stylehacks@6.1.1(postcss@8.5.3): + dependencies: + browserslist: 4.24.4 + postcss: 8.5.3 + postcss-selector-parser: 6.1.2 + styleq@0.1.3: {} stylis@4.2.0: {} @@ -46476,7 +46695,7 @@ snapshots: tabbable@6.2.0: {} - tailwindcss@3.4.13(ts-node@10.9.2(@types/node@20.16.10)(typescript@5.8.2)): + tailwindcss@3.4.13(ts-node@10.9.2(@swc/core@1.10.1(@swc/helpers@0.5.5))(@types/node@20.16.10)(typescript@5.8.2)): dependencies: '@alloc/quick-lru': 5.2.0 arg: 5.0.2 @@ -46495,7 +46714,7 @@ snapshots: postcss: 8.4.47 postcss-import: 15.1.0(postcss@8.4.47) postcss-js: 4.0.1(postcss@8.4.47) - postcss-load-config: 4.0.2(postcss@8.4.47)(ts-node@10.9.2(@types/node@20.16.10)(typescript@5.8.2)) + postcss-load-config: 4.0.2(postcss@8.4.47)(ts-node@10.9.2(@swc/core@1.10.1(@swc/helpers@0.5.5))(@types/node@20.16.10)(typescript@5.8.2)) postcss-nested: 6.2.0(postcss@8.4.47) postcss-selector-parser: 6.1.2 resolve: 1.22.8 @@ -46503,6 +46722,34 @@ snapshots: transitivePeerDependencies: - ts-node + tailwindcss@3.4.13(ts-node@10.9.2(@swc/core@1.10.1(@swc/helpers@0.5.5))(@types/node@22.7.4)(typescript@5.5.4)): + dependencies: + '@alloc/quick-lru': 5.2.0 + arg: 5.0.2 + chokidar: 3.6.0 + didyoumean: 1.2.2 + dlv: 1.1.3 + fast-glob: 3.3.2 + glob-parent: 6.0.2 + is-glob: 4.0.3 + jiti: 1.21.6 + lilconfig: 2.1.0 + micromatch: 4.0.8 + normalize-path: 3.0.0 + object-hash: 3.0.0 + picocolors: 1.1.0 + postcss: 8.4.47 + postcss-import: 15.1.0(postcss@8.4.47) + postcss-js: 4.0.1(postcss@8.4.47) + postcss-load-config: 4.0.2(postcss@8.4.47)(ts-node@10.9.2(@swc/core@1.10.1(@swc/helpers@0.5.5))(@types/node@22.7.4)(typescript@5.5.4)) + postcss-nested: 6.2.0(postcss@8.4.47) + postcss-selector-parser: 6.1.2 + resolve: 1.22.8 + sucrase: 3.35.0 + transitivePeerDependencies: + - ts-node + optional: true + tamagui@1.79.6(@types/react@18.3.11)(immer@9.0.21)(react-dom@18.2.0(react@18.2.0))(react-native-web@0.19.12(encoding@0.1.13)(react-dom@18.2.0(react@18.2.0))(react@18.2.0))(react-native@0.74.1(@babel/core@7.24.5)(@babel/preset-env@7.26.9(@babel/core@7.24.5))(@types/react@18.3.11)(encoding@0.1.13)(react@18.2.0))(react@18.2.0): dependencies: '@tamagui/accordion': 1.79.6(react@18.2.0) @@ -46681,17 +46928,6 @@ snapshots: optionalDependencies: '@swc/core': 1.10.1(@swc/helpers@0.5.5) - terser-webpack-plugin@5.3.10(@swc/core@1.10.1)(webpack@5.95.0(@swc/core@1.10.1)): - dependencies: - '@jridgewell/trace-mapping': 0.3.25 - jest-worker: 27.5.1 - schema-utils: 3.3.0 - serialize-javascript: 6.0.2 - terser: 5.34.1 - webpack: 5.95.0(@swc/core@1.10.1) - optionalDependencies: - '@swc/core': 1.10.1(@swc/helpers@0.5.5) - terser-webpack-plugin@5.3.10(@swc/core@1.6.13(@swc/helpers@0.5.5))(webpack@5.95.0(@swc/core@1.6.13(@swc/helpers@0.5.5))): dependencies: '@jridgewell/trace-mapping': 0.3.25 @@ -46703,7 +46939,7 @@ snapshots: optionalDependencies: '@swc/core': 1.6.13(@swc/helpers@0.5.5) - terser-webpack-plugin@5.3.10(webpack@5.95.0(webpack-cli@5.1.4)): + terser-webpack-plugin@5.3.10(webpack@5.95.0): dependencies: '@jridgewell/trace-mapping': 0.3.25 jest-worker: 27.5.1 @@ -46712,30 +46948,18 @@ snapshots: terser: 5.34.1 webpack: 5.95.0(webpack-cli@5.1.4) - terser-webpack-plugin@5.3.14(@swc/core@1.10.1)(esbuild@0.25.1)(webpack@5.98.0(@swc/core@1.10.1)(esbuild@0.25.1)): + terser-webpack-plugin@5.3.14(@swc/core@1.10.1(@swc/helpers@0.5.5))(esbuild@0.25.1)(webpack@5.98.0(@swc/core@1.10.1(@swc/helpers@0.5.5))): dependencies: '@jridgewell/trace-mapping': 0.3.25 jest-worker: 27.5.1 schema-utils: 4.3.0 serialize-javascript: 6.0.2 terser: 5.39.0 - webpack: 5.98.0(@swc/core@1.10.1)(esbuild@0.25.1) + webpack: 5.98.0(@swc/core@1.10.1(@swc/helpers@0.5.5))(esbuild@0.25.1) optionalDependencies: '@swc/core': 1.10.1(@swc/helpers@0.5.5) esbuild: 0.25.1 - terser-webpack-plugin@5.3.14(@swc/core@1.10.1)(webpack@5.98.0(@swc/core@1.10.1)): - dependencies: - '@jridgewell/trace-mapping': 0.3.25 - jest-worker: 27.5.1 - schema-utils: 4.3.0 - serialize-javascript: 6.0.2 - terser: 5.39.0 - webpack: 5.98.0(@swc/core@1.10.1) - optionalDependencies: - '@swc/core': 1.10.1(@swc/helpers@0.5.5) - optional: true - terser-webpack-plugin@5.3.14(@swc/core@1.6.13(@swc/helpers@0.5.5))(webpack@5.98.0(@swc/core@1.6.13(@swc/helpers@0.5.5))): dependencies: '@jridgewell/trace-mapping': 0.3.25 @@ -46747,15 +46971,6 @@ snapshots: optionalDependencies: '@swc/core': 1.6.13(@swc/helpers@0.5.5) - terser-webpack-plugin@5.3.14(webpack@5.98.0): - dependencies: - '@jridgewell/trace-mapping': 0.3.25 - jest-worker: 27.5.1 - schema-utils: 4.3.0 - serialize-javascript: 6.0.2 - terser: 5.39.0 - webpack: 5.98.0 - terser@5.34.1: dependencies: '@jridgewell/source-map': 0.3.6 @@ -46766,7 +46981,7 @@ snapshots: terser@5.39.0: dependencies: '@jridgewell/source-map': 0.3.6 - acorn: 8.12.1 + acorn: 8.14.1 commander: 2.20.3 source-map-support: 0.5.21 @@ -46916,7 +47131,7 @@ snapshots: ts-interface-checker@0.1.13: {} - ts-loader@9.5.2(typescript@5.8.2)(webpack@5.95.0(@swc/core@1.10.1)): + ts-loader@9.5.2(typescript@5.8.2)(webpack@5.95.0(@swc/core@1.10.1(@swc/helpers@0.5.5))): dependencies: chalk: 4.1.2 enhanced-resolve: 5.17.1 @@ -46924,29 +47139,30 @@ snapshots: semver: 7.6.3 source-map: 0.7.4 typescript: 5.8.2 - webpack: 5.95.0(@swc/core@1.10.1) + webpack: 5.95.0(@swc/core@1.10.1(@swc/helpers@0.5.5)) - ts-node@10.9.2(@swc/core@1.10.1)(@types/node@22.7.4)(typescript@5.3.3): + ts-node@10.9.2(@swc/core@1.10.1(@swc/helpers@0.5.5))(@types/node@20.16.10)(typescript@5.8.2): dependencies: '@cspotcode/source-map-support': 0.8.1 '@tsconfig/node10': 1.0.11 '@tsconfig/node12': 1.0.11 '@tsconfig/node14': 1.0.3 '@tsconfig/node16': 1.0.4 - '@types/node': 22.7.4 + '@types/node': 20.16.10 acorn: 8.12.1 acorn-walk: 8.3.4 arg: 4.1.3 create-require: 1.1.1 diff: 4.0.2 make-error: 1.3.6 - typescript: 5.3.3 + typescript: 5.8.2 v8-compile-cache-lib: 3.0.1 yn: 3.1.1 optionalDependencies: '@swc/core': 1.10.1(@swc/helpers@0.5.5) + optional: true - ts-node@10.9.2(@swc/core@1.10.1)(@types/node@22.7.4)(typescript@5.5.4): + ts-node@10.9.2(@swc/core@1.10.1(@swc/helpers@0.5.5))(@types/node@22.7.4)(typescript@5.3.3): dependencies: '@cspotcode/source-map-support': 0.8.1 '@tsconfig/node10': 1.0.11 @@ -46960,13 +47176,13 @@ snapshots: create-require: 1.1.1 diff: 4.0.2 make-error: 1.3.6 - typescript: 5.5.4 + typescript: 5.3.3 v8-compile-cache-lib: 3.0.1 yn: 3.1.1 optionalDependencies: '@swc/core': 1.10.1(@swc/helpers@0.5.5) - ts-node@10.9.2(@swc/core@1.10.1)(@types/node@22.7.4)(typescript@5.8.2): + ts-node@10.9.2(@swc/core@1.10.1(@swc/helpers@0.5.5))(@types/node@22.7.4)(typescript@5.5.4): dependencies: '@cspotcode/source-map-support': 0.8.1 '@tsconfig/node10': 1.0.11 @@ -46980,33 +47196,33 @@ snapshots: create-require: 1.1.1 diff: 4.0.2 make-error: 1.3.6 - typescript: 5.8.2 + typescript: 5.5.4 v8-compile-cache-lib: 3.0.1 yn: 3.1.1 optionalDependencies: '@swc/core': 1.10.1(@swc/helpers@0.5.5) - ts-node@10.9.2(@swc/core@1.6.13(@swc/helpers@0.5.5))(@types/node@20.16.10)(typescript@4.5.5): + ts-node@10.9.2(@swc/core@1.10.1(@swc/helpers@0.5.5))(@types/node@22.7.4)(typescript@5.8.2): dependencies: '@cspotcode/source-map-support': 0.8.1 '@tsconfig/node10': 1.0.11 '@tsconfig/node12': 1.0.11 '@tsconfig/node14': 1.0.3 '@tsconfig/node16': 1.0.4 - '@types/node': 20.16.10 + '@types/node': 22.7.4 acorn: 8.12.1 acorn-walk: 8.3.4 arg: 4.1.3 create-require: 1.1.1 diff: 4.0.2 make-error: 1.3.6 - typescript: 4.5.5 + typescript: 5.8.2 v8-compile-cache-lib: 3.0.1 yn: 3.1.1 optionalDependencies: - '@swc/core': 1.6.13(@swc/helpers@0.5.5) + '@swc/core': 1.10.1(@swc/helpers@0.5.5) - ts-node@10.9.2(@types/node@20.16.10)(typescript@5.8.2): + ts-node@10.9.2(@swc/core@1.6.13(@swc/helpers@0.5.5))(@types/node@20.16.10)(typescript@4.5.5): dependencies: '@cspotcode/source-map-support': 0.8.1 '@tsconfig/node10': 1.0.11 @@ -47020,10 +47236,11 @@ snapshots: create-require: 1.1.1 diff: 4.0.2 make-error: 1.3.6 - typescript: 5.8.2 + typescript: 4.5.5 v8-compile-cache-lib: 3.0.1 yn: 3.1.1 - optional: true + optionalDependencies: + '@swc/core': 1.6.13(@swc/helpers@0.5.5) ts-object-utils@0.0.5: {} @@ -47479,7 +47696,7 @@ snapshots: use-callback-ref@1.3.2(@types/react@18.3.11)(react@18.2.0): dependencies: react: 18.2.0 - tslib: 2.7.0 + tslib: 2.8.1 optionalDependencies: '@types/react': 18.3.11 @@ -47491,7 +47708,7 @@ snapshots: dependencies: detect-node-es: 1.1.0 react: 18.2.0 - tslib: 2.7.0 + tslib: 2.8.1 optionalDependencies: '@types/react': 18.3.11 @@ -47699,7 +47916,7 @@ snapshots: vite-plugin-vuetify@2.0.4(vite@5.4.8(@types/node@22.7.4)(less@4.2.2)(lightningcss@1.28.2)(sass@1.79.4)(terser@5.39.0))(vue@3.4.21(typescript@5.5.4))(vuetify@3.6.8): dependencies: - '@vuetify/loader-shared': 2.0.3(vue@3.4.21(typescript@5.5.4))(vuetify@3.6.8(typescript@5.5.4)(vite-plugin-vuetify@2.0.4)(vue@3.4.21(typescript@5.5.4))) + '@vuetify/loader-shared': 2.0.3(vue@3.4.21(typescript@5.5.4))(vuetify@3.6.8) debug: 4.3.7 upath: 2.0.1 vite: 5.4.8(@types/node@22.7.4)(less@4.2.2)(lightningcss@1.28.2)(sass@1.79.4)(terser@5.39.0) @@ -48065,9 +48282,9 @@ snapshots: webpack-cli@5.1.4(webpack@5.95.0): dependencies: '@discoveryjs/json-ext': 0.5.7 - '@webpack-cli/configtest': 2.1.1(webpack-cli@5.1.4(webpack@5.95.0))(webpack@5.95.0(webpack-cli@5.1.4)) - '@webpack-cli/info': 2.0.2(webpack-cli@5.1.4(webpack@5.95.0))(webpack@5.95.0(webpack-cli@5.1.4)) - '@webpack-cli/serve': 2.0.5(webpack-cli@5.1.4(webpack@5.95.0))(webpack@5.95.0(webpack-cli@5.1.4)) + '@webpack-cli/configtest': 2.1.1(webpack-cli@5.1.4)(webpack@5.95.0) + '@webpack-cli/info': 2.0.2(webpack-cli@5.1.4)(webpack@5.95.0) + '@webpack-cli/serve': 2.0.5(webpack-cli@5.1.4)(webpack@5.95.0) colorette: 2.0.20 commander: 10.0.1 cross-spawn: 7.0.3 @@ -48085,70 +48302,21 @@ snapshots: memfs: 3.5.3 mime-types: 2.1.35 range-parser: 1.2.1 - schema-utils: 4.2.0 + schema-utils: 4.3.0 webpack: 5.95.0(@swc/core@1.10.1(@swc/helpers@0.5.5)) - webpack-dev-middleware@5.3.4(webpack@5.95.0(@swc/core@1.10.1)): - dependencies: - colorette: 2.0.20 - memfs: 3.5.3 - mime-types: 2.1.35 - range-parser: 1.2.1 - schema-utils: 4.2.0 - webpack: 5.95.0(@swc/core@1.10.1) - - webpack-dev-middleware@7.4.2(webpack@5.98.0(@swc/core@1.10.1)(esbuild@0.25.1)): + webpack-dev-middleware@7.4.2(webpack@5.98.0(@swc/core@1.10.1(@swc/helpers@0.5.5))): dependencies: colorette: 2.0.20 memfs: 4.12.0 mime-types: 2.1.35 on-finished: 2.4.1 range-parser: 1.2.1 - schema-utils: 4.2.0 - optionalDependencies: - webpack: 5.98.0(@swc/core@1.10.1)(esbuild@0.25.1) - - webpack-dev-server@4.15.2(debug@4.4.0)(webpack@5.95.0(@swc/core@1.10.1)): - dependencies: - '@types/bonjour': 3.5.13 - '@types/connect-history-api-fallback': 1.5.4 - '@types/express': 4.17.21 - '@types/serve-index': 1.9.4 - '@types/serve-static': 1.15.7 - '@types/sockjs': 0.3.36 - '@types/ws': 8.5.12 - ansi-html-community: 0.0.8 - bonjour-service: 1.2.1 - chokidar: 3.6.0 - colorette: 2.0.20 - compression: 1.7.4 - connect-history-api-fallback: 2.0.0 - default-gateway: 6.0.3 - express: 4.21.0 - graceful-fs: 4.2.11 - html-entities: 2.5.2 - http-proxy-middleware: 2.0.7(@types/express@4.17.21)(debug@4.4.0) - ipaddr.js: 2.2.0 - launch-editor: 2.9.1 - open: 8.4.2 - p-retry: 4.6.2 - rimraf: 3.0.2 - schema-utils: 4.2.0 - selfsigned: 2.4.1 - serve-index: 1.9.1 - sockjs: 0.3.24 - spdy: 4.0.2 - webpack-dev-middleware: 5.3.4(webpack@5.95.0(@swc/core@1.10.1)) - ws: 8.18.1 + schema-utils: 4.3.0 optionalDependencies: - webpack: 5.95.0(@swc/core@1.10.1) - transitivePeerDependencies: - - bufferutil - - debug - - supports-color - - utf-8-validate + webpack: 5.98.0(@swc/core@1.10.1(@swc/helpers@0.5.5))(esbuild@0.25.1) - webpack-dev-server@4.15.2(webpack@5.95.0(@swc/core@1.10.1(@swc/helpers@0.5.5))): + webpack-dev-server@4.15.2(debug@4.4.0)(webpack@5.95.0(@swc/core@1.10.1(@swc/helpers@0.5.5))): dependencies: '@types/bonjour': 3.5.13 '@types/connect-history-api-fallback': 1.5.4 @@ -48188,7 +48356,7 @@ snapshots: - supports-color - utf-8-validate - webpack-dev-server@5.2.0(webpack@5.98.0(@swc/core@1.10.1)(esbuild@0.25.1)): + webpack-dev-server@5.2.0(webpack@5.98.0(@swc/core@1.10.1(@swc/helpers@0.5.5))): dependencies: '@types/bonjour': 3.5.13 '@types/connect-history-api-fallback': 1.5.4 @@ -48210,15 +48378,15 @@ snapshots: launch-editor: 2.9.1 open: 10.1.0 p-retry: 6.2.0 - schema-utils: 4.2.0 + schema-utils: 4.3.0 selfsigned: 2.4.1 serve-index: 1.9.1 sockjs: 0.3.24 spdy: 4.0.2 - webpack-dev-middleware: 7.4.2(webpack@5.98.0(@swc/core@1.10.1)(esbuild@0.25.1)) + webpack-dev-middleware: 7.4.2(webpack@5.98.0(@swc/core@1.10.1(@swc/helpers@0.5.5))) ws: 8.18.1 optionalDependencies: - webpack: 5.98.0(@swc/core@1.10.1)(esbuild@0.25.1) + webpack: 5.98.0(@swc/core@1.10.1(@swc/helpers@0.5.5))(esbuild@0.25.1) transitivePeerDependencies: - bufferutil - debug @@ -48241,12 +48409,12 @@ snapshots: webpack-sources@3.2.3: {} - webpack-subresource-integrity@5.1.0(html-webpack-plugin@5.6.0(@rspack/core@1.1.8)(webpack@5.98.0(@swc/core@1.10.1)))(webpack@5.98.0(@swc/core@1.10.1)(esbuild@0.25.1)): + webpack-subresource-integrity@5.1.0(html-webpack-plugin@5.6.0(@rspack/core@1.1.8(@swc/helpers@0.5.5))(webpack@5.98.0(@swc/core@1.10.1(@swc/helpers@0.5.5))))(webpack@5.98.0(@swc/core@1.10.1(@swc/helpers@0.5.5))): dependencies: typed-assert: 1.0.9 - webpack: 5.98.0(@swc/core@1.10.1)(esbuild@0.25.1) + webpack: 5.98.0(@swc/core@1.10.1(@swc/helpers@0.5.5))(esbuild@0.25.1) optionalDependencies: - html-webpack-plugin: 5.6.0(@rspack/core@1.1.8)(webpack@5.98.0(@swc/core@1.10.1)) + html-webpack-plugin: 5.6.0(@rspack/core@1.1.8(@swc/helpers@0.5.5))(webpack@5.98.0(@swc/core@1.10.1(@swc/helpers@0.5.5))) webpack-virtual-modules@0.6.2: {} @@ -48280,36 +48448,6 @@ snapshots: - esbuild - uglify-js - webpack@5.95.0(@swc/core@1.10.1): - dependencies: - '@types/estree': 1.0.6 - '@webassemblyjs/ast': 1.12.1 - '@webassemblyjs/wasm-edit': 1.12.1 - '@webassemblyjs/wasm-parser': 1.12.1 - acorn: 8.12.1 - acorn-import-attributes: 1.9.5(acorn@8.12.1) - browserslist: 4.24.0 - chrome-trace-event: 1.0.4 - enhanced-resolve: 5.17.1 - es-module-lexer: 1.5.4 - eslint-scope: 5.1.1 - events: 3.3.0 - glob-to-regexp: 0.4.1 - graceful-fs: 4.2.11 - json-parse-even-better-errors: 2.3.1 - loader-runner: 4.3.0 - mime-types: 2.1.35 - neo-async: 2.6.2 - schema-utils: 3.3.0 - tapable: 2.2.1 - terser-webpack-plugin: 5.3.10(@swc/core@1.10.1)(webpack@5.95.0(@swc/core@1.10.1)) - watchpack: 2.4.2 - webpack-sources: 3.2.3 - transitivePeerDependencies: - - '@swc/core' - - esbuild - - uglify-js - webpack@5.95.0(@swc/core@1.6.13(@swc/helpers@0.5.5)): dependencies: '@types/estree': 1.0.6 @@ -48362,7 +48500,7 @@ snapshots: neo-async: 2.6.2 schema-utils: 3.3.0 tapable: 2.2.1 - terser-webpack-plugin: 5.3.10(webpack@5.95.0(webpack-cli@5.1.4)) + terser-webpack-plugin: 5.3.10(webpack@5.95.0) watchpack: 2.4.2 webpack-sources: 3.2.3 optionalDependencies: @@ -48372,68 +48510,7 @@ snapshots: - esbuild - uglify-js - webpack@5.98.0: - dependencies: - '@types/eslint-scope': 3.7.7 - '@types/estree': 1.0.6 - '@webassemblyjs/ast': 1.14.1 - '@webassemblyjs/wasm-edit': 1.14.1 - '@webassemblyjs/wasm-parser': 1.14.1 - acorn: 8.14.1 - browserslist: 4.24.4 - chrome-trace-event: 1.0.4 - enhanced-resolve: 5.17.1 - es-module-lexer: 1.6.0 - eslint-scope: 5.1.1 - events: 3.3.0 - glob-to-regexp: 0.4.1 - graceful-fs: 4.2.11 - json-parse-even-better-errors: 2.3.1 - loader-runner: 4.3.0 - mime-types: 2.1.35 - neo-async: 2.6.2 - schema-utils: 4.3.0 - tapable: 2.2.1 - terser-webpack-plugin: 5.3.14(webpack@5.98.0) - watchpack: 2.4.2 - webpack-sources: 3.2.3 - transitivePeerDependencies: - - '@swc/core' - - esbuild - - uglify-js - - webpack@5.98.0(@swc/core@1.10.1): - dependencies: - '@types/eslint-scope': 3.7.7 - '@types/estree': 1.0.6 - '@webassemblyjs/ast': 1.14.1 - '@webassemblyjs/wasm-edit': 1.14.1 - '@webassemblyjs/wasm-parser': 1.14.1 - acorn: 8.14.1 - browserslist: 4.24.4 - chrome-trace-event: 1.0.4 - enhanced-resolve: 5.17.1 - es-module-lexer: 1.6.0 - eslint-scope: 5.1.1 - events: 3.3.0 - glob-to-regexp: 0.4.1 - graceful-fs: 4.2.11 - json-parse-even-better-errors: 2.3.1 - loader-runner: 4.3.0 - mime-types: 2.1.35 - neo-async: 2.6.2 - schema-utils: 4.3.0 - tapable: 2.2.1 - terser-webpack-plugin: 5.3.14(@swc/core@1.10.1)(webpack@5.98.0(@swc/core@1.10.1)) - watchpack: 2.4.2 - webpack-sources: 3.2.3 - transitivePeerDependencies: - - '@swc/core' - - esbuild - - uglify-js - optional: true - - webpack@5.98.0(@swc/core@1.10.1)(esbuild@0.25.1): + webpack@5.98.0(@swc/core@1.10.1(@swc/helpers@0.5.5))(esbuild@0.25.1): dependencies: '@types/eslint-scope': 3.7.7 '@types/estree': 1.0.6 @@ -48455,7 +48532,7 @@ snapshots: neo-async: 2.6.2 schema-utils: 4.3.0 tapable: 2.2.1 - terser-webpack-plugin: 5.3.14(@swc/core@1.10.1)(esbuild@0.25.1)(webpack@5.98.0(@swc/core@1.10.1)(esbuild@0.25.1)) + terser-webpack-plugin: 5.3.14(@swc/core@1.10.1(@swc/helpers@0.5.5))(esbuild@0.25.1)(webpack@5.98.0(@swc/core@1.10.1(@swc/helpers@0.5.5))) watchpack: 2.4.2 webpack-sources: 3.2.3 transitivePeerDependencies: From 7b1102c6d76f45706aa9da01fe3b7e3eef7935f3 Mon Sep 17 00:00:00 2001 From: Simon Binder Date: Tue, 1 Apr 2025 14:10:14 +0200 Subject: [PATCH 04/16] Actually get the thing to connect --- packages/node/tests/sync.test.ts | 9 ++++++--- packages/node/tests/utils.ts | 4 ++-- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/packages/node/tests/sync.test.ts b/packages/node/tests/sync.test.ts index a03be8b58..f68159021 100644 --- a/packages/node/tests/sync.test.ts +++ b/packages/node/tests/sync.test.ts @@ -1,7 +1,10 @@ import { describe, vi, expect, beforeEach } from 'vitest'; import { connectedDatabaseTest, MockSyncService, TestConnector, waitForSyncStatus } from "./utils"; -import { AbstractPowerSyncDatabase, BucketChecksum, OplogEntryJSON } from '@powersync/common'; +import { AbstractPowerSyncDatabase, BucketChecksum, OplogEntryJSON, SyncStreamConnectionMethod } from '@powersync/common'; +import Logger from 'js-logger'; + +Logger.useDefaults(); describe('Sync', () => { describe('reports progress', () => { @@ -48,8 +51,8 @@ describe('Sync', () => { } connectedDatabaseTest('without priorities', async ({database, syncService}) => { - await database.connect(new TestConnector()); - await vi.waitFor(() => expect(syncService.connectedListeners).toBe(1)); + database.connect(new TestConnector(), { connectionMethod: SyncStreamConnectionMethod.HTTP }); + await vi.waitFor(() => expect(syncService.connectedListeners).toEqual(1)); syncService.pushLine({checkpoint: { last_op_id: '10', diff --git a/packages/node/tests/utils.ts b/packages/node/tests/utils.ts index adf6b95df..4fe9ecbab 100644 --- a/packages/node/tests/utils.ts +++ b/packages/node/tests/utils.ts @@ -124,8 +124,8 @@ export interface MockSyncService { export class TestConnector implements PowerSyncBackendConnector { async fetchCredentials(): Promise { return { - endpoint: '', - token: '' + endpoint: 'https://powersync.example.org', + token: 'test' }; } async uploadData(database: AbstractPowerSyncDatabase): Promise { From cc4a081c68eff8c066998e138728706b8d8f71f0 Mon Sep 17 00:00:00 2001 From: Simon Binder Date: Wed, 2 Apr 2025 15:30:41 +0200 Subject: [PATCH 05/16] Add sync tests --- .../client/sync/bucket/SqliteBucketStorage.ts | 4 +- .../AbstractStreamingSyncImplementation.ts | 4 +- .../sync/stream/streaming-sync-types.ts | 2 +- packages/node/package.json | 1 - .../node/src/db/BetterSQLite3DBAdapter.ts | 4 +- packages/node/src/db/PowerSyncDatabase.ts | 6 +- packages/node/src/db/RemoteConnection.ts | 41 ++- packages/node/src/sync/stream/NodeRemote.ts | 2 +- packages/node/tests/PowerSyncDatabase.test.ts | 2 +- packages/node/tests/sync.test.ts | 317 +++++++++++++----- packages/node/tests/utils.ts | 140 ++++---- pnpm-lock.yaml | 25 -- 12 files changed, 365 insertions(+), 183 deletions(-) diff --git a/packages/common/src/client/sync/bucket/SqliteBucketStorage.ts b/packages/common/src/client/sync/bucket/SqliteBucketStorage.ts index 7acb24cf1..0c6c5c1ca 100644 --- a/packages/common/src/client/sync/bucket/SqliteBucketStorage.ts +++ b/packages/common/src/client/sync/bucket/SqliteBucketStorage.ts @@ -208,7 +208,9 @@ export class SqliteBucketStorage extends BaseObserver imp if (result == 1) { if (priority == null) { const bucketToCount = Object.fromEntries(checkpoint.buckets.map((b) => [b.bucket, b.count])); - await tx.execute('UPDATE ps_buckets SET count_since_last = 0, count_at_last = ?1->name WHERE ?1->name IS NOT NULL', [JSON.stringify(bucketToCount)]); + // The two parameters could be replaced with one, but: https://github.com/powersync-ja/better-sqlite3/pull/6 + const jsonBucketCount = JSON.stringify(bucketToCount); + await tx.execute('UPDATE ps_buckets SET count_since_last = 0, count_at_last = ?->name WHERE ?->name IS NOT NULL', [jsonBucketCount, jsonBucketCount]); } return true; diff --git a/packages/common/src/client/sync/stream/AbstractStreamingSyncImplementation.ts b/packages/common/src/client/sync/stream/AbstractStreamingSyncImplementation.ts index 94488ac7b..22fabaf93 100644 --- a/packages/common/src/client/sync/stream/AbstractStreamingSyncImplementation.ts +++ b/packages/common/src/client/sync/stream/AbstractStreamingSyncImplementation.ts @@ -771,7 +771,7 @@ The next upload iteration will be delayed.`); // will use by default. priority: bucket.priority ?? 3, atLast: savedProgress?.atLast ?? 0, - sinceLast: savedProgress.sinceLast ?? 0, + sinceLast: savedProgress?.sinceLast ?? 0, targetCount: bucket.count ?? 0, }; } @@ -797,7 +797,7 @@ The next upload iteration will be delayed.`); }); if (!this.syncStatus.isEqual(updatedStatus)) { - this.syncStatusOptions = options; + Object.assign(this.syncStatusOptions, options); this.syncStatus = updatedStatus; // Only trigger this is there was a change this.iterateListeners((cb) => cb.statusChanged?.(updatedStatus)); diff --git a/packages/common/src/client/sync/stream/streaming-sync-types.ts b/packages/common/src/client/sync/stream/streaming-sync-types.ts index 451520f42..bbc4b2f75 100644 --- a/packages/common/src/client/sync/stream/streaming-sync-types.ts +++ b/packages/common/src/client/sync/stream/streaming-sync-types.ts @@ -102,7 +102,7 @@ export interface StreamingSyncCheckpointDiff { last_op_id: OpId; updated_buckets: BucketChecksum[]; removed_buckets: string[]; - write_checkpoint: string; + write_checkpoint?: string; }; } diff --git a/packages/node/package.json b/packages/node/package.json index 683379bfe..71ab30302 100644 --- a/packages/node/package.json +++ b/packages/node/package.json @@ -57,7 +57,6 @@ "@powersync/drizzle-driver": "workspace:*", "@types/async-lock": "^1.4.0", "drizzle-orm": "^0.35.2", - "fetch-mock": "^12.5.2", "rollup": "4.14.3", "typescript": "^5.5.3", "vitest": "^3.0.5" diff --git a/packages/node/src/db/BetterSQLite3DBAdapter.ts b/packages/node/src/db/BetterSQLite3DBAdapter.ts index 2b689152c..83caa716a 100644 --- a/packages/node/src/db/BetterSQLite3DBAdapter.ts +++ b/packages/node/src/db/BetterSQLite3DBAdapter.ts @@ -64,7 +64,9 @@ export class BetterSQLite3DBAdapter extends BaseObserver impl } if (!directoryExists) { - throw new Error(`The dbLocation directory at "${this.options.dbLocation}" does not exist. Please create it before opening the PowerSync database!`); + throw new Error( + `The dbLocation directory at "${this.options.dbLocation}" does not exist. Please create it before opening the PowerSync database!` + ); } dbFilePath = path.join(this.options.dbLocation, dbFilePath); diff --git a/packages/node/src/db/PowerSyncDatabase.ts b/packages/node/src/db/PowerSyncDatabase.ts index 3dd0f90d1..41bd82ae5 100644 --- a/packages/node/src/db/PowerSyncDatabase.ts +++ b/packages/node/src/db/PowerSyncDatabase.ts @@ -22,10 +22,10 @@ export type NodePowerSyncDatabaseOptions = PowerSyncDatabaseOptions & { database: DBAdapter | SQLOpenFactory | NodeSQLOpenOptions; /** * Options to override how the SDK will connect to the sync service. - * + * * This option is intended to be used for internal tests. */ - remoteOptions?: Partial, + remoteOptions?: Partial; }; /** @@ -68,7 +68,7 @@ export class PowerSyncDatabase extends AbstractPowerSyncDatabase { const remote = new NodeRemote( connector, DEFAULT_REMOTE_LOGGER, - (this.options as NodePowerSyncDatabaseOptions).remoteOptions, + (this.options as NodePowerSyncDatabaseOptions).remoteOptions ); return new NodeStreamingSyncImplementation({ diff --git a/packages/node/src/db/RemoteConnection.ts b/packages/node/src/db/RemoteConnection.ts index aa61d39c8..fc8d94f4d 100644 --- a/packages/node/src/db/RemoteConnection.ts +++ b/packages/node/src/db/RemoteConnection.ts @@ -19,18 +19,43 @@ export class RemoteConnection implements LockContext { this.database = database; } - async executeBatch(query: string, params: any[][] = []): Promise { - const result = await this.database.executeBatch(query, params ?? []); - return RemoteConnection.wrapQueryResult(result); + /** + * Runs the inner function, but appends the stack trace where this function was called. This is useful for workers + * because stack traces from worker errors are otherwise unrelated to the application issue that has caused them. + */ + private async recoverTrace(inner: () => Promise): Promise { + const trace = {}; + Error.captureStackTrace(trace); + + try { + return await inner(); + } catch (e) { + if (e instanceof Error && e.stack) { + e.stack += (trace as any).stack; + } + + throw e; + } + } + + executeBatch(query: string, params: any[][] = []): Promise { + return this.recoverTrace(async () => { + const result = await this.database.executeBatch(query, params ?? []); + return RemoteConnection.wrapQueryResult(result); + }); } - async execute(query: string, params?: any[] | undefined): Promise { - const result = await this.database.execute(query, params ?? []); - return RemoteConnection.wrapQueryResult(result); + execute(query: string, params?: any[] | undefined): Promise { + return this.recoverTrace(async () => { + const result = await this.database.execute(query, params ?? []); + return RemoteConnection.wrapQueryResult(result); + }); } - async executeRaw(query: string, params?: any[] | undefined): Promise { - return await this.database.executeRaw(query, params ?? []); + executeRaw(query: string, params?: any[] | undefined): Promise { + return this.recoverTrace(async () => { + return await this.database.executeRaw(query, params ?? []); + }); } async getAll(sql: string, parameters?: any[]): Promise { diff --git a/packages/node/src/sync/stream/NodeRemote.ts b/packages/node/src/sync/stream/NodeRemote.ts index 54af8c5b0..b1494eb76 100644 --- a/packages/node/src/sync/stream/NodeRemote.ts +++ b/packages/node/src/sync/stream/NodeRemote.ts @@ -29,7 +29,7 @@ export class NodeRemote extends AbstractRemote { ) { super(connector, logger, { fetchImplementation: options?.fetchImplementation ?? new NodeFetchProvider(), - ...(options ?? {}), + ...(options ?? {}) }); } diff --git a/packages/node/tests/PowerSyncDatabase.test.ts b/packages/node/tests/PowerSyncDatabase.test.ts index 4f7f71a2f..28ab4b31f 100644 --- a/packages/node/tests/PowerSyncDatabase.test.ts +++ b/packages/node/tests/PowerSyncDatabase.test.ts @@ -95,7 +95,7 @@ databaseTest('can watch tables', async ({ database }) => { tempDirectoryTest('throws error if target directory does not exist', async ({ tmpdir }) => { const directory = path.join(tmpdir, 'some', 'nested', 'location', 'that', 'does', 'not', 'exist'); - expect(async () => { + await expect(async () => { const database = new PowerSyncDatabase({ schema: AppSchema, database: { diff --git a/packages/node/tests/sync.test.ts b/packages/node/tests/sync.test.ts index f68159021..3b28ba612 100644 --- a/packages/node/tests/sync.test.ts +++ b/packages/node/tests/sync.test.ts @@ -1,105 +1,264 @@ import { describe, vi, expect, beforeEach } from 'vitest'; -import { connectedDatabaseTest, MockSyncService, TestConnector, waitForSyncStatus } from "./utils"; -import { AbstractPowerSyncDatabase, BucketChecksum, OplogEntryJSON, SyncStreamConnectionMethod } from '@powersync/common'; +import { MockSyncService, mockSyncServiceTest, TestConnector, waitForSyncStatus } from './utils'; +import { + AbstractPowerSyncDatabase, + BucketChecksum, + OplogEntryJSON, + ProgressWithOperations, + SyncStreamConnectionMethod +} from '@powersync/common'; import Logger from 'js-logger'; -Logger.useDefaults(); +Logger.useDefaults({ defaultLevel: Logger.WARN }); describe('Sync', () => { - describe('reports progress', () => { - let lastOpId = 0; + describe('reports progress', () => { + let lastOpId = 0; - beforeEach(() => { - lastOpId = 0; + beforeEach(() => { + lastOpId = 0; + }); + + function pushDataLine(service: MockSyncService, bucket: string, amount: number) { + const data: OplogEntryJSON[] = []; + for (let i = 0; i < amount; i++) { + data.push({ + op_id: `${++lastOpId}`, + op: 'PUT', + object_type: bucket, + object_id: `${lastOpId}`, + checksum: 0, + data: '{}' }); + } - function pushDataLine(service: MockSyncService, bucket: string, amount: number) { - const data: OplogEntryJSON[] = []; - for (let i = 0; i < amount; i++) { - data.push({ - op_id: `${++lastOpId}`, - op: 'PUT', - object_type: bucket, - object_id: `${lastOpId}`, - checksum: 0, - data: '{}', - }); - } - - service.pushLine({data: { - bucket, - data, - }}); + service.pushLine({ + data: { + bucket, + data } + }); + } - function pushCheckpointComplete(service: MockSyncService, priority?: number) { - if (priority != null) { - service.pushLine({ - partial_checkpoint_complete: { - last_op_id: `${lastOpId}`, - priority, - }, - }); - } else { - service.pushLine({ - checkpoint_complete: { - last_op_id: `${lastOpId}`, - }, - }); - } + function pushCheckpointComplete(service: MockSyncService, priority?: number) { + if (priority != null) { + service.pushLine({ + partial_checkpoint_complete: { + last_op_id: `${lastOpId}`, + priority + } + }); + } else { + service.pushLine({ + checkpoint_complete: { + last_op_id: `${lastOpId}` + } + }); + } + } + + mockSyncServiceTest('without priorities', async ({ syncService }) => { + const database = await syncService.createDatabase(); + database.connect(new TestConnector(), { connectionMethod: SyncStreamConnectionMethod.HTTP }); + await vi.waitFor(() => expect(syncService.connectedListeners).toEqual(1)); + + syncService.pushLine({ + checkpoint: { + last_op_id: '10', + buckets: [bucket('a', 10)] + } + }); + + await waitForProgress(database, [0, 10]); + + pushDataLine(syncService, 'a', 10); + await waitForProgress(database, [10, 10]); + + pushCheckpointComplete(syncService); + await waitForSyncStatus(database, (s) => s.downloadProgress == null); + + // Emit new data, progress should be 0/2 instead of 10/12 + syncService.pushLine({ + checkpoint_diff: { + last_op_id: '12', + updated_buckets: [bucket('a', 12)], + removed_buckets: [] + } + }); + await waitForProgress(database, [0, 2]); + pushDataLine(syncService, 'a', 2); + await waitForProgress(database, [2, 2]); + pushCheckpointComplete(syncService); + await waitForSyncStatus(database, (s) => s.downloadProgress == null); + }); + + mockSyncServiceTest('interrupted sync', async ({ syncService }) => { + let database = await syncService.createDatabase(); + database.connect(new TestConnector(), { connectionMethod: SyncStreamConnectionMethod.HTTP }); + await vi.waitFor(() => expect(syncService.connectedListeners).toEqual(1)); + + syncService.pushLine({ + checkpoint: { + last_op_id: '10', + buckets: [bucket('a', 10)] + } + }); + + await waitForProgress(database, [0, 10]); + pushDataLine(syncService, 'a', 5); + await waitForProgress(database, [5, 10]); + + // Close this database before sending the checkpoint... + await database.close(); + await vi.waitFor(() => expect(syncService.connectedListeners).toEqual(0)); + + // And open a new one + database = await syncService.createDatabase(); + database.connect(new TestConnector(), { connectionMethod: SyncStreamConnectionMethod.HTTP }); + await vi.waitFor(() => expect(syncService.connectedListeners).toEqual(1)); + + // Send same checkpoint again + syncService.pushLine({ + checkpoint: { + last_op_id: '10', + buckets: [bucket('a', 10)] + } + }); + + // Progress should be restored instead of e.g. saying 0/5 now. + await waitForProgress(database, [5, 10]); + pushCheckpointComplete(syncService); + await waitForSyncStatus(database, (s) => s.downloadProgress == null); + }); + + mockSyncServiceTest('interrupted sync with new checkpoint', async ({ syncService }) => { + let database = await syncService.createDatabase(); + database.connect(new TestConnector(), { connectionMethod: SyncStreamConnectionMethod.HTTP }); + await vi.waitFor(() => expect(syncService.connectedListeners).toEqual(1)); + + syncService.pushLine({ + checkpoint: { + last_op_id: '10', + buckets: [bucket('a', 10)] } + }); + + await waitForProgress(database, [0, 10]); + pushDataLine(syncService, 'a', 5); + await waitForProgress(database, [5, 10]); + + // Re-open database + await database.close(); + await vi.waitFor(() => expect(syncService.connectedListeners).toEqual(0)); + database = await syncService.createDatabase(); + database.connect(new TestConnector(), { connectionMethod: SyncStreamConnectionMethod.HTTP }); + await vi.waitFor(() => expect(syncService.connectedListeners).toEqual(1)); - connectedDatabaseTest('without priorities', async ({database, syncService}) => { - database.connect(new TestConnector(), { connectionMethod: SyncStreamConnectionMethod.HTTP }); - await vi.waitFor(() => expect(syncService.connectedListeners).toEqual(1)); - - syncService.pushLine({checkpoint: { - last_op_id: '10', - buckets: [bucket('a', 10)] - }}); - - await waitForProgress(database, [0, 10]); - - pushDataLine(syncService, 'a', 10); - await waitForProgress(database, [10, 10]); - - pushCheckpointComplete(syncService); - await waitForSyncStatus(database, (s) => s.downloadProgress == null); - - // Emit new data, progress should be 0/2 instead of 10/12 - syncService.pushLine({checkpoint_diff: { - last_op_id: '12', - updated_buckets: [bucket('a', 12)], - removed_buckets: [], - write_checkpoint: '', - }}); - await waitForProgress(database, [0, 2]); - pushDataLine(syncService, 'a', 2); - await waitForProgress(database, [2, 2]); - pushCheckpointComplete(syncService); - await waitForSyncStatus(database, (s) => s.downloadProgress == null); + // Send checkpoint with new data + syncService.pushLine({ + checkpoint: { + last_op_id: '12', + buckets: [bucket('a', 12)] + } + }); + + await waitForProgress(database, [5, 12]); + pushCheckpointComplete(syncService); + await waitForSyncStatus(database, (s) => s.downloadProgress == null); + }); + + mockSyncServiceTest('different priorities', async ({ syncService }) => { + let database = await syncService.createDatabase(); + database.connect(new TestConnector(), { connectionMethod: SyncStreamConnectionMethod.HTTP }); + await vi.waitFor(() => expect(syncService.connectedListeners).toEqual(1)); + + syncService.pushLine({ + checkpoint: { + last_op_id: '10', + buckets: [ + bucket('a', 5, {priority: 0}), + bucket('b', 5, {priority: 2}), + ] + } }); + + // Should be at 0/10 for total progress (which is the same as the progress for prio 2), and a 0/5 towards prio 0. + await waitForProgress(database, [0, 10], [[0, [0, 5]], [2, [0, 10]]]); + + pushDataLine(syncService, 'a', 5); + await waitForProgress(database, [5, 10], [[0, [5, 5]], [2, [5, 10]]]); + + pushCheckpointComplete(syncService, 0); + await waitForProgress(database, [5, 10], [[0, [5, 5]], [2, [5, 10]]]); + + pushDataLine(syncService, 'b', 2); + await waitForProgress(database, [7, 10], [[0, [5, 5]], [2, [7, 10]]]); + + // Before syncing b fully, send a new checkpoint + syncService.pushLine({ + checkpoint: { + last_op_id: '14', + buckets: [ + bucket('a', 8, {priority: 0}), + bucket('b', 6, {priority: 2}), + ] + } + }); + await waitForProgress(database, [7, 14], [[0, [5, 8]], [2, [7, 14]]]); + + pushDataLine(syncService, 'a', 3); + await waitForProgress(database, [10, 14], [[0, [8, 8]], [2, [10, 14]]]); + + pushCheckpointComplete(syncService, 0); + await waitForProgress(database, [10, 14], [[0, [8, 8]], [2, [10, 14]]]); + + pushDataLine(syncService, 'b', 4); + await waitForProgress(database, [14, 14], [[0, [8, 8]], [2, [14, 14]]]); + + pushCheckpointComplete(syncService); + await waitForSyncStatus(database, (s) => s.downloadProgress == null); }); + }); }); -function bucket(name: string, count: number, priority: number = 3): BucketChecksum { +function bucket(name: string, count: number, options: {priority: number} = {priority: 3}): BucketChecksum { return { bucket: name, count, checksum: 0, - priority, + priority: options.priority, }; } -async function waitForProgress(database: AbstractPowerSyncDatabase, total: [number, number]) { - await waitForSyncStatus(database, (status) => { - const progress = status.downloadProgress; - if (!progress) { - return false; - } +async function waitForProgress( + database: AbstractPowerSyncDatabase, + total: [number, number], + forPriorities: [number, [number, number]][] = [] +) { + await waitForSyncStatus(database, (status) => { + const progress = status.downloadProgress; + if (!progress) { + return false; + } - const untilCompletion = progress.untilCompletion; - return untilCompletion.completed == total[0] && untilCompletion.total == total[1]; - }); + //console.log('checking', progress); + + const check = (expected: [number, number], actual: ProgressWithOperations): boolean => { + return actual.completed == expected[0] && actual.total == expected[1]; + }; + + if (!check(total, progress.untilCompletion)) { + return false; + } + + for (const [priority, expected] of forPriorities) { + if (!check(expected, progress.untilPriority(priority))) { + //console.log('failed for', priority, expected, progress); + return false; + } + } + + return true; + }); } diff --git a/packages/node/tests/utils.ts b/packages/node/tests/utils.ts index 4fe9ecbab..5c2c28988 100644 --- a/packages/node/tests/utils.ts +++ b/packages/node/tests/utils.ts @@ -1,9 +1,20 @@ import os from 'node:os'; import fs from 'node:fs/promises'; import path from 'node:path'; -import { defaultFetchMockConfig, FetchMock } from 'fetch-mock'; -import { test } from 'vitest'; -import { AbstractPowerSyncDatabase, AbstractRemoteOptions, column, NodePowerSyncDatabaseOptions, PowerSyncBackendConnector, PowerSyncCredentials, PowerSyncDatabase, Schema, StreamingSyncLine, SyncStatus, Table } from '../lib'; +import { onTestFinished, test } from 'vitest'; +import { + AbstractPowerSyncDatabase, + AbstractRemoteOptions, + column, + NodePowerSyncDatabaseOptions, + PowerSyncBackendConnector, + PowerSyncCredentials, + PowerSyncDatabase, + Schema, + StreamingSyncLine, + SyncStatus, + Table +} from '../lib'; export async function createTempDir() { const ostmpdir = os.tmpdir(); @@ -38,64 +49,76 @@ export const tempDirectoryTest = test.extend<{ tmpdir: string }>({ } }); -function createDatabaseFixture(options: Partial = {}) { - return async ({ tmpdir }, use) => { - const database = new PowerSyncDatabase({ - ...options, - schema: AppSchema, - database: { - dbFilename: 'test.db', - dbLocation: tmpdir - } - }); - await use(database); - await database.close(); - }; +async function createDatabase( + tmpdir: string, + options: Partial = {} +): Promise { + const database = new PowerSyncDatabase({ + ...options, + schema: AppSchema, + database: { + dbFilename: 'test.db', + dbLocation: tmpdir + } + }); + await database.init(); + return database; } export const databaseTest = tempDirectoryTest.extend<{ database: PowerSyncDatabase }>({ - database: async ({tmpdir}, use) => { - await createDatabaseFixture()({tmpdir}, use); - }, + database: async ({ tmpdir }, use) => { + const db = await createDatabase(tmpdir); + await use(db); + await db.close(); + } }); // TODO: Unify this with the test setup for the web SDK. -export const mockSyncServiceTest = tempDirectoryTest.extend<{syncService: MockSyncService}>({ - syncService: async ({}, use) => { - // Don't install global fetch mocks, we want tests to be isolated! - const fetchMock = new FetchMock(defaultFetchMockConfig); +export const mockSyncServiceTest = tempDirectoryTest.extend<{ syncService: MockSyncService }>({ + syncService: async ({ tmpdir }, use) => { const listeners: ReadableStreamDefaultController[] = []; - fetchMock.route('path:/sync/stream', async () => { - let thisController: ReadableStreamDefaultController | null = null; - - const syncLines = new ReadableStream({ - start(controller) { - thisController = controller; - listeners.push(controller); - }, - cancel() { - listeners.splice(listeners.indexOf(thisController!), 1); - }, - }); - + const inMemoryFetch: typeof fetch = async (info, init?) => { + const request = new Request(info, init); + if (request.url.endsWith('/sync/stream')) { + let thisController: ReadableStreamDefaultController | null = null; + + const syncLines = new ReadableStream({ + start(controller) { + thisController = controller; + listeners.push(controller); + }, + cancel() { + listeners.splice(listeners.indexOf(thisController!), 1); + } + }); + + const encoder = new TextEncoder(); + const asLines = new TransformStream({ + transform: (chunk, controller) => { + const line = `${JSON.stringify(chunk)}\n`; + controller.enqueue(encoder.encode(line)); + } + }); + + return new Response(syncLines.pipeThrough(asLines), { status: 200 }); + } else { + return new Response('Not found', { status: 404 }); + } + }; - const encoder = new TextEncoder(); - const asLines = new TransformStream({ - transform: (chunk, controller) => { - const line = `${JSON.stringify(chunk)}\n`; - controller.enqueue(encoder.encode(line)); - }, + const newConnection = async () => { + const db = await createDatabase(tmpdir, { + remoteOptions: { + fetchImplementation: inMemoryFetch + } }); - return new Response(syncLines.pipeThrough(asLines), {status: 200}); - }); - fetchMock.catch(404); + onTestFinished(async () => await db.close()); + return db; + }; await use({ - clientOptions: { - fetchImplementation: fetchMock.fetchHandler.bind(fetchMock), - }, get connectedListeners() { return listeners.length; }, @@ -104,21 +127,15 @@ export const mockSyncServiceTest = tempDirectoryTest.extend<{syncService: MockSy listener.enqueue(line); } }, + createDatabase: newConnection }); - }, -}); - -export const connectedDatabaseTest = mockSyncServiceTest.extend<{ database: PowerSyncDatabase }>({ - database: async ({ tmpdir, syncService }, use) => { - const fixture = createDatabaseFixture({remoteOptions: syncService.clientOptions}); - await fixture({ tmpdir }, use); - }, + } }); export interface MockSyncService { - clientOptions: Partial, - pushLine: (line: StreamingSyncLine) => void, - connectedListeners: number, + pushLine: (line: StreamingSyncLine) => void; + connectedListeners: number; + createDatabase: () => Promise; } export class TestConnector implements PowerSyncBackendConnector { @@ -134,7 +151,10 @@ export class TestConnector implements PowerSyncBackendConnector { } } -export function waitForSyncStatus(database: AbstractPowerSyncDatabase, matcher: (status: SyncStatus) => boolean): Promise { +export function waitForSyncStatus( + database: AbstractPowerSyncDatabase, + matcher: (status: SyncStatus) => boolean +): Promise { return new Promise((resolve) => { if (matcher(database.currentStatus)) { return resolve(); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 77dde2a7a..9adfdedc4 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -1817,9 +1817,6 @@ importers: drizzle-orm: specifier: ^0.35.2 version: 0.35.2(@op-engineering/op-sqlite@11.4.8(react-native@0.77.0(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@react-native-community/cli-server-api@15.1.3)(@types/react@18.3.18)(react@18.3.1))(react@18.3.1))(@types/better-sqlite3@7.6.12)(@types/react@18.3.18)(better-sqlite3@11.7.2)(kysely@0.27.4)(react@18.3.1) - fetch-mock: - specifier: ^12.5.2 - version: 12.5.2 rollup: specifier: 4.14.3 version: 4.14.3 @@ -9026,9 +9023,6 @@ packages: '@types/fs-extra@9.0.13': resolution: {integrity: sha512-nEnwB++1u5lVDM2UI4c1+5R+FYaKfaAzS4OococimjVm3nQw3TuzH5UNsocrcTBbhnerblyHj4A49qXbIiZdpA==} - '@types/glob-to-regexp@0.4.4': - resolution: {integrity: sha512-nDKoaKJYbnn1MZxUY0cA1bPmmgZbg0cTq7Rh13d0KWYNOiKbqoR+2d89SnRPszGh7ROzSwZ/GOjZ4jPbmmZ6Eg==} - '@types/glob@7.2.0': resolution: {integrity: sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==} @@ -12724,10 +12718,6 @@ packages: resolution: {integrity: sha512-7yAQpD2UMJzLi1Dqv7qFYnPbaPx7ZfFK6PiIxQ4PfkGPyNyl2Ugx+a/umUonmKqjhM4DnfbMvdX6otXq83soQQ==} engines: {node: ^12.20 || >= 14.13} - fetch-mock@12.5.2: - resolution: {integrity: sha512-b5KGDFmdmado2MPQjZl6ix3dAG3iwCitb0XQwN72y2s9VnWZ3ObaGNy+bkpm1390foiLDybdJ7yjRGKD36kATw==} - engines: {node: '>=18.11.0'} - fetch-retry@4.1.1: resolution: {integrity: sha512-e6eB7zN6UBSwGVwrbWVH+gdLnkW9WwHhmq2YDK1Sh30pzx1onRVGBvogTlUeWxwTa+L86NYdo4hFkh7O8ZjSnA==} @@ -17696,10 +17686,6 @@ packages: resolution: {integrity: sha512-vqlC04+RQoFalODCbCumG2xIOvapzVMHwsyIGM/SIE8fRhFFsXeH8/QQ+s0T0kDAhKc4k30s73/0ydkHQz6HlQ==} engines: {node: '>= 0.4'} - regexparam@3.0.0: - resolution: {integrity: sha512-RSYAtP31mvYLkAHrOlh25pCNQ5hWnT106VukGaaFfuJrZFkGRX5GhUAdPqpSDXxOhA2c4akmRuplv1mRqnBn6Q==} - engines: {node: '>=8'} - regexpp@3.2.0: resolution: {integrity: sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg==} engines: {node: '>=8'} @@ -32876,8 +32862,6 @@ snapshots: dependencies: '@types/node': 20.17.12 - '@types/glob-to-regexp@0.4.4': {} - '@types/glob@7.2.0': dependencies: '@types/minimatch': 5.1.2 @@ -38379,13 +38363,6 @@ snapshots: node-domexception: 1.0.0 web-streams-polyfill: 3.2.1 - fetch-mock@12.5.2: - dependencies: - '@types/glob-to-regexp': 0.4.4 - dequal: 2.0.3 - glob-to-regexp: 0.4.1 - regexparam: 3.0.0 - fetch-retry@4.1.1: {} figures@3.2.0: @@ -45387,8 +45364,6 @@ snapshots: es-errors: 1.3.0 set-function-name: 2.0.2 - regexparam@3.0.0: {} - regexpp@3.2.0: {} regexpu-core@6.1.1: From cb58548d7c9e1e8fc8dc65b84479443bb2535eec Mon Sep 17 00:00:00 2001 From: Simon Binder Date: Wed, 2 Apr 2025 15:33:36 +0200 Subject: [PATCH 06/16] Format --- packages/common/src/client/SQLOpenFactory.ts | 2 +- .../sync/bucket/BucketStorageAdapter.ts | 11 ++- .../client/sync/bucket/SqliteBucketStorage.ts | 11 ++- .../AbstractStreamingSyncImplementation.ts | 12 +-- packages/common/src/db/crud/SyncProgress.ts | 97 ++++++++++--------- packages/common/src/db/crud/SyncStatus.ts | 8 +- 6 files changed, 76 insertions(+), 65 deletions(-) diff --git a/packages/common/src/client/SQLOpenFactory.ts b/packages/common/src/client/SQLOpenFactory.ts index 05c90dc51..44d5b21e4 100644 --- a/packages/common/src/client/SQLOpenFactory.ts +++ b/packages/common/src/client/SQLOpenFactory.ts @@ -7,7 +7,7 @@ export interface SQLOpenOptions { dbFilename: string; /** * Directory where the database file is located. - * + * * When set, the directory must exist when the database is opened, it will * not be created automatically. */ diff --git a/packages/common/src/client/sync/bucket/BucketStorageAdapter.ts b/packages/common/src/client/sync/bucket/BucketStorageAdapter.ts index 1cfcc603c..cb00fb8be 100644 --- a/packages/common/src/client/sync/bucket/BucketStorageAdapter.ts +++ b/packages/common/src/client/sync/bucket/BucketStorageAdapter.ts @@ -30,10 +30,13 @@ export interface SyncLocalDatabaseResult { checkpointFailures?: string[]; } -export type BucketOperationProgress = Record; +export type BucketOperationProgress = Record< + string, + { + atLast: number; + sinceLast: number; + } +>; export interface BucketChecksum { bucket: string; diff --git a/packages/common/src/client/sync/bucket/SqliteBucketStorage.ts b/packages/common/src/client/sync/bucket/SqliteBucketStorage.ts index 0c6c5c1ca..869a4d810 100644 --- a/packages/common/src/client/sync/bucket/SqliteBucketStorage.ts +++ b/packages/common/src/client/sync/bucket/SqliteBucketStorage.ts @@ -93,8 +93,10 @@ export class SqliteBucketStorage extends BaseObserver imp } async getBucketOperationProgress(): Promise { - const rows = await this.db.getAll<{name: string, count_at_last: number, count_since_last: number}>("SELECT name, count_at_last, count_since_last FROM ps_buckets"); - return Object.fromEntries(rows.map((r) => [r.name, {atLast: r.count_at_last, sinceLast: r.count_since_last}])); + const rows = await this.db.getAll<{ name: string; count_at_last: number; count_since_last: number }>( + 'SELECT name, count_at_last, count_since_last FROM ps_buckets' + ); + return Object.fromEntries(rows.map((r) => [r.name, { atLast: r.count_at_last, sinceLast: r.count_since_last }])); } async saveSyncData(batch: SyncDataBatch) { @@ -210,7 +212,10 @@ export class SqliteBucketStorage extends BaseObserver imp const bucketToCount = Object.fromEntries(checkpoint.buckets.map((b) => [b.bucket, b.count])); // The two parameters could be replaced with one, but: https://github.com/powersync-ja/better-sqlite3/pull/6 const jsonBucketCount = JSON.stringify(bucketToCount); - await tx.execute('UPDATE ps_buckets SET count_since_last = 0, count_at_last = ?->name WHERE ?->name IS NOT NULL', [jsonBucketCount, jsonBucketCount]); + await tx.execute( + 'UPDATE ps_buckets SET count_since_last = 0, count_at_last = ?->name WHERE ?->name IS NOT NULL', + [jsonBucketCount, jsonBucketCount] + ); } return true; diff --git a/packages/common/src/client/sync/stream/AbstractStreamingSyncImplementation.ts b/packages/common/src/client/sync/stream/AbstractStreamingSyncImplementation.ts index 22fabaf93..78ec1f410 100644 --- a/packages/common/src/client/sync/stream/AbstractStreamingSyncImplementation.ts +++ b/packages/common/src/client/sync/stream/AbstractStreamingSyncImplementation.ts @@ -421,7 +421,7 @@ The next upload iteration will be delayed.`); connecting: false, dataFlow: { downloading: false, - downloadProgress: null, + downloadProgress: null } }); }); @@ -685,12 +685,12 @@ The next upload iteration will be delayed.`); const previousProgress = this.syncStatusOptions.dataFlow?.downloadProgress; let updatedProgress: InternalProgressInformation | null = null; if (previousProgress) { - updatedProgress = {...previousProgress}; + updatedProgress = { ...previousProgress }; const progressForBucket = updatedProgress[data.bucket]; if (progressForBucket) { updatedProgress[data.bucket] = { ...progressForBucket, - sinceLast: progressForBucket.sinceLast + data.data.length, + sinceLast: progressForBucket.sinceLast + data.data.length }; } } @@ -698,7 +698,7 @@ The next upload iteration will be delayed.`); this.updateSyncStatus({ dataFlow: { downloading: true, - downloadProgress: updatedProgress, + downloadProgress: updatedProgress } }); await this.options.adapter.saveSyncData({ buckets: [SyncDataBucket.fromRow(data)] }); @@ -772,14 +772,14 @@ The next upload iteration will be delayed.`); priority: bucket.priority ?? 3, atLast: savedProgress?.atLast ?? 0, sinceLast: savedProgress?.sinceLast ?? 0, - targetCount: bucket.count ?? 0, + targetCount: bucket.count ?? 0 }; } this.updateSyncStatus({ dataFlow: { downloading: true, - downloadProgress: progress, + downloadProgress: progress } }); } diff --git a/packages/common/src/db/crud/SyncProgress.ts b/packages/common/src/db/crud/SyncProgress.ts index b6a3f1266..48993396d 100644 --- a/packages/common/src/db/crud/SyncProgress.ts +++ b/packages/common/src/db/crud/SyncProgress.ts @@ -1,13 +1,16 @@ -import type { SyncStatus } from "./SyncStatus.js"; +import type { SyncStatus } from './SyncStatus.js'; // (bucket, progress) pairs /** @internal */ -export type InternalProgressInformation = Record; +export type InternalProgressInformation = Record< + string, + { + priority: number; // Priority of the associated buckets + atLast: number; // Total ops at last completed sync, or 0 + sinceLast: number; // Total ops _since_ the last completed sync. + targetCount: number; // Total opcount for next checkpoint as indicated by service. + } +>; /** * @internal The priority used by the core extension to indicate that a full sync was completed. @@ -16,67 +19,67 @@ export const FULL_SYNC_PRIORITY = 2147483647; /** * Information about a progressing download made by the PowerSync SDK. - * + * * To obtain these values, use {@link SyncProgress}, available through * {@link SyncStatus#downloadProgress}. */ export interface ProgressWithOperations { - /** - * The total amount of operations to download for the current sync iteration - * to complete. - */ - total: number; - /** - * The amount of operations that have already been downloaded. - */ - completed: number; + /** + * The total amount of operations to download for the current sync iteration + * to complete. + */ + total: number; + /** + * The amount of operations that have already been downloaded. + */ + completed: number; - /** - * Relative progress, as {@link completed} of {@link total}. This will be a number - * between `0.0` and `1.0`. - */ - fraction: number; -}; + /** + * Relative progress, as {@link completed} of {@link total}. This will be a number + * between `0.0` and `1.0`. + */ + fraction: number; +} /** * Provides realtime progress on how PowerSync is downloading rows. - * + * * The reported progress always reflects the status towards th end of a sync iteration (after * which a consistent snapshot of all buckets is available locally). - * + * * In rare cases (in particular, when a [compacting](https://docs.powersync.com/usage/lifecycle-maintenance/compacting-buckets) * operation takes place between syncs), it's possible for the returned numbers to be slightly * inaccurate. For this reason, {@link SyncProgress} should be seen as an approximation of progress. * The information returned is good enough to build progress bars, but not exact enough to track * individual download counts. - * + * * Also note that data is downloaded in bulk, which means that individual counters are unlikely * to be updated one-by-one. */ export class SyncProgress { - constructor(protected internal: InternalProgressInformation) {} - - get untilCompletion(): ProgressWithOperations { - return this.untilPriority(FULL_SYNC_PRIORITY); - } + constructor(protected internal: InternalProgressInformation) {} - untilPriority(priority: number): ProgressWithOperations { - let total = 0; - let downloaded = 0; + get untilCompletion(): ProgressWithOperations { + return this.untilPriority(FULL_SYNC_PRIORITY); + } - for (const progress of Object.values(this.internal)) { - // Include higher-priority buckets, which are represented by lower numbers. - if (progress.priority <= priority) { - downloaded += progress.sinceLast; - total += progress.targetCount - progress.atLast; - } - } + untilPriority(priority: number): ProgressWithOperations { + let total = 0; + let downloaded = 0; - let progress = total == 0 ? 0.0 : downloaded / total; - return { - total, - completed: downloaded, - fraction: progress, - } + for (const progress of Object.values(this.internal)) { + // Include higher-priority buckets, which are represented by lower numbers. + if (progress.priority <= priority) { + downloaded += progress.sinceLast; + total += progress.targetCount - progress.atLast; + } } + + let progress = total == 0 ? 0.0 : downloaded / total; + return { + total, + completed: downloaded, + fraction: progress + }; + } } diff --git a/packages/common/src/db/crud/SyncStatus.ts b/packages/common/src/db/crud/SyncStatus.ts index 520ac74d5..3dd734052 100644 --- a/packages/common/src/db/crud/SyncStatus.ts +++ b/packages/common/src/db/crud/SyncStatus.ts @@ -1,4 +1,4 @@ -import { InternalProgressInformation, SyncProgress } from "./SyncProgress.js"; +import { InternalProgressInformation, SyncProgress } from './SyncProgress.js'; export type SyncDataFlowStatus = Partial<{ downloading: boolean; @@ -16,10 +16,10 @@ export type SyncDataFlowStatus = Partial<{ uploadError?: Error; /** * Internal information about how far we are downloading operations in buckets. - * + * * Please use the {@link SyncStatus#downloadProgress} property to track sync progress. */ - downloadProgress: InternalProgressInformation | null, + downloadProgress: InternalProgressInformation | null; }>; export interface SyncPriorityStatus { @@ -96,7 +96,7 @@ export class SyncStatus { /** * A realtime progress report on how many operations have been downloaded and * how many are necessary in total to complete the next sync iteration. - * + * * This field is only set when {@link SyncDataFlowStatus#downloading} is also true. */ get downloadProgress(): SyncProgress | null { From 2912a49538b95280ab2b9ae91bd08b16936bcfa5 Mon Sep 17 00:00:00 2001 From: Simon Binder Date: Wed, 2 Apr 2025 15:36:14 +0200 Subject: [PATCH 07/16] Doc comments --- packages/common/src/db/crud/SyncProgress.ts | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/packages/common/src/db/crud/SyncProgress.ts b/packages/common/src/db/crud/SyncProgress.ts index 48993396d..fdadc5c5a 100644 --- a/packages/common/src/db/crud/SyncProgress.ts +++ b/packages/common/src/db/crud/SyncProgress.ts @@ -59,10 +59,22 @@ export interface ProgressWithOperations { export class SyncProgress { constructor(protected internal: InternalProgressInformation) {} + /** + * Returns donwload progress towards a complete checkpoint being received. + * + * The returned {@link ProgressWithOperations} tracks the target amount of operations that need + * to be downloaded in total and how many of them have already been received. + */ get untilCompletion(): ProgressWithOperations { return this.untilPriority(FULL_SYNC_PRIORITY); } + /** + * Returns download progress towards all data up until the specified priority being received. + * + * The returned {@link ProgressWithOperations} tracks the target amount of operations that need + * to be downloaded in total and how many of them have already been received. + */ untilPriority(priority: number): ProgressWithOperations { let total = 0; let downloaded = 0; From ed11438b61619299b7bdf4e4d2c11cf7591f60b7 Mon Sep 17 00:00:00 2001 From: Simon Binder Date: Wed, 2 Apr 2025 15:43:21 +0200 Subject: [PATCH 08/16] Add changeset --- .changeset/sharp-singers-search.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/sharp-singers-search.md diff --git a/.changeset/sharp-singers-search.md b/.changeset/sharp-singers-search.md new file mode 100644 index 000000000..c09a6af57 --- /dev/null +++ b/.changeset/sharp-singers-search.md @@ -0,0 +1,5 @@ +--- +'@powersync/common': minor +--- + +Report progress information about downloaded rows. From 6a3e3c2e1e6f7c25e522d18c7bfced84ebd55d7e Mon Sep 17 00:00:00 2001 From: Simon Binder Date: Mon, 14 Apr 2025 14:50:22 +0200 Subject: [PATCH 09/16] Simplify sync API --- packages/common/src/db/crud/SyncProgress.ts | 43 ++++++++++++--------- packages/node/tests/sync.test.ts | 4 +- 2 files changed, 27 insertions(+), 20 deletions(-) diff --git a/packages/common/src/db/crud/SyncProgress.ts b/packages/common/src/db/crud/SyncProgress.ts index fdadc5c5a..a718a604c 100644 --- a/packages/common/src/db/crud/SyncProgress.ts +++ b/packages/common/src/db/crud/SyncProgress.ts @@ -28,21 +28,27 @@ export interface ProgressWithOperations { * The total amount of operations to download for the current sync iteration * to complete. */ - total: number; + totalOperations: number; /** * The amount of operations that have already been downloaded. */ - completed: number; + downloadedOperations: number; /** - * Relative progress, as {@link completed} of {@link total}. This will be a number - * between `0.0` and `1.0`. + * Relative progress, as {@link downloadedOperations} of {@link totalOperations}. + * + * This will be a number between `0.0` and `1.0`. */ - fraction: number; + downloadedFraction: number; } /** * Provides realtime progress on how PowerSync is downloading rows. + * + * The progress until the next complete sync is available through the fields on {@link ProgressWithOperations}, + * which this class implements. + * Additionally, the {@link SyncProgress.untilPriority} method can be used to otbain progress towards + * a specific priority (instead of the progress for the entire download). * * The reported progress always reflects the status towards th end of a sync iteration (after * which a consistent snapshot of all buckets is available locally). @@ -56,17 +62,18 @@ export interface ProgressWithOperations { * Also note that data is downloaded in bulk, which means that individual counters are unlikely * to be updated one-by-one. */ -export class SyncProgress { - constructor(protected internal: InternalProgressInformation) {} +export class SyncProgress implements ProgressWithOperations { - /** - * Returns donwload progress towards a complete checkpoint being received. - * - * The returned {@link ProgressWithOperations} tracks the target amount of operations that need - * to be downloaded in total and how many of them have already been received. - */ - get untilCompletion(): ProgressWithOperations { - return this.untilPriority(FULL_SYNC_PRIORITY); + totalOperations: number; + downloadedOperations: number; + downloadedFraction: number; + + constructor(protected internal: InternalProgressInformation) { + const untilCompletion = this.untilPriority(FULL_SYNC_PRIORITY); + + this.totalOperations = untilCompletion.totalOperations; + this.downloadedOperations = untilCompletion.downloadedOperations; + this.downloadedFraction = untilCompletion.downloadedFraction; } /** @@ -89,9 +96,9 @@ export class SyncProgress { let progress = total == 0 ? 0.0 : downloaded / total; return { - total, - completed: downloaded, - fraction: progress + totalOperations: total, + downloadedOperations: downloaded, + downloadedFraction: progress }; } } diff --git a/packages/node/tests/sync.test.ts b/packages/node/tests/sync.test.ts index 3b28ba612..4eff5523f 100644 --- a/packages/node/tests/sync.test.ts +++ b/packages/node/tests/sync.test.ts @@ -245,10 +245,10 @@ async function waitForProgress( //console.log('checking', progress); const check = (expected: [number, number], actual: ProgressWithOperations): boolean => { - return actual.completed == expected[0] && actual.total == expected[1]; + return actual.downloadedOperations == expected[0] && actual.totalOperations == expected[1]; }; - if (!check(total, progress.untilCompletion)) { + if (!check(total, progress)) { return false; } From e577134b8bd77fedcf18cfd193a57d11151aee76 Mon Sep 17 00:00:00 2001 From: Simon Binder Date: Mon, 28 Apr 2025 12:09:32 +0200 Subject: [PATCH 10/16] Update docs on fraction --- .../client/sync/bucket/SqliteBucketStorage.ts | 2 +- .../AbstractStreamingSyncImplementation.ts | 7 ++--- packages/common/src/db/crud/SyncProgress.ts | 9 ++++-- packages/common/src/db/crud/SyncStatus.ts | 30 +++++++++---------- packages/node/src/db/PowerSyncDatabase.ts | 15 ++++------ 5 files changed, 30 insertions(+), 33 deletions(-) diff --git a/packages/common/src/client/sync/bucket/SqliteBucketStorage.ts b/packages/common/src/client/sync/bucket/SqliteBucketStorage.ts index 869a4d810..cd6686a77 100644 --- a/packages/common/src/client/sync/bucket/SqliteBucketStorage.ts +++ b/packages/common/src/client/sync/bucket/SqliteBucketStorage.ts @@ -213,7 +213,7 @@ export class SqliteBucketStorage extends BaseObserver imp // The two parameters could be replaced with one, but: https://github.com/powersync-ja/better-sqlite3/pull/6 const jsonBucketCount = JSON.stringify(bucketToCount); await tx.execute( - 'UPDATE ps_buckets SET count_since_last = 0, count_at_last = ?->name WHERE ?->name IS NOT NULL', + "UPDATE ps_buckets SET count_since_last = 0, count_at_last = ?->name WHERE name != '$local' AND ?->name IS NOT NULL", [jsonBucketCount, jsonBucketCount] ); } diff --git a/packages/common/src/client/sync/stream/AbstractStreamingSyncImplementation.ts b/packages/common/src/client/sync/stream/AbstractStreamingSyncImplementation.ts index cc66a0878..b490a4b91 100644 --- a/packages/common/src/client/sync/stream/AbstractStreamingSyncImplementation.ts +++ b/packages/common/src/client/sync/stream/AbstractStreamingSyncImplementation.ts @@ -501,10 +501,7 @@ The next upload iteration will be delayed.`); return [req, localDescriptions]; } - protected async streamingSyncIteration( - signal: AbortSignal, - options?: PowerSyncConnectionOptions - ): Promise { + protected async streamingSyncIteration(signal: AbortSignal, options?: PowerSyncConnectionOptions): Promise { await this.obtainLock({ type: LockType.SYNC, signal, @@ -693,7 +690,7 @@ The next upload iteration will be delayed.`); * (uses the same one), this should have some delay. */ await this.delayRetry(); - return ; + return; } this.triggerCrudUpload(); } else { diff --git a/packages/common/src/db/crud/SyncProgress.ts b/packages/common/src/db/crud/SyncProgress.ts index a718a604c..eae2a6dad 100644 --- a/packages/common/src/db/crud/SyncProgress.ts +++ b/packages/common/src/db/crud/SyncProgress.ts @@ -36,15 +36,19 @@ export interface ProgressWithOperations { /** * Relative progress, as {@link downloadedOperations} of {@link totalOperations}. + * + * This will be a number between `0.0` and `1.0` (inclusive). * - * This will be a number between `0.0` and `1.0`. + * When this number reaches `1.0`, all changes have been received from the sync service. + * Actually applying these changes happens before the `downloadProgress` field is cleared from + * {@link SyncStatus}, so progress can stay at `1.0` for a short while before completing. */ downloadedFraction: number; } /** * Provides realtime progress on how PowerSync is downloading rows. - * + * * The progress until the next complete sync is available through the fields on {@link ProgressWithOperations}, * which this class implements. * Additionally, the {@link SyncProgress.untilPriority} method can be used to otbain progress towards @@ -63,7 +67,6 @@ export interface ProgressWithOperations { * to be updated one-by-one. */ export class SyncProgress implements ProgressWithOperations { - totalOperations: number; downloadedOperations: number; downloadedFraction: number; diff --git a/packages/common/src/db/crud/SyncStatus.ts b/packages/common/src/db/crud/SyncStatus.ts index db2c622bc..f01211eaa 100644 --- a/packages/common/src/db/crud/SyncStatus.ts +++ b/packages/common/src/db/crud/SyncStatus.ts @@ -42,7 +42,7 @@ export class SyncStatus { /** * Indicates if the client is currently connected to the PowerSync service. - * + * * @returns {boolean} True if connected, false otherwise. Defaults to false if not specified. */ get connected() { @@ -51,7 +51,7 @@ export class SyncStatus { /** * Indicates if the client is in the process of establishing a connection to the PowerSync service. - * + * * @returns {boolean} True if connecting, false otherwise. Defaults to false if not specified. */ get connecting() { @@ -61,7 +61,7 @@ export class SyncStatus { /** * Time that a last sync has fully completed, if any. * This timestamp is reset to null after a restart of the PowerSync service. - * + * * @returns {Date | undefined} The timestamp of the last successful sync, or undefined if no sync has completed. */ get lastSyncedAt() { @@ -70,7 +70,7 @@ export class SyncStatus { /** * Indicates whether there has been at least one full sync completed since initialization. - * + * * @returns {boolean | undefined} True if at least one sync has completed, false if no sync has completed, * or undefined when the state is still being loaded from the database. */ @@ -80,7 +80,7 @@ export class SyncStatus { /** * Provides the current data flow status regarding uploads and downloads. - * + * * @returns {SyncDataFlowStatus} An object containing: * - downloading: True if actively downloading changes (only when connected is also true) * - uploading: True if actively uploading changes @@ -104,7 +104,7 @@ export class SyncStatus { /** * Provides sync status information for all bucket priorities, sorted by priority (highest first). - * + * * @returns {SyncPriorityStatus[]} An array of status entries for different sync priority levels, * sorted with highest priorities (lower numbers) first. */ @@ -128,18 +128,18 @@ export class SyncStatus { } /** - * Reports the sync status (a pair of {@link SyncStatus#hasSynced} and {@link SyncStatus#lastSyncedAt} fields) + * Reports the sync status (a pair of {@link SyncStatus#hasSynced} and {@link SyncStatus#lastSyncedAt} fields) * for a specific bucket priority level. - * + * * When buckets with different priorities are declared, PowerSync may choose to synchronize higher-priority * buckets first. When a consistent view over all buckets for all priorities up until the given priority is * reached, PowerSync makes data from those buckets available before lower-priority buckets have finished * syncing. - * - * This method returns the status for the requested priority or the next higher priority level that has - * status information available. This is because when PowerSync makes data for a given priority available, + * + * This method returns the status for the requested priority or the next higher priority level that has + * status information available. This is because when PowerSync makes data for a given priority available, * all buckets in higher-priorities are guaranteed to be consistent with that checkpoint. - * + * * For example, if PowerSync just finished synchronizing buckets in priority level 3, calling this method * with a priority of 1 may return information for priority level 3. * @@ -166,7 +166,7 @@ export class SyncStatus { /** * Compares this SyncStatus instance with another to determine if they are equal. * Equality is determined by comparing the serialized JSON representation of both instances. - * + * * @param {SyncStatus} status The SyncStatus instance to compare against * @returns {boolean} True if the instances are considered equal, false otherwise */ @@ -177,7 +177,7 @@ export class SyncStatus { /** * Creates a human-readable string representation of the current sync status. * Includes information about connection state, sync completion, and data flow. - * + * * @returns {string} A string representation of the sync status */ getMessage() { @@ -187,7 +187,7 @@ export class SyncStatus { /** * Serializes the SyncStatus instance to a plain object. - * + * * @returns {SyncStatusOptions} A plain object representation of the sync status */ toJSON(): SyncStatusOptions { diff --git a/packages/node/src/db/PowerSyncDatabase.ts b/packages/node/src/db/PowerSyncDatabase.ts index 3efc0c363..bbabad46e 100644 --- a/packages/node/src/db/PowerSyncDatabase.ts +++ b/packages/node/src/db/PowerSyncDatabase.ts @@ -24,12 +24,12 @@ import { Dispatcher } from 'undici'; export type NodePowerSyncDatabaseOptions = PowerSyncDatabaseOptions & { database: DBAdapter | SQLOpenFactory | NodeSQLOpenOptions; - /** + /** * Options to override how the SDK will connect to the sync service. * * This option is intended to be used for internal tests. */ - remoteOptions?: Partial; + remoteOptions?: Partial; }; export type NodeAdditionalConnectionOptions = AdditionalConnectionOptions & { @@ -87,13 +87,10 @@ export class PowerSyncDatabase extends AbstractPowerSyncDatabase { connector: PowerSyncBackendConnector, options: NodeAdditionalConnectionOptions ): AbstractStreamingSyncImplementation { - const remote = new NodeRemote( - connector, this.options.logger, - { - dispatcher: options.dispatcher, - ...(this.options as NodePowerSyncDatabaseOptions).remoteOptions, - } - ); + const remote = new NodeRemote(connector, this.options.logger, { + dispatcher: options.dispatcher, + ...(this.options as NodePowerSyncDatabaseOptions).remoteOptions + }); return new NodeStreamingSyncImplementation({ adapter: this.bucketStorageAdapter, From 149db50a76f8cbabdd10a80765f82a1807e832b3 Mon Sep 17 00:00:00 2001 From: Simon Binder Date: Wed, 30 Apr 2025 17:59:43 +0200 Subject: [PATCH 11/16] Review feedback --- .changeset/sharp-singers-search.md | 3 +++ .../src/client/sync/bucket/BucketStorageAdapter.ts | 13 ++++++------- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/.changeset/sharp-singers-search.md b/.changeset/sharp-singers-search.md index c09a6af57..4cf34915d 100644 --- a/.changeset/sharp-singers-search.md +++ b/.changeset/sharp-singers-search.md @@ -1,5 +1,8 @@ --- '@powersync/common': minor +'@powersync/web': minor +'@powersync/node': minor +'@powersync/react-native': minor --- Report progress information about downloaded rows. diff --git a/packages/common/src/client/sync/bucket/BucketStorageAdapter.ts b/packages/common/src/client/sync/bucket/BucketStorageAdapter.ts index cb00fb8be..c7bf525e7 100644 --- a/packages/common/src/client/sync/bucket/BucketStorageAdapter.ts +++ b/packages/common/src/client/sync/bucket/BucketStorageAdapter.ts @@ -30,13 +30,12 @@ export interface SyncLocalDatabaseResult { checkpointFailures?: string[]; } -export type BucketOperationProgress = Record< - string, - { - atLast: number; - sinceLast: number; - } ->; +export type SavedProgress = { + atLast: number; + sinceLast: number; +}; + +export type BucketOperationProgress = Record; export interface BucketChecksum { bucket: string; From 654b784607aab8794a01fa2e71959329cc0ca6d5 Mon Sep 17 00:00:00 2001 From: Simon Binder Date: Fri, 2 May 2025 12:20:48 +0200 Subject: [PATCH 12/16] Add progress indicator to demos --- .../app/views/todos/lists.tsx | 44 +++++++++---------- .../library/widgets/GuardBySync.tsx | 40 +++++++++++++++++ .../src/app/views/todo-lists/page.tsx | 5 ++- .../src/components/widgets/GuardBySync.tsx | 42 ++++++++++++++++++ .../AbstractStreamingSyncImplementation.ts | 9 ++-- 5 files changed, 111 insertions(+), 29 deletions(-) create mode 100644 demos/react-native-supabase-todolist/library/widgets/GuardBySync.tsx create mode 100644 demos/react-supabase-todolist/src/components/widgets/GuardBySync.tsx diff --git a/demos/react-native-supabase-todolist/app/views/todos/lists.tsx b/demos/react-native-supabase-todolist/app/views/todos/lists.tsx index acb50a709..f793c1c76 100644 --- a/demos/react-native-supabase-todolist/app/views/todos/lists.tsx +++ b/demos/react-native-supabase-todolist/app/views/todos/lists.tsx @@ -7,8 +7,9 @@ import prompt from 'react-native-prompt-android'; import { router, Stack } from 'expo-router'; import { LIST_TABLE, TODO_TABLE, ListRecord } from '../../../library/powersync/AppSchema'; import { useSystem } from '../../../library/powersync/system'; -import { useQuery, useStatus } from '@powersync/react-native'; +import { useQuery } from '@powersync/react-native'; import { ListItemWidget } from '../../../library/widgets/ListItemWidget'; +import { GuardBySync } from '../../../library/widgets/GuardBySync'; const description = (total: number, completed: number = 0) => { return `${total - completed} pending, ${completed} completed`; @@ -16,7 +17,6 @@ const description = (total: number, completed: number = 0) => { const ListsViewWidget: React.FC = () => { const system = useSystem(); - const status = useStatus(); const { data: listRecords } = useQuery(` SELECT ${LIST_TABLE}.*, COUNT(${TODO_TABLE}.id) AS total_tasks, SUM(CASE WHEN ${TODO_TABLE}.completed = true THEN 1 ELSE 0 END) as completed_tasks @@ -78,26 +78,26 @@ const ListsViewWidget: React.FC = () => { ); }} /> - - {!status.hasSynced ? ( - Busy with sync... - ) : ( - listRecords.map((r) => ( - deleteList(r.id)} - onPress={() => { - router.push({ - pathname: 'views/todos/edit/[id]', - params: { id: r.id } - }); - }} - /> - )) - )} - + + + {( + listRecords.map((r) => ( + deleteList(r.id)} + onPress={() => { + router.push({ + pathname: 'views/todos/edit/[id]', + params: { id: r.id } + }); + }} + /> + )) + )} + + diff --git a/demos/react-native-supabase-todolist/library/widgets/GuardBySync.tsx b/demos/react-native-supabase-todolist/library/widgets/GuardBySync.tsx new file mode 100644 index 000000000..902c0a314 --- /dev/null +++ b/demos/react-native-supabase-todolist/library/widgets/GuardBySync.tsx @@ -0,0 +1,40 @@ +import { useStatus } from '@powersync/react'; +import { FC, ReactNode } from 'react'; +import { View } from 'react-native'; +import { Text, LinearProgress } from '@rneui/themed'; + +/** + * A component that renders its child if the database has been synced at least once and shows + * a progress indicator otherwise. + */ +export const GuardBySync: FC<{ children: ReactNode; priority?: number }> = ({ children, priority }) => { + const status = useStatus(); + + const hasSynced = priority == null ? status.hasSynced : status.statusForPriority(priority).hasSynced; + if (hasSynced) { + return children; + } + + // If we haven't completed a sync yet, show a progress indicator! + const allProgress = status.downloadProgress; + const progress = priority == null ? allProgress : allProgress?.untilPriority(priority); + + return ( + + {progress != null ? ( + <> + + {progress.downloadedOperations == progress.totalOperations ? ( + Applying server-side changes + ) : ( + + Downloaded {progress.downloadedOperations} out of {progress.totalOperations}. + + )} + + ) : ( + + )} + + ); +}; diff --git a/demos/react-supabase-todolist/src/app/views/todo-lists/page.tsx b/demos/react-supabase-todolist/src/app/views/todo-lists/page.tsx index 1dc2e6217..1f1a686b7 100644 --- a/demos/react-supabase-todolist/src/app/views/todo-lists/page.tsx +++ b/demos/react-supabase-todolist/src/app/views/todo-lists/page.tsx @@ -18,6 +18,7 @@ import { LISTS_TABLE } from '@/library/powersync/AppSchema'; import { NavigationPage } from '@/components/navigation/NavigationPage'; import { SearchBarWidget } from '@/components/widgets/SearchBarWidget'; import { TodoListsWidget } from '@/components/widgets/TodoListsWidget'; +import { GuardBySync } from '@/components/widgets/GuardBySync'; export default function TodoListsPage() { const powerSync = usePowerSync(); @@ -53,7 +54,9 @@ export default function TodoListsPage() { - {!status.hasSynced ?

Busy with sync...

: } + + +
{/* TODO use a dialog service in future, this is just a simple example app */} = ({ children, priority }) => { + const status = useStatus(); + + const hasSynced = priority == null ? status.hasSynced : status.statusForPriority(priority).hasSynced; + if (hasSynced) { + return children; + } + + // If we haven't completed a sync yet, show a progress indicator! + const allProgress = status.downloadProgress; + const progress = priority == null ? allProgress : allProgress?.untilPriority(priority); + + return ( + + {progress != null ? ( + <> + + + {progress.downloadedOperations == progress.totalOperations ? ( + Applying server-side changes + ) : ( + + Downloaded {progress.downloadedOperations} out of {progress.totalOperations}. + + )} + + + ) : ( + + )} + + ); + }; + \ No newline at end of file diff --git a/packages/common/src/client/sync/stream/AbstractStreamingSyncImplementation.ts b/packages/common/src/client/sync/stream/AbstractStreamingSyncImplementation.ts index b490a4b91..a6179a039 100644 --- a/packages/common/src/client/sync/stream/AbstractStreamingSyncImplementation.ts +++ b/packages/common/src/client/sync/stream/AbstractStreamingSyncImplementation.ts @@ -165,14 +165,13 @@ export abstract class AbstractStreamingSyncImplementation private pendingCrudUpload?: Promise; syncStatus: SyncStatus; - private syncStatusOptions: SyncStatusOptions; triggerCrudUpload: () => void; constructor(options: AbstractStreamingSyncImplementationOptions) { super(); this.options = { ...DEFAULT_STREAMING_SYNC_OPTIONS, ...options }; - this.syncStatusOptions = { + this.syncStatus = new SyncStatus({ connected: false, connecting: false, lastSyncedAt: undefined, @@ -180,8 +179,7 @@ export abstract class AbstractStreamingSyncImplementation uploading: false, downloading: false } - }; - this.syncStatus = new SyncStatus(this.syncStatusOptions); + }); this.abortController = null; this.triggerCrudUpload = throttleLeadingTrailing(() => { @@ -660,7 +658,7 @@ The next upload iteration will be delayed.`); await this.options.adapter.setTargetCheckpoint(targetCheckpoint); } else if (isStreamingSyncData(line)) { const { data } = line; - const previousProgress = this.syncStatusOptions.dataFlow?.downloadProgress; + const previousProgress = this.syncStatus.dataFlowStatus.downloadProgress; let updatedProgress: InternalProgressInformation | null = null; if (previousProgress) { updatedProgress = { ...previousProgress }; @@ -805,7 +803,6 @@ The next upload iteration will be delayed.`); }); if (!this.syncStatus.isEqual(updatedStatus)) { - Object.assign(this.syncStatusOptions, options); this.syncStatus = updatedStatus; // Only trigger this is there was a change this.iterateListeners((cb) => cb.statusChanged?.(updatedStatus)); From d064f0842322840de9da3d1fd6643775ddcfbc1b Mon Sep 17 00:00:00 2001 From: Simon Binder Date: Fri, 2 May 2025 12:25:20 +0200 Subject: [PATCH 13/16] Reformat --- .../src/components/widgets/GuardBySync.tsx | 65 +++++++++---------- 1 file changed, 32 insertions(+), 33 deletions(-) diff --git a/demos/react-supabase-todolist/src/components/widgets/GuardBySync.tsx b/demos/react-supabase-todolist/src/components/widgets/GuardBySync.tsx index 9202a12ed..57907eb3b 100644 --- a/demos/react-supabase-todolist/src/components/widgets/GuardBySync.tsx +++ b/demos/react-supabase-todolist/src/components/widgets/GuardBySync.tsx @@ -7,36 +7,35 @@ import { FC, ReactNode } from 'react'; * a progress indicator otherwise. */ export const GuardBySync: FC<{ children: ReactNode; priority?: number }> = ({ children, priority }) => { - const status = useStatus(); - - const hasSynced = priority == null ? status.hasSynced : status.statusForPriority(priority).hasSynced; - if (hasSynced) { - return children; - } - - // If we haven't completed a sync yet, show a progress indicator! - const allProgress = status.downloadProgress; - const progress = priority == null ? allProgress : allProgress?.untilPriority(priority); - - return ( - - {progress != null ? ( - <> - - - {progress.downloadedOperations == progress.totalOperations ? ( - Applying server-side changes - ) : ( - - Downloaded {progress.downloadedOperations} out of {progress.totalOperations}. - - )} - - - ) : ( - - )} - - ); - }; - \ No newline at end of file + const status = useStatus(); + + const hasSynced = priority == null ? status.hasSynced : status.statusForPriority(priority).hasSynced; + if (hasSynced) { + return children; + } + + // If we haven't completed a sync yet, show a progress indicator! + const allProgress = status.downloadProgress; + const progress = priority == null ? allProgress : allProgress?.untilPriority(priority); + + return ( + + {progress != null ? ( + <> + + + {progress.downloadedOperations == progress.totalOperations ? ( + Applying server-side changes + ) : ( + + Downloaded {progress.downloadedOperations} out of {progress.totalOperations}. + + )} + + + ) : ( + + )} + + ); +}; From 143ff12ad7c85deeca76f5338d6d8f38fbac769b Mon Sep 17 00:00:00 2001 From: Simon Binder Date: Fri, 2 May 2025 12:29:40 +0200 Subject: [PATCH 14/16] Update react-native-quick-sqlite --- demos/django-react-native-todolist/package.json | 2 +- demos/react-native-supabase-group-chat/package.json | 2 +- demos/react-native-supabase-todolist/package.json | 2 +- packages/react-native/package.json | 4 ++-- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/demos/django-react-native-todolist/package.json b/demos/django-react-native-todolist/package.json index f086cbde5..9e2f80ddc 100644 --- a/demos/django-react-native-todolist/package.json +++ b/demos/django-react-native-todolist/package.json @@ -11,7 +11,7 @@ "@azure/core-asynciterator-polyfill": "^1.0.2", "@expo/metro-runtime": "^4.0.1", "@expo/vector-icons": "^14.0.0", - "@journeyapps/react-native-quick-sqlite": "^2.4.3", + "@journeyapps/react-native-quick-sqlite": "^2.4.4", "@powersync/common": "workspace:*", "@powersync/react": "workspace:*", "@powersync/react-native": "workspace:*", diff --git a/demos/react-native-supabase-group-chat/package.json b/demos/react-native-supabase-group-chat/package.json index 139547de1..ea0094020 100644 --- a/demos/react-native-supabase-group-chat/package.json +++ b/demos/react-native-supabase-group-chat/package.json @@ -22,7 +22,7 @@ "@azure/core-asynciterator-polyfill": "^1.0.2", "@expo/metro-runtime": "^4.0.1", "@faker-js/faker": "8.3.1", - "@journeyapps/react-native-quick-sqlite": "^2.4.3", + "@journeyapps/react-native-quick-sqlite": "^2.4.4", "@powersync/common": "workspace:*", "@powersync/react": "workspace:*", "@powersync/react-native": "workspace:*", diff --git a/demos/react-native-supabase-todolist/package.json b/demos/react-native-supabase-todolist/package.json index 8e210783d..57f37052d 100644 --- a/demos/react-native-supabase-todolist/package.json +++ b/demos/react-native-supabase-todolist/package.json @@ -10,7 +10,7 @@ "dependencies": { "@azure/core-asynciterator-polyfill": "^1.0.2", "@expo/vector-icons": "^14.0.3", - "@journeyapps/react-native-quick-sqlite": "^2.4.3", + "@journeyapps/react-native-quick-sqlite": "^2.4.4", "@powersync/attachments": "workspace:*", "@powersync/common": "workspace:*", "@powersync/react": "workspace:*", diff --git a/packages/react-native/package.json b/packages/react-native/package.json index 085f16775..a928e2e6a 100644 --- a/packages/react-native/package.json +++ b/packages/react-native/package.json @@ -30,7 +30,7 @@ }, "homepage": "https://docs.powersync.com/", "peerDependencies": { - "@journeyapps/react-native-quick-sqlite": "^2.4.3", + "@journeyapps/react-native-quick-sqlite": "^2.4.4", "@powersync/common": "workspace:^1.28.0", "react": "*", "react-native": "*" @@ -46,7 +46,7 @@ }, "devDependencies": { "@craftzdog/react-native-buffer": "^6.0.5", - "@journeyapps/react-native-quick-sqlite": "^2.4.3", + "@journeyapps/react-native-quick-sqlite": "^2.4.4", "@rollup/plugin-alias": "^5.1.0", "@rollup/plugin-commonjs": "^25.0.7", "@rollup/plugin-inject": "^5.0.5", From a309531b1fe9561dfd2f41590fd88bf40729b047 Mon Sep 17 00:00:00 2001 From: Simon Binder Date: Fri, 2 May 2025 15:02:16 +0200 Subject: [PATCH 15/16] Update lockfile --- pnpm-lock.yaml | 37 ++++++++++++++++++++++--------------- 1 file changed, 22 insertions(+), 15 deletions(-) diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 5aad5663b..18e23841a 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -121,8 +121,8 @@ importers: specifier: ^14.0.0 version: 14.0.4 '@journeyapps/react-native-quick-sqlite': - specifier: ^2.4.3 - version: 2.4.3(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.2))(@types/react@18.3.18)(encoding@0.1.13)(react@18.3.1))(react@18.3.1) + specifier: ^2.4.4 + version: 2.4.4(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.2))(@types/react@18.3.18)(encoding@0.1.13)(react@18.3.1))(react@18.3.1) '@powersync/common': specifier: workspace:* version: link:../../packages/common @@ -392,7 +392,7 @@ importers: version: 10.4.20(postcss@8.5.3) babel-loader: specifier: ^9.1.3 - version: 9.2.1(@babel/core@7.26.10)(webpack@5.98.0(@swc/core@1.6.13(@swc/helpers@0.5.5))) + version: 9.2.1(@babel/core@7.26.10)(webpack@5.95.0(@swc/core@1.6.13(@swc/helpers@0.5.5))) electron: specifier: 30.0.2 version: 30.0.2 @@ -804,8 +804,8 @@ importers: specifier: 8.3.1 version: 8.3.1 '@journeyapps/react-native-quick-sqlite': - specifier: ^2.4.3 - version: 2.4.3(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.3.3))(@types/react@18.3.18)(encoding@0.1.13)(react@18.3.1))(react@18.3.1) + specifier: ^2.4.4 + version: 2.4.4(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.3.3))(@types/react@18.3.18)(encoding@0.1.13)(react@18.3.1))(react@18.3.1) '@powersync/common': specifier: workspace:* version: link:../../packages/common @@ -937,8 +937,8 @@ importers: specifier: ^14.0.3 version: 14.0.4 '@journeyapps/react-native-quick-sqlite': - specifier: ^2.4.3 - version: 2.4.3(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.2))(@types/react@18.3.18)(encoding@0.1.13)(react@18.3.1))(react@18.3.1) + specifier: ^2.4.4 + version: 2.4.4(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.2))(@types/react@18.3.18)(encoding@0.1.13)(react@18.3.1))(react@18.3.1) '@powersync/attachments': specifier: workspace:* version: link:../../packages/attachments @@ -1077,7 +1077,7 @@ importers: version: 14.0.4 '@journeyapps/react-native-quick-sqlite': specifier: ^2.4.0 - version: 2.4.3(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.2))(@types/react@18.3.18)(encoding@0.1.13)(react@18.3.1))(react@18.3.1) + version: 2.4.4(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.2))(@types/react@18.3.18)(encoding@0.1.13)(react@18.3.1))(react@18.3.1) '@journeyapps/wa-sqlite': specifier: ^1.2.0 version: 1.2.3 @@ -1889,8 +1889,8 @@ importers: specifier: ^6.0.5 version: 6.0.5(react-native@0.72.4(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(encoding@0.1.13)(react@18.3.1))(react@18.3.1) '@journeyapps/react-native-quick-sqlite': - specifier: ^2.4.3 - version: 2.4.3(react-native@0.72.4(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(encoding@0.1.13)(react@18.3.1))(react@18.3.1) + specifier: ^2.4.4 + version: 2.4.4(react-native@0.72.4(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(encoding@0.1.13)(react@18.3.1))(react@18.3.1) '@rollup/plugin-alias': specifier: ^5.1.0 version: 5.1.1(rollup@4.14.3) @@ -5103,8 +5103,8 @@ packages: resolution: {integrity: sha512-u3UPsIilWKOM3F9CXtrG8LEJmNxwoCQC/XVj4IKYXvvpx7QIi/Kg1LI5uDmDpKlac62NUtX7eLjRh+jVZcLOzw==} engines: {node: ^14.15.0 || ^16.10.0 || >=18.0.0} - '@journeyapps/react-native-quick-sqlite@2.4.3': - resolution: {integrity: sha512-w9KOid3upSyJfrScvKjtxEfnMkmEvcyPF1cWwKApM7a7NKQs8Vkth89NsnHs4k1M0Ktpm2eM26cR2/Qply+yfQ==} + '@journeyapps/react-native-quick-sqlite@2.4.4': + resolution: {integrity: sha512-XoAGByoyxJqKNTh0lqakRb/A8uZwksbP4KaYXqcEmeGyOBxhOdjBDR15pkCIMoJU1JTBzU8LXxQRtx20+7jCWg==} peerDependencies: react: '*' react-native: '*' @@ -24721,17 +24721,17 @@ snapshots: '@types/yargs': 17.0.33 chalk: 4.1.2 - '@journeyapps/react-native-quick-sqlite@2.4.3(react-native@0.72.4(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(encoding@0.1.13)(react@18.3.1))(react@18.3.1)': + '@journeyapps/react-native-quick-sqlite@2.4.4(react-native@0.72.4(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(encoding@0.1.13)(react@18.3.1))(react@18.3.1)': dependencies: react: 18.3.1 react-native: 0.72.4(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(encoding@0.1.13)(react@18.3.1) - '@journeyapps/react-native-quick-sqlite@2.4.3(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.3.3))(@types/react@18.3.18)(encoding@0.1.13)(react@18.3.1))(react@18.3.1)': + '@journeyapps/react-native-quick-sqlite@2.4.4(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.3.3))(@types/react@18.3.18)(encoding@0.1.13)(react@18.3.1))(react@18.3.1)': dependencies: react: 18.3.1 react-native: 0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.3.3))(@types/react@18.3.18)(encoding@0.1.13)(react@18.3.1) - '@journeyapps/react-native-quick-sqlite@2.4.3(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.2))(@types/react@18.3.18)(encoding@0.1.13)(react@18.3.1))(react@18.3.1)': + '@journeyapps/react-native-quick-sqlite@2.4.4(react-native@0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.2))(@types/react@18.3.18)(encoding@0.1.13)(react@18.3.1))(react@18.3.1)': dependencies: react: 18.3.1 react-native: 0.76.9(@babel/core@7.26.10)(@babel/preset-env@7.26.9(@babel/core@7.26.10))(@react-native-community/cli@15.1.3(typescript@5.8.2))(@types/react@18.3.18)(encoding@0.1.13)(react@18.3.1) @@ -31010,6 +31010,13 @@ snapshots: transitivePeerDependencies: - supports-color + babel-loader@9.2.1(@babel/core@7.26.10)(webpack@5.95.0(@swc/core@1.6.13(@swc/helpers@0.5.5))): + dependencies: + '@babel/core': 7.26.10 + find-cache-dir: 4.0.0 + schema-utils: 4.2.0 + webpack: 5.95.0(@swc/core@1.6.13(@swc/helpers@0.5.5)) + babel-loader@9.2.1(@babel/core@7.26.10)(webpack@5.98.0(@swc/core@1.10.1(@swc/helpers@0.5.5))): dependencies: '@babel/core': 7.26.10 From c45e84e0491d3e594a110c6b27ba3e3b6811c6e3 Mon Sep 17 00:00:00 2001 From: Simon Binder Date: Fri, 2 May 2025 19:33:10 +0200 Subject: [PATCH 16/16] Mention entrypoint to progress API --- .changeset/sharp-singers-search.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changeset/sharp-singers-search.md b/.changeset/sharp-singers-search.md index 4cf34915d..78cfa9cd9 100644 --- a/.changeset/sharp-singers-search.md +++ b/.changeset/sharp-singers-search.md @@ -5,4 +5,4 @@ '@powersync/react-native': minor --- -Report progress information about downloaded rows. +Report progress information about downloaded rows. Sync progress is available through `SyncStatus.downloadProgress`.