@truenas/api-client 3.0.2 → 3.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.cts CHANGED
@@ -12460,6 +12460,16 @@ declare class TrueNasSocket {
12460
12460
  complete(): void;
12461
12461
  }
12462
12462
 
12463
+ /**
12464
+ * The scheme used to reach the appliance, in `location.protocol` form.
12465
+ *
12466
+ * Colon included, so a caller served *by the appliance* can pass
12467
+ * `location.protocol` unchanged. That equivalence only holds same-origin: this
12468
+ * value is spliced onto the hostname the client connects to, so a page served
12469
+ * from somewhere else must say what the appliance uses, not what it uses.
12470
+ */
12471
+ type ApplianceProtocol = 'http:' | 'https:';
12472
+
12463
12473
  interface ActiveConnection {
12464
12474
  ws: TrueNasSocket;
12465
12475
  hostname: string;
@@ -12482,6 +12492,7 @@ declare class TrueNasConnection {
12482
12492
  readonly retryDelay: number;
12483
12493
  readonly maxRetry: number;
12484
12494
  readonly logger: Logger;
12495
+ readonly protocol: ApplianceProtocol;
12485
12496
  opened: BehaviorSubject<boolean>;
12486
12497
  closed: Subject<void>;
12487
12498
  hostname: BehaviorSubject<string>;
@@ -12544,7 +12555,7 @@ declare class TrueNasConnection {
12544
12555
  * observable which always emits messages from the current socket.
12545
12556
  */
12546
12557
  messages$: Observable<TrueNasMessage>;
12547
- constructor(initialEnabled: boolean, hostnames: string[], systemUuid: string, websocketPath: string, systemName?: string | undefined, retryDelay?: number, maxRetry?: number, logger?: Logger);
12558
+ constructor(initialEnabled: boolean, hostnames: string[], systemUuid: string, websocketPath: string, systemName?: string | undefined, retryDelay?: number, maxRetry?: number, logger?: Logger, protocol?: ApplianceProtocol);
12548
12559
  /**
12549
12560
  * whether the connection has exhausted its retries — the **cumulative** snapshot, read
12550
12561
  * synchronously. (Formerly `hasConnectionError()`; renamed to disambiguate it from the
@@ -13192,7 +13203,8 @@ declare abstract class TrueNasApiClient<D extends ApiDirectoryShape = BaseApiDir
13192
13203
  protected readonly systemName: string | undefined;
13193
13204
  /** Logger forwarded to the connection (defaults to a no-op). */
13194
13205
  protected readonly logger: Logger;
13195
- constructor(uuid: string, hostnames: string[], version: ApiVersion, enabled: boolean, systemName?: string, logger?: Logger);
13206
+ protected readonly protocol: ApplianceProtocol;
13207
+ constructor(uuid: string, hostnames: string[], version: ApiVersion, enabled: boolean, systemName?: string, logger?: Logger, protocol?: ApplianceProtocol);
13196
13208
  /**
13197
13209
  * Get current connection status.
13198
13210
  * @returns true if WebSocket is connected
@@ -27559,6 +27571,19 @@ declare const SUPPORTED_API_VERSIONS: readonly ["v25.10.0", "v25.10.1", "v25.10.
27559
27571
  * how the missing 22 methods went unnoticed in the first place.
27560
27572
  */
27561
27573
  type DefaultApiDirectory = ApiDirectory$7;
27574
+ /**
27575
+ * The surface a named version derives, falling back when nothing was narrowed.
27576
+ *
27577
+ * `V` only pins a directory when inference narrowed it. A wrapper typed
27578
+ * `(version: SupportedApiVersion)` widens it back to the whole union, and
27579
+ * indexing by a union yields a union of directories whose usable methods are
27580
+ * their *intersection* — narrower than the default surface, so naming the
27581
+ * version would buy fewer methods than naming nothing. That case falls back to
27582
+ * {@link DefaultApiDirectory} instead, matching every other shape that loses
27583
+ * the literal. A partial union still derives: methods common to the versions
27584
+ * named is the right answer for "one of these".
27585
+ */
27586
+ type DerivedDirectory<V extends SupportedApiVersion> = SupportedApiVersion extends V ? DefaultApiDirectory : ApiDirectoryByVersion[V];
27562
27587
  /** Options for {@link createTrueNasClient}. */
27563
27588
  interface CreateClientOptions {
27564
27589
  /** System UUID. */
@@ -27582,12 +27607,44 @@ interface CreateClientOptions {
27582
27607
  * through the client, to the connection.
27583
27608
  */
27584
27609
  logger?: Logger;
27610
+ /**
27611
+ * The appliance's API version, when the caller already knows it.
27612
+ *
27613
+ * Supplying it skips version discovery entirely — no `GET /api/versions`, no
27614
+ * CORS fallback — and *derives* the client's typed surface from the string,
27615
+ * so `version: 'v27.0.0'` yields `TrueNasApiClient<ApiDirectoryV27_0_0>`
27616
+ * without the caller asserting it through a type parameter.
27617
+ */
27618
+ version?: SupportedApiVersion;
27619
+ /**
27620
+ * The scheme to reach the appliance on, in `location.protocol` form.
27621
+ *
27622
+ * Selects both halves of the transport: `https:` gives `https` discovery and
27623
+ * a `wss` socket, `http:` gives `http` and `ws`. Defaults to `https:`, which
27624
+ * is what an appliance serves and what Connect uses.
27625
+ *
27626
+ * This describes the *appliance*, not the page. Passing
27627
+ * `location.protocol` is correct when the appliance serves the page — the
27628
+ * same-origin case this exists for — and wrong otherwise. A page on
27629
+ * `http://localhost:5173` talking to an https appliance gets both halves
27630
+ * wrong, but only one of them says so: `fetch` follows the redirect and
27631
+ * discovery appears to work, while the WebSocket has no such tolerance and
27632
+ * fails the handshake without naming the scheme.
27633
+ *
27634
+ * Omitting it against a plaintext appliance is the quieter failure and the
27635
+ * likelier one, since it is the case this option exists for. Discovery tries
27636
+ * `https`, `fetch` rejects, and that is indistinguishable from the CORS block
27637
+ * v25.10.0 has on `/api/versions` — so the fallback fires and the caller gets
27638
+ * a client pinned to v25.10.0, warned about only in the log.
27639
+ */
27640
+ protocol?: ApplianceProtocol;
27585
27641
  }
27586
27642
  /**
27587
27643
  * Creates a version-specific TrueNAS API client.
27588
27644
  *
27589
27645
  * 1. Discovers the API version (`GET /api/versions`), asking every hostname in
27590
- * parallel. The first usable answer wins.
27646
+ * parallel. The first usable answer wins — *unless* `opts.version` says
27647
+ * which version this is, in which case discovery is skipped entirely.
27591
27648
  * 2. Selects the matching client implementation (`v25.10.x` -> `TrueNasApiClientV2510`,
27592
27649
  * `v26.x.y` -> `TrueNasApiClientV26`, `v27.x.y` -> `TrueNasApiClientV27`).
27593
27650
  * 3. Instantiates and returns it.
@@ -27618,9 +27675,77 @@ interface CreateClientOptions {
27618
27675
  * supported version. Operations that must work across versions belong on
27619
27676
  * `client.ops`, which resolves them at runtime.
27620
27677
  *
27678
+ * ## Naming the version instead
27679
+ *
27680
+ * A caller that already knows its appliance — a UI served by the appliance
27681
+ * itself, a test harness against a pinned image — can say so and skip discovery
27682
+ * altogether:
27683
+ *
27684
+ * ```typescript
27685
+ * const client = await createTrueNasClient({
27686
+ * uuid, hostnames, enabled: true, version: 'v27.0.0',
27687
+ * });
27688
+ * // client: TrueNasApiClient<ApiDirectoryV27_0_0>, derived from the string
27689
+ * ```
27690
+ *
27691
+ * The surface is *derived* rather than asserted: `ApiDirectoryByVersion` maps
27692
+ * the version string to its directory, so the caller writes no cast and names
27693
+ * no directory type. A version this package ships no types for does not
27694
+ * compile.
27695
+ *
27696
+ * **The derivation needs the version to be literal at the call site.** It comes
27697
+ * from inference on `{ version: V }`, so it holds for a string literal written
27698
+ * in the options object (or a `const`-typed one). It does not survive
27699
+ * indirection:
27700
+ *
27701
+ * - `createTrueNasClient<D>({ …, version: 'v27.0.0' })` — an explicit type
27702
+ * argument makes the derived overload inapplicable, so `D` wins.
27703
+ * - `(v?: SupportedApiVersion) => createTrueNasClient({ …, version: v })` — the
27704
+ * property is `SupportedApiVersion | undefined`, which no `V` satisfies.
27705
+ * - `(v: SupportedApiVersion) => …` — reaches this overload, but `V` widens to
27706
+ * the whole union, which derives nothing.
27707
+ * - `const opts: CreateClientOptions = { …, version: 'v27.0.0' }` — the
27708
+ * annotation widens the property before the call sees it.
27709
+ *
27710
+ * All of them compile, run against the named version, and type as
27711
+ * {@link DefaultApiDirectory}. That fails in the safe direction — understated
27712
+ * types give a compile error at the method call rather than a runtime surprise —
27713
+ * but it is silent, so a wrapper that forwards a version gets none of the
27714
+ * surface it named. Keep the literal at the call site, and if you are adding
27715
+ * `version` to an existing `createTrueNasClient<ApiDirectoryV26_0_0>(opts)`
27716
+ * call, delete the type argument in the same edit.
27717
+ *
27718
+ * Two consequences worth knowing before reaching for it.
27719
+ *
27720
+ * It is a stronger claim than `D` alone, because it also picks the websocket
27721
+ * path. Naming `v27.0.0` at a v26 appliance connects on `/api/v27.0.0` with v27
27722
+ * types over a v26 server, and discovery cannot correct it — declining
27723
+ * discovery is the whole point. `D` on its own only mistyped the surface; this
27724
+ * mistypes the surface *and* dials the wrong number.
27725
+ *
27726
+ * Compatibility is still checked. Skipping discovery skips the network round
27727
+ * trip, not the range check, which is local and free. Two refusals reach a
27728
+ * caller, and they are not interchangeable:
27729
+ *
27730
+ * - a string that is not a `SupportedApiVersion` at all — only reachable from
27731
+ * JavaScript — throws a plain `Error` naming the versions that are.
27732
+ * - a version this package ships types for but cannot build a client for
27733
+ * throws {@link VersionTooNewError}, the same error discovery raises.
27734
+ *
27735
+ * The second is not hypothetical. `MAX_SUPPORTED_VERSION` is a hand-written
27736
+ * literal, and while it matches the newest generated version today, a
27737
+ * regeneration can add a year before anyone writes its client — at which point
27738
+ * that version is nameable, promised by the overload, and has nothing to build.
27739
+ * `VersionTooOldError` has no counterpart here: `MIN_SUPPORTED_VERSION` is
27740
+ * derived from the same list that constrains the type, so nothing nameable is
27741
+ * below it.
27742
+ *
27743
+ * @typeParam V - the version named in `opts.version`, when one is. The returned
27744
+ * surface is `ApiDirectoryByVersion[V]`, so it is derived rather than chosen.
27621
27745
  * @typeParam D - the generated API surface the client is typed against, as a
27622
- * whole (`call`, `job`, `event`). Every verb resolves method names against
27623
- * it, so naming a method this surface does not have is a build error.
27746
+ * whole (`call`, `job`, `event`), for the discovery path where no version is
27747
+ * named. Every verb resolves method names against it, so naming a method this
27748
+ * surface does not have is a build error.
27624
27749
  * @returns a Promise that resolves with the created client, or rejects with a
27625
27750
  * {@link VersionDiscoveryError} subclass (or a client-selection error).
27626
27751
  * Rejects if version discovery on all hostnames *fails* and is not recoverable.
@@ -27630,6 +27755,9 @@ interface CreateClientOptions {
27630
27755
  * bug. A network error alongside a version-compatibility error or a 404 does
27631
27756
  * *not* reach the fallback — see `selectRepresentativeFailure`.
27632
27757
  */
27758
+ declare function createTrueNasClient<V extends SupportedApiVersion>(opts: CreateClientOptions & {
27759
+ version: V;
27760
+ }): Promise<TrueNasApiClient<DerivedDirectory<V>>>;
27633
27761
  declare function createTrueNasClient<D extends ApiDirectoryShape = DefaultApiDirectory>(opts: CreateClientOptions): Promise<TrueNasApiClient<D>>;
27634
27762
 
27635
27763
  /**
@@ -27789,12 +27917,14 @@ declare class TrueNasApiClientV27 extends TrueNasApiClient<ApiDirectory> {
27789
27917
  */
27790
27918
  declare class VersionDiscovery {
27791
27919
  private readonly logger;
27920
+ private readonly protocol;
27792
27921
  private versionCache;
27793
- constructor(logger?: Logger);
27922
+ constructor(logger?: Logger, protocol?: ApplianceProtocol);
27923
+ private versionsUrl;
27794
27924
  /**
27795
27925
  * Discovers the API version for a given hostname.
27796
27926
  *
27797
- * Makes a GET request to `https://{hostname}/api/versions` and returns the latest
27927
+ * Makes a GET request to `{protocol}//{hostname}/api/versions` and returns the latest
27798
27928
  * compatible version. Results are cached per hostname; the cache entry is removed
27799
27929
  * on failure so the next call retries.
27800
27930
  *
@@ -27973,4 +28103,4 @@ type ApiError = JsonRpcError | TrueNasError;
27973
28103
  */
27974
28104
  declare function getApiErrorMessage(error: unknown, fallback?: string): string;
27975
28105
 
27976
- export { type ApiCallDirectory$7 as ApiCallDirectoryV25_10_0, type ApiCallDirectory$6 as ApiCallDirectoryV25_10_1, type ApiCallDirectory$5 as ApiCallDirectoryV25_10_2, type ApiCallDirectory$4 as ApiCallDirectoryV25_10_3, type ApiCallDirectory$3 as ApiCallDirectoryV25_10_4, type ApiCallDirectory$2 as ApiCallDirectoryV25_10_5, type ApiCallDirectory$1 as ApiCallDirectoryV26_0_0, type ApiCallDirectory as ApiCallDirectoryV27_0_0, type ApiDirectoryByVersion, type ApiDirectoryShape, type ApiDirectory$7 as ApiDirectoryV25_10_0, type ApiDirectory$6 as ApiDirectoryV25_10_1, type ApiDirectory$5 as ApiDirectoryV25_10_2, type ApiDirectory$4 as ApiDirectoryV25_10_3, type ApiDirectory$3 as ApiDirectoryV25_10_4, type ApiDirectory$2 as ApiDirectoryV25_10_5, type ApiDirectory$1 as ApiDirectoryV26_0_0, type ApiDirectory as ApiDirectoryV27_0_0, type ApiError, type ApiEventDirectory$7 as ApiEventDirectoryV25_10_0, type ApiEventDirectory$6 as ApiEventDirectoryV25_10_1, type ApiEventDirectory$5 as ApiEventDirectoryV25_10_2, type ApiEventDirectory$4 as ApiEventDirectoryV25_10_3, type ApiEventDirectory$3 as ApiEventDirectoryV25_10_4, type ApiEventDirectory$2 as ApiEventDirectoryV25_10_5, type ApiEventDirectory$1 as ApiEventDirectoryV26_0_0, type ApiEventDirectory as ApiEventDirectoryV27_0_0, type ApiJobDirectory$7 as ApiJobDirectoryV25_10_0, type ApiJobDirectory$6 as ApiJobDirectoryV25_10_1, type ApiJobDirectory$5 as ApiJobDirectoryV25_10_2, type ApiJobDirectory$4 as ApiJobDirectoryV25_10_3, type ApiJobDirectory$3 as ApiJobDirectoryV25_10_4, type ApiJobDirectory$2 as ApiJobDirectoryV25_10_5, type ApiJobDirectory$1 as ApiJobDirectoryV26_0_0, type ApiJobDirectory as ApiJobDirectoryV27_0_0, type ApiKeyCreate, type ApiVersion, type ApiVersionResponse, AppState, type ArgsOf, AuthError, AuthErrorCode, type AuthResponse, type BaseApiDirectory, type CallMethod, type CallParams, type CallResponse, type Container, type CreateClientOptions, type DefaultApiDirectory, type EventKind, type EventName, type EventUnion, InvalidVersionResponseError, type Job, type JobMethod, type JobParams, type JobProgress, type JobResult, JobState, type Logger, NoCompatibleVersionsError, type OperationMappings, type QueryDirectory, type QueryEntity, type QueryListOptions, type QueryMethod, type QuerySingleOptions, SUPPORTED_API_VERSIONS, type SupportedApiVersion, TrueNasApiClient, TrueNasApiClientV2510, TrueNasApiClientV26, TrueNasApiClientV27, TrueNasAuthMechanism, type TrueNasDate, VersionCompatibility, VersionDiscovery, VersionDiscoveryError, VersionDiscoveryNetworkError, VersionDiscoveryTimeoutError, VersionEndpointNotFoundError, VersionTooNewError, VersionTooOldError, consoleLogger, createTrueNasClient, getApiErrorMessage, isJobFinished, noopLogger, index$7 as v25_10_0, index$6 as v25_10_1, index$5 as v25_10_2, index$4 as v25_10_3, index$3 as v25_10_4, index$2 as v25_10_5, index$1 as v26_0_0, index as v27_0_0 };
28106
+ export { type ApiCallDirectory$7 as ApiCallDirectoryV25_10_0, type ApiCallDirectory$6 as ApiCallDirectoryV25_10_1, type ApiCallDirectory$5 as ApiCallDirectoryV25_10_2, type ApiCallDirectory$4 as ApiCallDirectoryV25_10_3, type ApiCallDirectory$3 as ApiCallDirectoryV25_10_4, type ApiCallDirectory$2 as ApiCallDirectoryV25_10_5, type ApiCallDirectory$1 as ApiCallDirectoryV26_0_0, type ApiCallDirectory as ApiCallDirectoryV27_0_0, type ApiDirectoryByVersion, type ApiDirectoryShape, type ApiDirectory$7 as ApiDirectoryV25_10_0, type ApiDirectory$6 as ApiDirectoryV25_10_1, type ApiDirectory$5 as ApiDirectoryV25_10_2, type ApiDirectory$4 as ApiDirectoryV25_10_3, type ApiDirectory$3 as ApiDirectoryV25_10_4, type ApiDirectory$2 as ApiDirectoryV25_10_5, type ApiDirectory$1 as ApiDirectoryV26_0_0, type ApiDirectory as ApiDirectoryV27_0_0, type ApiError, type ApiEventDirectory$7 as ApiEventDirectoryV25_10_0, type ApiEventDirectory$6 as ApiEventDirectoryV25_10_1, type ApiEventDirectory$5 as ApiEventDirectoryV25_10_2, type ApiEventDirectory$4 as ApiEventDirectoryV25_10_3, type ApiEventDirectory$3 as ApiEventDirectoryV25_10_4, type ApiEventDirectory$2 as ApiEventDirectoryV25_10_5, type ApiEventDirectory$1 as ApiEventDirectoryV26_0_0, type ApiEventDirectory as ApiEventDirectoryV27_0_0, type ApiJobDirectory$7 as ApiJobDirectoryV25_10_0, type ApiJobDirectory$6 as ApiJobDirectoryV25_10_1, type ApiJobDirectory$5 as ApiJobDirectoryV25_10_2, type ApiJobDirectory$4 as ApiJobDirectoryV25_10_3, type ApiJobDirectory$3 as ApiJobDirectoryV25_10_4, type ApiJobDirectory$2 as ApiJobDirectoryV25_10_5, type ApiJobDirectory$1 as ApiJobDirectoryV26_0_0, type ApiJobDirectory as ApiJobDirectoryV27_0_0, type ApiKeyCreate, type ApiVersion, type ApiVersionResponse, AppState, type ApplianceProtocol, type ArgsOf, AuthError, AuthErrorCode, type AuthResponse, type BaseApiDirectory, type CallMethod, type CallParams, type CallResponse, type Container, type CreateClientOptions, type DefaultApiDirectory, type EventKind, type EventName, type EventUnion, InvalidVersionResponseError, type Job, type JobMethod, type JobParams, type JobProgress, type JobResult, JobState, type Logger, NoCompatibleVersionsError, type OperationMappings, type QueryDirectory, type QueryEntity, type QueryListOptions, type QueryMethod, type QuerySingleOptions, SUPPORTED_API_VERSIONS, type SupportedApiVersion, TrueNasApiClient, TrueNasApiClientV2510, TrueNasApiClientV26, TrueNasApiClientV27, TrueNasAuthMechanism, type TrueNasDate, VersionCompatibility, VersionDiscovery, VersionDiscoveryError, VersionDiscoveryNetworkError, VersionDiscoveryTimeoutError, VersionEndpointNotFoundError, VersionTooNewError, VersionTooOldError, consoleLogger, createTrueNasClient, getApiErrorMessage, isJobFinished, noopLogger, index$7 as v25_10_0, index$6 as v25_10_1, index$5 as v25_10_2, index$4 as v25_10_3, index$3 as v25_10_4, index$2 as v25_10_5, index$1 as v26_0_0, index as v27_0_0 };
package/dist/index.d.ts CHANGED
@@ -12460,6 +12460,16 @@ declare class TrueNasSocket {
12460
12460
  complete(): void;
12461
12461
  }
12462
12462
 
12463
+ /**
12464
+ * The scheme used to reach the appliance, in `location.protocol` form.
12465
+ *
12466
+ * Colon included, so a caller served *by the appliance* can pass
12467
+ * `location.protocol` unchanged. That equivalence only holds same-origin: this
12468
+ * value is spliced onto the hostname the client connects to, so a page served
12469
+ * from somewhere else must say what the appliance uses, not what it uses.
12470
+ */
12471
+ type ApplianceProtocol = 'http:' | 'https:';
12472
+
12463
12473
  interface ActiveConnection {
12464
12474
  ws: TrueNasSocket;
12465
12475
  hostname: string;
@@ -12482,6 +12492,7 @@ declare class TrueNasConnection {
12482
12492
  readonly retryDelay: number;
12483
12493
  readonly maxRetry: number;
12484
12494
  readonly logger: Logger;
12495
+ readonly protocol: ApplianceProtocol;
12485
12496
  opened: BehaviorSubject<boolean>;
12486
12497
  closed: Subject<void>;
12487
12498
  hostname: BehaviorSubject<string>;
@@ -12544,7 +12555,7 @@ declare class TrueNasConnection {
12544
12555
  * observable which always emits messages from the current socket.
12545
12556
  */
12546
12557
  messages$: Observable<TrueNasMessage>;
12547
- constructor(initialEnabled: boolean, hostnames: string[], systemUuid: string, websocketPath: string, systemName?: string | undefined, retryDelay?: number, maxRetry?: number, logger?: Logger);
12558
+ constructor(initialEnabled: boolean, hostnames: string[], systemUuid: string, websocketPath: string, systemName?: string | undefined, retryDelay?: number, maxRetry?: number, logger?: Logger, protocol?: ApplianceProtocol);
12548
12559
  /**
12549
12560
  * whether the connection has exhausted its retries — the **cumulative** snapshot, read
12550
12561
  * synchronously. (Formerly `hasConnectionError()`; renamed to disambiguate it from the
@@ -13192,7 +13203,8 @@ declare abstract class TrueNasApiClient<D extends ApiDirectoryShape = BaseApiDir
13192
13203
  protected readonly systemName: string | undefined;
13193
13204
  /** Logger forwarded to the connection (defaults to a no-op). */
13194
13205
  protected readonly logger: Logger;
13195
- constructor(uuid: string, hostnames: string[], version: ApiVersion, enabled: boolean, systemName?: string, logger?: Logger);
13206
+ protected readonly protocol: ApplianceProtocol;
13207
+ constructor(uuid: string, hostnames: string[], version: ApiVersion, enabled: boolean, systemName?: string, logger?: Logger, protocol?: ApplianceProtocol);
13196
13208
  /**
13197
13209
  * Get current connection status.
13198
13210
  * @returns true if WebSocket is connected
@@ -27559,6 +27571,19 @@ declare const SUPPORTED_API_VERSIONS: readonly ["v25.10.0", "v25.10.1", "v25.10.
27559
27571
  * how the missing 22 methods went unnoticed in the first place.
27560
27572
  */
27561
27573
  type DefaultApiDirectory = ApiDirectory$7;
27574
+ /**
27575
+ * The surface a named version derives, falling back when nothing was narrowed.
27576
+ *
27577
+ * `V` only pins a directory when inference narrowed it. A wrapper typed
27578
+ * `(version: SupportedApiVersion)` widens it back to the whole union, and
27579
+ * indexing by a union yields a union of directories whose usable methods are
27580
+ * their *intersection* — narrower than the default surface, so naming the
27581
+ * version would buy fewer methods than naming nothing. That case falls back to
27582
+ * {@link DefaultApiDirectory} instead, matching every other shape that loses
27583
+ * the literal. A partial union still derives: methods common to the versions
27584
+ * named is the right answer for "one of these".
27585
+ */
27586
+ type DerivedDirectory<V extends SupportedApiVersion> = SupportedApiVersion extends V ? DefaultApiDirectory : ApiDirectoryByVersion[V];
27562
27587
  /** Options for {@link createTrueNasClient}. */
27563
27588
  interface CreateClientOptions {
27564
27589
  /** System UUID. */
@@ -27582,12 +27607,44 @@ interface CreateClientOptions {
27582
27607
  * through the client, to the connection.
27583
27608
  */
27584
27609
  logger?: Logger;
27610
+ /**
27611
+ * The appliance's API version, when the caller already knows it.
27612
+ *
27613
+ * Supplying it skips version discovery entirely — no `GET /api/versions`, no
27614
+ * CORS fallback — and *derives* the client's typed surface from the string,
27615
+ * so `version: 'v27.0.0'` yields `TrueNasApiClient<ApiDirectoryV27_0_0>`
27616
+ * without the caller asserting it through a type parameter.
27617
+ */
27618
+ version?: SupportedApiVersion;
27619
+ /**
27620
+ * The scheme to reach the appliance on, in `location.protocol` form.
27621
+ *
27622
+ * Selects both halves of the transport: `https:` gives `https` discovery and
27623
+ * a `wss` socket, `http:` gives `http` and `ws`. Defaults to `https:`, which
27624
+ * is what an appliance serves and what Connect uses.
27625
+ *
27626
+ * This describes the *appliance*, not the page. Passing
27627
+ * `location.protocol` is correct when the appliance serves the page — the
27628
+ * same-origin case this exists for — and wrong otherwise. A page on
27629
+ * `http://localhost:5173` talking to an https appliance gets both halves
27630
+ * wrong, but only one of them says so: `fetch` follows the redirect and
27631
+ * discovery appears to work, while the WebSocket has no such tolerance and
27632
+ * fails the handshake without naming the scheme.
27633
+ *
27634
+ * Omitting it against a plaintext appliance is the quieter failure and the
27635
+ * likelier one, since it is the case this option exists for. Discovery tries
27636
+ * `https`, `fetch` rejects, and that is indistinguishable from the CORS block
27637
+ * v25.10.0 has on `/api/versions` — so the fallback fires and the caller gets
27638
+ * a client pinned to v25.10.0, warned about only in the log.
27639
+ */
27640
+ protocol?: ApplianceProtocol;
27585
27641
  }
27586
27642
  /**
27587
27643
  * Creates a version-specific TrueNAS API client.
27588
27644
  *
27589
27645
  * 1. Discovers the API version (`GET /api/versions`), asking every hostname in
27590
- * parallel. The first usable answer wins.
27646
+ * parallel. The first usable answer wins — *unless* `opts.version` says
27647
+ * which version this is, in which case discovery is skipped entirely.
27591
27648
  * 2. Selects the matching client implementation (`v25.10.x` -> `TrueNasApiClientV2510`,
27592
27649
  * `v26.x.y` -> `TrueNasApiClientV26`, `v27.x.y` -> `TrueNasApiClientV27`).
27593
27650
  * 3. Instantiates and returns it.
@@ -27618,9 +27675,77 @@ interface CreateClientOptions {
27618
27675
  * supported version. Operations that must work across versions belong on
27619
27676
  * `client.ops`, which resolves them at runtime.
27620
27677
  *
27678
+ * ## Naming the version instead
27679
+ *
27680
+ * A caller that already knows its appliance — a UI served by the appliance
27681
+ * itself, a test harness against a pinned image — can say so and skip discovery
27682
+ * altogether:
27683
+ *
27684
+ * ```typescript
27685
+ * const client = await createTrueNasClient({
27686
+ * uuid, hostnames, enabled: true, version: 'v27.0.0',
27687
+ * });
27688
+ * // client: TrueNasApiClient<ApiDirectoryV27_0_0>, derived from the string
27689
+ * ```
27690
+ *
27691
+ * The surface is *derived* rather than asserted: `ApiDirectoryByVersion` maps
27692
+ * the version string to its directory, so the caller writes no cast and names
27693
+ * no directory type. A version this package ships no types for does not
27694
+ * compile.
27695
+ *
27696
+ * **The derivation needs the version to be literal at the call site.** It comes
27697
+ * from inference on `{ version: V }`, so it holds for a string literal written
27698
+ * in the options object (or a `const`-typed one). It does not survive
27699
+ * indirection:
27700
+ *
27701
+ * - `createTrueNasClient<D>({ …, version: 'v27.0.0' })` — an explicit type
27702
+ * argument makes the derived overload inapplicable, so `D` wins.
27703
+ * - `(v?: SupportedApiVersion) => createTrueNasClient({ …, version: v })` — the
27704
+ * property is `SupportedApiVersion | undefined`, which no `V` satisfies.
27705
+ * - `(v: SupportedApiVersion) => …` — reaches this overload, but `V` widens to
27706
+ * the whole union, which derives nothing.
27707
+ * - `const opts: CreateClientOptions = { …, version: 'v27.0.0' }` — the
27708
+ * annotation widens the property before the call sees it.
27709
+ *
27710
+ * All of them compile, run against the named version, and type as
27711
+ * {@link DefaultApiDirectory}. That fails in the safe direction — understated
27712
+ * types give a compile error at the method call rather than a runtime surprise —
27713
+ * but it is silent, so a wrapper that forwards a version gets none of the
27714
+ * surface it named. Keep the literal at the call site, and if you are adding
27715
+ * `version` to an existing `createTrueNasClient<ApiDirectoryV26_0_0>(opts)`
27716
+ * call, delete the type argument in the same edit.
27717
+ *
27718
+ * Two consequences worth knowing before reaching for it.
27719
+ *
27720
+ * It is a stronger claim than `D` alone, because it also picks the websocket
27721
+ * path. Naming `v27.0.0` at a v26 appliance connects on `/api/v27.0.0` with v27
27722
+ * types over a v26 server, and discovery cannot correct it — declining
27723
+ * discovery is the whole point. `D` on its own only mistyped the surface; this
27724
+ * mistypes the surface *and* dials the wrong number.
27725
+ *
27726
+ * Compatibility is still checked. Skipping discovery skips the network round
27727
+ * trip, not the range check, which is local and free. Two refusals reach a
27728
+ * caller, and they are not interchangeable:
27729
+ *
27730
+ * - a string that is not a `SupportedApiVersion` at all — only reachable from
27731
+ * JavaScript — throws a plain `Error` naming the versions that are.
27732
+ * - a version this package ships types for but cannot build a client for
27733
+ * throws {@link VersionTooNewError}, the same error discovery raises.
27734
+ *
27735
+ * The second is not hypothetical. `MAX_SUPPORTED_VERSION` is a hand-written
27736
+ * literal, and while it matches the newest generated version today, a
27737
+ * regeneration can add a year before anyone writes its client — at which point
27738
+ * that version is nameable, promised by the overload, and has nothing to build.
27739
+ * `VersionTooOldError` has no counterpart here: `MIN_SUPPORTED_VERSION` is
27740
+ * derived from the same list that constrains the type, so nothing nameable is
27741
+ * below it.
27742
+ *
27743
+ * @typeParam V - the version named in `opts.version`, when one is. The returned
27744
+ * surface is `ApiDirectoryByVersion[V]`, so it is derived rather than chosen.
27621
27745
  * @typeParam D - the generated API surface the client is typed against, as a
27622
- * whole (`call`, `job`, `event`). Every verb resolves method names against
27623
- * it, so naming a method this surface does not have is a build error.
27746
+ * whole (`call`, `job`, `event`), for the discovery path where no version is
27747
+ * named. Every verb resolves method names against it, so naming a method this
27748
+ * surface does not have is a build error.
27624
27749
  * @returns a Promise that resolves with the created client, or rejects with a
27625
27750
  * {@link VersionDiscoveryError} subclass (or a client-selection error).
27626
27751
  * Rejects if version discovery on all hostnames *fails* and is not recoverable.
@@ -27630,6 +27755,9 @@ interface CreateClientOptions {
27630
27755
  * bug. A network error alongside a version-compatibility error or a 404 does
27631
27756
  * *not* reach the fallback — see `selectRepresentativeFailure`.
27632
27757
  */
27758
+ declare function createTrueNasClient<V extends SupportedApiVersion>(opts: CreateClientOptions & {
27759
+ version: V;
27760
+ }): Promise<TrueNasApiClient<DerivedDirectory<V>>>;
27633
27761
  declare function createTrueNasClient<D extends ApiDirectoryShape = DefaultApiDirectory>(opts: CreateClientOptions): Promise<TrueNasApiClient<D>>;
27634
27762
 
27635
27763
  /**
@@ -27789,12 +27917,14 @@ declare class TrueNasApiClientV27 extends TrueNasApiClient<ApiDirectory> {
27789
27917
  */
27790
27918
  declare class VersionDiscovery {
27791
27919
  private readonly logger;
27920
+ private readonly protocol;
27792
27921
  private versionCache;
27793
- constructor(logger?: Logger);
27922
+ constructor(logger?: Logger, protocol?: ApplianceProtocol);
27923
+ private versionsUrl;
27794
27924
  /**
27795
27925
  * Discovers the API version for a given hostname.
27796
27926
  *
27797
- * Makes a GET request to `https://{hostname}/api/versions` and returns the latest
27927
+ * Makes a GET request to `{protocol}//{hostname}/api/versions` and returns the latest
27798
27928
  * compatible version. Results are cached per hostname; the cache entry is removed
27799
27929
  * on failure so the next call retries.
27800
27930
  *
@@ -27973,4 +28103,4 @@ type ApiError = JsonRpcError | TrueNasError;
27973
28103
  */
27974
28104
  declare function getApiErrorMessage(error: unknown, fallback?: string): string;
27975
28105
 
27976
- export { type ApiCallDirectory$7 as ApiCallDirectoryV25_10_0, type ApiCallDirectory$6 as ApiCallDirectoryV25_10_1, type ApiCallDirectory$5 as ApiCallDirectoryV25_10_2, type ApiCallDirectory$4 as ApiCallDirectoryV25_10_3, type ApiCallDirectory$3 as ApiCallDirectoryV25_10_4, type ApiCallDirectory$2 as ApiCallDirectoryV25_10_5, type ApiCallDirectory$1 as ApiCallDirectoryV26_0_0, type ApiCallDirectory as ApiCallDirectoryV27_0_0, type ApiDirectoryByVersion, type ApiDirectoryShape, type ApiDirectory$7 as ApiDirectoryV25_10_0, type ApiDirectory$6 as ApiDirectoryV25_10_1, type ApiDirectory$5 as ApiDirectoryV25_10_2, type ApiDirectory$4 as ApiDirectoryV25_10_3, type ApiDirectory$3 as ApiDirectoryV25_10_4, type ApiDirectory$2 as ApiDirectoryV25_10_5, type ApiDirectory$1 as ApiDirectoryV26_0_0, type ApiDirectory as ApiDirectoryV27_0_0, type ApiError, type ApiEventDirectory$7 as ApiEventDirectoryV25_10_0, type ApiEventDirectory$6 as ApiEventDirectoryV25_10_1, type ApiEventDirectory$5 as ApiEventDirectoryV25_10_2, type ApiEventDirectory$4 as ApiEventDirectoryV25_10_3, type ApiEventDirectory$3 as ApiEventDirectoryV25_10_4, type ApiEventDirectory$2 as ApiEventDirectoryV25_10_5, type ApiEventDirectory$1 as ApiEventDirectoryV26_0_0, type ApiEventDirectory as ApiEventDirectoryV27_0_0, type ApiJobDirectory$7 as ApiJobDirectoryV25_10_0, type ApiJobDirectory$6 as ApiJobDirectoryV25_10_1, type ApiJobDirectory$5 as ApiJobDirectoryV25_10_2, type ApiJobDirectory$4 as ApiJobDirectoryV25_10_3, type ApiJobDirectory$3 as ApiJobDirectoryV25_10_4, type ApiJobDirectory$2 as ApiJobDirectoryV25_10_5, type ApiJobDirectory$1 as ApiJobDirectoryV26_0_0, type ApiJobDirectory as ApiJobDirectoryV27_0_0, type ApiKeyCreate, type ApiVersion, type ApiVersionResponse, AppState, type ArgsOf, AuthError, AuthErrorCode, type AuthResponse, type BaseApiDirectory, type CallMethod, type CallParams, type CallResponse, type Container, type CreateClientOptions, type DefaultApiDirectory, type EventKind, type EventName, type EventUnion, InvalidVersionResponseError, type Job, type JobMethod, type JobParams, type JobProgress, type JobResult, JobState, type Logger, NoCompatibleVersionsError, type OperationMappings, type QueryDirectory, type QueryEntity, type QueryListOptions, type QueryMethod, type QuerySingleOptions, SUPPORTED_API_VERSIONS, type SupportedApiVersion, TrueNasApiClient, TrueNasApiClientV2510, TrueNasApiClientV26, TrueNasApiClientV27, TrueNasAuthMechanism, type TrueNasDate, VersionCompatibility, VersionDiscovery, VersionDiscoveryError, VersionDiscoveryNetworkError, VersionDiscoveryTimeoutError, VersionEndpointNotFoundError, VersionTooNewError, VersionTooOldError, consoleLogger, createTrueNasClient, getApiErrorMessage, isJobFinished, noopLogger, index$7 as v25_10_0, index$6 as v25_10_1, index$5 as v25_10_2, index$4 as v25_10_3, index$3 as v25_10_4, index$2 as v25_10_5, index$1 as v26_0_0, index as v27_0_0 };
28106
+ export { type ApiCallDirectory$7 as ApiCallDirectoryV25_10_0, type ApiCallDirectory$6 as ApiCallDirectoryV25_10_1, type ApiCallDirectory$5 as ApiCallDirectoryV25_10_2, type ApiCallDirectory$4 as ApiCallDirectoryV25_10_3, type ApiCallDirectory$3 as ApiCallDirectoryV25_10_4, type ApiCallDirectory$2 as ApiCallDirectoryV25_10_5, type ApiCallDirectory$1 as ApiCallDirectoryV26_0_0, type ApiCallDirectory as ApiCallDirectoryV27_0_0, type ApiDirectoryByVersion, type ApiDirectoryShape, type ApiDirectory$7 as ApiDirectoryV25_10_0, type ApiDirectory$6 as ApiDirectoryV25_10_1, type ApiDirectory$5 as ApiDirectoryV25_10_2, type ApiDirectory$4 as ApiDirectoryV25_10_3, type ApiDirectory$3 as ApiDirectoryV25_10_4, type ApiDirectory$2 as ApiDirectoryV25_10_5, type ApiDirectory$1 as ApiDirectoryV26_0_0, type ApiDirectory as ApiDirectoryV27_0_0, type ApiError, type ApiEventDirectory$7 as ApiEventDirectoryV25_10_0, type ApiEventDirectory$6 as ApiEventDirectoryV25_10_1, type ApiEventDirectory$5 as ApiEventDirectoryV25_10_2, type ApiEventDirectory$4 as ApiEventDirectoryV25_10_3, type ApiEventDirectory$3 as ApiEventDirectoryV25_10_4, type ApiEventDirectory$2 as ApiEventDirectoryV25_10_5, type ApiEventDirectory$1 as ApiEventDirectoryV26_0_0, type ApiEventDirectory as ApiEventDirectoryV27_0_0, type ApiJobDirectory$7 as ApiJobDirectoryV25_10_0, type ApiJobDirectory$6 as ApiJobDirectoryV25_10_1, type ApiJobDirectory$5 as ApiJobDirectoryV25_10_2, type ApiJobDirectory$4 as ApiJobDirectoryV25_10_3, type ApiJobDirectory$3 as ApiJobDirectoryV25_10_4, type ApiJobDirectory$2 as ApiJobDirectoryV25_10_5, type ApiJobDirectory$1 as ApiJobDirectoryV26_0_0, type ApiJobDirectory as ApiJobDirectoryV27_0_0, type ApiKeyCreate, type ApiVersion, type ApiVersionResponse, AppState, type ApplianceProtocol, type ArgsOf, AuthError, AuthErrorCode, type AuthResponse, type BaseApiDirectory, type CallMethod, type CallParams, type CallResponse, type Container, type CreateClientOptions, type DefaultApiDirectory, type EventKind, type EventName, type EventUnion, InvalidVersionResponseError, type Job, type JobMethod, type JobParams, type JobProgress, type JobResult, JobState, type Logger, NoCompatibleVersionsError, type OperationMappings, type QueryDirectory, type QueryEntity, type QueryListOptions, type QueryMethod, type QuerySingleOptions, SUPPORTED_API_VERSIONS, type SupportedApiVersion, TrueNasApiClient, TrueNasApiClientV2510, TrueNasApiClientV26, TrueNasApiClientV27, TrueNasAuthMechanism, type TrueNasDate, VersionCompatibility, VersionDiscovery, VersionDiscoveryError, VersionDiscoveryNetworkError, VersionDiscoveryTimeoutError, VersionEndpointNotFoundError, VersionTooNewError, VersionTooOldError, consoleLogger, createTrueNasClient, getApiErrorMessage, isJobFinished, noopLogger, index$7 as v25_10_0, index$6 as v25_10_1, index$5 as v25_10_2, index$4 as v25_10_3, index$3 as v25_10_4, index$2 as v25_10_5, index$1 as v26_0_0, index as v27_0_0 };
package/dist/index.js CHANGED
@@ -692,11 +692,19 @@ var TrueNasSocket = class {
692
692
  }
693
693
  };
694
694
 
695
+ // src/types/transport.type.ts
696
+ function httpScheme(protocol) {
697
+ return protocol === "http:" ? "http:" : "https:";
698
+ }
699
+ function socketScheme(protocol) {
700
+ return protocol === "http:" ? "ws:" : "wss:";
701
+ }
702
+
695
703
  // src/connection/truenas-connection.ts
696
704
  var tenSeconds = 10 * 1e3;
697
705
  var twentySeconds = 20 * 1e3;
698
706
  var TrueNasConnection = class {
699
- constructor(initialEnabled, hostnames, systemUuid, websocketPath, systemName, retryDelay = tenSeconds, maxRetry = 3, logger = noopLogger) {
707
+ constructor(initialEnabled, hostnames, systemUuid, websocketPath, systemName, retryDelay = tenSeconds, maxRetry = 3, logger = noopLogger, protocol = "https:") {
700
708
  this.hostnames = hostnames;
701
709
  this.systemUuid = systemUuid;
702
710
  this.websocketPath = websocketPath;
@@ -704,6 +712,7 @@ var TrueNasConnection = class {
704
712
  this.retryDelay = retryDelay;
705
713
  this.maxRetry = maxRetry;
706
714
  this.logger = logger;
715
+ this.protocol = protocol;
707
716
  // compatibility properties
708
717
  this.opened = new BehaviorSubject(false);
709
718
  this.closed = new Subject();
@@ -900,7 +909,7 @@ var TrueNasConnection = class {
900
909
  * error if the connection is never established and will not complete until unsubscribed from or closed.
901
910
  */
902
911
  createSocket(hostname) {
903
- const url = `wss://${hostname}${this.websocketPath}`;
912
+ const url = `${socketScheme(this.protocol)}//${hostname}${this.websocketPath}`;
904
913
  let hasOpened = false;
905
914
  return new Observable((subscriber) => {
906
915
  const ws = new TrueNasSocket({
@@ -2999,13 +3008,14 @@ function getWebSocketPath(version) {
2999
3008
 
3000
3009
  // src/client/truenas-api-client.ts
3001
3010
  var TrueNasApiClient = class {
3002
- constructor(uuid, hostnames, version, enabled, systemName, logger = noopLogger) {
3011
+ constructor(uuid, hostnames, version, enabled, systemName, logger = noopLogger, protocol = "https:") {
3003
3012
  this.uuid = uuid;
3004
3013
  this.hostnames = hostnames;
3005
3014
  this.version = version;
3006
3015
  this.enabled = enabled;
3007
3016
  this.systemName = systemName;
3008
3017
  this.logger = logger;
3018
+ this.protocol = protocol;
3009
3019
  this.connection = this.createConnection();
3010
3020
  this.authenticator = this.createAuthenticator();
3011
3021
  this.api = this.createApi();
@@ -3048,7 +3058,8 @@ var TrueNasApiClient = class {
3048
3058
  // retryDelay (use default)
3049
3059
  void 0,
3050
3060
  // maxRetry (use default)
3051
- this.logger
3061
+ this.logger,
3062
+ this.protocol
3052
3063
  );
3053
3064
  }
3054
3065
  /**
@@ -3442,14 +3453,18 @@ function hasErrorName(error, expected) {
3442
3453
  return typeof error === "object" && error !== null && "name" in error && error.name === expected;
3443
3454
  }
3444
3455
  var VersionDiscovery = class {
3445
- constructor(logger = noopLogger) {
3456
+ constructor(logger = noopLogger, protocol = "https:") {
3446
3457
  this.logger = logger;
3458
+ this.protocol = protocol;
3447
3459
  this.versionCache = /* @__PURE__ */ new Map();
3448
3460
  }
3461
+ versionsUrl(hostname) {
3462
+ return `${httpScheme(this.protocol)}//${hostname}/api/versions`;
3463
+ }
3449
3464
  /**
3450
3465
  * Discovers the API version for a given hostname.
3451
3466
  *
3452
- * Makes a GET request to `https://{hostname}/api/versions` and returns the latest
3467
+ * Makes a GET request to `{protocol}//{hostname}/api/versions` and returns the latest
3453
3468
  * compatible version. Results are cached per hostname; the cache entry is removed
3454
3469
  * on failure so the next call retries.
3455
3470
  *
@@ -3463,8 +3478,10 @@ var VersionDiscovery = class {
3463
3478
  this.logger.info("Version discovery cache hit", { hostname });
3464
3479
  return cached;
3465
3480
  }
3466
- const url = `https://${hostname}/api/versions`;
3467
- this.logger.info("Starting version discovery", { hostname, url });
3481
+ this.logger.info("Starting version discovery", {
3482
+ hostname,
3483
+ url: this.versionsUrl(hostname)
3484
+ });
3468
3485
  const discovery$ = defer(() => from(this.fetchVersions(hostname))).pipe(
3469
3486
  map$1((versionStrings) => this.selectVersion(hostname, versionStrings)),
3470
3487
  catchError((error) => {
@@ -3502,7 +3519,7 @@ var VersionDiscovery = class {
3502
3519
  * misfile as a network error. Validating here keeps it an `InvalidVersionResponseError`.
3503
3520
  */
3504
3521
  async fetchVersions(hostname) {
3505
- const url = `https://${hostname}/api/versions`;
3522
+ const url = this.versionsUrl(hostname);
3506
3523
  const controller = new AbortController();
3507
3524
  const timer2 = setTimeout(() => controller.abort(), discoveryTimeoutMs);
3508
3525
  try {
@@ -3642,12 +3659,40 @@ async function createTrueNasClient(opts) {
3642
3659
  `Cannot create client for system ${uuid}: hostnames array is empty`
3643
3660
  );
3644
3661
  }
3645
- const versionDiscovery = new VersionDiscovery(logger);
3646
3662
  logger.info("Creating versioned API client", {
3647
3663
  uuid: uuid.slice(0, 8),
3648
3664
  hostnames: hostnames.join(", "),
3649
3665
  systemName
3650
3666
  });
3667
+ if (opts.version !== void 0) {
3668
+ if (!SUPPORTED_API_VERSIONS.includes(opts.version)) {
3669
+ throw new Error(
3670
+ `Cannot create client for system ${uuid}: '${opts.version}' is not a version this package ships types for. Supported: ${SUPPORTED_API_VERSIONS.join(", ")}.`
3671
+ );
3672
+ }
3673
+ const known = parseApiVersion(opts.version);
3674
+ if (!known) {
3675
+ throw new Error(
3676
+ `Cannot create client for system ${uuid}: supported version '${opts.version}' failed to parse.`
3677
+ );
3678
+ }
3679
+ const compatibility = checkVersionCompatibility(known);
3680
+ if (compatibility === "too-new" /* TooNew */) {
3681
+ throw new VersionTooNewError(hostnames[0], [known.version]);
3682
+ }
3683
+ if (compatibility !== "compatible" /* Compatible */) {
3684
+ throw new Error(
3685
+ `Cannot create client for system ${uuid}: the supported version range is not usable (${apiVersionConfig.MIN_SUPPORTED_VERSION}..${apiVersionConfig.MAX_SUPPORTED_VERSION}).`
3686
+ );
3687
+ }
3688
+ logger.info("API version supplied by the caller, skipping discovery", {
3689
+ uuid: uuid.slice(0, 8),
3690
+ version: known.version,
3691
+ websocketPath: known.websocketPath
3692
+ });
3693
+ return instantiateClientForVersion(known, opts, logger);
3694
+ }
3695
+ const versionDiscovery = new VersionDiscovery(logger, opts.protocol);
3651
3696
  let version;
3652
3697
  try {
3653
3698
  const winner = await discoverVersionFromAnyHostname(
@@ -3756,7 +3801,8 @@ function instantiateClientForVersion(version, opts, logger) {
3756
3801
  version,
3757
3802
  enabled,
3758
3803
  systemName,
3759
- logger
3804
+ logger,
3805
+ opts.protocol
3760
3806
  );
3761
3807
  }
3762
3808
  function errorMessageOrDefault(error, fallback) {