diff --git a/docs/configuration.md b/docs/configuration.md index 35d310d..dde0bcd 100644 --- a/docs/configuration.md +++ b/docs/configuration.md @@ -21,7 +21,7 @@ | Field | Type | Description | |---|---|---| | `persistence` | `{ dbName: string, passphrase?: string }` | Enable IndexedDB persistence. A `passphrase` turns on AES-GCM encryption at rest | -| `remote` | `{ url: string, clientId?: string, ticket?: string, username?: string, password?: string }` | Enable MQTT sync. `url` is a `ws://`/`wss://` MQTT endpoint; `ticket` is a JWT for MQTT v5 enhanced auth; `username`/`password` drive classic MQTT password auth | +| `remote` | `{ url: string, clientId?: string, ticket?: string, username?: string, password?: string, autoConnect?: boolean }` | Enable MQTT sync. `url` is a `ws://`/`wss://` MQTT endpoint; `ticket` is a JWT for MQTT v5 enhanced auth; `username`/`password` drive classic MQTT password auth. `autoConnect` (default `true`) → set `false` to skip the connect on `initialize()` and drive it yourself via `reconnect(url, ticket)`, the usual pattern when the JWT is minted dynamically per connection | ## Scope model diff --git a/package-lock.json b/package-lock.json index 7528259..b821ffe 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,15 +1,15 @@ { "name": "@laboverwire/stitch", - "version": "0.5.0", + "version": "0.5.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@laboverwire/stitch", - "version": "0.5.0", + "version": "0.5.1", "license": "Apache-2.0", "dependencies": { - "@laboverwire/stitch-wasm": "^0.2.2" + "@laboverwire/stitch-wasm": "^0.3.0" }, "devDependencies": { "@eslint/js": "^10.0.1", @@ -1031,9 +1031,9 @@ } }, "node_modules/@laboverwire/stitch-wasm": { - "version": "0.2.2", - "resolved": "https://registry.npmjs.org/@laboverwire/stitch-wasm/-/stitch-wasm-0.2.2.tgz", - "integrity": "sha512-OiRh3sr7qAvAhfvOc5uAvOmiGBymzv00GNVmfBglZHZs2kWXivbV6bgfCVLPGyKGxQEHiWlXjDvQMM70MtK5xg==", + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@laboverwire/stitch-wasm/-/stitch-wasm-0.3.0.tgz", + "integrity": "sha512-DVzBdR+8+hUeRa7opRAnoMnWzmsattFpnZVMr0qqJVazL48LISuHz4AqD4DbS2gF0UD6wx3LsAnXaWOPXK0lBg==", "license": "Apache-2.0" }, "node_modules/@napi-rs/lzma-linux-x64-gnu": { diff --git a/package.json b/package.json index 5f83181..3cc747e 100644 --- a/package.json +++ b/package.json @@ -74,7 +74,7 @@ } }, "dependencies": { - "@laboverwire/stitch-wasm": "^0.2.2" + "@laboverwire/stitch-wasm": "^0.3.0" }, "peerDependencies": { "react": "^19.0.0", diff --git a/src/types.ts b/src/types.ts index 3323ac3..f52f4d7 100644 --- a/src/types.ts +++ b/src/types.ts @@ -65,6 +65,7 @@ export interface RemoteConfig { ticket?: string; username?: string; password?: string; + autoConnect?: boolean; } export interface StoreOptions { diff --git a/tests/integration/auto-connect.test.ts b/tests/integration/auto-connect.test.ts new file mode 100644 index 0000000..1710738 --- /dev/null +++ b/tests/integration/auto-connect.test.ts @@ -0,0 +1,46 @@ +import { afterEach, describe, it, expect, vi } from 'vitest'; +import { createStore } from '../../src/store.ts'; +import { projectTaskConfig, uniqueDbName } from '../helpers/fixtures.ts'; +import type { RemoteConfig, Store } from '../../src/types.ts'; + +const UNROUTABLE = 'ws://127.0.0.1:49871'; + +describe('remote.autoConnect', () => { + const stores: Store[] = []; + + afterEach(async () => { + while (stores.length > 0) { + const store = stores.pop(); + if (store) await store.destroy(); + } + }); + + function open(remote: RemoteConfig): Store { + const store = createStore(projectTaskConfig(), { + persistence: { dbName: uniqueDbName() }, + remote, + }); + stores.push(store); + return store; + } + + it('autoConnect:false does not start a connection on initialize', async () => { + const store = open({ url: UNROUTABLE, autoConnect: false }); + await store.initialize(); + + await new Promise((resolve) => setTimeout(resolve, 150)); + + expect(store.connectionStatus).not.toBe('connecting'); + expect(store.connectionStatus).not.toBe('connected'); + expect(store.isReconnecting).toBe(false); + expect(store.hasRemote).toBe(true); + }); + + it('default (autoConnect omitted) starts the connection on initialize', async () => { + const store = open({ url: UNROUTABLE }); + await store.initialize(); + + await vi.waitFor(() => expect(store.connectionStatus).toBe('connecting')); + expect(store.hasRemote).toBe(true); + }); +});