spindb 0.34.5 → 0.35.3

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.
Files changed (51) hide show
  1. package/README.md +4 -4
  2. package/cli/commands/create.ts +22 -1
  3. package/cli/commands/engines.ts +56 -22
  4. package/cli/commands/menu/container-handlers.ts +17 -1
  5. package/cli/commands/menu/engine-handlers.ts +48 -29
  6. package/cli/ui/theme.ts +5 -2
  7. package/config/engines-registry.ts +56 -0
  8. package/config/engines.json +14 -3
  9. package/config/engines.schema.json +13 -0
  10. package/core/base-binary-manager.ts +6 -2
  11. package/core/base-document-binary-manager.ts +5 -2
  12. package/core/base-embedded-binary-manager.ts +5 -2
  13. package/core/base-server-binary-manager.ts +5 -2
  14. package/core/hostdb-client.ts +157 -22
  15. package/core/hostdb-metadata.ts +67 -43
  16. package/engines/clickhouse/binary-urls.ts +1 -1
  17. package/engines/cockroachdb/binary-urls.ts +9 -7
  18. package/engines/cockroachdb/hostdb-releases.ts +18 -106
  19. package/engines/cockroachdb/version-maps.ts +1 -1
  20. package/engines/couchdb/binary-urls.ts +1 -1
  21. package/engines/duckdb/binary-urls.ts +1 -1
  22. package/engines/duckdb/index.ts +4 -74
  23. package/engines/ferretdb/README.md +76 -38
  24. package/engines/ferretdb/backup.ts +18 -10
  25. package/engines/ferretdb/binary-manager.ts +233 -35
  26. package/engines/ferretdb/binary-urls.ts +69 -24
  27. package/engines/ferretdb/index.ts +424 -213
  28. package/engines/ferretdb/restore.ts +23 -16
  29. package/engines/ferretdb/version-maps.ts +36 -8
  30. package/engines/index.ts +3 -4
  31. package/engines/influxdb/binary-urls.ts +1 -1
  32. package/engines/mariadb/binary-urls.ts +2 -2
  33. package/engines/meilisearch/binary-urls.ts +1 -1
  34. package/engines/mysql/binary-urls.ts +2 -2
  35. package/engines/postgresql/binary-urls.ts +1 -1
  36. package/engines/qdrant/binary-urls.ts +1 -1
  37. package/engines/questdb/binary-manager.ts +16 -9
  38. package/engines/questdb/binary-urls.ts +9 -10
  39. package/engines/questdb/hostdb-releases.ts +19 -97
  40. package/engines/questdb/version-maps.ts +2 -2
  41. package/engines/redis/binary-urls.ts +1 -8
  42. package/engines/sqlite/binary-urls.ts +1 -1
  43. package/engines/sqlite/index.ts +4 -74
  44. package/engines/surrealdb/binary-urls.ts +9 -7
  45. package/engines/surrealdb/hostdb-releases.ts +18 -106
  46. package/engines/surrealdb/version-maps.ts +1 -1
  47. package/engines/typedb/binary-urls.ts +10 -8
  48. package/engines/typedb/hostdb-releases.ts +18 -113
  49. package/engines/typedb/version-maps.ts +1 -1
  50. package/engines/valkey/binary-urls.ts +1 -1
  51. package/package.json +4 -1
@@ -1,9 +1,15 @@
1
1
  /**
2
2
  * FerretDB Composite Binary Manager
3
3
  *
4
- * Handles downloading and managing both FerretDB binaries:
5
- * 1. ferretdb - The MongoDB-compatible Go proxy
6
- * 2. postgresql-documentdb - PostgreSQL 17 with DocumentDB extension
4
+ * Handles downloading and managing FerretDB binaries:
5
+ *
6
+ * v2 (default): Two binaries required:
7
+ * 1. ferretdb - The MongoDB-compatible Go proxy
8
+ * 2. postgresql-documentdb - PostgreSQL 17 with DocumentDB extension
9
+ *
10
+ * v1: Two binaries, but backend is shared:
11
+ * 1. ferretdb - The MongoDB-compatible Go proxy
12
+ * 2. Plain PostgreSQL - Managed by postgresqlBinaryManager (shared with standalone PG containers)
7
13
  *
8
14
  * This is a composite manager that coordinates the installation of both
9
15
  * binaries, which are required for FerretDB to function.
@@ -15,9 +21,10 @@ import { join } from 'path'
15
21
  import { Readable } from 'stream'
16
22
  import { pipeline } from 'stream/promises'
17
23
  import { paths } from '../../config/paths'
18
- import { spawnAsync } from '../../core/spawn-utils'
24
+ import { spawnAsync, extractWindowsArchive } from '../../core/spawn-utils'
19
25
  import { isRenameFallbackError } from '../../core/fs-error-utils'
20
26
  import { logDebug } from '../../core/error-handler'
27
+ import { fetchWithRegistryFallback } from '../../core/hostdb-client'
21
28
  import {
22
29
  Engine,
23
30
  Platform,
@@ -31,12 +38,15 @@ import {
31
38
  normalizeVersion,
32
39
  normalizeDocumentDBVersion,
33
40
  DEFAULT_DOCUMENTDB_VERSION,
41
+ DEFAULT_V1_POSTGRESQL_VERSION,
42
+ isV1,
34
43
  } from './version-maps'
35
44
  import {
36
45
  isPlatformSupported,
37
46
  getFerretDBBinaryUrl,
38
47
  getDocumentDBBinaryUrl,
39
48
  } from './binary-urls'
49
+ import { postgresqlBinaryManager } from '../postgresql/binary-manager'
40
50
 
41
51
  const DOWNLOAD_TIMEOUT_MS = 5 * 60 * 1000 // 5 minutes
42
52
 
@@ -45,7 +55,7 @@ const DOWNLOAD_TIMEOUT_MS = 5 * 60 * 1000 // 5 minutes
45
55
  */
46
56
  export type FerretDBBinaryPaths = {
47
57
  ferretdbPath: string // Path to ferretdb binary directory
48
- documentdbPath: string // Path to postgresql-documentdb binary directory
58
+ backendPath: string // Path to backend binary directory (postgresql-documentdb for v2, postgresql for v1)
49
59
  }
50
60
 
51
61
  /**
@@ -56,9 +66,14 @@ export type FerretDBBinaryPaths = {
56
66
  class FerretDBCompositeBinaryManager {
57
67
  /**
58
68
  * Check if the current platform supports FerretDB
69
+ * @param version - Optional version to check platform support for (v1 supports Windows, v2 does not)
59
70
  */
60
- isPlatformSupported(platform: Platform, arch: Arch): boolean {
61
- return isPlatformSupported(platform, arch)
71
+ isPlatformSupported(
72
+ platform: Platform,
73
+ arch: Arch,
74
+ version?: string,
75
+ ): boolean {
76
+ return isPlatformSupported(platform, arch, version)
62
77
  }
63
78
 
64
79
  /**
@@ -85,7 +100,6 @@ class FerretDBCompositeBinaryManager {
85
100
  backendVersion: string = DEFAULT_DOCUMENTDB_VERSION,
86
101
  ): Promise<boolean> {
87
102
  const fullVersion = this.getFullVersion(version)
88
- const fullBackendVersion = this.getFullDocumentDBVersion(backendVersion)
89
103
 
90
104
  // Check FerretDB proxy
91
105
  const ferretdbPath = this.getFerretDBBinaryPath(fullVersion, platform, arch)
@@ -95,7 +109,18 @@ class FerretDBCompositeBinaryManager {
95
109
  return false
96
110
  }
97
111
 
98
- // Check postgresql-documentdb
112
+ // Check backend
113
+ if (isV1(version)) {
114
+ // v1: check plain PostgreSQL via postgresqlBinaryManager
115
+ return postgresqlBinaryManager.isInstalled(
116
+ DEFAULT_V1_POSTGRESQL_VERSION,
117
+ platform,
118
+ arch,
119
+ )
120
+ }
121
+
122
+ // v2: check postgresql-documentdb
123
+ const fullBackendVersion = this.getFullDocumentDBVersion(backendVersion)
99
124
  const documentdbPath = this.getDocumentDBBinaryPath(
100
125
  fullBackendVersion,
101
126
  platform,
@@ -176,6 +201,82 @@ class FerretDBCompositeBinaryManager {
176
201
  }
177
202
  }
178
203
 
204
+ /**
205
+ * Get the backend binary directory path for a FerretDB version.
206
+ * For v1: returns the plain PostgreSQL binary path
207
+ * For v2: returns the postgresql-documentdb binary path
208
+ *
209
+ * @param ferretdbVersion - FerretDB version (e.g., "1.24.2" or "2.7.0")
210
+ * @param backendVersion - Backend version (PostgreSQL version for v1, DocumentDB version for v2)
211
+ * @param platform - Operating system
212
+ * @param arch - Architecture
213
+ */
214
+ getBackendBinaryPath(
215
+ ferretdbVersion: string,
216
+ backendVersion: string,
217
+ platform: Platform,
218
+ arch: Arch,
219
+ ): string {
220
+ if (isV1(ferretdbVersion)) {
221
+ const pgFullVersion = postgresqlBinaryManager.getFullVersion(
222
+ backendVersion || DEFAULT_V1_POSTGRESQL_VERSION,
223
+ )
224
+ return paths.getBinaryPath({
225
+ engine: 'postgresql',
226
+ version: pgFullVersion,
227
+ platform,
228
+ arch,
229
+ })
230
+ }
231
+
232
+ const fullBackendVersion = this.getFullDocumentDBVersion(
233
+ backendVersion || DEFAULT_DOCUMENTDB_VERSION,
234
+ )
235
+ return this.getDocumentDBBinaryPath(fullBackendVersion, platform, arch)
236
+ }
237
+
238
+ /**
239
+ * Get environment variables needed to run backend binaries.
240
+ * For v1: delegates to PostgreSQL's standard env (usually none needed)
241
+ * For v2: delegates to getDocumentDBSpawnEnv
242
+ *
243
+ * @param ferretdbVersion - FerretDB version
244
+ * @param backendVersion - Backend version
245
+ * @param platform - Operating system
246
+ * @param arch - Architecture
247
+ */
248
+ getBackendSpawnEnv(
249
+ ferretdbVersion: string,
250
+ backendVersion: string,
251
+ platform: Platform,
252
+ arch: Arch,
253
+ ): Record<string, string> | undefined {
254
+ if (isV1(ferretdbVersion)) {
255
+ // Plain PostgreSQL doesn't need special env vars on most platforms
256
+ // Linux may need LD_LIBRARY_PATH
257
+ if (platform !== Platform.Linux) {
258
+ return undefined
259
+ }
260
+ const pgPath = this.getBackendBinaryPath(
261
+ ferretdbVersion,
262
+ backendVersion,
263
+ platform,
264
+ arch,
265
+ )
266
+ const libPath = join(pgPath, 'lib')
267
+ const existingLdPath = process.env['LD_LIBRARY_PATH'] || ''
268
+ const newLdPath = existingLdPath
269
+ ? `${libPath}:${existingLdPath}`
270
+ : libPath
271
+ return { LD_LIBRARY_PATH: newLdPath }
272
+ }
273
+
274
+ const fullBackendVersion = this.getFullDocumentDBVersion(
275
+ backendVersion || DEFAULT_DOCUMENTDB_VERSION,
276
+ )
277
+ return this.getDocumentDBSpawnEnv(fullBackendVersion, platform, arch)
278
+ }
279
+
179
280
  /**
180
281
  * List all installed FerretDB versions
181
282
  */
@@ -223,7 +324,7 @@ class FerretDBCompositeBinaryManager {
223
324
  * @param platform - Operating system
224
325
  * @param arch - Architecture
225
326
  * @param onProgress - Progress callback
226
- * @param backendVersion - postgresql-documentdb version (optional)
327
+ * @param backendVersion - Backend version (postgresql-documentdb for v2, PostgreSQL major for v1)
227
328
  * @returns Paths to both binary directories
228
329
  */
229
330
  async ensureInstalled(
@@ -231,27 +332,97 @@ class FerretDBCompositeBinaryManager {
231
332
  platform: Platform,
232
333
  arch: Arch,
233
334
  onProgress?: ProgressCallback,
234
- backendVersion: string = DEFAULT_DOCUMENTDB_VERSION,
335
+ backendVersion?: string,
235
336
  ): Promise<FerretDBBinaryPaths> {
236
337
  const fullVersion = this.getFullVersion(version)
237
- const fullBackendVersion = this.getFullDocumentDBVersion(backendVersion)
338
+ const v1 = isV1(version)
339
+ const effectiveBackendVersion =
340
+ backendVersion ||
341
+ (v1 ? DEFAULT_V1_POSTGRESQL_VERSION : DEFAULT_DOCUMENTDB_VERSION)
238
342
 
239
343
  // Check if already installed
240
- if (await this.isInstalled(version, platform, arch, backendVersion)) {
344
+ if (
345
+ await this.isInstalled(version, platform, arch, effectiveBackendVersion)
346
+ ) {
241
347
  onProgress?.({
242
348
  stage: 'cached',
243
349
  message: 'Using cached FerretDB binaries',
244
350
  })
245
351
  return {
246
352
  ferretdbPath: this.getFerretDBBinaryPath(fullVersion, platform, arch),
247
- documentdbPath: this.getDocumentDBBinaryPath(
248
- fullBackendVersion,
353
+ backendPath: this.getBackendBinaryPath(
354
+ fullVersion,
355
+ effectiveBackendVersion,
249
356
  platform,
250
357
  arch,
251
358
  ),
252
359
  }
253
360
  }
254
361
 
362
+ if (v1) {
363
+ return this.ensureInstalledV1(
364
+ version,
365
+ platform,
366
+ arch,
367
+ onProgress,
368
+ effectiveBackendVersion,
369
+ )
370
+ }
371
+
372
+ return this.ensureInstalledV2(
373
+ version,
374
+ platform,
375
+ arch,
376
+ onProgress,
377
+ effectiveBackendVersion,
378
+ )
379
+ }
380
+
381
+ /**
382
+ * Ensure v1 FerretDB binaries are installed (proxy + plain PostgreSQL)
383
+ */
384
+ private async ensureInstalledV1(
385
+ version: string,
386
+ platform: Platform,
387
+ arch: Arch,
388
+ onProgress?: ProgressCallback,
389
+ backendVersion: string = DEFAULT_V1_POSTGRESQL_VERSION,
390
+ ): Promise<FerretDBBinaryPaths> {
391
+ // Download FerretDB v1 proxy
392
+ const ferretdbPath = await this.downloadFerretDB(
393
+ version,
394
+ platform,
395
+ arch,
396
+ onProgress,
397
+ )
398
+
399
+ // Ensure plain PostgreSQL is installed via postgresqlBinaryManager
400
+ onProgress?.({
401
+ stage: 'downloading',
402
+ message: 'Ensuring PostgreSQL backend is available...',
403
+ })
404
+ const backendPath = await postgresqlBinaryManager.ensureInstalled(
405
+ backendVersion,
406
+ platform,
407
+ arch,
408
+ onProgress,
409
+ )
410
+
411
+ return { ferretdbPath, backendPath }
412
+ }
413
+
414
+ /**
415
+ * Ensure v2 FerretDB binaries are installed (proxy + postgresql-documentdb)
416
+ */
417
+ private async ensureInstalledV2(
418
+ version: string,
419
+ platform: Platform,
420
+ arch: Arch,
421
+ onProgress?: ProgressCallback,
422
+ backendVersion: string = DEFAULT_DOCUMENTDB_VERSION,
423
+ ): Promise<FerretDBBinaryPaths> {
424
+ const fullVersion = this.getFullVersion(version)
425
+
255
426
  // Check if FerretDB is already installed (DocumentDB might be missing)
256
427
  const ext = platform === Platform.Win32 ? '.exe' : ''
257
428
  const ferretdbBinaryPath = this.getFerretDBBinaryPath(
@@ -271,9 +442,9 @@ class FerretDBCompositeBinaryManager {
271
442
  onProgress,
272
443
  )
273
444
 
274
- let documentdbPath: string
445
+ let backendPath: string
275
446
  try {
276
- documentdbPath = await this.downloadDocumentDB(
447
+ backendPath = await this.downloadDocumentDB(
277
448
  backendVersion,
278
449
  platform,
279
450
  arch,
@@ -292,7 +463,7 @@ class FerretDBCompositeBinaryManager {
292
463
  throw error
293
464
  }
294
465
 
295
- return { ferretdbPath, documentdbPath }
466
+ return { ferretdbPath, backendPath }
296
467
  }
297
468
 
298
469
  /**
@@ -498,14 +669,16 @@ class FerretDBCompositeBinaryManager {
498
669
  const timeoutId = setTimeout(() => controller.abort(), DOWNLOAD_TIMEOUT_MS)
499
670
 
500
671
  try {
501
- const response = await fetch(url, { signal: controller.signal })
672
+ const response = await fetchWithRegistryFallback(url, {
673
+ signal: controller.signal,
674
+ })
502
675
 
503
676
  if (!response.ok) {
504
677
  if (response.status === 404) {
505
678
  throw new Error(
506
679
  `${displayName} binaries not found (404). ` +
507
680
  'This version may have been removed from hostdb. ' +
508
- 'Try a different version or check https://github.com/robertjbass/hostdb/releases',
681
+ 'Try a different version or check https://registry.layerbase.host',
509
682
  )
510
683
  }
511
684
  throw new Error(
@@ -585,19 +758,24 @@ class FerretDBCompositeBinaryManager {
585
758
  /**
586
759
  * Extract Windows binaries from ZIP file
587
760
  *
588
- * FerretDB does not support Windows due to postgresql-documentdb startup issues.
589
- * Override to throw a clear error.
761
+ * FerretDB v1 supports Windows. v2 does not (postgresql-documentdb startup issues).
590
762
  */
591
763
  private async extractWindowsBinaries(
592
- _zipFile: string,
593
- _binPath: string,
594
- _tempDir: string,
595
- _onProgress?: ProgressCallback,
764
+ zipFile: string,
765
+ binPath: string,
766
+ tempDir: string,
767
+ onProgress?: ProgressCallback,
596
768
  ): Promise<void> {
597
- throw new Error(
598
- 'FerretDB binaries are not available for Windows. ' +
599
- 'FerretDB is only supported on macOS and Linux.',
600
- )
769
+ onProgress?.({
770
+ stage: 'extracting',
771
+ message: 'Extracting binaries...',
772
+ })
773
+
774
+ const extractDir = join(tempDir, 'extract')
775
+ await mkdir(extractDir, { recursive: true })
776
+
777
+ await extractWindowsArchive(zipFile, extractDir)
778
+ await this.moveExtractedEntries(extractDir, binPath)
601
779
  }
602
780
 
603
781
  /**
@@ -656,6 +834,12 @@ class FerretDBCompositeBinaryManager {
656
834
  throw new Error(`FerretDB binary not found at ${binPath}/bin/`)
657
835
  }
658
836
 
837
+ // FerretDB v1 hostdb builds panic on --version due to missing version.txt
838
+ // at build time. For v1, just verify the binary exists (checked above).
839
+ if (isV1(version)) {
840
+ return
841
+ }
842
+
659
843
  try {
660
844
  const { stdout } = await spawnAsync(ferretdbBinary, ['--version'])
661
845
  const match = stdout.match(
@@ -794,6 +978,11 @@ class FerretDBCompositeBinaryManager {
794
978
 
795
979
  /**
796
980
  * Delete installed binaries for a specific version
981
+ *
982
+ * For v1: Only deletes the FerretDB proxy. Plain PostgreSQL binaries are shared
983
+ * with standalone PostgreSQL containers and should NOT be deleted.
984
+ *
985
+ * For v2: Deletes both FerretDB proxy and postgresql-documentdb backend.
797
986
  */
798
987
  async delete(
799
988
  version: string,
@@ -802,18 +991,27 @@ class FerretDBCompositeBinaryManager {
802
991
  backendVersion: string = DEFAULT_DOCUMENTDB_VERSION,
803
992
  ): Promise<void> {
804
993
  const fullVersion = this.getFullVersion(version)
805
- const fullBackendVersion = this.getFullDocumentDBVersion(backendVersion)
806
994
 
807
995
  const ferretdbPath = this.getFerretDBBinaryPath(fullVersion, platform, arch)
996
+ if (existsSync(ferretdbPath)) {
997
+ await rm(ferretdbPath, { recursive: true, force: true })
998
+ }
999
+
1000
+ // v1: Don't delete shared PostgreSQL binaries (cascadeDelete: false)
1001
+ if (isV1(version)) {
1002
+ logDebug(
1003
+ 'Skipping PostgreSQL backend deletion for FerretDB v1 (shared with standalone PG containers)',
1004
+ )
1005
+ return
1006
+ }
1007
+
1008
+ // v2: Delete postgresql-documentdb backend
1009
+ const fullBackendVersion = this.getFullDocumentDBVersion(backendVersion)
808
1010
  const documentdbPath = this.getDocumentDBBinaryPath(
809
1011
  fullBackendVersion,
810
1012
  platform,
811
1013
  arch,
812
1014
  )
813
-
814
- if (existsSync(ferretdbPath)) {
815
- await rm(ferretdbPath, { recursive: true, force: true })
816
- }
817
1015
  if (existsSync(documentdbPath)) {
818
1016
  await rm(documentdbPath, { recursive: true, force: true })
819
1017
  }
@@ -2,47 +2,77 @@
2
2
  * FerretDB binary URL generation for hostdb
3
3
  *
4
4
  * Generates download URLs for FerretDB binaries from the hostdb GitHub releases.
5
- * FerretDB requires two binaries:
5
+ *
6
+ * FerretDB v2 requires two binaries:
6
7
  * - ferretdb: MongoDB-compatible proxy
7
8
  * - postgresql-documentdb: PostgreSQL 17 + DocumentDB extension
8
9
  *
9
- * Note: Windows is not currently supported due to postgresql-documentdb startup issues.
10
- * The binaries exist on hostdb but fail to start properly on Windows.
10
+ * FerretDB v1 requires:
11
+ * - ferretdb: MongoDB-compatible proxy
12
+ * - Plain PostgreSQL (managed by postgresqlBinaryManager, not downloaded here)
13
+ *
14
+ * Both v1 and v2 use the same "ferretdb" hostdb engine name.
15
+ * v1 supports all platforms including Windows.
16
+ * v2 is macOS/Linux only (postgresql-documentdb has Windows startup issues).
11
17
  */
12
18
 
13
- import { normalizeVersion, normalizeDocumentDBVersion } from './version-maps'
19
+ import {
20
+ normalizeVersion,
21
+ normalizeDocumentDBVersion,
22
+ isV1,
23
+ } from './version-maps'
14
24
  import { buildHostdbUrl } from '../../core/hostdb-client'
15
25
  import { Engine, Platform, type Arch } from '../../types'
16
26
 
17
- // Supported platforms for FerretDB (both proxy and backend)
18
- // Note: Windows (win32-x64) is excluded due to postgresql-documentdb startup issues
19
- export const FERRETDB_SUPPORTED_PLATFORMS = new Set([
27
+ // Supported platforms for FerretDB v2 (requires postgresql-documentdb)
28
+ // Windows is excluded due to postgresql-documentdb startup issues
29
+ export const FERRETDB_V2_SUPPORTED_PLATFORMS = new Set([
20
30
  'darwin-arm64',
21
31
  'darwin-x64',
22
32
  'linux-arm64',
23
33
  'linux-x64',
24
34
  ])
25
35
 
26
- // Supported platforms for postgresql-documentdb backend
27
- export const DOCUMENTDB_SUPPORTED_PLATFORMS = FERRETDB_SUPPORTED_PLATFORMS
36
+ // Supported platforms for FerretDB v1 (uses plain PostgreSQL)
37
+ // All platforms including Windows
38
+ export const FERRETDB_V1_SUPPORTED_PLATFORMS = new Set([
39
+ 'darwin-arm64',
40
+ 'darwin-x64',
41
+ 'linux-arm64',
42
+ 'linux-x64',
43
+ 'win32-x64',
44
+ ])
45
+
46
+ // Supported platforms for postgresql-documentdb backend (v2 only)
47
+ export const DOCUMENTDB_SUPPORTED_PLATFORMS = FERRETDB_V2_SUPPORTED_PLATFORMS
28
48
 
29
49
  /**
30
50
  * Map Node.js platform/arch to hostdb platform key
51
+ * @param version - Optional FerretDB version to determine platform support (v1 vs v2)
31
52
  */
32
53
  export function getHostdbPlatform(
33
54
  platform: Platform,
34
55
  arch: Arch,
56
+ version?: string,
35
57
  ): string | null {
36
58
  const key = `${platform}-${arch}`
37
- return FERRETDB_SUPPORTED_PLATFORMS.has(key) ? key : null
59
+ const platforms =
60
+ version && isV1(version)
61
+ ? FERRETDB_V1_SUPPORTED_PLATFORMS
62
+ : FERRETDB_V2_SUPPORTED_PLATFORMS
63
+ return platforms.has(key) ? key : null
38
64
  }
39
65
 
40
66
  /**
41
67
  * Check if the current platform supports FerretDB
68
+ * @param version - Optional FerretDB version to determine platform support (v1 vs v2)
42
69
  */
43
- export function isPlatformSupported(platform: Platform, arch: Arch): boolean {
44
- const key = `${platform}-${arch}`
45
- return FERRETDB_SUPPORTED_PLATFORMS.has(key)
70
+ export function isPlatformSupported(
71
+ platform: Platform,
72
+ arch: Arch,
73
+ version?: string,
74
+ ): boolean {
75
+ return getHostdbPlatform(platform, arch, version) !== null
46
76
  }
47
77
 
48
78
  /**
@@ -59,11 +89,12 @@ export function getFerretDBBinaryUrl(
59
89
  arch: Arch,
60
90
  ): string {
61
91
  const fullVersion = normalizeVersion(version)
62
- const hostdbPlatform = getHostdbPlatform(platform, arch)
92
+ const hostdbPlatform = getHostdbPlatform(platform, arch, version)
63
93
 
64
94
  if (!hostdbPlatform) {
95
+ const v1 = isV1(version)
65
96
  throw new Error(
66
- `Unsupported platform: ${platform}-${arch}. FerretDB is only supported on macOS and Linux.`,
97
+ `Unsupported platform: ${platform}-${arch}. FerretDB ${v1 ? 'v1' : 'v2'} is ${v1 ? 'not available on this platform' : 'only supported on macOS and Linux'}.`,
67
98
  )
68
99
  }
69
100
 
@@ -94,7 +125,7 @@ export function getDocumentDBBinaryUrl(
94
125
 
95
126
  if (!DOCUMENTDB_SUPPORTED_PLATFORMS.has(key)) {
96
127
  throw new Error(
97
- `Unsupported platform: ${platform}-${arch}. FerretDB is only supported on macOS and Linux.`,
128
+ `Unsupported platform: ${platform}-${arch}. postgresql-documentdb (FerretDB v2 backend) is only supported on macOS and Linux.`,
98
129
  )
99
130
  }
100
131
 
@@ -109,28 +140,42 @@ export function getDocumentDBBinaryUrl(
109
140
  }
110
141
 
111
142
  /**
112
- * Get the combined binary URLs for FerretDB (both proxy and backend)
143
+ * Get the combined binary URLs for FerretDB (proxy and backend)
144
+ *
145
+ * For v1: Returns only ferretdb URL (backend is plain PostgreSQL, managed separately)
146
+ * For v2: Returns both ferretdb and documentdb URLs
113
147
  *
114
148
  * @param version - FerretDB version (major or full)
115
- * @param backendVersion - postgresql-documentdb version (e.g., "17-0.107.0")
149
+ * @param backendVersion - postgresql-documentdb version (e.g., "17-0.107.0"), used for v2 only
116
150
  * @param platform - Operating system
117
151
  * @param arch - Architecture
118
- * @returns Object with ferretdb and documentdb URLs
152
+ * @returns Object with ferretdb URL and optional documentdb URL
119
153
  */
120
154
  export function getBinaryUrls(
121
155
  version: string,
122
156
  backendVersion: string,
123
157
  platform: Platform,
124
158
  arch: Arch,
125
- ): { ferretdb: string; documentdb: string } {
126
- // Validate platform supports FerretDB
127
- if (!isPlatformSupported(platform, arch)) {
159
+ ): { ferretdb: string; documentdb?: string } {
160
+ // Validate platform supports this FerretDB version
161
+ if (!isPlatformSupported(platform, arch, version)) {
162
+ const v1 = isV1(version)
128
163
  throw new Error(
129
- `FerretDB is not available on ${platform}-${arch}.\n` +
130
- 'FerretDB is only supported on macOS and Linux.',
164
+ `FerretDB ${v1 ? 'v1' : 'v2'} is not available on ${platform}-${arch}.\n` +
165
+ (v1
166
+ ? 'This platform is not supported.'
167
+ : 'FerretDB v2 is only supported on macOS and Linux. Try v1 for Windows support.'),
131
168
  )
132
169
  }
133
170
 
171
+ if (isV1(version)) {
172
+ // v1: backend is plain PostgreSQL (managed by postgresqlBinaryManager)
173
+ return {
174
+ ferretdb: getFerretDBBinaryUrl(version, platform, arch),
175
+ }
176
+ }
177
+
178
+ // v2: backend is postgresql-documentdb
134
179
  return {
135
180
  ferretdb: getFerretDBBinaryUrl(version, platform, arch),
136
181
  documentdb: getDocumentDBBinaryUrl(backendVersion, platform, arch),