@qvac/sdk 0.20.1 → 0.21.1

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 (104) hide show
  1. package/NOTICE +130 -62
  2. package/README.md +39 -5
  3. package/dist/examples/advisory-model-fit.d.ts +17 -16
  4. package/dist/examples/advisory-model-fit.js +18 -18
  5. package/dist/examples/asr/parakeet-indic-conformer-filesystem.js +3 -3
  6. package/dist/examples/asr/parakeet-unified-coreml.d.ts +2 -0
  7. package/dist/examples/asr/parakeet-unified-coreml.js +113 -0
  8. package/dist/examples/assess-model-fit.js +9 -4
  9. package/dist/examples/model-fit-ui/server.js +5 -2
  10. package/dist/examples/rpc-inference.d.ts +2 -0
  11. package/dist/examples/rpc-inference.js +51 -0
  12. package/dist/examples/rpc-server.d.ts +2 -0
  13. package/dist/examples/rpc-server.js +32 -0
  14. package/dist/examples/tools/llamacpp-deferred-tools.d.ts +2 -0
  15. package/dist/examples/tools/llamacpp-deferred-tools.js +77 -0
  16. package/dist/examples/tts/audio8.js +4 -0
  17. package/dist/examples/tts/moss-dialogue.d.ts +2 -0
  18. package/dist/examples/tts/moss-dialogue.js +63 -0
  19. package/dist/examples/tts/moss.d.ts +2 -0
  20. package/dist/examples/tts/moss.js +71 -0
  21. package/dist/scripts/contract/build-contract.d.ts +2 -1
  22. package/dist/scripts/contract/build-contract.js +4 -1
  23. package/dist/scripts/contract/build-numeric-constants.d.ts +15 -0
  24. package/dist/scripts/contract/build-numeric-constants.js +13 -0
  25. package/dist/scripts/contract/method-shapes.d.ts +3 -0
  26. package/dist/scripts/contract/method-shapes.js +3 -0
  27. package/dist/scripts/enforce-inference-versions.d.ts +18 -0
  28. package/dist/scripts/enforce-inference-versions.js +158 -0
  29. package/dist/scripts/generate-bare-kit-runtimes.d.ts +2 -0
  30. package/dist/scripts/generate-bare-kit-runtimes.js +106 -0
  31. package/dist/src/client/api/assess-model-fit.d.ts +5 -4
  32. package/dist/src/client/api/assess-model-fit.js +24 -7
  33. package/dist/src/client/api/bci-transcribe.d.ts +4 -1
  34. package/dist/src/client/api/get-system-resources.d.ts +8 -0
  35. package/dist/src/client/api/get-system-resources.js +8 -0
  36. package/dist/src/client/api/index.d.ts +1 -0
  37. package/dist/src/client/api/index.js +1 -0
  38. package/dist/src/client/api/rpc-server.d.ts +20 -0
  39. package/dist/src/client/api/rpc-server.js +45 -0
  40. package/dist/src/client/api/text-to-speech.d.ts +9 -0
  41. package/dist/src/client/api/text-to-speech.js +9 -0
  42. package/dist/src/client/api/transcribe.d.ts +21 -15
  43. package/dist/src/client/api/transcribe.js +65 -20
  44. package/dist/src/client/rpc/rpc-error.js +11 -7
  45. package/dist/src/commands/bundle/entry-gen.d.ts +2 -2
  46. package/dist/src/commands/bundle/entry-gen.js +8 -4
  47. package/dist/src/commands/bundle/index.d.ts +20 -0
  48. package/dist/src/commands/bundle/index.js +88 -12
  49. package/dist/src/commands/bundle/plugins.js +1 -1
  50. package/dist/src/commands/command-logger.d.ts +6 -0
  51. package/dist/src/commands/command-logger.js +12 -0
  52. package/dist/src/commands/host-prebuilds/index.d.ts +71 -0
  53. package/dist/src/commands/host-prebuilds/index.js +227 -0
  54. package/dist/src/commands/host-prebuilds/package-manager.d.ts +54 -0
  55. package/dist/src/commands/host-prebuilds/package-manager.js +278 -0
  56. package/dist/src/commands/index.d.ts +10 -1
  57. package/dist/src/commands/index.js +6 -0
  58. package/dist/src/commands/verify/abi.d.ts +22 -2
  59. package/dist/src/commands/verify/abi.js +49 -27
  60. package/dist/src/commands/verify/addon-source.d.ts +22 -0
  61. package/dist/src/commands/verify/addon-source.js +69 -3
  62. package/dist/src/commands/verify/bare-kit-runtime.d.ts +38 -0
  63. package/dist/src/commands/verify/bare-kit-runtime.js +201 -0
  64. package/dist/src/commands/verify/bare-kit-runtimes.d.ts +12 -0
  65. package/dist/src/commands/verify/bare-kit-runtimes.js +108 -0
  66. package/dist/src/commands/verify/bundle-source.js +16 -15
  67. package/dist/src/commands/verify/engines-advice.d.ts +73 -0
  68. package/dist/src/commands/verify/engines-advice.js +271 -0
  69. package/dist/src/commands/verify/index.d.ts +22 -0
  70. package/dist/src/commands/verify/index.js +151 -13
  71. package/dist/src/commands/verify/node-modules-source.js +43 -39
  72. package/dist/src/commands/verify/prebuilds.d.ts +19 -0
  73. package/dist/src/commands/verify/prebuilds.js +52 -13
  74. package/dist/src/expo/plugins/index.d.ts +2 -0
  75. package/dist/src/expo/plugins/withMobileBundle.d.ts +15 -5
  76. package/dist/src/expo/plugins/withMobileBundle.js +68 -42
  77. package/dist/src/expo/plugins/withQvacSDK.d.ts +7 -1
  78. package/dist/src/expo/plugins/withQvacSDK.js +6 -3
  79. package/dist/src/index.d.ts +5 -2
  80. package/dist/src/index.js +4 -2
  81. package/dist/src/schemas/sdk-errors-client.d.ts +2 -0
  82. package/dist/src/schemas/sdk-errors-client.js +16 -0
  83. package/dist/src/schemas/sdk-errors-server.d.ts +1 -0
  84. package/dist/src/schemas/sdk-errors-server.js +5 -0
  85. package/dist/src/utils/errors-client.d.ts +15 -0
  86. package/dist/src/utils/errors-client.js +26 -0
  87. package/dist/src/utils/errors-server.d.ts +1 -0
  88. package/dist/src/utils/errors-server.js +1 -0
  89. package/dist/src/utils/mcp-adapter.js +7 -1
  90. package/dist/src/utils/tool-helpers.d.ts +4 -0
  91. package/dist/src/utils/tool-helpers.js +2 -0
  92. package/dist/src/worker/ggml-rpc-server-provider.d.ts +2 -0
  93. package/dist/src/worker/ggml-rpc-server-provider.js +1 -0
  94. package/dist/src/worker/rpc-server-provider.d.ts +3 -0
  95. package/dist/src/worker/rpc-server-provider.js +1 -0
  96. package/package.json +30 -25
  97. package/dist/scripts/enforce-inference-peer-dependencies.d.ts +0 -2
  98. package/dist/scripts/enforce-inference-peer-dependencies.js +0 -39
  99. package/dist/src/deprecate.d.ts +0 -2
  100. package/dist/src/deprecate.js +0 -9
  101. package/dist/src/worker/legacy-worker-entry.d.ts +0 -2
  102. package/dist/src/worker/legacy-worker-entry.js +0 -3
  103. package/dist/src/worker/worker-core.d.ts +0 -7
  104. package/dist/src/worker/worker-core.js +0 -8
@@ -70,30 +70,37 @@ export function formatConfigLabel(projectRoot, configPath) {
70
70
  return configPath;
71
71
  return rel;
72
72
  }
73
+ export function formatRuntimeSource(runtime) {
74
+ return runtime.detail === undefined ? runtime.source : `${runtime.source}: ${runtime.detail}`;
75
+ }
73
76
  export function checkAbi(options) {
74
- const { addons, runtime } = options;
75
- const addonsWithEngines = addons.filter((addon) => addon.enginesBare !== undefined);
76
- if (addonsWithEngines.length === 0)
77
+ const { addons, runtime, packages = [] } = options;
78
+ const constrained = [
79
+ ...addons.map((addon) => ({
80
+ id: formatAddonId(addon),
81
+ range: addon.enginesBare,
82
+ isAddon: true
83
+ })),
84
+ ...packages.map((pkg) => ({ id: formatAddonId(pkg), range: pkg.enginesBare, isAddon: false }))
85
+ ].filter((entry) => !!entry.range);
86
+ if (constrained.length === 0)
77
87
  return [];
78
88
  const issues = [];
79
89
  const checkable = [];
80
- for (const addon of addonsWithEngines) {
81
- const range = addon.enginesBare;
82
- if (!range)
83
- continue;
84
- if (!semver.validRange(range)) {
90
+ for (const entry of constrained) {
91
+ if (!semver.validRange(entry.range)) {
85
92
  issues.push({
86
93
  code: 'malformed-engines-bare',
87
94
  level: 'warning',
88
- addon: formatAddonId(addon),
89
- enginesBare: range,
90
- message: `${formatAddonId(addon)} declares engines.bare "${range}", which is ` +
91
- 'not a valid semver range. ABI check skipped for this addon. ' +
92
- 'Report this to the addon maintainer.'
95
+ addon: entry.id,
96
+ enginesBare: entry.range,
97
+ message: `${entry.id} declares engines.bare "${entry.range}", which is ` +
98
+ `not a valid semver range. ABI check skipped for this ${entry.isAddon ? 'addon' : 'package'}. ` +
99
+ 'Report this to the package maintainer.'
93
100
  });
94
101
  continue;
95
102
  }
96
- checkable.push({ addon, range });
103
+ checkable.push(entry);
97
104
  }
98
105
  if (checkable.length === 0)
99
106
  return issues;
@@ -102,24 +109,39 @@ export function checkAbi(options) {
102
109
  code: 'unknown-runtime-version',
103
110
  level: 'warning',
104
111
  message: `${runtime.error.reason}. ABI checks skipped for ${checkable.length} ` +
105
- `addon${checkable.length === 1 ? '' : 's'}. ` +
106
- 'Pass bareRuntimeVersion to enable strict ABI verification.',
112
+ `package${checkable.length === 1 ? '' : 's'}. ` +
113
+ 'For mobile hosts, install react-native-bare-kit; for a desktop build, ' +
114
+ 'install bare-runtime or pass bareRuntimeVersion.',
107
115
  triedPaths: runtime.error.triedPaths
108
116
  });
109
117
  return issues;
110
118
  }
111
- for (const { addon, range } of checkable) {
112
- if (semver.satisfies(runtime.runtime.version, range))
119
+ const { version } = runtime.runtime;
120
+ for (const entry of checkable) {
121
+ if (semver.satisfies(version, entry.range))
113
122
  continue;
114
- issues.push({
115
- code: 'abi-mismatch',
116
- level: 'error',
117
- addon: formatAddonId(addon),
118
- enginesBare: range,
119
- runtimeVersion: runtime.runtime.version,
120
- message: `${formatAddonId(addon)} requires bare ${range}, ` +
121
- `runtime is ${runtime.runtime.version} (from ${runtime.runtime.source}).`
122
- });
123
+ const message = `${entry.id} requires bare ${entry.range}, ` +
124
+ `runtime is ${version} (from ${formatRuntimeSource(runtime.runtime)}).`;
125
+ if (entry.isAddon) {
126
+ issues.push({
127
+ code: 'abi-mismatch',
128
+ level: 'error',
129
+ addon: entry.id,
130
+ enginesBare: entry.range,
131
+ runtimeVersion: version,
132
+ message
133
+ });
134
+ }
135
+ else {
136
+ issues.push({
137
+ code: 'engines-mismatch',
138
+ level: 'error',
139
+ package: entry.id,
140
+ enginesBare: entry.range,
141
+ runtimeVersion: version,
142
+ message
143
+ });
144
+ }
123
145
  }
124
146
  return issues;
125
147
  }
@@ -19,6 +19,19 @@ export interface AddonPackageJson {
19
19
  engines?: {
20
20
  bare?: string;
21
21
  };
22
+ dependencies?: Record<string, string>;
23
+ optionalDependencies?: Record<string, string>;
24
+ peerDependencies?: Record<string, string>;
25
+ }
26
+ /** Any package in the collected graph, addon or not. */
27
+ export interface PackageRecord {
28
+ name: string;
29
+ version?: string;
30
+ packageJsonPath: string;
31
+ isAddon: boolean;
32
+ enginesBare?: string;
33
+ /** Declared ranges of every dependency kind, keyed by dependency name. */
34
+ dependencies: Record<string, string>;
22
35
  }
23
36
  export interface ReadAddonPackageJsonOptions {
24
37
  packageJsonPath: string;
@@ -34,13 +47,22 @@ export interface ReadAddonPackageJsonResult {
34
47
  isAddon: boolean;
35
48
  invalid?: InvalidPackageJsonRecord;
36
49
  addon?: NativeAddon;
50
+ record?: PackageRecord;
37
51
  }
38
52
  export declare function readAddonPackageJson(options: ReadAddonPackageJsonOptions): Promise<ReadAddonPackageJsonResult>;
39
53
  export interface CollectDiagnostics {
40
54
  invalidPackageJsons: InvalidPackageJsonRecord[];
41
55
  emptyResolutions: boolean;
56
+ /** Every readable package the collector visited, in visit order. */
57
+ packages: PackageRecord[];
42
58
  }
43
59
  export declare function createCollectDiagnostics(): CollectDiagnostics;
60
+ /**
61
+ * Caps concurrent filesystem calls so a large node_modules tree is read in
62
+ * parallel without exhausting file descriptors.
63
+ */
64
+ export declare function createLimiter(max: number): <T>(task: () => Promise<T>) => Promise<T>;
65
+ export declare const FS_CONCURRENCY = 32;
44
66
  export declare function formatAddonId(addon: {
45
67
  name: string;
46
68
  version?: string;
@@ -29,8 +29,11 @@ export async function readAddonPackageJson(options) {
29
29
  };
30
30
  }
31
31
  const pkg = parsed;
32
+ const record = buildRecord(pkg, packageJsonPath, expectedName);
32
33
  if (pkg.addon !== true) {
33
- return { found: true, isAddon: false };
34
+ return record === null
35
+ ? { found: true, isAddon: false }
36
+ : { found: true, isAddon: false, record };
34
37
  }
35
38
  const name = pkg.name ?? expectedName;
36
39
  if (!name) {
@@ -49,7 +52,39 @@ export async function readAddonPackageJson(options) {
49
52
  addon.version = pkg.version;
50
53
  if (typeof pkg.engines?.bare === 'string')
51
54
  addon.enginesBare = pkg.engines.bare;
52
- return { found: true, isAddon: true, addon };
55
+ return record === null
56
+ ? { found: true, isAddon: true, addon }
57
+ : { found: true, isAddon: true, addon, record };
58
+ }
59
+ function stringRecord(value) {
60
+ const out = {};
61
+ if (typeof value !== 'object' || value === null || Array.isArray(value))
62
+ return out;
63
+ for (const [key, range] of Object.entries(value)) {
64
+ if (typeof range === 'string')
65
+ out[key] = range;
66
+ }
67
+ return out;
68
+ }
69
+ function buildRecord(pkg, packageJsonPath, expectedName) {
70
+ const name = typeof pkg.name === 'string' ? pkg.name : expectedName;
71
+ if (!name)
72
+ return null;
73
+ const record = {
74
+ name,
75
+ packageJsonPath,
76
+ isAddon: pkg.addon === true,
77
+ dependencies: {
78
+ ...stringRecord(pkg.peerDependencies),
79
+ ...stringRecord(pkg.optionalDependencies),
80
+ ...stringRecord(pkg.dependencies)
81
+ }
82
+ };
83
+ if (typeof pkg.version === 'string')
84
+ record.version = pkg.version;
85
+ if (typeof pkg.engines?.bare === 'string')
86
+ record.enginesBare = pkg.engines.bare;
87
+ return record;
53
88
  }
54
89
  function buildInvalid(packageJsonPath, expectedName, reason) {
55
90
  const record = { packageJsonPath, reason };
@@ -58,8 +93,39 @@ function buildInvalid(packageJsonPath, expectedName, reason) {
58
93
  return record;
59
94
  }
60
95
  export function createCollectDiagnostics() {
61
- return { invalidPackageJsons: [], emptyResolutions: false };
96
+ return { invalidPackageJsons: [], emptyResolutions: false, packages: [] };
97
+ }
98
+ /**
99
+ * Caps concurrent filesystem calls so a large node_modules tree is read in
100
+ * parallel without exhausting file descriptors.
101
+ */
102
+ export function createLimiter(max) {
103
+ let active = 0;
104
+ const queue = [];
105
+ // A finishing task hands its slot straight to the next waiter, so a caller
106
+ // arriving in between cannot take it as well.
107
+ function release() {
108
+ const next = queue.shift();
109
+ if (next)
110
+ next();
111
+ else
112
+ active--;
113
+ }
114
+ async function run(task) {
115
+ if (active >= max)
116
+ await new Promise((resolve) => queue.push(resolve));
117
+ else
118
+ active++;
119
+ try {
120
+ return await task();
121
+ }
122
+ finally {
123
+ release();
124
+ }
125
+ }
126
+ return run;
62
127
  }
128
+ export const FS_CONCURRENCY = 32;
63
129
  export function formatAddonId(addon) {
64
130
  return `${addon.name}@${addon.version ?? 'unknown'}`;
65
131
  }
@@ -0,0 +1,38 @@
1
+ import type { BareRuntimeResolution } from './abi.js';
2
+ export declare const REACT_NATIVE_BARE_KIT = "react-native-bare-kit";
3
+ export declare const NETWORK_TIMEOUT_MS = 5000;
4
+ export type FetchText = (url: string) => Promise<string>;
5
+ export type ProgressFn = (message: string) => void;
6
+ export interface ResolveMobileBareRuntimeOptions {
7
+ projectRoot: string;
8
+ network?: boolean | undefined;
9
+ onProgress?: ProgressFn | undefined;
10
+ fetchText?: FetchText | undefined;
11
+ }
12
+ export declare function isReactNativeBareKitInstalled(projectRoot: string): boolean;
13
+ export declare function fetchText(url: string): Promise<string>;
14
+ export declare function parseBareKitReleaseVersion(cmakeLists: string): string | null;
15
+ export declare function parseBareVersion(cmakeLists: string): string | null;
16
+ export declare function parseInfoPlistVersion(plist: string): string | null;
17
+ export declare function fetchBareKitVersionFromGitHub(reactNativeBareKitVersion: string, fetch?: FetchText): Promise<string | null>;
18
+ export declare function fetchBareVersionFromGitHub(bareKitVersion: string, fetch?: FetchText): Promise<string | null>;
19
+ export declare function bareVersionForBareKit(bareKitVersion: string): string | null;
20
+ /**
21
+ * The oldest react-native-bare-kit release newer than `currentVersion` whose
22
+ * embedded Bare satisfies every range, or null if the table has none.
23
+ */
24
+ export declare function findReactNativeBareKitUpgrade(currentVersion: string, ranges: string[]): {
25
+ version: string;
26
+ bareKit: string;
27
+ bare: string;
28
+ } | null;
29
+ /**
30
+ * Bare version the app runs on mobile: the one compiled into the bare-kit
31
+ * binaries that react-native-bare-kit ships, not any `bare-runtime` package
32
+ * in node_modules.
33
+ *
34
+ * Checks the built-in table, then the installed iOS framework's Info.plist,
35
+ * and only then GitHub.
36
+ */
37
+ export declare function resolveMobileBareRuntime(options: ResolveMobileBareRuntimeOptions): Promise<BareRuntimeResolution>;
38
+ //# sourceMappingURL=bare-kit-runtime.d.ts.map
@@ -0,0 +1,201 @@
1
+ import { promises as fsp } from 'node:fs';
2
+ import path from 'node:path';
3
+ import semver from 'semver';
4
+ import { BARE_KIT_BARE_VERSIONS, REACT_NATIVE_BARE_KIT_RUNTIMES } from './bare-kit-runtimes.js';
5
+ import { findInAncestorNodeModules } from '../../expo/plugins/find-in-ancestor-node-modules.js';
6
+ export const REACT_NATIVE_BARE_KIT = 'react-native-bare-kit';
7
+ export const NETWORK_TIMEOUT_MS = 5000;
8
+ const RAW_GITHUB_BASE = 'https://raw.githubusercontent.com/holepunchto';
9
+ /**
10
+ * The iOS framework ships inside the npm package, and its bundle version is
11
+ * the bare-kit release it was built from, so it identifies the embedded
12
+ * runtime without a network request.
13
+ */
14
+ const BARE_KIT_INFO_PLIST = path.join('ios', 'BareKit.xcframework', 'ios-arm64', 'BareKit.framework', 'Info.plist');
15
+ export function isReactNativeBareKitInstalled(projectRoot) {
16
+ return findInAncestorNodeModules(projectRoot, REACT_NATIVE_BARE_KIT) !== null;
17
+ }
18
+ export async function fetchText(url) {
19
+ const response = await fetch(url, { signal: AbortSignal.timeout(NETWORK_TIMEOUT_MS) });
20
+ if (!response.ok)
21
+ throw new Error(`GET ${url} returned HTTP ${response.status}`);
22
+ return response.text();
23
+ }
24
+ export function parseBareKitReleaseVersion(cmakeLists) {
25
+ const match = /holepunchto\/bare-kit\/releases\/download\/v(\d+\.\d+\.\d+[^/"\s]*)\//.exec(cmakeLists);
26
+ return match?.[1] ?? null;
27
+ }
28
+ export function parseBareVersion(cmakeLists) {
29
+ const match = /fetch_package\(\s*"github:holepunchto\/bare@(\d+\.\d+\.\d+[^"\s]*)"/.exec(cmakeLists);
30
+ return match?.[1] ?? null;
31
+ }
32
+ export function parseInfoPlistVersion(plist) {
33
+ const match = /<key>CFBundleShortVersionString<\/key>\s*<string>(\d+\.\d+\.\d+[^<]*)<\/string>/.exec(plist);
34
+ return match?.[1] ?? null;
35
+ }
36
+ export async function fetchBareKitVersionFromGitHub(reactNativeBareKitVersion, fetch = fetchText) {
37
+ const cmakeLists = await fetch(`${RAW_GITHUB_BASE}/${REACT_NATIVE_BARE_KIT}/v${reactNativeBareKitVersion}/CMakeLists.txt`);
38
+ return parseBareKitReleaseVersion(cmakeLists);
39
+ }
40
+ export async function fetchBareVersionFromGitHub(bareKitVersion, fetch = fetchText) {
41
+ const cmakeLists = await fetch(`${RAW_GITHUB_BASE}/bare-kit/v${bareKitVersion}/CMakeLists.txt`);
42
+ return parseBareVersion(cmakeLists);
43
+ }
44
+ export function bareVersionForBareKit(bareKitVersion) {
45
+ return BARE_KIT_BARE_VERSIONS[bareKitVersion] ?? null;
46
+ }
47
+ function newestKey(record) {
48
+ const versions = Object.keys(record).filter((version) => semver.valid(version) !== null);
49
+ return versions.length === 0 ? null : versions.sort(semver.rcompare)[0];
50
+ }
51
+ /**
52
+ * The table generator has already probed every release up to the newest
53
+ * entry, so only newer releases can have data on GitHub that the table lacks.
54
+ */
55
+ function isNewerThanTable(version, record) {
56
+ const newest = newestKey(record);
57
+ return newest === null || semver.valid(version) === null || semver.gt(version, newest);
58
+ }
59
+ /**
60
+ * The oldest react-native-bare-kit release newer than `currentVersion` whose
61
+ * embedded Bare satisfies every range, or null if the table has none.
62
+ */
63
+ export function findReactNativeBareKitUpgrade(currentVersion, ranges) {
64
+ const candidates = Object.entries(REACT_NATIVE_BARE_KIT_RUNTIMES)
65
+ .filter(([version]) => semver.valid(version) !== null && semver.prerelease(version) === null)
66
+ .sort(([a], [b]) => semver.compare(a, b));
67
+ for (const [version, runtime] of candidates) {
68
+ if (semver.valid(currentVersion) !== null && !semver.gt(version, currentVersion))
69
+ continue;
70
+ if (ranges.every((range) => semver.satisfies(runtime.bare, range))) {
71
+ return { version, bareKit: runtime.bareKit, bare: runtime.bare };
72
+ }
73
+ }
74
+ return null;
75
+ }
76
+ async function readJsonVersion(packageJsonPath) {
77
+ try {
78
+ const parsed = JSON.parse(await fsp.readFile(packageJsonPath, 'utf8'));
79
+ return typeof parsed.version === 'string' ? parsed.version : null;
80
+ }
81
+ catch {
82
+ return null;
83
+ }
84
+ }
85
+ async function readInfoPlistVersion(packageDir) {
86
+ try {
87
+ return parseInfoPlistVersion(await fsp.readFile(path.join(packageDir, BARE_KIT_INFO_PLIST), 'utf8'));
88
+ }
89
+ catch {
90
+ return null;
91
+ }
92
+ }
93
+ function resolved(version, reactNativeBareKitVersion, bareKitVersion, via) {
94
+ return {
95
+ resolved: true,
96
+ runtime: {
97
+ version,
98
+ source: 'react-native-bare-kit',
99
+ packageVersion: reactNativeBareKitVersion,
100
+ detail: `react-native-bare-kit@${reactNativeBareKitVersion} embeds bare-kit ${bareKitVersion}` +
101
+ (via === 'github' ? ', looked up on GitHub' : '')
102
+ }
103
+ };
104
+ }
105
+ /**
106
+ * Bare version the app runs on mobile: the one compiled into the bare-kit
107
+ * binaries that react-native-bare-kit ships, not any `bare-runtime` package
108
+ * in node_modules.
109
+ *
110
+ * Checks the built-in table, then the installed iOS framework's Info.plist,
111
+ * and only then GitHub.
112
+ */
113
+ export async function resolveMobileBareRuntime(options) {
114
+ const { projectRoot, network = true, onProgress, fetchText: fetch = fetchText } = options;
115
+ const packageDir = findInAncestorNodeModules(projectRoot, REACT_NATIVE_BARE_KIT);
116
+ if (packageDir === null) {
117
+ return {
118
+ resolved: false,
119
+ error: {
120
+ reason: `${REACT_NATIVE_BARE_KIT} is not installed, so the mobile Bare version is unknown`,
121
+ triedPaths: [path.join(projectRoot, 'node_modules', REACT_NATIVE_BARE_KIT)]
122
+ }
123
+ };
124
+ }
125
+ const packageJsonPath = path.join(packageDir, 'package.json');
126
+ const version = await readJsonVersion(packageJsonPath);
127
+ if (version === null) {
128
+ return {
129
+ resolved: false,
130
+ error: {
131
+ reason: `Could not read the version of ${REACT_NATIVE_BARE_KIT}`,
132
+ triedPaths: [packageJsonPath]
133
+ }
134
+ };
135
+ }
136
+ const known = REACT_NATIVE_BARE_KIT_RUNTIMES[version];
137
+ if (known !== undefined)
138
+ return resolved(known.bare, version, known.bareKit, 'table');
139
+ let bareKitVersion = await readInfoPlistVersion(packageDir);
140
+ if (bareKitVersion !== null) {
141
+ const bare = bareVersionForBareKit(bareKitVersion);
142
+ if (bare !== null)
143
+ return resolved(bare, version, bareKitVersion, 'info-plist');
144
+ }
145
+ const canLookUp = bareKitVersion === null
146
+ ? isNewerThanTable(version, REACT_NATIVE_BARE_KIT_RUNTIMES)
147
+ : isNewerThanTable(bareKitVersion, BARE_KIT_BARE_VERSIONS);
148
+ if (!canLookUp) {
149
+ return {
150
+ resolved: false,
151
+ error: {
152
+ reason: `The Bare version of ${REACT_NATIVE_BARE_KIT}@${version} could not be determined: ` +
153
+ (bareKitVersion === null
154
+ ? 'the release does not record its bare-kit version and its iOS framework Info.plist could not be read'
155
+ : `bare-kit ${bareKitVersion} does not name its Bare version in CMakeLists.txt`),
156
+ triedPaths: [packageJsonPath, path.join(packageDir, BARE_KIT_INFO_PLIST)]
157
+ }
158
+ };
159
+ }
160
+ if (!network) {
161
+ return {
162
+ resolved: false,
163
+ error: {
164
+ reason: `${REACT_NATIVE_BARE_KIT}@${version} is not in the built-in runtime table ` +
165
+ 'and network lookups are disabled',
166
+ triedPaths: [packageJsonPath]
167
+ }
168
+ };
169
+ }
170
+ onProgress?.(`Looking up the Bare version embedded in ${REACT_NATIVE_BARE_KIT}@${version} on ` +
171
+ `raw.githubusercontent.com (not in the built-in table, timeout ${NETWORK_TIMEOUT_MS / 1000}s per request)...`);
172
+ try {
173
+ if (bareKitVersion === null) {
174
+ bareKitVersion = await fetchBareKitVersionFromGitHub(version, fetch);
175
+ }
176
+ const bare = bareKitVersion === null
177
+ ? null
178
+ : (bareVersionForBareKit(bareKitVersion) ??
179
+ (await fetchBareVersionFromGitHub(bareKitVersion, fetch)));
180
+ if (bareKitVersion !== null && bare !== null) {
181
+ return resolved(bare, version, bareKitVersion, 'github');
182
+ }
183
+ return {
184
+ resolved: false,
185
+ error: {
186
+ reason: `Could not find the bare-kit or Bare version in the CMakeLists.txt of ${REACT_NATIVE_BARE_KIT}@${version}`,
187
+ triedPaths: [packageJsonPath]
188
+ }
189
+ };
190
+ }
191
+ catch (error) {
192
+ const message = error instanceof Error ? error.message : String(error);
193
+ return {
194
+ resolved: false,
195
+ error: {
196
+ reason: `Could not look up the Bare version of ${REACT_NATIVE_BARE_KIT}@${version}: ${message}`,
197
+ triedPaths: [packageJsonPath]
198
+ }
199
+ };
200
+ }
201
+ }
@@ -0,0 +1,12 @@
1
+ export interface BareKitRuntime {
2
+ bareKit: string;
3
+ bare: string;
4
+ }
5
+ /**
6
+ * react-native-bare-kit releases whose CMakeLists.txt names the bare-kit
7
+ * prebuilds it ships. Older releases carry no such reference.
8
+ */
9
+ export declare const REACT_NATIVE_BARE_KIT_RUNTIMES: Record<string, BareKitRuntime>;
10
+ /** Bare version each bare-kit release is built against. */
11
+ export declare const BARE_KIT_BARE_VERSIONS: Record<string, string>;
12
+ //# sourceMappingURL=bare-kit-runtimes.d.ts.map
@@ -0,0 +1,108 @@
1
+ // Generated by scripts/generate-bare-kit-runtimes.ts. Do not edit by hand.
2
+ /**
3
+ * react-native-bare-kit releases whose CMakeLists.txt names the bare-kit
4
+ * prebuilds it ships. Older releases carry no such reference.
5
+ */
6
+ export const REACT_NATIVE_BARE_KIT_RUNTIMES = {
7
+ '0.13.3': { bareKit: '2.0.2', bare: '1.28.1' },
8
+ '0.14.0': { bareKit: '2.1.0', bare: '1.28.1' },
9
+ '0.14.1': { bareKit: '2.1.1', bare: '1.28.1' },
10
+ '0.14.2': { bareKit: '2.1.2', bare: '1.28.6' },
11
+ '0.14.3': { bareKit: '2.1.3', bare: '1.28.6' },
12
+ '0.14.4': { bareKit: '2.2.0', bare: '1.29.3' },
13
+ '0.14.5': { bareKit: '2.2.1', bare: '1.29.4' },
14
+ '0.15.0': { bareKit: '2.3.0', bare: '1.29.4' },
15
+ '0.15.1': { bareKit: '2.5.0', bare: '1.33.1' },
16
+ '0.15.2': { bareKit: '2.5.0', bare: '1.33.1' },
17
+ '0.15.3': { bareKit: '2.5.1', bare: '1.33.2' },
18
+ '0.15.4': { bareKit: '2.5.3', bare: '1.33.3' },
19
+ '0.15.5': { bareKit: '2.5.4', bare: '1.33.4' },
20
+ '0.15.6': { bareKit: '2.5.4', bare: '1.33.4' }
21
+ };
22
+ /** Bare version each bare-kit release is built against. */
23
+ export const BARE_KIT_BARE_VERSIONS = {
24
+ '1.0.0': '1.12.2',
25
+ '1.0.1': '1.12.3',
26
+ '1.0.2': '1.12.3',
27
+ '1.1.0': '1.13.1',
28
+ '1.2.0': '1.15.0',
29
+ '1.2.1': '1.15.0',
30
+ '1.2.2': '1.15.2',
31
+ '1.2.3': '1.15.2',
32
+ '1.2.4': '1.15.2',
33
+ '1.2.5': '1.15.2',
34
+ '1.3.0': '1.16.0',
35
+ '1.3.1': '1.16.0',
36
+ '1.3.2': '1.16.1',
37
+ '1.3.3': '1.16.1',
38
+ '1.3.4': '1.16.2',
39
+ '1.3.5': '1.16.4',
40
+ '1.3.6': '1.16.5',
41
+ '1.4.0': '1.17.0',
42
+ '1.4.1': '1.17.1',
43
+ '1.4.2': '1.17.3',
44
+ '1.4.3': '1.17.3',
45
+ '1.4.4': '1.17.3',
46
+ '1.4.5': '1.17.5',
47
+ '1.4.6': '1.17.6',
48
+ '1.5.0': '1.17.6',
49
+ '1.5.1': '1.17.6',
50
+ '1.5.2': '1.18.0',
51
+ '1.5.3': '1.18.1',
52
+ '1.5.4': '1.18.2',
53
+ '1.5.5': '1.18.3',
54
+ '1.5.6': '1.18.4',
55
+ '1.6.0': '1.19.0',
56
+ '1.7.0': '1.20.1',
57
+ '1.7.1': '1.20.2',
58
+ '1.8.0': '1.20.2',
59
+ '1.8.1': '1.20.2',
60
+ '1.8.2': '1.20.2',
61
+ '1.8.3': '1.20.2',
62
+ '1.9.0': '1.21.5',
63
+ '1.9.1': '1.21.6',
64
+ '1.9.2': '1.21.6',
65
+ '1.9.3': '1.21.7',
66
+ '1.9.4': '1.21.8',
67
+ '1.9.5': '1.21.8',
68
+ '1.10.0': '1.22.0',
69
+ '1.10.1': '1.22.0',
70
+ '1.10.2': '1.22.1',
71
+ '1.11.0': '1.23.3',
72
+ '1.11.1': '1.23.4',
73
+ '1.11.2': '1.23.4',
74
+ '1.11.3': '1.23.4',
75
+ '1.12.0': '1.24.0',
76
+ '1.12.1': '1.24.1',
77
+ '1.12.2': '1.24.1',
78
+ '1.12.3': '1.24.3',
79
+ '1.12.4': '1.24.3',
80
+ '1.13.0': '1.24.3',
81
+ '1.13.1': '1.24.3',
82
+ '1.13.2': '1.24.5',
83
+ '1.13.3': '1.24.6',
84
+ '1.14.0': '1.25.0',
85
+ '1.15.0': '1.27.0',
86
+ '1.15.1': '1.27.0',
87
+ '1.15.2': '1.27.0',
88
+ '2.0.0': '1.28.1',
89
+ '2.0.1': '1.28.1',
90
+ '2.0.2': '1.28.1',
91
+ '2.1.0': '1.28.1',
92
+ '2.1.1': '1.28.1',
93
+ '2.1.2': '1.28.6',
94
+ '2.1.3': '1.28.6',
95
+ '2.2.0': '1.29.3',
96
+ '2.2.1': '1.29.4',
97
+ '2.3.0': '1.29.4',
98
+ '2.4.0': '1.29.4',
99
+ '2.4.1': '1.31.1',
100
+ '2.4.2': '1.31.2',
101
+ '2.4.3': '1.31.2',
102
+ '2.5.0': '1.33.1',
103
+ '2.5.1': '1.33.2',
104
+ '2.5.2': '1.33.3',
105
+ '2.5.3': '1.33.3',
106
+ '2.5.4': '1.33.4',
107
+ '2.5.5': '1.33.4'
108
+ };
@@ -2,7 +2,7 @@ import { promises as fsp } from 'node:fs';
2
2
  import path from 'node:path';
3
3
  import { DEFAULT_HOSTS } from '../bundle/constants.js';
4
4
  import { buildNestedPathIndex, extractBarePackHeader, extractPackedString } from '../bundle/manifest.js';
5
- import { deduplicateAddons, readAddonPackageJson } from './addon-source.js';
5
+ import { createLimiter, deduplicateAddons, FS_CONCURRENCY, readAddonPackageJson } from './addon-source.js';
6
6
  /** bare-pack resolves a linked native addon to this prefix instead of a module path. */
7
7
  const LINKED_PREFIX = 'linked:';
8
8
  /** Reserved resolution key naming the package.json that owns a module. */
@@ -58,21 +58,22 @@ export async function collectAddonsFromBundle(options) {
58
58
  projectRoot,
59
59
  pathsByPackage
60
60
  });
61
+ const limit = createLimiter(FS_CONCURRENCY);
62
+ const lookups = [...pathsByPackage].flatMap(([pkgName, candidates]) => [...candidates].map((candidate) => ({ pkgName, candidate })));
63
+ const results = await Promise.all(lookups.map(({ pkgName, candidate }) => limit(() => readAddonPackageJson({ packageJsonPath: candidate, expectedName: pkgName }))));
61
64
  const addons = [];
62
- for (const [pkgName, candidates] of pathsByPackage) {
63
- for (const candidate of candidates) {
64
- const result = await readAddonPackageJson({
65
- packageJsonPath: candidate,
66
- expectedName: pkgName
67
- });
68
- if (result.isAddon && result.addon) {
69
- if (analysed !== null)
70
- result.addon.linkedHosts = analysed.get(candidate) ?? [];
71
- addons.push(result.addon);
72
- }
73
- else if (result.invalid !== undefined && diagnostics !== undefined) {
74
- diagnostics.invalidPackageJsons.push(result.invalid);
75
- }
65
+ for (const [index, { candidate }] of lookups.entries()) {
66
+ const result = results[index];
67
+ if (result.record !== undefined && diagnostics !== undefined) {
68
+ diagnostics.packages.push(result.record);
69
+ }
70
+ if (result.isAddon && result.addon) {
71
+ if (analysed !== null)
72
+ result.addon.linkedHosts = analysed.get(candidate) ?? [];
73
+ addons.push(result.addon);
74
+ }
75
+ else if (result.invalid !== undefined && diagnostics !== undefined) {
76
+ diagnostics.invalidPackageJsons.push(result.invalid);
76
77
  }
77
78
  }
78
79
  return deduplicateAddons(addons);