diff --git a/.changeset/serious-rice-buy.md b/.changeset/serious-rice-buy.md new file mode 100644 index 000000000..aefcd913d --- /dev/null +++ b/.changeset/serious-rice-buy.md @@ -0,0 +1,5 @@ +--- +'@powersync/node': minor +--- + +Initial version diff --git a/README.md b/README.md index 68c46913d..51ed617ec 100644 --- a/README.md +++ b/README.md @@ -18,6 +18,10 @@ _[PowerSync](https://www.powersync.com) is a sync engine for building local-firs - JS Web SDK implementation (extension of `packages/common`) +- [packages/node](./packages/node/README.md) + + - Node.js client implementation (extension of `packages/common`) + - [packages/react](./packages/react/README.md) - React integration for PowerSync. @@ -80,6 +84,10 @@ Demo applications are located in the [`demos/`](./demos/) directory. Also see ou - [demos/example-capacitor](./demos/example-capacitor/README.md) A Capacitor example app using the PowerSync Web SDK. +### Node + +- [demos/example-node](./demos/example-node/README.md) A small CLI example built using the PowerSync SDK for Node.js. + ## Tools - [tools/diagnostics-app](./tools/diagnostics-app): A standalone web app that presents stats about a user's local database (incl. tables and sync buckets). diff --git a/demos/example-node/.env b/demos/example-node/.env new file mode 100644 index 000000000..170d91d37 --- /dev/null +++ b/demos/example-node/.env @@ -0,0 +1,2 @@ +BACKEND=http://localhost:6060 +SYNC_SERVICE=http://localhost:8080 diff --git a/demos/example-node/README.md b/demos/example-node/README.md new file mode 100644 index 000000000..85b16e181 --- /dev/null +++ b/demos/example-node/README.md @@ -0,0 +1,16 @@ +## Node.js Demo + +This demonstrates a small Node.js client opening a database and connecting PowerSync. + +This demo is configured to talk to an example backend [you can host yourself](https://github.com/powersync-ja/self-host-demo). To get started: + +1. Start one of the Node.js backend examples from [the self-host-demo repository](https://github.com/powersync-ja/self-host-demo). +2. If necessary, change `.env` to point to the started backend and sync service. +3. Run `pnpm install` and `pnpm build:packages` in the root of this repo. +4. In this directory, run `pnpm run start`. + +This opens the local database, connects to PowerSync, waits for a first sync and then runs a simple query. +Results from the query are printed every time it changes. Try: + +1. Updating a row in the backend database and see changes reflected in the running client. +2. Enter `add('my list')` and see the new list show up in the backend database. diff --git a/demos/example-node/package.json b/demos/example-node/package.json new file mode 100644 index 000000000..cdabd63ce --- /dev/null +++ b/demos/example-node/package.json @@ -0,0 +1,20 @@ +{ + "name": "example-node", + "version": "1.0.0", + "description": "", + "type": "module", + "private": true, + "scripts": { + "build": "tsc -b", + "watch": "tsc -b -w", + "start": "node --loader ts-node/esm -r dotenv/config src/main.ts" + }, + "dependencies": { + "@powersync/node": "workspace:*", + "dotenv": "^16.4.7" + }, + "devDependencies": { + "ts-node": "^10.9.2", + "typescript": "^5.8.2" + } +} diff --git a/demos/example-node/src/main.ts b/demos/example-node/src/main.ts new file mode 100644 index 000000000..04e13dedd --- /dev/null +++ b/demos/example-node/src/main.ts @@ -0,0 +1,65 @@ +import repl_factory from 'node:repl'; +import { once } from 'node:events'; + +import { PowerSyncDatabase, SyncStreamConnectionMethod } from '@powersync/node'; +import Logger from 'js-logger'; +import { AppSchema, DemoConnector } from './powersync.js'; +import { exit } from 'node:process'; + +const main = async () => { + Logger.useDefaults({ defaultLevel: Logger.WARN }); + + if (!('BACKEND' in process.env) || !('SYNC_SERVICE' in process.env)) { + console.warn( + 'Set the BACKEND and SYNC_SERVICE environment variables to point to a sync service and a running demo backend.' + ); + return; + } + + const db = new PowerSyncDatabase({ + schema: AppSchema, + database: { + dbFilename: 'test.db' + }, + logger: Logger + }); + console.log(await db.get('SELECT powersync_rs_version();')); + + await db.connect(new DemoConnector(), { connectionMethod: SyncStreamConnectionMethod.HTTP }); + await db.waitForFirstSync(); + console.log('First sync complete!'); + + let hasFirstRow: ((value: any) => void) | null = null; + const firstRow = new Promise((resolve) => (hasFirstRow = resolve)); + const watchLists = async () => { + for await (const rows of db.watch('SELECT * FROM lists')) { + if (hasFirstRow) { + hasFirstRow(null); + hasFirstRow = null; + } + console.log('Has todo lists', rows.rows?._array); + } + }; + + watchLists(); + await firstRow; + + console.log('Connected to PowerSync. Try updating the lists in the database and see it reflected here.'); + console.log("To upload a list here, enter `await add('name of new list');`"); + + const repl = repl_factory.start(); + repl.context.add = async (name: string) => { + await db.execute( + "INSERT INTO lists (id, created_at, name, owner_id) VALUEs (uuid(), datetime('now'), ?, uuid());", + [name] + ); + }; + + await once(repl, 'exit'); + console.log('shutting down'); + await db.disconnect(); + await db.close(); + exit(0); +}; + +await main(); diff --git a/demos/example-node/src/powersync.ts b/demos/example-node/src/powersync.ts new file mode 100644 index 000000000..ee36a8e9f --- /dev/null +++ b/demos/example-node/src/powersync.ts @@ -0,0 +1,77 @@ +import { AbstractPowerSyncDatabase, column, PowerSyncBackendConnector, Schema, Table } from '@powersync/node'; + +export class DemoConnector implements PowerSyncBackendConnector { + async fetchCredentials() { + const response = await fetch(`${process.env.BACKEND}/api/auth/token`); + if (response.status != 200) { + throw 'Could not fetch token'; + } + + const { token } = await response.json(); + + return { + endpoint: process.env.SYNC_SERVICE!, + token: token + }; + } + + async uploadData(database: AbstractPowerSyncDatabase) { + const batch = await database.getCrudBatch(); + if (batch == null) { + return; + } + + const entries: any[] = []; + for (const op of batch.crud) { + entries.push({ + table: op.table, + op: op.op, + id: op.id, + data: op.opData + }); + } + + const response = await fetch(`${process.env.BACKEND}/api/data/`, { + method: 'POST', + headers: {'Content-Type': 'application/json'}, + body: JSON.stringify({batch: entries}), + }); + if (response.status !== 200) { + throw new Error(`Server returned HTTP ${response.status}: ${await response.text()}`); + } + + await batch?.complete(); + } +} + +export const LIST_TABLE = 'lists'; +export const TODO_TABLE = 'todos'; + +const todos = new Table( + { + list_id: column.text, + created_at: column.text, + completed_at: column.text, + description: column.text, + created_by: column.text, + completed_by: column.text, + completed: column.integer, + photo_id: column.text + }, + { indexes: { list: ['list_id'] } } +); + +const lists = new Table({ + created_at: column.text, + name: column.text, + owner_id: column.text +}); + +export const AppSchema = new Schema({ + lists, + todos +}); + +export type Database = (typeof AppSchema)['types']; +export type TodoRecord = Database['todos']; +export type ListRecord = Database['lists']; diff --git a/demos/example-node/tsconfig.json b/demos/example-node/tsconfig.json new file mode 100644 index 000000000..9d2259b00 --- /dev/null +++ b/demos/example-node/tsconfig.json @@ -0,0 +1,14 @@ +{ + "extends": "../../tsconfig.base", + "compilerOptions": { + "baseUrl": ".", + "rootDir": "src", + "outDir": "lib", + "strictNullChecks": true + }, + "references": [ + { + "path": "../../packages/node" + } + ] +} diff --git a/docs/utils/packageMap.ts b/docs/utils/packageMap.ts index 01b83fed0..daf9aab1c 100644 --- a/docs/utils/packageMap.ts +++ b/docs/utils/packageMap.ts @@ -6,7 +6,8 @@ enum Packages { VueSdk = 'vue-sdk', AttachmentsSdk = 'attachments-sdk', WebSdk = 'web-sdk', - TanstackReactQuerySdk = 'tanstack-react-query-sdk' + TanstackReactQuerySdk = 'tanstack-react-query-sdk', + NodeSdk = 'node-sdk', } interface Package { @@ -63,5 +64,12 @@ export const packageMap: PackageMap = { entryPoints: ['../packages/attachments/src/index.ts'], tsconfig: '../packages/attachments/tsconfig.json', id: Packages.AttachmentsSdk - } + }, + [Packages.NodeSdk]: { + name: 'Node SDK', + dirName: Packages.NodeSdk, + entryPoints: ['../packages/node/src/index.ts'], + tsconfig: '../packages/node/tsconfig.json', + id: Packages.NodeSdk + }, }; diff --git a/packages/node/CHANGELOG.md b/packages/node/CHANGELOG.md new file mode 100644 index 000000000..3906dd8d3 --- /dev/null +++ b/packages/node/CHANGELOG.md @@ -0,0 +1 @@ +# @powersync/node diff --git a/packages/node/LICENSE b/packages/node/LICENSE new file mode 100644 index 000000000..c61b66391 --- /dev/null +++ b/packages/node/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + +TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + +1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + +2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + +3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + +4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + +5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + +6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + +7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + +8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + +9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + +END OF TERMS AND CONDITIONS + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/packages/node/README.md b/packages/node/README.md new file mode 100644 index 000000000..22783a38c --- /dev/null +++ b/packages/node/README.md @@ -0,0 +1,44 @@ +

+ +

+ +# PowerSync SDK for Node.js + +_[PowerSync](https://www.powersync.com) is a sync engine for building local-first apps with instantly-responsive UI/UX and simplified state transfer. Syncs between SQLite on the client-side and Postgres, MongoDB or MySQL on the server-side._ + +This package (`packages/node`) is the PowerSync SDK for Node.js clients. It is an extension of `packages/common`. +Using this package is not necessary for PowerSync on servers, see [our documentation](https://docs.powersync.com/installation/app-backend-setup) for more details on that. + +This package has an API similar to the PowerSync web SDK, for which a summary of features is available [here](https://docs.powersync.com/client-sdk-references/js-web). + +# Installation + +## Install Package + +```bash +npm install @powersync/node +``` + +Both `@powersync/node` and the `better-sqlite3` packages have install scripts that need to run to compile +or download sqlite3 and PowerSync binaries. + +# Getting Started + +You can follow along our [web SDK reference](https://docs.powersync.com/client-sdk-references/js-web) +which contains everything you need to know to get started implementing PowerSync in your project. +Replace imports of `@powersync/web` with `@powersync/node` where necessary. + +# Examples + +A simple example using `@powersync/node` is available in the [`demos/example-node/`](../demos/example-node) directory. + +# Found a bug or need help? + +- Join our [Discord server](https://discord.gg/powersync) where you can browse topics from our community, ask questions, share feedback, or just say hello :) +- Please open a [GitHub issue](https://github.com/powersync-ja/powersync-js/issues) when you come across a bug. +- Have feedback or an idea? [Submit an idea](https://roadmap.powersync.com/tabs/5-roadmap/submit-idea) via our public roadmap or [schedule a chat](https://calendly.com/powersync-product/powersync-chat) with someone from our product team. + +# Thanks + +The PowerSync Node.js SDK relies on the work contributors and maintainers have put into the upstream better-sqlite3 package. +In particular, we'd like to thank [@spinda](https://github.com/spinda) for contributing support for update, commit and rollback hooks! diff --git a/packages/node/download_core.js b/packages/node/download_core.js new file mode 100644 index 000000000..60d986894 --- /dev/null +++ b/packages/node/download_core.js @@ -0,0 +1,46 @@ +// TODO: Make this a pre-publish hook and just bundle everything +import * as OS from 'node:os'; +import * as fs from 'node:fs/promises'; +import * as path from 'node:path'; +import { Readable } from 'node:stream'; +import { finished } from 'node:stream/promises'; +import { exit } from 'node:process'; + +const version = '0.3.11'; + +const platform = OS.platform(); +let destination; +let asset; + +if (platform === 'win32') { + asset = 'powersync_x64.dll'; + destination = 'powersync.dll'; +} else if (platform === 'linux') { + asset = OS.arch() === 'x64' ? 'libpowersync_x64.so' : 'libpowersync_aarch64.so'; + destination = 'libpowersync.so'; +} else if (platform === 'darwin') { + asset = OS.arch() === 'x64' ? 'libpowersync_x64.dylib' : 'libpowersync_aarch64.dylib'; + destination = 'libpowersync.dylib'; +} + +const destinationPath = path.resolve('lib', destination); +try { + await fs.access(destinationPath); + exit(0); +} catch {} + +const url = `https://github.com/powersync-ja/powersync-sqlite-core/releases/download/v${version}/${asset}`; +const response = await fetch(url); +if (response.status != 200) { + throw `Could not download ${url}`; +} + +try { + await fs.access('lib'); +} catch { + await fs.mkdir('lib'); +} + +const file = await fs.open(destinationPath, 'w'); +await finished(Readable.fromWeb(response.body).pipe(file.createWriteStream())); +await file.close(); diff --git a/packages/node/package.json b/packages/node/package.json new file mode 100644 index 000000000..cdf8b5472 --- /dev/null +++ b/packages/node/package.json @@ -0,0 +1,58 @@ +{ + "name": "@powersync/node", + "version": "0.0.0", + "publishConfig": { + "registry": "https://registry.npmjs.org/", + "access": "public" + }, + "description": "PowerSync - sync Postgres with SQLite in your Node.js app for offline-first and real-time data", + "main": "./lib/index.js", + "module": "./lib/index.js", + "types": "./lib/index.d.ts", + "files": [ + "lib", + "dist", + "download_core.js" + ], + "scripts": { + "install": "node download_core.js", + "build": "tsc -b", + "build:prod": "tsc -b --sourceMap false", + "clean": "rm -rf lib dist tsconfig.tsbuildinfo dist", + "watch": "tsc -b -w", + "test": "vitest" + }, + "type": "module", + "repository": { + "type": "git", + "url": "git+https://github.com/powersync-ja/powersync-js.git" + }, + "author": "JOURNEYAPPS", + "license": "Apache-2.0", + "bugs": { + "url": "https://github.com/powersync-ja/powersync-js/issues" + }, + "homepage": "https://docs.powersync.com/", + "peerDependencies": { + "@powersync/common": "workspace:^1.22.0", + "@powersync/better-sqlite3": "^0.1.0" + }, + "dependencies": { + "@powersync/common": "workspace:*", + "async-lock": "^1.4.0", + "bson": "^6.6.0", + "comlink": "^4.4.2" + }, + "devDependencies": { + "@types/async-lock": "^1.4.0", + "typescript": "^5.5.3", + "vitest": "^3.0.5" + }, + "keywords": [ + "data sync", + "offline-first", + "sqlite", + "real-time data stream", + "live data" + ] +} diff --git a/packages/node/src/db/AsyncDatabase.ts b/packages/node/src/db/AsyncDatabase.ts new file mode 100644 index 000000000..61abae7ec --- /dev/null +++ b/packages/node/src/db/AsyncDatabase.ts @@ -0,0 +1,23 @@ +import { QueryResult } from '@powersync/common'; + +export type ProxiedQueryResult = Omit & { + rows?: { + _array: any[]; + length: number; + }; +}; + +export interface AsyncDatabaseOpener { + open(path: string, isWriter: boolean): Promise; +} + +export interface AsyncDatabase { + execute: (query: string, params: any[]) => Promise; + executeBatch: (query: string, params: any[][]) => Promise; + close: () => Promise; + // Collect table updates made since the last call to collectCommittedUpdates. + // This happens on the worker because we otherwise get race conditions when wrapping + // callbacks to invoke on the main thread (we need a guarantee that collectCommittedUpdates + // contains entries immediately after calling COMMIT). + collectCommittedUpdates: () => Promise; +} diff --git a/packages/node/src/db/BetterSQLite3DBAdapter.ts b/packages/node/src/db/BetterSQLite3DBAdapter.ts new file mode 100644 index 000000000..7b09557b3 --- /dev/null +++ b/packages/node/src/db/BetterSQLite3DBAdapter.ts @@ -0,0 +1,266 @@ +import * as path from 'node:path'; +import { Worker } from 'node:worker_threads'; +import * as Comlink from 'comlink'; + +import { + BaseObserver, + BatchedUpdateNotification, + DBAdapter, + DBAdapterListener, + LockContext, + Transaction, + DBLockOptions, + QueryResult, + SQLOpenOptions +} from '@powersync/common'; +import { Remote } from 'comlink'; +import { AsyncResource } from 'node:async_hooks'; +import { AsyncDatabase, AsyncDatabaseOpener } from './AsyncDatabase.js'; +import { RemoteConnection } from './RemoteConnection.js'; + +export type BetterSQLite3LockContext = LockContext & { + executeBatch(query: string, params?: any[][]): Promise; +}; + +export type BetterSQLite3Transaction = Transaction & BetterSQLite3LockContext; + +const READ_CONNECTIONS = 5; + +/** + * Adapter for better-sqlite3 + */ +export class BetterSQLite3DBAdapter extends BaseObserver implements DBAdapter { + private readonly options: SQLOpenOptions; + public readonly name: string; + + private readConnections: RemoteConnection[]; + private writeConnection: RemoteConnection; + + private readonly readQueue: Array<(connection: RemoteConnection) => void> = []; + private readonly writeQueue: Array<() => void> = []; + + constructor(options: SQLOpenOptions) { + super(); + + this.options = options; + this.name = options.dbFilename; + } + + async initialize() { + let dbFilePath = this.options.dbFilename; + if (this.options.dbLocation !== undefined) { + dbFilePath = path.join(this.options.dbLocation, dbFilePath); + } + + const openWorker = async (isWriter: boolean) => { + const worker = new Worker(new URL('./SqliteWorker.js', import.meta.url), {name: isWriter ? `write ${dbFilePath}` : `read ${dbFilePath}`}); + const listeners = new WeakMap void>(); + + const comlink = Comlink.wrap({ + postMessage: worker.postMessage.bind(worker), + addEventListener: (type, listener) => { + let resolved: (event: any) => void = + 'handleEvent' in listener ? listener.handleEvent.bind(listener) : listener; + + // Comlink wants message events, but the message event on workers in Node returns the data only. + if (type === 'message') { + const original = resolved; + + resolved = (data) => { + original({ data }); + }; + } + + listeners.set(listener, resolved); + worker.addListener(type, resolved); + }, + removeEventListener: (type, listener) => { + const resolved = listeners.get(listener); + if (!resolved) { + return; + } + worker.removeListener(type, resolved); + } + }); + + worker.once('error', (e) => { + console.error('Unexpected PowerSync database worker error', e); + }); + + const database = (await comlink.open(dbFilePath, isWriter)) as Remote; + return new RemoteConnection(worker, comlink, database); + }; + + // Open the writer first to avoid multiple threads enabling WAL concurrently (causing "database is locked" errors). + this.writeConnection = await openWorker(true); + const createWorkers: Promise[] = []; + for (let i = 0; i < READ_CONNECTIONS; i++) { + createWorkers.push(openWorker(false)); + } + this.readConnections = await Promise.all(createWorkers); + } + + async close() { + await this.writeConnection.close(); + for (const connection of this.readConnections) { + await connection.close(); + } + } + + readLock(fn: (tx: BetterSQLite3LockContext) => Promise, _options?: DBLockOptions | undefined): Promise { + let resolveConnectionPromise!: (connection: RemoteConnection) => void; + const connectionPromise = new Promise((resolve, _reject) => { + resolveConnectionPromise = AsyncResource.bind(resolve); + }); + + const connection = this.readConnections.find((connection) => !connection.isBusy); + if (connection) { + connection.isBusy = true; + resolveConnectionPromise(connection); + } else { + this.readQueue.push(resolveConnectionPromise); + } + + return (async () => { + const connection = await connectionPromise; + + try { + return await fn(connection); + } finally { + const next = this.readQueue.shift(); + if (next) { + next(connection); + } else { + connection.isBusy = false; + } + } + })(); + } + + writeLock(fn: (tx: BetterSQLite3LockContext) => Promise, _options?: DBLockOptions | undefined): Promise { + let resolveLockPromise!: () => void; + const lockPromise = new Promise((resolve, _reject) => { + resolveLockPromise = AsyncResource.bind(resolve); + }); + + if (!this.writeConnection.isBusy) { + this.writeConnection.isBusy = true; + resolveLockPromise(); + } else { + this.writeQueue.push(resolveLockPromise); + } + + return (async () => { + await lockPromise; + + try { + try { + return await fn(this.writeConnection); + } finally { + const updates = await this.writeConnection.database.collectCommittedUpdates(); + + if (updates.length > 0) { + const event: BatchedUpdateNotification = { + tables: updates, + groupedUpdates: {}, + rawUpdates: [] + }; + this.iterateListeners((cb) => cb.tablesUpdated?.(event)); + } + } + } finally { + const next = this.writeQueue.shift(); + if (next) { + next(); + } else { + this.writeConnection.isBusy = false; + } + } + })(); + } + + readTransaction( + fn: (tx: BetterSQLite3Transaction) => Promise, + _options?: DBLockOptions | undefined + ): Promise { + return this.readLock((ctx) => this.internalTransaction(ctx as RemoteConnection, fn)); + } + + writeTransaction( + fn: (tx: BetterSQLite3Transaction) => Promise, + _options?: DBLockOptions | undefined + ): Promise { + return this.writeLock((ctx) => this.internalTransaction(ctx as RemoteConnection, fn)); + } + + private async internalTransaction( + connection: RemoteConnection, + fn: (tx: BetterSQLite3Transaction) => Promise + ): Promise { + let finalized = false; + const commit = async (): Promise => { + if (!finalized) { + finalized = true; + await connection.execute('COMMIT'); + } + return { rowsAffected: 0 }; + }; + const rollback = async (): Promise => { + if (!finalized) { + finalized = true; + await connection.execute('ROLLBACK'); + } + return { rowsAffected: 0 }; + }; + try { + await connection.execute('BEGIN'); + const result = await fn({ + execute: (query, params) => connection.execute(query, params), + executeBatch: (query, params) => connection.executeBatch(query, params), + get: (query, params) => connection.get(query, params), + getAll: (query, params) => connection.getAll(query, params), + getOptional: (query, params) => connection.getOptional(query, params), + commit, + rollback + }); + await commit(); + return result; + } catch (ex) { + try { + await rollback(); + } catch (ex2) { + // In rare cases, a rollback may fail. + // Safe to ignore. + } + throw ex; + } + } + + getAll(sql: string, parameters?: any[]): Promise { + return this.readLock((ctx) => ctx.getAll(sql, parameters)); + } + + getOptional(sql: string, parameters?: any[]): Promise { + return this.readLock((ctx) => ctx.getOptional(sql, parameters)); + } + + get(sql: string, parameters?: any[]): Promise { + return this.readLock((ctx) => ctx.get(sql, parameters)); + } + + execute(query: string, params?: any[] | undefined): Promise { + return this.writeLock((ctx) => ctx.execute(query, params)); + } + + executeBatch(query: string, params?: any[][]): Promise { + return this.writeTransaction((ctx) => ctx.executeBatch(query, params)); + } + + async refreshSchema() { + await this.writeConnection.refreshSchema(); + + for (const readConnection of this.readConnections) { + await readConnection.refreshSchema(); + } + } +} diff --git a/packages/node/src/db/PowerSyncDatabase.ts b/packages/node/src/db/PowerSyncDatabase.ts new file mode 100644 index 000000000..73f9ce706 --- /dev/null +++ b/packages/node/src/db/PowerSyncDatabase.ts @@ -0,0 +1,63 @@ +import { + AbstractPowerSyncDatabase, + AbstractStreamingSyncImplementation, + BucketStorageAdapter, + DBAdapter, + PowerSyncBackendConnector, + PowerSyncDatabaseOptionsWithSettings, + SqliteBucketStorage +} from '@powersync/common'; + +import { NodeRemote } from '../sync/stream/NodeRemote.js'; +import { NodeStreamingSyncImplementation } from '../sync/stream/NodeStreamingSyncImplementation.js'; + +import { BetterSQLite3DBAdapter } from './BetterSQLite3DBAdapter.js'; + +/** + * A PowerSync database which provides SQLite functionality + * which is automatically synced. + * + * @example + * ```typescript + * export const db = new PowerSyncDatabase({ + * schema: AppSchema, + * database: { + * dbFilename: 'example.db' + * } + * }); + * ``` + */ +export class PowerSyncDatabase extends AbstractPowerSyncDatabase { + async _initialize(): Promise { + await (this.database as BetterSQLite3DBAdapter).initialize(); + } + + /** + * Opens a DBAdapter using better-sqlite3 as the default SQLite open factory. + */ + protected openDBAdapter(options: PowerSyncDatabaseOptionsWithSettings): DBAdapter { + return new BetterSQLite3DBAdapter(options.database); + } + + protected generateBucketStorageAdapter(): BucketStorageAdapter { + return new SqliteBucketStorage(this.database, AbstractPowerSyncDatabase.transactionMutex); + } + + protected generateSyncStreamImplementation( + connector: PowerSyncBackendConnector + ): AbstractStreamingSyncImplementation { + const remote = new NodeRemote(connector); + + return new NodeStreamingSyncImplementation({ + adapter: this.bucketStorageAdapter, + remote, + uploadCrud: async () => { + await this.waitForReady(); + await connector.uploadData(this); + }, + retryDelayMs: this.options.retryDelayMs, + crudUploadThrottleMs: this.options.crudUploadThrottleMs, + identifier: this.database.name + }); + } +} diff --git a/packages/node/src/db/RemoteConnection.ts b/packages/node/src/db/RemoteConnection.ts new file mode 100644 index 000000000..0a090f523 --- /dev/null +++ b/packages/node/src/db/RemoteConnection.ts @@ -0,0 +1,76 @@ +import { Worker } from 'node:worker_threads'; +import { LockContext, QueryResult } from '@powersync/common'; +import { releaseProxy, Remote } from 'comlink'; +import { AsyncDatabase, AsyncDatabaseOpener, ProxiedQueryResult } from './AsyncDatabase.js'; + +/** + * A PowerSync database connection implemented with RPC calls to a background worker. + */ +export class RemoteConnection implements LockContext { + isBusy = false; + + private readonly worker: Worker; + private readonly comlink: Remote; + readonly database: Remote; + + constructor(worker: Worker, comlink: Remote, database: Remote) { + this.worker = worker; + this.comlink = comlink; + this.database = database; + } + + async executeBatch(query: string, params: any[][] = []): Promise { + 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); + } + + async getAll(sql: string, parameters?: any[]): Promise { + const res = await this.execute(sql, parameters); + return res.rows?._array ?? []; + } + + async getOptional(sql: string, parameters?: any[]): Promise { + const res = await this.execute(sql, parameters); + return res.rows?.item(0) ?? null; + } + + async get(sql: string, parameters?: any[]): Promise { + const res = await this.execute(sql, parameters); + const first = res.rows?.item(0); + if (!first) { + throw new Error('Result set is empty'); + } + return first; + } + + async refreshSchema() { + await this.execute("pragma table_info('sqlite_master')"); + } + + async close() { + await this.database.close(); + this.database[releaseProxy](); + this.comlink[releaseProxy](); + await this.worker.terminate(); + } + + static wrapQueryResult(result: ProxiedQueryResult): QueryResult { + let rows: QueryResult['rows'] | undefined = undefined; + if (result.rows) { + rows = { + ...result.rows, + item: (idx) => result.rows?._array[idx] + } satisfies QueryResult['rows']; + } + + return { + ...result, + rows + }; + } +} diff --git a/packages/node/src/db/SqliteWorker.ts b/packages/node/src/db/SqliteWorker.ts new file mode 100644 index 000000000..66ac01436 --- /dev/null +++ b/packages/node/src/db/SqliteWorker.ts @@ -0,0 +1,116 @@ +import BetterSQLite3Database, { Database } from '@powersync/better-sqlite3'; +import * as Comlink from 'comlink'; +import { parentPort, threadId } from 'node:worker_threads'; +import OS from 'node:os'; +import url from 'node:url'; +import { AsyncDatabase, AsyncDatabaseOpener } from './AsyncDatabase.js'; + +class BlockingAsyncDatabase implements AsyncDatabase { + private readonly db: Database; + + private readonly uncommittedUpdatedTables = new Set(); + private readonly committedUpdatedTables = new Set(); + + constructor(db: Database) { + this.db = db; + + db.function('node_thread_id', () => threadId); + } + + collectCommittedUpdates() { + const resolved = Promise.resolve([...this.committedUpdatedTables]); + this.committedUpdatedTables.clear(); + return resolved; + } + + installUpdateHooks() { + this.db.updateHook((_op: string, _dbName: string, tableName: string, _rowid: bigint) => { + this.uncommittedUpdatedTables.add(tableName); + }); + + this.db.commitHook(() => { + for (const tableName of this.uncommittedUpdatedTables) { + this.committedUpdatedTables.add(tableName); + } + this.uncommittedUpdatedTables.clear(); + return true; + }); + + this.db.rollbackHook(() => { + this.uncommittedUpdatedTables.clear(); + }); + } + + async close() { + this.db.close(); + } + + async execute(query: string, params: any[]) { + const stmt = this.db.prepare(query); + if (stmt.reader) { + const rows = stmt.all(params); + return { + rowsAffected: 0, + rows: { + _array: rows, + length: rows.length + } + }; + } else { + const info = stmt.run(params); + return { + rowsAffected: info.changes, + insertId: Number(info.lastInsertRowid) + }; + } + } + + async executeBatch(query: string, params: any[][]) { + params = params ?? []; + + let rowsAffected = 0; + + const stmt = this.db.prepare(query); + for (const paramSet of params) { + const info = stmt.run(paramSet); + rowsAffected += info.changes; + } + + return { rowsAffected }; + } +} + +class BetterSqliteWorker implements AsyncDatabaseOpener { + async open(path: string, isWriter: boolean): Promise { + const baseDB = new BetterSQLite3Database(path); + baseDB.pragma('journal_mode = WAL'); + loadExtension(baseDB); + if (!isWriter) { + baseDB.pragma('query_only = true'); + } + + const asyncDb = new BlockingAsyncDatabase(baseDB); + asyncDb.installUpdateHooks(); + + return Comlink.proxy(asyncDb); + } +} + +const loadExtension = (db: Database) => { + const platform = OS.platform(); + let extensionPath: string; + if (platform === 'win32') { + extensionPath = 'powersync.dll'; + } else if (platform === 'linux') { + extensionPath = 'libpowersync.so'; + } else if (platform === 'darwin') { + extensionPath = 'libpowersync.dylib'; + } else { + throw 'Unknown platform, PowerSync for Node.js currently supports Windows, Linux and macOS.'; + } + + const resolved = url.fileURLToPath(new URL(`../${extensionPath}`, import.meta.url)); + db.loadExtension(resolved, 'sqlite3_powersync_init'); +}; + +Comlink.expose(new BetterSqliteWorker(), parentPort! as Comlink.Endpoint); diff --git a/packages/node/src/index.ts b/packages/node/src/index.ts new file mode 100644 index 000000000..aa019c363 --- /dev/null +++ b/packages/node/src/index.ts @@ -0,0 +1,4 @@ +// Re export to only require one import in client side code +export * from '@powersync/common'; + +export * from './db/PowerSyncDatabase.js'; diff --git a/packages/node/src/sync/stream/NodeRemote.ts b/packages/node/src/sync/stream/NodeRemote.ts new file mode 100644 index 000000000..b0c147484 --- /dev/null +++ b/packages/node/src/sync/stream/NodeRemote.ts @@ -0,0 +1,48 @@ +import * as os from 'node:os'; + +import { ILogger } from 'js-logger'; + +import { + AbstractRemote, + AbstractRemoteOptions, + BSONImplementation, + DEFAULT_REMOTE_LOGGER, + FetchImplementation, + FetchImplementationProvider, + RemoteConnector +} from '@powersync/common'; +import { BSON } from 'bson'; + +export const STREAMING_POST_TIMEOUT_MS = 30_000; + +class NodeFetchProvider extends FetchImplementationProvider { + getFetch(): FetchImplementation { + return fetch.bind(globalThis); + } +} + +export class NodeRemote extends AbstractRemote { + constructor( + protected connector: RemoteConnector, + protected logger: ILogger = DEFAULT_REMOTE_LOGGER, + options?: Partial + ) { + super(connector, logger, { + ...(options ?? {}), + fetchImplementation: options?.fetchImplementation ?? new NodeFetchProvider() + }); + } + + getUserAgent(): string { + return [ + super.getUserAgent(), + `powersync-node`, + `node/${process.versions.node}`, + `${os.platform()}/${os.release()}` + ].join(' '); + } + + async getBSON(): Promise { + return BSON; + } +} diff --git a/packages/node/src/sync/stream/NodeStreamingSyncImplementation.ts b/packages/node/src/sync/stream/NodeStreamingSyncImplementation.ts new file mode 100644 index 000000000..d97849f6a --- /dev/null +++ b/packages/node/src/sync/stream/NodeStreamingSyncImplementation.ts @@ -0,0 +1,54 @@ +import { + AbstractStreamingSyncImplementation, + AbstractStreamingSyncImplementationOptions, + LockOptions, + LockType +} from '@powersync/common'; +import Lock from 'async-lock'; + +/** + * Global locks which prevent multiple instances from syncing + * concurrently. + */ +const LOCKS = new Map(); + +const lockTypes = new Set(Object.values(LockType)); + +export class NodeStreamingSyncImplementation extends AbstractStreamingSyncImplementation { + locks: Lock; + + constructor(options: AbstractStreamingSyncImplementationOptions) { + super(options); + this.initLocks(); + } + + /** + * Configures global locks on sync process + */ + initLocks() { + const { identifier } = this.options; + if (identifier && LOCKS.has(identifier)) { + this.locks = LOCKS.get(identifier)!; + return; + } + + this.locks = new Lock(); + + if (identifier) { + LOCKS.set(identifier, this.locks); + } + } + + obtainLock(lockOptions: LockOptions): Promise { + if (!lockTypes.has(lockOptions.type)) { + throw new Error(`Lock type ${lockOptions.type} not found`); + } + return this.locks.acquire(lockOptions.type, async () => { + if (lockOptions.signal?.aborted) { + throw new Error('Aborted'); + } + + return lockOptions.callback(); + }); + } +} diff --git a/packages/node/tests/PowerSyncDatabase.test.ts b/packages/node/tests/PowerSyncDatabase.test.ts new file mode 100644 index 000000000..3857ab368 --- /dev/null +++ b/packages/node/tests/PowerSyncDatabase.test.ts @@ -0,0 +1,79 @@ +import { vi, expect, test } from 'vitest'; +import { databaseTest } from './utils'; + +databaseTest('links powersync', async ({ database }) => { + await database.get('select powersync_rs_version();'); +}); + +databaseTest('runs queries on multiple threads', async ({ database }) => { + const threads = new Set(); + + const collectWorkerThreadId = async () => { + const row = await database.get<{ r: number }>('SELECT node_thread_id() AS r'); + threads.add(row.r); + return row.r; + }; + + const queryTasks: Promise[] = []; + for (let i = 0; i < 10; i++) { + queryTasks.push(collectWorkerThreadId()); + } + + const res = await Promise.all(queryTasks); + expect(res).toHaveLength(10); + expect([...threads]).toHaveLength(5); +}); + +databaseTest('can watch tables', async ({ database }) => { + const fn = vi.fn(); + const disposeWatch = database.onChangeWithCallback( + { + onChange: () => { + fn(); + } + }, + { tables: ['todos'], throttleMs: 0 } + ); + + await database.execute('INSERT INTO todos (id, content) VALUES (uuid(), ?)', ['first']); + await expect.poll(() => fn).toHaveBeenCalledOnce(); + + await database.writeTransaction(async (tx) => { + await tx.execute('INSERT INTO todos (id, content) VALUES (uuid(), ?)', ['second']); + }); + await expect.poll(() => fn).toHaveBeenCalledTimes(2); + + await database.writeTransaction(async (tx) => { + await tx.execute('DELETE FROM todos;'); + await tx.rollback(); + }); + await expect.poll(() => fn).toHaveBeenCalledTimes(2); + + disposeWatch(); + await database.execute('INSERT INTO todos (id, content) VALUES (uuid(), ?)', ['fourth']); + await expect.poll(() => fn).toHaveBeenCalledTimes(2); +}); + +databaseTest.skip('can watch queries', async ({ database }) => { + const query = await database.watch('SELECT * FROM todos;', [])[Symbol.asyncIterator](); + expect((await query.next()).value.rows).toHaveLength(0); + + await database.execute('INSERT INTO todos (id, content) VALUES (uuid(), ?)', ['first']); + // TODO: There is a race condition somewhere, this reports now rows sometimes. + expect((await query.next()).value.rows).toHaveLength(1); + + await database.writeTransaction(async (tx) => { + await tx.execute('INSERT INTO todos (id, content) VALUES (uuid(), ?)', ['second']); + await tx.execute('INSERT INTO todos (id, content) VALUES (uuid(), ?)', ['third']); + }); + + expect((await query.next()).value.rows).toHaveLength(3); + + await database.writeTransaction(async (tx) => { + await tx.execute('DELETE FROM todos;'); + await tx.rollback(); + }); + + await database.execute('INSERT INTO todos (id, content) VALUES (uuid(), ?)', ['fourth']); + expect((await query.next()).value.rows).toHaveLength(4); +}); diff --git a/packages/node/tests/utils.ts b/packages/node/tests/utils.ts new file mode 100644 index 000000000..c8ce4345e --- /dev/null +++ b/packages/node/tests/utils.ts @@ -0,0 +1,39 @@ +import os from 'node:os'; +import fs from 'node:fs/promises'; +import path from 'node:path'; +import { test } from 'vitest'; +import { column, PowerSyncDatabase, Schema, Table } from '../lib'; + +async function createTempDir() { + const ostmpdir = os.tmpdir(); + const tmpdir = path.join(ostmpdir, 'powersync-node-test-'); + return await fs.mkdtemp(tmpdir); +} + +export const LIST_TABLE = 'lists'; +export const TODO_TABLE = 'todos'; + +const todos = new Table({ + content: column.text +}); + +export const AppSchema = new Schema({ + todos +}); + +export type Database = (typeof AppSchema)['types']; + +export const databaseTest = test.extend<{ database: PowerSyncDatabase }>({ + database: async ({}, use) => { + const directory = await createTempDir(); + const database = new PowerSyncDatabase({ + schema: AppSchema, + database: { + dbFilename: 'test.db', + dbLocation: directory + } + }); + await use(database); + await fs.rm(directory, { recursive: true }); + } +}); diff --git a/packages/node/tsconfig.json b/packages/node/tsconfig.json new file mode 100644 index 000000000..2cb0b7091 --- /dev/null +++ b/packages/node/tsconfig.json @@ -0,0 +1,24 @@ +{ + "extends": "../../tsconfig.base", + "compilerOptions": { + "baseUrl": "./", + "jsx": "react", + "types": ["node"], + "rootDir": "src", + "outDir": "./lib", + "lib": ["esnext"], + "declaration": true, + "module": "nodenext", + "moduleResolution": "nodenext", + "preserveConstEnums": true, + "esModuleInterop": true, + "skipLibCheck": false, + "strictNullChecks": true + }, + "include": ["src/**/*"], + "references": [ + { + "path": "../common" + } + ] +} diff --git a/packages/node/vitest.config.ts b/packages/node/vitest.config.ts new file mode 100644 index 000000000..94ec60f24 --- /dev/null +++ b/packages/node/vitest.config.ts @@ -0,0 +1,4 @@ +import { defineConfig } from 'vitest/config'; + +// We need to define an empty config to be part of the vitest works +export default defineConfig({}); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 5b42746ca..1157a8e38 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@5.4.11(@types/node@22.7.4)(less@4.2.0)(lightningcss@1.28.2)(sass@1.79.4)(terser@5.34.1))(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.1.0(@types/node@22.7.4)(jiti@1.21.6)(less@4.2.0)(lightningcss@1.28.2)(sass@1.79.4)(terser@5.34.1)(yaml@2.6.1))(vitest@3.0.8)(webdriverio@9.8.0) husky: specifier: ^9.0.11 version: 9.1.6 @@ -137,7 +137,7 @@ importers: version: 0.1.11(react-native@0.74.5(@babel/core@7.26.0)(@babel/preset-env@7.25.7(@babel/core@7.26.0))(@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(yaao3llbshooz2bjipuf6mkduy) + version: 6.7.2(de9b7caae7cef38a32afa5b76a3c9d54) '@react-navigation/native': specifier: ^6.1.17 version: 6.1.18(react-native@0.74.5(@babel/core@7.26.0)(@babel/preset-env@7.25.7(@babel/core@7.26.0))(@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(gtohwu5bdvnl7tvlmjhokmubum) + version: 3.5.21(49b2fd6c45ca81e2d20f2f5a4be05a3e) 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.0)(@babel/preset-env@7.25.7(@babel/core@7.26.0))(encoding@0.1.13)) @@ -215,7 +215,7 @@ importers: version: 10.2.0 react-navigation-stack: specifier: ^2.10.4 - version: 2.10.4(ei6zhj5w65kzzp3jt27w3zu7ea) + version: 2.10.4(b5d6035dfb87b14e0677db2e89c1e7ef) typed-async-storage: specifier: ^3.1.2 version: 3.1.2 @@ -495,7 +495,7 @@ importers: version: 8.57.1 eslint-config-next: specifier: 14.0.0 - version: 14.0.0(eslint@8.57.1)(typescript@5.7.2) + version: 14.0.0(eslint@8.57.1)(typescript@5.8.2) postcss: specifier: ^8.4.35 version: 8.4.47 @@ -510,7 +510,23 @@ importers: version: 3.3.4(webpack@5.95.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(@swc/core@1.10.1(@swc/helpers@0.5.5))(@types/node@20.16.10)(typescript@5.7.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: + '@powersync/node': + specifier: workspace:* + version: link:../../packages/node + dotenv: + specifier: ^16.4.7 + version: 16.4.7 + devDependencies: + ts-node: + specifier: ^10.9.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 demos/example-vite: dependencies: @@ -702,7 +718,7 @@ importers: version: 6.3.1(expo@51.0.27(@babel/core@7.24.5)(@babel/preset-env@7.26.0(@babel/core@7.24.5))(encoding@0.1.13)) expo-router: specifier: ^3.5.15 - version: 3.5.21(j6qjh2jsuy2ozdtd6girxrw3ky) + version: 3.5.21(988d822f9e58e176bb73f45e8e45eb4a) 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.0(@babel/core@7.24.5))(encoding@0.1.13)) @@ -799,7 +815,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) @@ -838,7 +854,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)) @@ -886,7 +902,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 @@ -950,7 +966,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) @@ -983,7 +999,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)) @@ -1043,7 +1059,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 @@ -1630,7 +1646,7 @@ importers: version: 20.17.6 drizzle-orm: specifier: ^0.35.2 - version: 0.35.2(@op-engineering/op-sqlite@11.2.13(react-native@0.75.3(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@types/react@18.3.12)(encoding@0.1.13)(react@18.3.1)(typescript@5.7.2))(react@18.3.1))(@types/react@18.3.12)(kysely@0.27.4)(react@18.3.1) + version: 0.35.2(@op-engineering/op-sqlite@11.2.13(react-native@0.75.3(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@types/react@18.3.12)(encoding@0.1.13)(react@18.3.1)(typescript@5.8.2))(react@18.3.1))(@types/better-sqlite3@7.6.12)(@types/react@18.3.12)(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.0)(lightningcss@1.28.2)(sass@1.79.4)(terser@5.34.1)(yaml@2.6.1) @@ -1669,6 +1685,34 @@ importers: specifier: ^3.3.0 version: 3.3.0(vite@6.1.0(@types/node@20.17.6)(jiti@1.21.6)(less@4.2.0)(lightningcss@1.28.2)(sass@1.79.4)(terser@5.34.1)(yaml@2.6.1)) + packages/node: + dependencies: + '@powersync/better-sqlite3': + specifier: ^0.1.0 + version: 0.1.0 + '@powersync/common': + specifier: workspace:* + version: link:../common + async-lock: + specifier: ^1.4.0 + version: 1.4.1 + bson: + specifier: ^6.6.0 + version: 6.8.0 + comlink: + specifier: ^4.4.2 + version: 4.4.2 + devDependencies: + '@types/async-lock': + specifier: ^1.4.0 + version: 1.4.2 + typescript: + specifier: ^5.5.3 + version: 5.7.2 + vitest: + specifier: ^3.0.5 + version: 3.0.8(@types/debug@4.1.12)(@types/node@22.7.4)(@vitest/browser@3.0.8)(jsdom@24.1.3)(less@4.2.0)(lightningcss@1.28.2)(msw@2.7.3(@types/node@22.7.4)(typescript@5.7.2))(sass@1.79.4)(terser@5.34.1) + packages/powersync-op-sqlite: dependencies: '@powersync/common': @@ -1680,10 +1724,10 @@ importers: devDependencies: '@op-engineering/op-sqlite': specifier: ^11.2.13 - version: 11.2.13(react-native@0.75.3(@babel/core@7.25.7)(@babel/preset-env@7.26.0(@babel/core@7.25.7))(@types/react@18.3.11)(encoding@0.1.13)(react@18.3.1)(typescript@5.7.2))(react@18.3.1) + version: 11.2.13(react-native@0.75.3(@babel/core@7.25.7)(@babel/preset-env@7.26.0(@babel/core@7.25.7))(@types/react@18.3.11)(encoding@0.1.13)(react@18.3.1)(typescript@5.8.2))(react@18.3.1) '@react-native/eslint-config': specifier: ^0.73.1 - version: 0.73.2(eslint@8.57.1)(prettier@3.3.3)(typescript@5.7.2) + version: 0.73.2(eslint@8.57.1)(prettier@3.3.3)(typescript@5.8.2) '@types/async-lock': specifier: ^1.4.0 version: 1.4.2 @@ -1710,10 +1754,10 @@ importers: version: 18.3.1 react-native: specifier: 0.75.3 - version: 0.75.3(@babel/core@7.25.7)(@babel/preset-env@7.26.0(@babel/core@7.25.7))(@types/react@18.3.11)(encoding@0.1.13)(react@18.3.1)(typescript@5.7.2) + version: 0.75.3(@babel/core@7.25.7)(@babel/preset-env@7.26.0(@babel/core@7.25.7))(@types/react@18.3.11)(encoding@0.1.13)(react@18.3.1)(typescript@5.8.2) react-native-builder-bob: specifier: ^0.30.2 - version: 0.30.2(typescript@5.7.2) + version: 0.30.2(typescript@5.8.2) turbo: specifier: ^1.10.7 version: 1.13.4 @@ -1841,7 +1885,7 @@ importers: version: 24.1.3 vue: specifier: 3.4.21 - version: 3.4.21(typescript@5.7.2) + version: 3.4.21(typescript@5.8.2) packages/web: dependencies: @@ -6287,6 +6331,9 @@ packages: '@popperjs/core@2.11.8': resolution: {integrity: sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==} + '@powersync/better-sqlite3@0.1.0': + resolution: {integrity: sha512-DKiLB8Fk5FrkjxknZYTAvWwLmXf40qlWJb6iQGXQOx4VAu3ZInhYHc0n/msTqPcrBLNHStteuOmiy7h7XvtbcQ==} + '@promptbook/utils@0.70.0-1': resolution: {integrity: sha512-qd2lLRRN+sE6UuNMi2tEeUUeb4zmXnxY5EMdfHVXNE+bqBDpUC7/aEfXgA3jnUXEr+xFjQ8PTFQgWvBMaKvw0g==} @@ -8526,6 +8573,9 @@ packages: '@types/babel__traverse@7.20.6': resolution: {integrity: sha512-r1bzfrm0tomOI8g1SzvCaQHo6Lcv6zu0EA+W2kHrt8dyrHQxGzBBL4kdkzIS+jBMV+EYcMAEAqXqYaLJq5rOZg==} + '@types/better-sqlite3@7.6.12': + resolution: {integrity: sha512-fnQmj8lELIj7BSrZQAdBMHEHX8OZLYIHXqAKT1O7tDfLxaINzf00PMjw22r3N/xXh0w/sGHlO6SVaCQ2mj78lg==} + '@types/body-parser@1.19.5': resolution: {integrity: sha512-fB3Zu92ucau0iQ0JMCFQE7b/dv8Ot07NI3KaZIkIUNXq82k4eBAqUaneXfleGY9JWskeS9y+u0nXMyspcuQrCg==} @@ -9775,6 +9825,9 @@ packages: resolution: {integrity: sha512-pbnl5XzGBdrFU/wT4jqmJVPn2B6UHPBOhzMQkY/SPUPB6QtUXtmBHBIwCbXJol93mOpGMnQyP/+BB19q04xj7g==} engines: {node: '>=4'} + better-sqlite3@11.7.2: + resolution: {integrity: sha512-10a57cHVDmfNQS4jrZ9AH2t+2ekzYh5Rhbcnb4ytpmYweoLdogDmyTt5D+hLiY9b44Mx9foowb/4iXBTO2yP3Q==} + big-integer@1.6.52: resolution: {integrity: sha512-QxD8cf2eVqJOOz63z6JIN9BzvVs/dlySa5HGSBH5xtR8dPteIRQnBxxKqkNTiT6jbDTF6jAfrd4oMcND9RGbQg==} engines: {node: '>=0.6'} @@ -9790,6 +9843,9 @@ packages: resolution: {integrity: sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==} engines: {node: '>=8'} + bindings@1.5.0: + resolution: {integrity: sha512-p2q/t/mhvuOj/UeLlV6566GD/guowlr0hHxClI0W9m7MWYkL1F0hLo+0Aexs9HSPCtR1SXQ0TD3MMKrXZajbiQ==} + bl@4.1.0: resolution: {integrity: sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==} @@ -10128,6 +10184,9 @@ packages: resolution: {integrity: sha512-n8enUVCED/KVRQlab1hr3MVpcVMvxtZjmEa956u+4YijlmQED223XMSYj2tLuKvr4jcCTzNNMpQDUer72MMmzA==} engines: {node: '>= 14.16.0'} + chownr@1.1.4: + resolution: {integrity: sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==} + chownr@2.0.0: resolution: {integrity: sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==} engines: {node: '>=10'} @@ -11928,6 +11987,10 @@ packages: resolution: {integrity: sha512-VyhnebXciFV2DESc+p6B+y0LjSm0krU4OgJN44qFAhBY0TJ+1V61tYD2+wHusZ6F9n5K+vl8k0sTy7PEfV4qpg==} engines: {node: '>=16.17'} + expand-template@2.0.3: + resolution: {integrity: sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==} + engines: {node: '>=6'} + expand-tilde@2.0.2: resolution: {integrity: sha512-A5EmesHW6rfnZ9ysHQjPdJRni0SRar0tjtG5MNtm9n5TUvsYU8oozprtRD4AqHxcZWWlVuAmQo2nWKfN9oyjTw==} engines: {node: '>=0.10.0'} @@ -12216,6 +12279,9 @@ packages: peerDependencies: webpack: ^4.0.0 || ^5.0.0 + file-uri-to-path@1.0.0: + resolution: {integrity: sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==} + filelist@1.0.4: resolution: {integrity: sha512-w1cEuf3S+DrLCQL7ET6kz+gmlJdbq9J7yXCSjK/OZCPA+qEN1WyF4ZAf0YYJa4/shHJra2t/d/r8SV4Ji+x+8Q==} @@ -12405,6 +12471,9 @@ packages: resolution: {integrity: sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==} engines: {node: '>= 0.6'} + fs-constants@1.0.0: + resolution: {integrity: sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==} + fs-extra@10.1.0: resolution: {integrity: sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==} engines: {node: '>=12'} @@ -12561,6 +12630,9 @@ packages: resolution: {integrity: sha512-7yetJWqbS9sbn0vIfliPsFgoXMKn/YMF+Wuiog97x+urnSRRRZ7xB+uVkwGKzRgq9CDFfMQnE9ruL5DHv9c6Xg==} engines: {node: '>=6'} + github-from-package@0.0.0: + resolution: {integrity: sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==} + github-slugger@1.5.0: resolution: {integrity: sha512-wIh+gKBI9Nshz2o46B0B3f5k/W+WI9ZAv6y5Dn5WJ5SK1t0TnDimB4WE5rmTD05ZAIn8HALCZVmCsvj0w0v0lw==} @@ -14855,6 +14927,9 @@ packages: resolution: {integrity: sha512-5H76ANWinB1H3twpJ6JY8uvAtpmFvHNArpilJAjXRKXSDDLPIMoZArw5SH0q9z+lLs8IrMw7Q2VWpWimFKFT1Q==} engines: {node: '>= 8.0.0'} + mkdirp-classic@0.5.3: + resolution: {integrity: sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==} + mkdirp@0.5.6: resolution: {integrity: sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==} hasBin: true @@ -14951,6 +15026,9 @@ packages: engines: {node: ^10 || ^12 || ^13.7 || ^14 || >=15.0.1} hasBin: true + napi-build-utils@2.0.0: + resolution: {integrity: sha512-GEbrYkbfF7MoNaoh2iGG84Mnf/WZfB0GdGEsM8wz7Expx/LlWf5U8t9nvJKXSp3qr5IsEbK04cBGhol/KwOsWA==} + native-run@2.0.1: resolution: {integrity: sha512-XfG1FBZLM50J10xH9361whJRC9SHZ0Bub4iNRhhI61C8Jv0e1ud19muex6sNKB51ibQNUJNuYn25MuYET/rE6w==} engines: {node: '>=16.0.0'} @@ -16211,6 +16289,11 @@ packages: engines: {node: '>=14.0.0'} hasBin: true + prebuild-install@7.1.3: + resolution: {integrity: sha512-8Mf2cbV7x1cXPUILADGI3wuhfqWvtiLA1iclTDbFRZkgRQS0NqsPZphna9V+HyTEadheuPmjaJMsbzKQFOzLug==} + engines: {node: '>=10'} + hasBin: true + preferred-pm@3.1.4: resolution: {integrity: sha512-lEHd+yEm22jXdCphDrkvIJQU66EuLojPPtvZkpKIkiD+l0DMThF/niqZKJSoU8Vl7iuvtmzyMhir9LdVy5WMnA==} engines: {node: '>=10'} @@ -17598,6 +17681,12 @@ packages: resolution: {integrity: sha512-8G+/XDU8wNsJOQS5ysDVO0Etg9/2uA5gR9l4ZwijjlwxBcrU6RPfwi2+jJmbP+Ap1Hlp/nVAaEO4Fj22/SL2gQ==} engines: {node: ^16.14.0 || >=18.0.0} + simple-concat@1.0.1: + resolution: {integrity: sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==} + + simple-get@4.0.1: + resolution: {integrity: sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==} + simple-plist@1.3.1: resolution: {integrity: sha512-iMSw5i0XseMnrhtIzRb7XpQEXepa9xhWxGUojHBL43SIpQuDQkh3Wpy67ZbDzZVr6EKxvwVChnVpdl8hEVLDiw==} @@ -18122,9 +18211,16 @@ packages: resolution: {integrity: sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==} engines: {node: '>=6'} + tar-fs@2.1.2: + resolution: {integrity: sha512-EsaAXwxmx8UB7FRKqeozqEPop69DXcmYwTQwXvyAPF352HJsPdkVhvTaDPYqfNgruveJIJy3TA2l+2zj8LJIJA==} + tar-fs@3.0.6: resolution: {integrity: sha512-iokBDQQkUyeXhgPYaZxmczGPhnhXZ0CmrqI+MOb/WFGS9DW5wnfrLgtjUJBvz50vQ3qfRwJ62QVoCFu8mPVu5w==} + tar-stream@2.2.0: + resolution: {integrity: sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==} + engines: {node: '>=6'} + tar-stream@3.1.7: resolution: {integrity: sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ==} @@ -18589,6 +18685,11 @@ packages: engines: {node: '>=14.17'} hasBin: true + typescript@5.8.2: + resolution: {integrity: sha512-aJn6wq13/afZp/jT9QZmwEjDqqvSGp1VT5GVg+f/t6/oVyrgXM6BY1h9BRh/O5p3PlUPAe+WuiEZOmb/49RqoQ==} + engines: {node: '>=14.17'} + hasBin: true + ua-parser-js@1.0.39: resolution: {integrity: sha512-k24RCVWlEcjkdOxYmVJgeD/0a1TiSpqLg+ZalVGV9lsnr4yqu0w7tX/x2xX6G4zpkgQnRf89lxuZ1wsbjXM8lw==} hasBin: true @@ -29430,15 +29531,15 @@ snapshots: '@oclif/screen@3.0.8': {} - '@op-engineering/op-sqlite@11.2.13(react-native@0.75.3(@babel/core@7.25.7)(@babel/preset-env@7.26.0(@babel/core@7.25.7))(@types/react@18.3.11)(encoding@0.1.13)(react@18.3.1)(typescript@5.7.2))(react@18.3.1)': + '@op-engineering/op-sqlite@11.2.13(react-native@0.75.3(@babel/core@7.25.7)(@babel/preset-env@7.26.0(@babel/core@7.25.7))(@types/react@18.3.11)(encoding@0.1.13)(react@18.3.1)(typescript@5.8.2))(react@18.3.1)': dependencies: react: 18.3.1 - react-native: 0.75.3(@babel/core@7.25.7)(@babel/preset-env@7.26.0(@babel/core@7.25.7))(@types/react@18.3.11)(encoding@0.1.13)(react@18.3.1)(typescript@5.7.2) + react-native: 0.75.3(@babel/core@7.25.7)(@babel/preset-env@7.26.0(@babel/core@7.25.7))(@types/react@18.3.11)(encoding@0.1.13)(react@18.3.1)(typescript@5.8.2) - '@op-engineering/op-sqlite@11.2.13(react-native@0.75.3(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@types/react@18.3.12)(encoding@0.1.13)(react@18.3.1)(typescript@5.7.2))(react@18.3.1)': + '@op-engineering/op-sqlite@11.2.13(react-native@0.75.3(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@types/react@18.3.12)(encoding@0.1.13)(react@18.3.1)(typescript@5.8.2))(react@18.3.1)': dependencies: react: 18.3.1 - react-native: 0.75.3(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@types/react@18.3.12)(encoding@0.1.13)(react@18.3.1)(typescript@5.7.2) + react-native: 0.75.3(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@types/react@18.3.12)(encoding@0.1.13)(react@18.3.1)(typescript@5.8.2) optional: true '@open-draft/deferred-promise@2.2.0': {} @@ -29743,6 +29844,10 @@ snapshots: '@popperjs/core@2.11.8': {} + '@powersync/better-sqlite3@0.1.0': + dependencies: + bindings: 1.5.0 + '@promptbook/utils@0.70.0-1': dependencies: spacetrim: 0.11.39 @@ -29867,11 +29972,11 @@ snapshots: transitivePeerDependencies: - typescript - '@react-native-community/cli-config@14.1.0(typescript@5.7.2)': + '@react-native-community/cli-config@14.1.0(typescript@5.8.2)': dependencies: '@react-native-community/cli-tools': 14.1.0 chalk: 4.1.2 - cosmiconfig: 9.0.0(typescript@5.7.2) + cosmiconfig: 9.0.0(typescript@5.8.2) deepmerge: 4.3.1 fast-glob: 3.3.2 joi: 17.13.3 @@ -29990,9 +30095,9 @@ snapshots: transitivePeerDependencies: - typescript - '@react-native-community/cli-doctor@14.1.0(typescript@5.7.2)': + '@react-native-community/cli-doctor@14.1.0(typescript@5.8.2)': dependencies: - '@react-native-community/cli-config': 14.1.0(typescript@5.7.2) + '@react-native-community/cli-config': 14.1.0(typescript@5.8.2) '@react-native-community/cli-platform-android': 14.1.0 '@react-native-community/cli-platform-apple': 14.1.0 '@react-native-community/cli-platform-ios': 14.1.0 @@ -30400,12 +30505,12 @@ snapshots: - typescript - utf-8-validate - '@react-native-community/cli@14.1.0(typescript@5.7.2)': + '@react-native-community/cli@14.1.0(typescript@5.8.2)': dependencies: '@react-native-community/cli-clean': 14.1.0 - '@react-native-community/cli-config': 14.1.0(typescript@5.7.2) + '@react-native-community/cli-config': 14.1.0(typescript@5.8.2) '@react-native-community/cli-debugger-ui': 14.1.0 - '@react-native-community/cli-doctor': 14.1.0(typescript@5.7.2) + '@react-native-community/cli-doctor': 14.1.0(typescript@5.8.2) '@react-native-community/cli-server-api': 14.1.0 '@react-native-community/cli-tools': 14.1.0 '@react-native-community/cli-types': 14.1.0 @@ -31171,18 +31276,18 @@ snapshots: - supports-color - utf-8-validate - '@react-native/eslint-config@0.73.2(eslint@8.57.1)(prettier@3.3.3)(typescript@5.7.2)': + '@react-native/eslint-config@0.73.2(eslint@8.57.1)(prettier@3.3.3)(typescript@5.8.2)': dependencies: '@babel/core': 7.24.5 '@babel/eslint-parser': 7.25.8(@babel/core@7.25.7)(eslint@8.57.1) '@react-native/eslint-plugin': 0.73.1 - '@typescript-eslint/eslint-plugin': 5.62.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.7.2))(eslint@8.57.1)(typescript@5.7.2) - '@typescript-eslint/parser': 5.62.0(eslint@8.57.1)(typescript@5.7.2) + '@typescript-eslint/eslint-plugin': 5.62.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.8.2))(eslint@8.57.1)(typescript@5.8.2) + '@typescript-eslint/parser': 5.62.0(eslint@8.57.1)(typescript@5.8.2) eslint: 8.57.1 eslint-config-prettier: 8.10.0(eslint@8.57.1) eslint-plugin-eslint-comments: 3.2.0(eslint@8.57.1) eslint-plugin-ft-flow: 2.0.3(@babel/eslint-parser@7.25.8(@babel/core@7.24.5)(eslint@8.57.1))(eslint@8.57.1) - eslint-plugin-jest: 26.9.0(@typescript-eslint/eslint-plugin@5.62.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.7.2))(eslint@8.57.1)(typescript@5.7.2))(eslint@8.57.1)(typescript@5.7.2) + eslint-plugin-jest: 26.9.0(@typescript-eslint/eslint-plugin@5.62.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.8.2))(eslint@8.57.1)(typescript@5.8.2))(eslint@8.57.1)(typescript@5.8.2) eslint-plugin-prettier: 4.2.1(eslint-config-prettier@8.10.0(eslint@8.57.1))(eslint@8.57.1)(prettier@3.3.3) eslint-plugin-react: 7.37.1(eslint@8.57.1) eslint-plugin-react-hooks: 4.6.2(eslint@8.57.1) @@ -31321,12 +31426,12 @@ snapshots: optionalDependencies: '@types/react': 18.2.79 - '@react-native/virtualized-lists@0.75.3(@types/react@18.3.11)(react-native@0.75.3(@babel/core@7.25.7)(@babel/preset-env@7.26.0(@babel/core@7.25.7))(@types/react@18.3.11)(encoding@0.1.13)(react@18.3.1)(typescript@5.7.2))(react@18.3.1)': + '@react-native/virtualized-lists@0.75.3(@types/react@18.3.11)(react-native@0.75.3(@babel/core@7.25.7)(@babel/preset-env@7.26.0(@babel/core@7.25.7))(@types/react@18.3.11)(encoding@0.1.13)(react@18.3.1)(typescript@5.8.2))(react@18.3.1)': dependencies: invariant: 2.2.4 nullthrows: 1.1.1 react: 18.3.1 - react-native: 0.75.3(@babel/core@7.25.7)(@babel/preset-env@7.26.0(@babel/core@7.25.7))(@types/react@18.3.11)(encoding@0.1.13)(react@18.3.1)(typescript@5.7.2) + react-native: 0.75.3(@babel/core@7.25.7)(@babel/preset-env@7.26.0(@babel/core@7.25.7))(@types/react@18.3.11)(encoding@0.1.13)(react@18.3.1)(typescript@5.8.2) optionalDependencies: '@types/react': 18.3.11 @@ -31339,12 +31444,12 @@ snapshots: optionalDependencies: '@types/react': 18.3.12 - '@react-native/virtualized-lists@0.75.3(@types/react@18.3.12)(react-native@0.75.3(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@types/react@18.3.12)(encoding@0.1.13)(react@18.3.1)(typescript@5.7.2))(react@18.3.1)': + '@react-native/virtualized-lists@0.75.3(@types/react@18.3.12)(react-native@0.75.3(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@types/react@18.3.12)(encoding@0.1.13)(react@18.3.1)(typescript@5.8.2))(react@18.3.1)': dependencies: invariant: 2.2.4 nullthrows: 1.1.1 react: 18.3.1 - react-native: 0.75.3(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@types/react@18.3.12)(encoding@0.1.13)(react@18.3.1)(typescript@5.7.2) + react-native: 0.75.3(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@types/react@18.3.12)(encoding@0.1.13)(react@18.3.1)(typescript@5.8.2) optionalDependencies: '@types/react': 18.3.12 optional: true @@ -31400,7 +31505,7 @@ snapshots: react-is: 16.13.1 use-latest-callback: 0.2.1(react@18.2.0) - '@react-navigation/drawer@6.7.2(bmedeebhe3ixiqe753c2r26xfi)': + '@react-navigation/drawer@6.7.2(038ae2d2ed70d2cde1afeae3252026e4)': 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.0(@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.0(@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.0(@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.0(@babel/core@7.24.5))(@types/react@18.3.11)(encoding@0.1.13)(react@18.2.0))(react@18.2.0) @@ -31414,20 +31519,7 @@ snapshots: warn-once: 0.1.1 optional: true - '@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(yaao3llbshooz2bjipuf6mkduy)': + '@react-navigation/drawer@6.7.2(de9b7caae7cef38a32afa5b76a3c9d54)': dependencies: '@react-navigation/elements': 1.3.31(@react-navigation/native@6.1.18(react-native@0.74.5(@babel/core@7.26.0)(@babel/preset-env@7.25.7(@babel/core@7.26.0))(@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.0)(@babel/preset-env@7.25.7(@babel/core@7.26.0))(@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.0)(@babel/preset-env@7.25.7(@babel/core@7.26.0))(@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.0)(@babel/preset-env@7.25.7(@babel/core@7.26.0))(@types/react@18.2.79)(encoding@0.1.13)(react@18.2.0))(react@18.2.0) @@ -31440,6 +31532,19 @@ snapshots: react-native-screens: 3.31.1(react-native@0.74.5(@babel/core@7.26.0)(@babel/preset-env@7.25.7(@babel/core@7.26.0))(@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.0(@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.0(@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.0(@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.0(@babel/core@7.24.5))(@types/react@18.3.11)(encoding@0.1.13)(react@18.2.0))(react@18.2.0) @@ -33694,6 +33799,11 @@ snapshots: dependencies: '@babel/types': 7.25.7 + '@types/better-sqlite3@7.6.12': + dependencies: + '@types/node': 20.17.12 + optional: true + '@types/body-parser@1.19.5': dependencies: '@types/connect': 3.4.38 @@ -34077,22 +34187,22 @@ snapshots: '@types/node': 20.17.6 optional: true - '@typescript-eslint/eslint-plugin@5.62.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.7.2))(eslint@8.57.1)(typescript@5.7.2)': + '@typescript-eslint/eslint-plugin@5.62.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.8.2))(eslint@8.57.1)(typescript@5.8.2)': dependencies: '@eslint-community/regexpp': 4.11.1 - '@typescript-eslint/parser': 5.62.0(eslint@8.57.1)(typescript@5.7.2) + '@typescript-eslint/parser': 5.62.0(eslint@8.57.1)(typescript@5.8.2) '@typescript-eslint/scope-manager': 5.62.0 - '@typescript-eslint/type-utils': 5.62.0(eslint@8.57.1)(typescript@5.7.2) - '@typescript-eslint/utils': 5.62.0(eslint@8.57.1)(typescript@5.7.2) + '@typescript-eslint/type-utils': 5.62.0(eslint@8.57.1)(typescript@5.8.2) + '@typescript-eslint/utils': 5.62.0(eslint@8.57.1)(typescript@5.8.2) debug: 4.3.7(supports-color@8.1.1) eslint: 8.57.1 graphemer: 1.4.0 ignore: 5.3.2 natural-compare-lite: 1.4.0 semver: 7.6.3 - tsutils: 3.21.0(typescript@5.7.2) + tsutils: 3.21.0(typescript@5.8.2) optionalDependencies: - typescript: 5.7.2 + typescript: 5.8.2 transitivePeerDependencies: - supports-color @@ -34116,15 +34226,15 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.7.2)': + '@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.8.2)': dependencies: '@typescript-eslint/scope-manager': 5.62.0 '@typescript-eslint/types': 5.62.0 - '@typescript-eslint/typescript-estree': 5.62.0(typescript@5.7.2) + '@typescript-eslint/typescript-estree': 5.62.0(typescript@5.8.2) debug: 4.3.7(supports-color@8.1.1) eslint: 8.57.1 optionalDependencies: - typescript: 5.7.2 + typescript: 5.8.2 transitivePeerDependencies: - supports-color @@ -34141,16 +34251,16 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.7.2)': + '@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.8.2)': dependencies: '@typescript-eslint/scope-manager': 6.21.0 '@typescript-eslint/types': 6.21.0 - '@typescript-eslint/typescript-estree': 6.21.0(typescript@5.7.2) + '@typescript-eslint/typescript-estree': 6.21.0(typescript@5.8.2) '@typescript-eslint/visitor-keys': 6.21.0 debug: 4.3.7(supports-color@8.1.1) eslint: 8.57.1 optionalDependencies: - typescript: 5.7.2 + typescript: 5.8.2 transitivePeerDependencies: - supports-color @@ -34164,15 +34274,15 @@ snapshots: '@typescript-eslint/types': 6.21.0 '@typescript-eslint/visitor-keys': 6.21.0 - '@typescript-eslint/type-utils@5.62.0(eslint@8.57.1)(typescript@5.7.2)': + '@typescript-eslint/type-utils@5.62.0(eslint@8.57.1)(typescript@5.8.2)': dependencies: - '@typescript-eslint/typescript-estree': 5.62.0(typescript@5.7.2) - '@typescript-eslint/utils': 5.62.0(eslint@8.57.1)(typescript@5.7.2) + '@typescript-eslint/typescript-estree': 5.62.0(typescript@5.8.2) + '@typescript-eslint/utils': 5.62.0(eslint@8.57.1)(typescript@5.8.2) debug: 4.4.0(supports-color@8.1.1) eslint: 8.57.1 - tsutils: 3.21.0(typescript@5.7.2) + tsutils: 3.21.0(typescript@5.8.2) optionalDependencies: - typescript: 5.7.2 + typescript: 5.8.2 transitivePeerDependencies: - supports-color @@ -34192,7 +34302,7 @@ snapshots: '@typescript-eslint/types@6.21.0': {} - '@typescript-eslint/typescript-estree@5.62.0(typescript@5.7.2)': + '@typescript-eslint/typescript-estree@5.62.0(typescript@5.8.2)': dependencies: '@typescript-eslint/types': 5.62.0 '@typescript-eslint/visitor-keys': 5.62.0 @@ -34200,9 +34310,9 @@ snapshots: globby: 11.1.0 is-glob: 4.0.3 semver: 7.6.3 - tsutils: 3.21.0(typescript@5.7.2) + tsutils: 3.21.0(typescript@5.8.2) optionalDependencies: - typescript: 5.7.2 + typescript: 5.8.2 transitivePeerDependencies: - supports-color @@ -34221,7 +34331,7 @@ snapshots: transitivePeerDependencies: - supports-color - '@typescript-eslint/typescript-estree@6.21.0(typescript@5.7.2)': + '@typescript-eslint/typescript-estree@6.21.0(typescript@5.8.2)': dependencies: '@typescript-eslint/types': 6.21.0 '@typescript-eslint/visitor-keys': 6.21.0 @@ -34230,20 +34340,20 @@ snapshots: is-glob: 4.0.3 minimatch: 9.0.3 semver: 7.6.3 - ts-api-utils: 1.3.0(typescript@5.7.2) + ts-api-utils: 1.3.0(typescript@5.8.2) optionalDependencies: - typescript: 5.7.2 + typescript: 5.8.2 transitivePeerDependencies: - supports-color - '@typescript-eslint/utils@5.62.0(eslint@8.57.1)(typescript@5.7.2)': + '@typescript-eslint/utils@5.62.0(eslint@8.57.1)(typescript@5.8.2)': dependencies: '@eslint-community/eslint-utils': 4.4.0(eslint@8.57.1) '@types/json-schema': 7.0.15 '@types/semver': 7.5.8 '@typescript-eslint/scope-manager': 5.62.0 '@typescript-eslint/types': 5.62.0 - '@typescript-eslint/typescript-estree': 5.62.0(typescript@5.7.2) + '@typescript-eslint/typescript-estree': 5.62.0(typescript@5.8.2) eslint: 8.57.1 eslint-scope: 5.1.1 semver: 7.6.3 @@ -34351,6 +34461,29 @@ snapshots: - typescript - utf-8-validate - 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.1.0(@types/node@22.7.4)(jiti@1.21.6)(less@4.2.0)(lightningcss@1.28.2)(sass@1.79.4)(terser@5.34.1)(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.1.0(@types/node@22.7.4)(jiti@1.21.6)(less@4.2.0)(lightningcss@1.28.2)(sass@1.79.4)(terser@5.34.1)(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) + sirv: 3.0.1 + tinyrainbow: 2.0.0 + vitest: 3.0.8(@types/debug@4.1.12)(@types/node@22.7.4)(@vitest/browser@3.0.8)(jsdom@24.1.3)(less@4.2.0)(lightningcss@1.28.2)(msw@2.7.3(@types/node@22.7.4)(typescript@5.7.2))(sass@1.79.4)(terser@5.34.1) + ws: 8.18.1 + optionalDependencies: + playwright: 1.51.0 + webdriverio: 9.8.0 + transitivePeerDependencies: + - '@testing-library/dom' + - '@types/node' + - bufferutil + - typescript + - utf-8-validate + - vite '@vitest/expect@3.0.8': dependencies: @@ -34368,6 +34501,15 @@ 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.0)(lightningcss@1.28.2)(sass@1.79.4)(terser@5.34.1) + '@vitest/mocker@3.0.8(msw@2.7.3(@types/node@22.7.4)(typescript@5.7.2))(vite@6.1.0(@types/node@22.7.4)(jiti@1.21.6)(less@4.2.0)(lightningcss@1.28.2)(sass@1.79.4)(terser@5.34.1)(yaml@2.6.1))': + dependencies: + '@vitest/spy': 3.0.8 + estree-walker: 3.0.3 + magic-string: 0.30.17 + optionalDependencies: + msw: 2.7.3(@types/node@22.7.4)(typescript@5.7.2) + vite: 6.1.0(@types/node@22.7.4)(jiti@1.21.6)(less@4.2.0)(lightningcss@1.28.2)(sass@1.79.4)(terser@5.34.1)(yaml@2.6.1) + '@vitest/pretty-format@3.0.8': dependencies: tinyrainbow: 2.0.0 @@ -34509,11 +34651,11 @@ snapshots: '@vue/shared': 3.4.21 vue: 3.4.21(typescript@5.5.4) - '@vue/server-renderer@3.4.21(vue@3.4.21(typescript@5.7.2))': + '@vue/server-renderer@3.4.21(vue@3.4.21(typescript@5.8.2))': dependencies: '@vue/compiler-ssr': 3.4.21 '@vue/shared': 3.4.21 - vue: 3.4.21(typescript@5.7.2) + vue: 3.4.21(typescript@5.8.2) '@vue/shared@3.4.21': {} @@ -35535,6 +35677,12 @@ snapshots: dependencies: is-windows: 1.0.2 + better-sqlite3@11.7.2: + dependencies: + bindings: 1.5.0 + prebuild-install: 7.1.3 + optional: true + big-integer@1.6.52: {} big.js@5.2.2: {} @@ -35548,6 +35696,10 @@ snapshots: binary-extensions@2.3.0: {} + bindings@1.5.0: + dependencies: + file-uri-to-path: 1.0.0 + bl@4.1.0: dependencies: buffer: 5.7.1 @@ -36005,6 +36157,9 @@ snapshots: dependencies: readdirp: 4.0.2 + chownr@1.1.4: + optional: true + chownr@2.0.0: {} chownr@3.0.0: {} @@ -36390,14 +36545,14 @@ snapshots: optionalDependencies: typescript: 5.5.4 - cosmiconfig@9.0.0(typescript@5.7.2): + cosmiconfig@9.0.0(typescript@5.8.2): dependencies: env-paths: 2.2.1 import-fresh: 3.3.0 js-yaml: 4.1.0 parse-json: 5.2.0 optionalDependencies: - typescript: 5.7.2 + typescript: 5.8.2 crc-32@1.2.2: optional: true @@ -37202,7 +37357,7 @@ snapshots: dotenv-expand@11.0.6: dependencies: - dotenv: 16.4.5 + dotenv: 16.4.7 dotenv@16.3.1: {} @@ -37210,10 +37365,12 @@ snapshots: dotenv@16.4.7: {} - drizzle-orm@0.35.2(@op-engineering/op-sqlite@11.2.13(react-native@0.75.3(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@types/react@18.3.12)(encoding@0.1.13)(react@18.3.1)(typescript@5.7.2))(react@18.3.1))(@types/react@18.3.12)(kysely@0.27.4)(react@18.3.1): + drizzle-orm@0.35.2(@op-engineering/op-sqlite@11.2.13(react-native@0.75.3(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@types/react@18.3.12)(encoding@0.1.13)(react@18.3.1)(typescript@5.8.2))(react@18.3.1))(@types/better-sqlite3@7.6.12)(@types/react@18.3.12)(better-sqlite3@11.7.2)(kysely@0.27.4)(react@18.3.1): optionalDependencies: - '@op-engineering/op-sqlite': 11.2.13(react-native@0.75.3(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@types/react@18.3.12)(encoding@0.1.13)(react@18.3.1)(typescript@5.7.2))(react@18.3.1) + '@op-engineering/op-sqlite': 11.2.13(react-native@0.75.3(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@types/react@18.3.12)(encoding@0.1.13)(react@18.3.1)(typescript@5.8.2))(react@18.3.1) + '@types/better-sqlite3': 7.6.12 '@types/react': 18.3.12 + better-sqlite3: 11.7.2 kysely: 0.27.4 react: 18.3.1 @@ -37758,20 +37915,20 @@ snapshots: source-map: 0.6.1 optional: true - eslint-config-next@14.0.0(eslint@8.57.1)(typescript@5.7.2): + eslint-config-next@14.0.0(eslint@8.57.1)(typescript@5.8.2): dependencies: '@next/eslint-plugin-next': 14.0.0 '@rushstack/eslint-patch': 1.10.4 - '@typescript-eslint/parser': 6.21.0(eslint@8.57.1)(typescript@5.7.2) + '@typescript-eslint/parser': 6.21.0(eslint@8.57.1)(typescript@5.8.2) eslint: 8.57.1 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.7.2))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0(eslint@8.57.1))(eslint@8.57.1) - eslint-plugin-import: 2.31.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.7.2))(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1) + 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-plugin-import: 2.31.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.8.2))(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1) eslint-plugin-jsx-a11y: 6.10.0(eslint@8.57.1) eslint-plugin-react: 7.37.1(eslint@8.57.1) eslint-plugin-react-hooks: 4.6.2(eslint@8.57.1) optionalDependencies: - typescript: 5.7.2 + typescript: 5.8.2 transitivePeerDependencies: - eslint-import-resolver-webpack - eslint-plugin-import-x @@ -37817,19 +37974,19 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-import-resolver-typescript@3.6.3(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.7.2))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0(eslint@8.57.1))(eslint@8.57.1): + 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): dependencies: '@nolyfill/is-core-module': 1.0.39 debug: 4.3.7(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.7.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(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 is-glob: 4.0.3 optionalDependencies: - eslint-plugin-import: 2.31.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.7.2))(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1) + eslint-plugin-import: 2.31.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.8.2))(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1) transitivePeerDependencies: - '@typescript-eslint/parser' - eslint-import-resolver-node @@ -37846,14 +38003,14 @@ snapshots: transitivePeerDependencies: - supports-color - eslint-module-utils@2.12.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.7.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(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: - '@typescript-eslint/parser': 6.21.0(eslint@8.57.1)(typescript@5.7.2) + '@typescript-eslint/parser': 6.21.0(eslint@8.57.1)(typescript@5.8.2) eslint: 8.57.1 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.7.2))(eslint-import-resolver-node@0.3.9)(eslint-plugin-import@2.31.0(eslint@8.57.1))(eslint@8.57.1) + 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) transitivePeerDependencies: - supports-color @@ -37905,7 +38062,7 @@ snapshots: - eslint-import-resolver-webpack - supports-color - eslint-plugin-import@2.31.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.7.2))(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1): + eslint-plugin-import@2.31.0(@typescript-eslint/parser@6.21.0(eslint@8.57.1)(typescript@5.8.2))(eslint-import-resolver-typescript@3.6.3)(eslint@8.57.1): dependencies: '@rtsao/scc': 1.1.0 array-includes: 3.1.8 @@ -37916,7 +38073,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.7.2))(eslint-import-resolver-node@0.3.9)(eslint-import-resolver-typescript@3.6.3)(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 @@ -37928,18 +38085,18 @@ snapshots: string.prototype.trimend: 1.0.8 tsconfig-paths: 3.15.0 optionalDependencies: - '@typescript-eslint/parser': 6.21.0(eslint@8.57.1)(typescript@5.7.2) + '@typescript-eslint/parser': 6.21.0(eslint@8.57.1)(typescript@5.8.2) transitivePeerDependencies: - eslint-import-resolver-typescript - eslint-import-resolver-webpack - supports-color - eslint-plugin-jest@26.9.0(@typescript-eslint/eslint-plugin@5.62.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.7.2))(eslint@8.57.1)(typescript@5.7.2))(eslint@8.57.1)(typescript@5.7.2): + eslint-plugin-jest@26.9.0(@typescript-eslint/eslint-plugin@5.62.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.8.2))(eslint@8.57.1)(typescript@5.8.2))(eslint@8.57.1)(typescript@5.8.2): dependencies: - '@typescript-eslint/utils': 5.62.0(eslint@8.57.1)(typescript@5.7.2) + '@typescript-eslint/utils': 5.62.0(eslint@8.57.1)(typescript@5.8.2) eslint: 8.57.1 optionalDependencies: - '@typescript-eslint/eslint-plugin': 5.62.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.7.2))(eslint@8.57.1)(typescript@5.7.2) + '@typescript-eslint/eslint-plugin': 5.62.0(@typescript-eslint/parser@5.62.0(eslint@8.57.1)(typescript@5.8.2))(eslint@8.57.1)(typescript@5.8.2) transitivePeerDependencies: - supports-color - typescript @@ -38295,6 +38452,9 @@ snapshots: signal-exit: 4.1.0 strip-final-newline: 3.0.0 + expand-template@2.0.3: + optional: true + expand-tilde@2.0.2: dependencies: homedir-polyfill: 1.0.3 @@ -38570,7 +38730,35 @@ snapshots: dependencies: invariant: 2.2.4 - expo-router@3.5.21(gtohwu5bdvnl7tvlmjhokmubum): + expo-router@3.5.21(43cc03a7fb538f7aef105856925492f6): + 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) + '@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)) + 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) + schema-utils: 4.2.0 + optionalDependencies: + '@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 + - react + - react-native + - supports-color + - typescript + + expo-router@3.5.21(49b2fd6c45ca81e2d20f2f5a4be05a3e): dependencies: '@expo/metro-runtime': 3.2.1(react-native@0.74.5(@babel/core@7.26.0)(@babel/preset-env@7.25.7(@babel/core@7.26.0))(@types/react@18.2.79)(encoding@0.1.13)(react@18.2.0)) '@expo/server': 0.4.4(typescript@5.5.4) @@ -38588,7 +38776,7 @@ snapshots: react-native-screens: 3.31.1(react-native@0.74.5(@babel/core@7.26.0)(@babel/preset-env@7.25.7(@babel/core@7.26.0))(@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(yaao3llbshooz2bjipuf6mkduy) + '@react-navigation/drawer': 6.7.2(de9b7caae7cef38a32afa5b76a3c9d54) react-native-reanimated: 3.10.1(@babel/core@7.26.0)(react-native@0.74.5(@babel/core@7.26.0)(@babel/preset-env@7.25.7(@babel/core@7.26.0))(@types/react@18.2.79)(encoding@0.1.13)(react@18.2.0))(react@18.2.0) transitivePeerDependencies: - encoding @@ -38598,7 +38786,7 @@ snapshots: - supports-color - typescript - expo-router@3.5.21(j6qjh2jsuy2ozdtd6girxrw3ky): + expo-router@3.5.21(988d822f9e58e176bb73f45e8e45eb4a): dependencies: '@expo/metro-runtime': 3.2.1(react-native@0.74.1(@babel/core@7.24.5)(@babel/preset-env@7.26.0(@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) @@ -38616,7 +38804,7 @@ snapshots: react-native-screens: 3.31.1(react-native@0.74.1(@babel/core@7.24.5)(@babel/preset-env@7.26.0(@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(bmedeebhe3ixiqe753c2r26xfi) + '@react-navigation/drawer': 6.7.2(038ae2d2ed70d2cde1afeae3252026e4) 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.0(@babel/core@7.24.5))(@types/react@18.3.11)(encoding@0.1.13)(react@18.2.0))(react@18.2.0) transitivePeerDependencies: - encoding @@ -38626,35 +38814,7 @@ snapshots: - supports-color - typescript - expo-router@3.5.21(qrxjjyxvihi5xb6jovt7bb6fjy): - 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) - '@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)) - 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) - 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) - transitivePeerDependencies: - - encoding - - expo-modules-autolinking - - react - - react-native - - 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) @@ -38672,7 +38832,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 @@ -39041,6 +39201,8 @@ snapshots: schema-utils: 3.3.0 webpack: 5.95.0(@swc/core@1.10.1(@swc/helpers@0.5.5)) + file-uri-to-path@1.0.0: {} + filelist@1.0.4: dependencies: minimatch: 5.1.6 @@ -39260,6 +39422,9 @@ snapshots: fresh@0.5.2: {} + fs-constants@1.0.0: + optional: true + fs-extra@10.1.0: dependencies: graceful-fs: 4.2.11 @@ -39446,6 +39611,9 @@ snapshots: getenv@1.0.0: {} + github-from-package@0.0.0: + optional: true + github-slugger@1.5.0: {} glob-parent@5.1.2: @@ -42644,6 +42812,9 @@ snapshots: mixme@0.5.10: {} + mkdirp-classic@0.5.3: + optional: true + mkdirp@0.5.6: dependencies: minimist: 1.2.8 @@ -42747,6 +42918,9 @@ snapshots: nanoid@3.3.8: {} + napi-build-utils@2.0.0: + optional: true + native-run@2.0.1: dependencies: '@ionic/utils-fs': 3.1.7 @@ -43757,13 +43931,13 @@ snapshots: '@csstools/utilities': 2.0.0(postcss@8.4.47) 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@20.16.10)(typescript@5.7.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.7.2) + 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: @@ -44112,6 +44286,22 @@ snapshots: dependencies: commander: 9.5.0 + prebuild-install@7.1.3: + dependencies: + detect-libc: 2.0.3 + expand-template: 2.0.3 + github-from-package: 0.0.0 + minimist: 1.2.8 + mkdirp-classic: 0.5.3 + napi-build-utils: 2.0.0 + node-abi: 3.68.0 + pump: 3.0.2 + rc: 1.2.8 + simple-get: 4.0.1 + tar-fs: 2.1.2 + tunnel-agent: 0.6.0 + optional: true + preferred-pm@3.1.4: dependencies: find-up: 5.0.0 @@ -44538,7 +44728,7 @@ snapshots: react-loadable: '@docusaurus/react-loadable@6.0.0(react@18.2.0)' webpack: 5.95.0(@swc/core@1.10.1(@swc/helpers@0.5.5)) - react-native-builder-bob@0.30.2(typescript@5.7.2): + react-native-builder-bob@0.30.2(typescript@5.8.2): dependencies: '@babel/core': 7.25.7 '@babel/plugin-transform-strict-mode': 7.25.7(@babel/core@7.25.7) @@ -44548,7 +44738,7 @@ snapshots: '@babel/preset-typescript': 7.25.7(@babel/core@7.25.7) babel-plugin-module-resolver: 5.0.2 browserslist: 4.24.0 - cosmiconfig: 9.0.0(typescript@5.7.2) + cosmiconfig: 9.0.0(typescript@5.8.2) cross-spawn: 7.0.3 dedent: 0.7.0 del: 6.1.1 @@ -45074,10 +45264,10 @@ snapshots: - supports-color - utf-8-validate - react-native@0.75.3(@babel/core@7.25.7)(@babel/preset-env@7.26.0(@babel/core@7.25.7))(@types/react@18.3.11)(encoding@0.1.13)(react@18.3.1)(typescript@5.7.2): + react-native@0.75.3(@babel/core@7.25.7)(@babel/preset-env@7.26.0(@babel/core@7.25.7))(@types/react@18.3.11)(encoding@0.1.13)(react@18.3.1)(typescript@5.8.2): dependencies: '@jest/create-cache-key-function': 29.7.0 - '@react-native-community/cli': 14.1.0(typescript@5.7.2) + '@react-native-community/cli': 14.1.0(typescript@5.8.2) '@react-native-community/cli-platform-android': 14.1.0 '@react-native-community/cli-platform-ios': 14.1.0 '@react-native/assets-registry': 0.75.3 @@ -45086,7 +45276,7 @@ snapshots: '@react-native/gradle-plugin': 0.75.3 '@react-native/js-polyfills': 0.75.3 '@react-native/normalize-colors': 0.75.3 - '@react-native/virtualized-lists': 0.75.3(@types/react@18.3.11)(react-native@0.75.3(@babel/core@7.25.7)(@babel/preset-env@7.26.0(@babel/core@7.25.7))(@types/react@18.3.11)(encoding@0.1.13)(react@18.3.1)(typescript@5.7.2))(react@18.3.1) + '@react-native/virtualized-lists': 0.75.3(@types/react@18.3.11)(react-native@0.75.3(@babel/core@7.25.7)(@babel/preset-env@7.26.0(@babel/core@7.25.7))(@types/react@18.3.11)(encoding@0.1.13)(react@18.3.1)(typescript@5.8.2))(react@18.3.1) abort-controller: 3.0.0 anser: 1.4.10 ansi-regex: 5.0.1 @@ -45180,10 +45370,10 @@ snapshots: - typescript - utf-8-validate - react-native@0.75.3(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@types/react@18.3.12)(encoding@0.1.13)(react@18.3.1)(typescript@5.7.2): + react-native@0.75.3(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@types/react@18.3.12)(encoding@0.1.13)(react@18.3.1)(typescript@5.8.2): dependencies: '@jest/create-cache-key-function': 29.7.0 - '@react-native-community/cli': 14.1.0(typescript@5.7.2) + '@react-native-community/cli': 14.1.0(typescript@5.8.2) '@react-native-community/cli-platform-android': 14.1.0 '@react-native-community/cli-platform-ios': 14.1.0 '@react-native/assets-registry': 0.75.3 @@ -45192,7 +45382,7 @@ snapshots: '@react-native/gradle-plugin': 0.75.3 '@react-native/js-polyfills': 0.75.3 '@react-native/normalize-colors': 0.75.3 - '@react-native/virtualized-lists': 0.75.3(@types/react@18.3.12)(react-native@0.75.3(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@types/react@18.3.12)(encoding@0.1.13)(react@18.3.1)(typescript@5.7.2))(react@18.3.1) + '@react-native/virtualized-lists': 0.75.3(@types/react@18.3.12)(react-native@0.75.3(@babel/core@7.26.0)(@babel/preset-env@7.26.0(@babel/core@7.26.0))(@types/react@18.3.12)(encoding@0.1.13)(react@18.3.1)(typescript@5.8.2))(react@18.3.1) abort-controller: 3.0.0 anser: 1.4.10 ansi-regex: 5.0.1 @@ -45234,19 +45424,7 @@ snapshots: - utf-8-validate optional: true - 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(ei6zhj5w65kzzp3jt27w3zu7ea): + react-navigation-stack@2.10.4(b5d6035dfb87b14e0677db2e89c1e7ef): dependencies: '@react-native-community/masked-view': 0.1.11(react-native@0.74.5(@babel/core@7.26.0)(@babel/preset-env@7.25.7(@babel/core@7.26.0))(@types/react@18.2.79)(encoding@0.1.13)(react@18.2.0))(react@18.2.0) color: 3.2.1 @@ -45258,6 +45436,18 @@ snapshots: react-native-screens: 3.31.1(react-native@0.74.5(@babel/core@7.26.0)(@babel/preset-env@7.25.7(@babel/core@7.26.0))(@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.0)(@babel/preset-env@7.25.7(@babel/core@7.26.0))(@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) @@ -46312,6 +46502,16 @@ snapshots: transitivePeerDependencies: - supports-color + simple-concat@1.0.1: + optional: true + + simple-get@4.0.1: + dependencies: + decompress-response: 6.0.0 + once: 1.4.0 + simple-concat: 1.0.1 + optional: true + simple-plist@1.3.1: dependencies: bplist-creator: 0.1.0 @@ -46867,7 +47067,7 @@ snapshots: tabbable@6.2.0: {} - 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.7.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 @@ -46886,7 +47086,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(@swc/core@1.10.1(@swc/helpers@0.5.5))(@types/node@20.16.10)(typescript@5.7.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 @@ -46987,6 +47187,14 @@ snapshots: tapable@2.2.1: {} + tar-fs@2.1.2: + dependencies: + chownr: 1.1.4 + mkdirp-classic: 0.5.3 + pump: 3.0.2 + tar-stream: 2.2.0 + optional: true + tar-fs@3.0.6: dependencies: pump: 3.0.2 @@ -46996,6 +47204,15 @@ snapshots: bare-path: 2.1.3 optional: true + tar-stream@2.2.0: + dependencies: + bl: 4.1.0 + end-of-stream: 1.4.4 + fs-constants: 1.0.0 + inherits: 2.0.4 + readable-stream: 3.6.2 + optional: true + tar-stream@3.1.7: dependencies: b4a: 1.6.7 @@ -47259,13 +47476,13 @@ snapshots: dependencies: typescript: 5.3.3 - ts-api-utils@1.3.0(typescript@5.7.2): + ts-api-utils@1.3.0(typescript@5.8.2): dependencies: - typescript: 5.7.2 + typescript: 5.8.2 ts-interface-checker@0.1.13: {} - ts-node@10.9.2(@swc/core@1.10.1(@swc/helpers@0.5.5))(@types/node@20.16.10)(typescript@5.7.2): + 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 @@ -47279,7 +47496,7 @@ snapshots: create-require: 1.1.1 diff: 4.0.2 make-error: 1.3.6 - typescript: 5.7.2 + typescript: 5.8.2 v8-compile-cache-lib: 3.0.1 yn: 3.1.1 optionalDependencies: @@ -47326,6 +47543,26 @@ snapshots: optionalDependencies: '@swc/core': 1.10.1(@swc/helpers@0.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': 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: 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) + 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 @@ -47373,10 +47610,10 @@ snapshots: tslib@2.7.0: {} - tsutils@3.21.0(typescript@5.7.2): + tsutils@3.21.0(typescript@5.8.2): dependencies: tslib: 1.14.1 - typescript: 5.7.2 + typescript: 5.8.2 tty-table@4.2.3: dependencies: @@ -47543,6 +47780,8 @@ snapshots: typescript@5.7.2: {} + typescript@5.8.2: {} + ua-parser-js@1.0.39: {} uc.micro@2.1.0: {} @@ -48175,15 +48414,15 @@ snapshots: optionalDependencies: typescript: 5.5.4 - vue@3.4.21(typescript@5.7.2): + vue@3.4.21(typescript@5.8.2): dependencies: '@vue/compiler-dom': 3.4.21 '@vue/compiler-sfc': 3.4.21 '@vue/runtime-dom': 3.4.21 - '@vue/server-renderer': 3.4.21(vue@3.4.21(typescript@5.7.2)) + '@vue/server-renderer': 3.4.21(vue@3.4.21(typescript@5.8.2)) '@vue/shared': 3.4.21 optionalDependencies: - typescript: 5.7.2 + typescript: 5.8.2 vuetify@3.6.8(typescript@5.5.4)(vite-plugin-vuetify@2.0.4)(vue@3.4.21(typescript@5.5.4)): dependencies: diff --git a/verdaccio-config.yaml b/verdaccio-config.yaml index e58226111..b354099c7 100644 --- a/verdaccio-config.yaml +++ b/verdaccio-config.yaml @@ -2,7 +2,15 @@ storage: /tmp/storage auth: htpasswd: file: /tmp/htpasswd +uplinks: + npmjs: + url: https://registry.npmjs.org/ packages: + # Our better-sqlite3 fork is published under @powersync without being part of this repository. + '@powersync/better-sqlite3': + access: $all + publish: false + proxy: npmjs '@powersync/*': access: $all publish: $all diff --git a/vitest.workspace.ts b/vitest.workspace.ts new file mode 100644 index 000000000..8e6c09dda --- /dev/null +++ b/vitest.workspace.ts @@ -0,0 +1,4 @@ +export default [ + // Consider all packages with a vitest configuration file as part of the test workspace. + 'packages/*/vitest.config.ts' +];