@qvac/sdk 0.20.0 → 0.21.0
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/NOTICE +134 -66
- package/README.md +39 -3
- package/dist/examples/advisory-model-fit.d.ts +17 -16
- package/dist/examples/advisory-model-fit.js +18 -18
- package/dist/examples/asr/parakeet-indic-conformer-filesystem.js +3 -3
- package/dist/examples/asr/parakeet-unified-coreml.d.ts +2 -0
- package/dist/examples/asr/parakeet-unified-coreml.js +113 -0
- package/dist/examples/assess-model-fit.js +9 -4
- package/dist/examples/model-fit-ui/server.js +5 -2
- package/dist/examples/rpc-inference.d.ts +2 -0
- package/dist/examples/rpc-inference.js +51 -0
- package/dist/examples/rpc-server.d.ts +2 -0
- package/dist/examples/rpc-server.js +32 -0
- package/dist/examples/tools/llamacpp-deferred-tools.d.ts +2 -0
- package/dist/examples/tools/llamacpp-deferred-tools.js +77 -0
- package/dist/examples/tts/audio8.js +4 -0
- package/dist/examples/tts/moss-dialogue.d.ts +2 -0
- package/dist/examples/tts/moss-dialogue.js +63 -0
- package/dist/examples/tts/moss.d.ts +2 -0
- package/dist/examples/tts/moss.js +71 -0
- package/dist/scripts/contract/build-contract.d.ts +2 -1
- package/dist/scripts/contract/build-contract.js +4 -1
- package/dist/scripts/contract/build-numeric-constants.d.ts +15 -0
- package/dist/scripts/contract/build-numeric-constants.js +13 -0
- package/dist/scripts/contract/method-shapes.d.ts +3 -0
- package/dist/scripts/contract/method-shapes.js +3 -0
- package/dist/scripts/enforce-inference-versions.d.ts +18 -0
- package/dist/scripts/enforce-inference-versions.js +158 -0
- package/dist/scripts/generate-bare-kit-runtimes.d.ts +2 -0
- package/dist/scripts/generate-bare-kit-runtimes.js +106 -0
- package/dist/src/client/api/assess-model-fit.d.ts +11 -5
- package/dist/src/client/api/assess-model-fit.js +30 -8
- package/dist/src/client/api/bci-transcribe.d.ts +4 -1
- package/dist/src/client/api/get-system-resources.d.ts +8 -0
- package/dist/src/client/api/get-system-resources.js +8 -0
- package/dist/src/client/api/index.d.ts +1 -0
- package/dist/src/client/api/index.js +1 -0
- package/dist/src/client/api/rpc-server.d.ts +20 -0
- package/dist/src/client/api/rpc-server.js +45 -0
- package/dist/src/client/api/text-to-speech.d.ts +9 -0
- package/dist/src/client/api/text-to-speech.js +9 -0
- package/dist/src/client/api/transcribe.d.ts +21 -15
- package/dist/src/client/api/transcribe.js +65 -20
- package/dist/src/client/rpc/rpc-error.js +11 -7
- package/dist/src/commands/bundle/entry-gen.d.ts +2 -2
- package/dist/src/commands/bundle/entry-gen.js +8 -4
- package/dist/src/commands/bundle/index.d.ts +20 -0
- package/dist/src/commands/bundle/index.js +88 -12
- package/dist/src/commands/bundle/plugins.js +1 -1
- package/dist/src/commands/command-logger.d.ts +6 -0
- package/dist/src/commands/command-logger.js +12 -0
- package/dist/src/commands/host-prebuilds/index.d.ts +71 -0
- package/dist/src/commands/host-prebuilds/index.js +227 -0
- package/dist/src/commands/host-prebuilds/package-manager.d.ts +54 -0
- package/dist/src/commands/host-prebuilds/package-manager.js +278 -0
- package/dist/src/commands/index.d.ts +10 -1
- package/dist/src/commands/index.js +6 -0
- package/dist/src/commands/verify/abi.d.ts +22 -2
- package/dist/src/commands/verify/abi.js +49 -27
- package/dist/src/commands/verify/addon-source.d.ts +22 -0
- package/dist/src/commands/verify/addon-source.js +69 -3
- package/dist/src/commands/verify/bare-kit-runtime.d.ts +38 -0
- package/dist/src/commands/verify/bare-kit-runtime.js +201 -0
- package/dist/src/commands/verify/bare-kit-runtimes.d.ts +12 -0
- package/dist/src/commands/verify/bare-kit-runtimes.js +108 -0
- package/dist/src/commands/verify/bundle-source.js +16 -15
- package/dist/src/commands/verify/engines-advice.d.ts +73 -0
- package/dist/src/commands/verify/engines-advice.js +271 -0
- package/dist/src/commands/verify/index.d.ts +22 -0
- package/dist/src/commands/verify/index.js +151 -13
- package/dist/src/commands/verify/node-modules-source.js +43 -39
- package/dist/src/commands/verify/prebuilds.d.ts +19 -0
- package/dist/src/commands/verify/prebuilds.js +52 -13
- package/dist/src/expo/plugins/index.d.ts +2 -0
- package/dist/src/expo/plugins/withMobileBundle.d.ts +15 -5
- package/dist/src/expo/plugins/withMobileBundle.js +68 -42
- package/dist/src/expo/plugins/withQvacSDK.d.ts +7 -1
- package/dist/src/expo/plugins/withQvacSDK.js +6 -3
- package/dist/src/index.d.ts +5 -2
- package/dist/src/index.js +4 -2
- package/dist/src/schemas/sdk-errors-client.d.ts +2 -0
- package/dist/src/schemas/sdk-errors-client.js +16 -0
- package/dist/src/schemas/sdk-errors-server.d.ts +1 -0
- package/dist/src/schemas/sdk-errors-server.js +5 -0
- package/dist/src/utils/errors-client.d.ts +15 -0
- package/dist/src/utils/errors-client.js +26 -0
- package/dist/src/utils/errors-server.d.ts +1 -0
- package/dist/src/utils/errors-server.js +1 -0
- package/dist/src/utils/mcp-adapter.js +7 -1
- package/dist/src/utils/tool-helpers.d.ts +4 -0
- package/dist/src/utils/tool-helpers.js +2 -0
- package/dist/src/worker/ggml-rpc-server-provider.d.ts +2 -0
- package/dist/src/worker/ggml-rpc-server-provider.js +1 -0
- package/dist/src/worker/rpc-server-provider.d.ts +3 -0
- package/dist/src/worker/rpc-server-provider.js +1 -0
- package/package.json +31 -27
- package/dist/scripts/enforce-inference-peer-dependencies.d.ts +0 -2
- package/dist/scripts/enforce-inference-peer-dependencies.js +0 -39
- package/dist/src/deprecate.d.ts +0 -2
- package/dist/src/deprecate.js +0 -9
- package/dist/src/worker/legacy-worker-entry.d.ts +0 -2
- package/dist/src/worker/legacy-worker-entry.js +0 -3
- package/dist/src/worker/worker-core.d.ts +0 -7
- package/dist/src/worker/worker-core.js +0 -8
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import { type PackageManagerName } from '../host-prebuilds/package-manager.js';
|
|
2
|
+
import { type BareRuntime } from './abi.js';
|
|
3
|
+
import type { PackageRecord } from './addon-source.js';
|
|
4
|
+
import { type ProgressFn } from './bare-kit-runtime.js';
|
|
5
|
+
export interface EnginesFailure {
|
|
6
|
+
name: string;
|
|
7
|
+
version?: string;
|
|
8
|
+
enginesBare: string;
|
|
9
|
+
}
|
|
10
|
+
export interface EnginesParent {
|
|
11
|
+
name: string;
|
|
12
|
+
range: string;
|
|
13
|
+
/** Whether the suggested override version satisfies this parent's range. */
|
|
14
|
+
satisfied: boolean;
|
|
15
|
+
}
|
|
16
|
+
export interface EnginesOverride {
|
|
17
|
+
name: string;
|
|
18
|
+
installedVersions: string[];
|
|
19
|
+
enginesBare: string[];
|
|
20
|
+
/** Newest published version compatible with the runtime, or null if none was found. */
|
|
21
|
+
version: string | null;
|
|
22
|
+
parents: EnginesParent[];
|
|
23
|
+
snippet: string | null;
|
|
24
|
+
/** True when network lookups were disabled, so no version was searched for. */
|
|
25
|
+
lookupSkipped?: boolean;
|
|
26
|
+
lookupError?: string;
|
|
27
|
+
}
|
|
28
|
+
export interface EnginesUpgrade {
|
|
29
|
+
packageName: string;
|
|
30
|
+
from: string;
|
|
31
|
+
to: string;
|
|
32
|
+
bare: string;
|
|
33
|
+
}
|
|
34
|
+
export interface EnginesAdvice {
|
|
35
|
+
hosts: string[];
|
|
36
|
+
runtime: BareRuntime;
|
|
37
|
+
requiredBare: string;
|
|
38
|
+
upgrade: EnginesUpgrade | null;
|
|
39
|
+
upgradeHint: string;
|
|
40
|
+
overrides: EnginesOverride[];
|
|
41
|
+
packageManager: PackageManagerName | null;
|
|
42
|
+
}
|
|
43
|
+
export type FetchPackageMetadata = (name: string) => Promise<PackageMetadata>;
|
|
44
|
+
export interface PackageMetadata {
|
|
45
|
+
versions: Record<string, {
|
|
46
|
+
engines?: {
|
|
47
|
+
bare?: unknown;
|
|
48
|
+
};
|
|
49
|
+
}>;
|
|
50
|
+
}
|
|
51
|
+
export interface BuildEnginesAdviceOptions {
|
|
52
|
+
projectRoot: string;
|
|
53
|
+
hosts: string[];
|
|
54
|
+
runtime: BareRuntime;
|
|
55
|
+
failures: EnginesFailure[];
|
|
56
|
+
packages: PackageRecord[];
|
|
57
|
+
network?: boolean | undefined;
|
|
58
|
+
onProgress?: ProgressFn | undefined;
|
|
59
|
+
fetchPackageMetadata?: FetchPackageMetadata | undefined;
|
|
60
|
+
}
|
|
61
|
+
export declare function fetchPackageMetadata(name: string): Promise<PackageMetadata>;
|
|
62
|
+
export declare function formatOverrideSnippet(manager: PackageManagerName | null, name: string, version: string, parents: string[]): string;
|
|
63
|
+
/**
|
|
64
|
+
* Newest release that runs on the runtime and that every parent accepts,
|
|
65
|
+
* else one that at least one parent accepts. Without known parents, only the
|
|
66
|
+
* installed release line (`^installed`) is considered. A version no
|
|
67
|
+
* dependent accepts would only trade one failure for another, so none is
|
|
68
|
+
* suggested then.
|
|
69
|
+
*/
|
|
70
|
+
export declare function pickOverrideVersion(metadata: PackageMetadata, runtimeVersion: string, installedVersions: string[], parentRanges: string[]): string | null;
|
|
71
|
+
export declare function buildEnginesAdvice(options: BuildEnginesAdviceOptions): Promise<EnginesAdvice>;
|
|
72
|
+
export declare function formatEnginesAdvice(advice: EnginesAdvice): string[];
|
|
73
|
+
//# sourceMappingURL=engines-advice.d.ts.map
|
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
import semver from 'semver';
|
|
2
|
+
import { detectPackageManager } from '../host-prebuilds/package-manager.js';
|
|
3
|
+
import { formatRuntimeSource } from './abi.js';
|
|
4
|
+
import { findReactNativeBareKitUpgrade, NETWORK_TIMEOUT_MS, REACT_NATIVE_BARE_KIT } from './bare-kit-runtime.js';
|
|
5
|
+
import { REACT_NATIVE_BARE_KIT_RUNTIMES } from './bare-kit-runtimes.js';
|
|
6
|
+
const REGISTRY_URL = 'https://registry.npmjs.org';
|
|
7
|
+
/** The registry's abbreviated metadata lists `engines` per version at a fraction of the full size. */
|
|
8
|
+
const ABBREVIATED_METADATA_TYPE = 'application/vnd.npm.install-v1+json';
|
|
9
|
+
export async function fetchPackageMetadata(name) {
|
|
10
|
+
const url = `${REGISTRY_URL}/${encodeURIComponent(name)}`;
|
|
11
|
+
const response = await fetch(url, {
|
|
12
|
+
headers: { accept: ABBREVIATED_METADATA_TYPE },
|
|
13
|
+
signal: AbortSignal.timeout(NETWORK_TIMEOUT_MS)
|
|
14
|
+
});
|
|
15
|
+
if (!response.ok)
|
|
16
|
+
throw new Error(`GET ${url} returned HTTP ${response.status}`);
|
|
17
|
+
return (await response.json());
|
|
18
|
+
}
|
|
19
|
+
export function formatOverrideSnippet(manager, name, version, parents) {
|
|
20
|
+
let manifest;
|
|
21
|
+
switch (manager) {
|
|
22
|
+
case 'pnpm':
|
|
23
|
+
manifest = {
|
|
24
|
+
pnpm: {
|
|
25
|
+
overrides: Object.fromEntries(parents.length > 0 ? parents.map((p) => [`${p}>${name}`, version]) : [[name, version]])
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
break;
|
|
29
|
+
case 'yarn':
|
|
30
|
+
manifest = {
|
|
31
|
+
resolutions: Object.fromEntries(parents.length > 0 ? parents.map((p) => [`${p}/${name}`, version]) : [[name, version]])
|
|
32
|
+
};
|
|
33
|
+
break;
|
|
34
|
+
case 'bun':
|
|
35
|
+
// bun only supports top-level overrides.
|
|
36
|
+
manifest = { overrides: { [name]: version } };
|
|
37
|
+
break;
|
|
38
|
+
default:
|
|
39
|
+
manifest = {
|
|
40
|
+
overrides: Object.fromEntries(parents.length > 0 ? parents.map((p) => [p, { [name]: version }]) : [[name, version]])
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
return JSON.stringify(manifest, null, 2).replace(/\{\n\s+("[^"\n]+": "[^"\n]+")\n\s+\}/g, '{ $1 }');
|
|
44
|
+
}
|
|
45
|
+
function groupFailures(failures) {
|
|
46
|
+
const byName = new Map();
|
|
47
|
+
for (const failure of failures) {
|
|
48
|
+
let entry = byName.get(failure.name);
|
|
49
|
+
if (entry === undefined) {
|
|
50
|
+
entry = { versions: new Set(), ranges: new Set() };
|
|
51
|
+
byName.set(failure.name, entry);
|
|
52
|
+
}
|
|
53
|
+
if (failure.version !== undefined)
|
|
54
|
+
entry.versions.add(failure.version);
|
|
55
|
+
entry.ranges.add(failure.enginesBare);
|
|
56
|
+
}
|
|
57
|
+
return byName;
|
|
58
|
+
}
|
|
59
|
+
function findParents(name, packages) {
|
|
60
|
+
const seen = new Set();
|
|
61
|
+
const parents = [];
|
|
62
|
+
for (const record of packages) {
|
|
63
|
+
const range = record.dependencies[name];
|
|
64
|
+
if (range === undefined)
|
|
65
|
+
continue;
|
|
66
|
+
const key = `${record.name}\0${range}`;
|
|
67
|
+
if (seen.has(key))
|
|
68
|
+
continue;
|
|
69
|
+
seen.add(key);
|
|
70
|
+
parents.push({ name: record.name, range });
|
|
71
|
+
}
|
|
72
|
+
return parents.sort((a, b) => a.name.localeCompare(b.name));
|
|
73
|
+
}
|
|
74
|
+
function runsOn(runtimeVersion, engines) {
|
|
75
|
+
const range = engines?.bare;
|
|
76
|
+
if (typeof range !== 'string')
|
|
77
|
+
return true;
|
|
78
|
+
return semver.validRange(range) !== null && semver.satisfies(runtimeVersion, range);
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Newest release that runs on the runtime and that every parent accepts,
|
|
82
|
+
* else one that at least one parent accepts. Without known parents, only the
|
|
83
|
+
* installed release line (`^installed`) is considered. A version no
|
|
84
|
+
* dependent accepts would only trade one failure for another, so none is
|
|
85
|
+
* suggested then.
|
|
86
|
+
*/
|
|
87
|
+
export function pickOverrideVersion(metadata, runtimeVersion, installedVersions, parentRanges) {
|
|
88
|
+
const compatible = Object.entries(metadata.versions)
|
|
89
|
+
.filter(([version, manifest]) => {
|
|
90
|
+
if (semver.valid(version) === null || semver.prerelease(version) !== null)
|
|
91
|
+
return false;
|
|
92
|
+
return runsOn(runtimeVersion, manifest.engines);
|
|
93
|
+
})
|
|
94
|
+
.map(([version]) => version)
|
|
95
|
+
.sort(semver.rcompare);
|
|
96
|
+
if (parentRanges.length > 0) {
|
|
97
|
+
const acceptedByAll = compatible.find((version) => parentRanges.every((range) => semver.satisfies(version, range)));
|
|
98
|
+
if (acceptedByAll !== undefined)
|
|
99
|
+
return acceptedByAll;
|
|
100
|
+
return (compatible.find((version) => parentRanges.some((range) => semver.satisfies(version, range))) ?? null);
|
|
101
|
+
}
|
|
102
|
+
const lines = installedVersions.filter((v) => semver.valid(v) !== null).map(releaseLine);
|
|
103
|
+
return (compatible.find((version) => lines.some((range) => semver.satisfies(version, range))) ?? null);
|
|
104
|
+
}
|
|
105
|
+
/** Versions `^version` would treat as compatible, including older ones: 1.4.0 -> 1.x, 0.20.3 -> 0.20.x. */
|
|
106
|
+
function releaseLine(version) {
|
|
107
|
+
const major = semver.major(version);
|
|
108
|
+
const minor = semver.minor(version);
|
|
109
|
+
if (major > 0)
|
|
110
|
+
return `${major}.x`;
|
|
111
|
+
if (minor > 0)
|
|
112
|
+
return `0.${minor}.x`;
|
|
113
|
+
return `0.0.${semver.patch(version)}`;
|
|
114
|
+
}
|
|
115
|
+
function requiredBareVersion(ranges) {
|
|
116
|
+
let required = null;
|
|
117
|
+
for (const range of ranges) {
|
|
118
|
+
const min = semver.validRange(range) === null ? null : semver.minVersion(range);
|
|
119
|
+
if (min !== null && (required === null || semver.gt(min.version, required))) {
|
|
120
|
+
required = min.version;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
return required ?? 'unknown';
|
|
124
|
+
}
|
|
125
|
+
function newestTableEntry() {
|
|
126
|
+
const versions = Object.keys(REACT_NATIVE_BARE_KIT_RUNTIMES).sort(semver.rcompare);
|
|
127
|
+
const newest = versions[0];
|
|
128
|
+
return newest === undefined
|
|
129
|
+
? null
|
|
130
|
+
: { version: newest, ...REACT_NATIVE_BARE_KIT_RUNTIMES[newest] };
|
|
131
|
+
}
|
|
132
|
+
function buildUpgrade(runtime, ranges, requiredBare) {
|
|
133
|
+
if (runtime.source === 'react-native-bare-kit' && runtime.packageVersion !== undefined) {
|
|
134
|
+
const target = findReactNativeBareKitUpgrade(runtime.packageVersion, ranges);
|
|
135
|
+
if (target !== null) {
|
|
136
|
+
return {
|
|
137
|
+
upgrade: {
|
|
138
|
+
packageName: REACT_NATIVE_BARE_KIT,
|
|
139
|
+
from: runtime.packageVersion,
|
|
140
|
+
to: target.version,
|
|
141
|
+
bare: target.bare
|
|
142
|
+
},
|
|
143
|
+
upgradeHint: `Upgrade ${REACT_NATIVE_BARE_KIT} to ${target.version} or newer ` +
|
|
144
|
+
`(embeds bare-kit ${target.bareKit}, Bare ${target.bare}).`
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
const newest = newestTableEntry();
|
|
148
|
+
return {
|
|
149
|
+
upgrade: null,
|
|
150
|
+
upgradeHint: `No ${REACT_NATIVE_BARE_KIT} release in the built-in table embeds Bare ${requiredBare} or newer` +
|
|
151
|
+
(newest === null
|
|
152
|
+
? '.'
|
|
153
|
+
: `; the newest known, ${newest.version}, embeds Bare ${newest.bare}. Check for a newer release.`)
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
if (runtime.source === 'bare-runtime' || runtime.source === 'bare') {
|
|
157
|
+
return {
|
|
158
|
+
upgrade: null,
|
|
159
|
+
upgradeHint: `Upgrade ${runtime.source} to ${requiredBare} or newer.`
|
|
160
|
+
};
|
|
161
|
+
}
|
|
162
|
+
return {
|
|
163
|
+
upgrade: null,
|
|
164
|
+
upgradeHint: `The runtime version comes from ${runtime.source}; raise it to ${requiredBare} or newer if the target runtime allows it.`
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
export async function buildEnginesAdvice(options) {
|
|
168
|
+
const { projectRoot, hosts, runtime, failures, packages, network = true, onProgress, fetchPackageMetadata: fetchOne = fetchPackageMetadata } = options;
|
|
169
|
+
const grouped = groupFailures(failures);
|
|
170
|
+
const allRanges = [...grouped.values()].flatMap((entry) => [...entry.ranges]);
|
|
171
|
+
const requiredBare = requiredBareVersion(allRanges);
|
|
172
|
+
const { manager: packageManager } = await detectPackageManager(projectRoot);
|
|
173
|
+
const names = [...grouped.keys()].sort();
|
|
174
|
+
if (network && names.length > 0) {
|
|
175
|
+
onProgress?.(`Looking up releases of ${names.join(', ')} on registry.npmjs.org that run on Bare ` +
|
|
176
|
+
`${runtime.version} (${names.length} request${names.length === 1 ? '' : 's'}, timeout ${NETWORK_TIMEOUT_MS / 1000}s)...`);
|
|
177
|
+
}
|
|
178
|
+
const overrides = await Promise.all(names.map(async (name) => {
|
|
179
|
+
const entry = grouped.get(name);
|
|
180
|
+
const installedVersions = [...entry.versions].sort();
|
|
181
|
+
const parents = findParents(name, packages);
|
|
182
|
+
const override = {
|
|
183
|
+
name,
|
|
184
|
+
installedVersions,
|
|
185
|
+
enginesBare: [...entry.ranges].sort(),
|
|
186
|
+
version: null,
|
|
187
|
+
parents: parents.map((parent) => ({ ...parent, satisfied: false })),
|
|
188
|
+
snippet: null
|
|
189
|
+
};
|
|
190
|
+
if (!network) {
|
|
191
|
+
override.lookupSkipped = true;
|
|
192
|
+
return override;
|
|
193
|
+
}
|
|
194
|
+
try {
|
|
195
|
+
const metadata = await fetchOne(name);
|
|
196
|
+
override.version = pickOverrideVersion(metadata, runtime.version, installedVersions, parents.map((parent) => parent.range));
|
|
197
|
+
}
|
|
198
|
+
catch (error) {
|
|
199
|
+
override.lookupError = error instanceof Error ? error.message : String(error);
|
|
200
|
+
return override;
|
|
201
|
+
}
|
|
202
|
+
const version = override.version;
|
|
203
|
+
if (version === null)
|
|
204
|
+
return override;
|
|
205
|
+
override.parents = parents.map((parent) => ({
|
|
206
|
+
...parent,
|
|
207
|
+
satisfied: semver.satisfies(version, parent.range)
|
|
208
|
+
}));
|
|
209
|
+
// Scoping only matters when some dependent must keep its current copy.
|
|
210
|
+
const accepting = override.parents.filter((parent) => parent.satisfied);
|
|
211
|
+
override.snippet = formatOverrideSnippet(packageManager, name, version, accepting.length === override.parents.length ? [] : accepting.map((parent) => parent.name));
|
|
212
|
+
return override;
|
|
213
|
+
}));
|
|
214
|
+
return {
|
|
215
|
+
hosts,
|
|
216
|
+
runtime,
|
|
217
|
+
requiredBare,
|
|
218
|
+
...buildUpgrade(runtime, allRanges, requiredBare),
|
|
219
|
+
overrides,
|
|
220
|
+
packageManager
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
const MANIFEST_FIELD = {
|
|
224
|
+
npm: '"overrides"',
|
|
225
|
+
pnpm: '"pnpm.overrides"',
|
|
226
|
+
yarn: '"resolutions"',
|
|
227
|
+
bun: '"overrides"'
|
|
228
|
+
};
|
|
229
|
+
export function formatEnginesAdvice(advice) {
|
|
230
|
+
const lines = [
|
|
231
|
+
` Fix for ${advice.hosts.join(', ')}:`,
|
|
232
|
+
` Runtime: Bare ${advice.runtime.version} (from ${formatRuntimeSource(advice.runtime)})`,
|
|
233
|
+
...advice.overrides.map((override) => ` Requires: ${override.name}@${override.installedVersions.join(', ') || 'unknown'} needs Bare ${override.enginesBare.join(' and ')}`),
|
|
234
|
+
` Option 1: ${advice.upgradeHint}`
|
|
235
|
+
];
|
|
236
|
+
for (const override of advice.overrides) {
|
|
237
|
+
const installed = override.installedVersions.join(', ') || 'unknown';
|
|
238
|
+
if (override.lookupSkipped === true) {
|
|
239
|
+
lines.push(` Option 2 (${override.name}): pin an older release; run again with network lookups ` +
|
|
240
|
+
'enabled (without --offline) to find one that runs on this Bare.');
|
|
241
|
+
continue;
|
|
242
|
+
}
|
|
243
|
+
if (override.version === null) {
|
|
244
|
+
const acceptedBy = override.parents.length === 0
|
|
245
|
+
? ` on the ${installed} release line`
|
|
246
|
+
: ` that ${override.parents.map((p) => `${p.name} (${p.range})`).join(', ')} accept${override.parents.length === 1 ? 's' : ''}`;
|
|
247
|
+
lines.push(` Option 2 (${override.name}): no release that runs on Bare ${advice.runtime.version}${acceptedBy} was found` +
|
|
248
|
+
(override.lookupError === undefined
|
|
249
|
+
? '; upgrade the runtime.'
|
|
250
|
+
: ` (${override.lookupError}).`));
|
|
251
|
+
continue;
|
|
252
|
+
}
|
|
253
|
+
const field = advice.packageManager === null
|
|
254
|
+
? '"overrides" (npm/bun), "pnpm.overrides" or "resolutions" (yarn)'
|
|
255
|
+
: MANIFEST_FIELD[advice.packageManager];
|
|
256
|
+
lines.push(` Option 2 (${override.name}): pin ${installed} -> ${override.version} with ${field} in your app's package.json:`);
|
|
257
|
+
for (const line of (override.snippet ?? '').split('\n'))
|
|
258
|
+
lines.push(` ${line}`);
|
|
259
|
+
const rejected = override.parents.filter((parent) => !parent.satisfied);
|
|
260
|
+
if (rejected.length > 0) {
|
|
261
|
+
lines.push(` ${rejected.map((p) => `${p.name} (${p.range})`).join(', ')} ` +
|
|
262
|
+
`${rejected.length === 1 ? 'does' : 'do'} not accept ${override.version}; ` +
|
|
263
|
+
'those copies are left as they are.');
|
|
264
|
+
}
|
|
265
|
+
if (advice.packageManager === 'bun' && override.parents.length > 0) {
|
|
266
|
+
lines.push(' bun applies overrides to every copy in the tree.');
|
|
267
|
+
}
|
|
268
|
+
}
|
|
269
|
+
lines.push('');
|
|
270
|
+
return lines;
|
|
271
|
+
}
|
|
@@ -1,12 +1,29 @@
|
|
|
1
1
|
import { type AddonSourceKind, type NativeAddon } from './addon-source.js';
|
|
2
2
|
import { type MissingPrebuildIssue } from './prebuilds.js';
|
|
3
3
|
import { type AbiIssue, type BareRuntimeResolution } from './abi.js';
|
|
4
|
+
import { type FetchText, type ProgressFn } from './bare-kit-runtime.js';
|
|
5
|
+
import { type EnginesAdvice, type FetchPackageMetadata } from './engines-advice.js';
|
|
4
6
|
export interface VerifyBundleOptions {
|
|
5
7
|
projectRoot: string;
|
|
6
8
|
addonsSource: string;
|
|
7
9
|
hosts: string[];
|
|
8
10
|
bareRuntimeVersion?: string;
|
|
9
11
|
configPath?: string;
|
|
12
|
+
/**
|
|
13
|
+
* Allow GitHub and npm registry requests: GitHub for a react-native-bare-kit
|
|
14
|
+
* release newer than the built-in table, the registry only after a mismatch
|
|
15
|
+
* is found, to suggest an override. Defaults to true.
|
|
16
|
+
*/
|
|
17
|
+
network?: boolean;
|
|
18
|
+
/** Called before any step that waits on the network. */
|
|
19
|
+
onProgress?: ProgressFn;
|
|
20
|
+
/** Test seams for the network lookups. */
|
|
21
|
+
fetchText?: FetchText;
|
|
22
|
+
fetchPackageMetadata?: FetchPackageMetadata;
|
|
23
|
+
}
|
|
24
|
+
export interface RuntimeGroup {
|
|
25
|
+
hosts: string[];
|
|
26
|
+
resolution: BareRuntimeResolution;
|
|
10
27
|
}
|
|
11
28
|
export interface InvalidSourceIssue {
|
|
12
29
|
code: 'invalid-source';
|
|
@@ -48,9 +65,14 @@ export interface VerifyBundleResult {
|
|
|
48
65
|
resolvedAddonsSource: string;
|
|
49
66
|
sourceKind: AddonSourceKind | null;
|
|
50
67
|
hosts: string[];
|
|
68
|
+
/** Runtime of the first entry in `runtimes`: the mobile one when any host is mobile. */
|
|
51
69
|
runtime: BareRuntimeResolution | null;
|
|
70
|
+
/** Mobile and desktop hosts run different Bare builds, so each is resolved separately. */
|
|
71
|
+
runtimes?: RuntimeGroup[];
|
|
52
72
|
addons: NativeAddon[];
|
|
53
73
|
issues: VerifyBundleIssue[];
|
|
74
|
+
/** How to fix each runtime that fails an engines.bare range. */
|
|
75
|
+
advice?: EnginesAdvice[];
|
|
54
76
|
}
|
|
55
77
|
export declare function verifyBundle(options: VerifyBundleOptions): Promise<VerifyBundleResult>;
|
|
56
78
|
export declare function hasErrors(result: VerifyBundleResult): boolean;
|
|
@@ -4,8 +4,10 @@ import { resolveConfigFileInProject, loadConfigFromPath } from '../../client/con
|
|
|
4
4
|
import { createCollectDiagnostics, formatAddonId } from './addon-source.js';
|
|
5
5
|
import { collectAddonsFromBundle, InvalidBundleSourceError } from './bundle-source.js';
|
|
6
6
|
import { collectAddonsFromNodeModules, InvalidNodeModulesSourceError } from './node-modules-source.js';
|
|
7
|
-
import { checkPrebuilds } from './prebuilds.js';
|
|
7
|
+
import { checkPrebuilds, isMobileHost } from './prebuilds.js';
|
|
8
8
|
import { checkAbi, formatConfigLabel, normalizeVersion, resolveBareRuntime } from './abi.js';
|
|
9
|
+
import { isReactNativeBareKitInstalled, resolveMobileBareRuntime } from './bare-kit-runtime.js';
|
|
10
|
+
import { buildEnginesAdvice, formatEnginesAdvice } from './engines-advice.js';
|
|
9
11
|
export async function verifyBundle(options) {
|
|
10
12
|
const { projectRoot, addonsSource, hosts, bareRuntimeVersion, configPath } = options;
|
|
11
13
|
const resolvedAddonsSource = path.isAbsolute(addonsSource)
|
|
@@ -119,6 +121,9 @@ export async function verifyBundle(options) {
|
|
|
119
121
|
};
|
|
120
122
|
}
|
|
121
123
|
const diagnostics = createCollectDiagnostics();
|
|
124
|
+
if (sourceKind === 'node-modules') {
|
|
125
|
+
options.onProgress?.(`Scanning ${resolvedAddonsSource} for native addons and engines.bare...`);
|
|
126
|
+
}
|
|
122
127
|
let addons;
|
|
123
128
|
try {
|
|
124
129
|
addons =
|
|
@@ -178,20 +183,57 @@ export async function verifyBundle(options) {
|
|
|
178
183
|
issues.push(...prebuildIssues);
|
|
179
184
|
}
|
|
180
185
|
let runtime = null;
|
|
186
|
+
let runtimes;
|
|
187
|
+
const advice = [];
|
|
181
188
|
if (invalidRuntimeVersion === null) {
|
|
182
|
-
const
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
189
|
+
const explicit = bareRuntimeVersion !== undefined
|
|
190
|
+
? { version: bareRuntimeVersion, source: 'flag' }
|
|
191
|
+
: configRuntimeVersion !== undefined
|
|
192
|
+
? { version: configRuntimeVersion, source: 'config' }
|
|
193
|
+
: null;
|
|
194
|
+
runtimes = await resolveRuntimeGroups({
|
|
195
|
+
projectRoot,
|
|
196
|
+
hosts,
|
|
197
|
+
explicit,
|
|
198
|
+
network: options.network,
|
|
199
|
+
onProgress: options.onProgress,
|
|
200
|
+
fetchText: options.fetchText
|
|
201
|
+
});
|
|
202
|
+
runtime = runtimes[0]?.resolution ?? null;
|
|
203
|
+
const packages = enginesPackages(diagnostics.packages);
|
|
204
|
+
const seen = new Set();
|
|
205
|
+
for (const group of runtimes) {
|
|
206
|
+
const groupIssues = checkAbi({
|
|
207
|
+
addons: addonsLinkedOn(addons, group.hosts),
|
|
208
|
+
runtime: group.resolution,
|
|
209
|
+
packages
|
|
210
|
+
}).filter((issue) => {
|
|
211
|
+
if (seen.has(issue.message))
|
|
212
|
+
return false;
|
|
213
|
+
seen.add(issue.message);
|
|
214
|
+
return true;
|
|
215
|
+
});
|
|
216
|
+
issues.push(...groupIssues);
|
|
217
|
+
const failures = groupIssues.flatMap((issue) => issue.code === 'abi-mismatch' || issue.code === 'engines-mismatch'
|
|
218
|
+
? [
|
|
219
|
+
failureOf(issue.code === 'abi-mismatch' ? issue.addon : issue.package, issue.enginesBare)
|
|
220
|
+
]
|
|
221
|
+
: []);
|
|
222
|
+
if (failures.length > 0 && group.resolution.resolved) {
|
|
223
|
+
advice.push(await buildEnginesAdvice({
|
|
224
|
+
projectRoot,
|
|
225
|
+
hosts: group.hosts,
|
|
226
|
+
runtime: group.resolution.runtime,
|
|
227
|
+
failures,
|
|
228
|
+
packages: diagnostics.packages,
|
|
229
|
+
network: options.network,
|
|
230
|
+
onProgress: options.onProgress,
|
|
231
|
+
fetchPackageMetadata: options.fetchPackageMetadata
|
|
232
|
+
}));
|
|
233
|
+
}
|
|
190
234
|
}
|
|
191
|
-
runtime = await resolveBareRuntime(runtimeOptions);
|
|
192
|
-
issues.push(...checkAbi({ addons, runtime }));
|
|
193
235
|
}
|
|
194
|
-
|
|
236
|
+
const result = {
|
|
195
237
|
addonsSource,
|
|
196
238
|
resolvedAddonsSource,
|
|
197
239
|
sourceKind,
|
|
@@ -200,6 +242,85 @@ export async function verifyBundle(options) {
|
|
|
200
242
|
addons,
|
|
201
243
|
issues
|
|
202
244
|
};
|
|
245
|
+
if (runtimes !== undefined)
|
|
246
|
+
result.runtimes = runtimes;
|
|
247
|
+
if (advice.length > 0)
|
|
248
|
+
result.advice = advice;
|
|
249
|
+
return result;
|
|
250
|
+
}
|
|
251
|
+
/** `name@version` ids as built by `formatAddonId`; scoped names keep their leading `@`. */
|
|
252
|
+
function failureOf(id, enginesBare) {
|
|
253
|
+
const at = id.lastIndexOf('@');
|
|
254
|
+
if (at <= 0)
|
|
255
|
+
return { name: id, enginesBare };
|
|
256
|
+
const version = id.slice(at + 1);
|
|
257
|
+
return version === 'unknown'
|
|
258
|
+
? { name: id.slice(0, at), enginesBare }
|
|
259
|
+
: { name: id.slice(0, at), version, enginesBare };
|
|
260
|
+
}
|
|
261
|
+
/**
|
|
262
|
+
* Addons a runtime group loads: those the bundle links on one of its hosts.
|
|
263
|
+
* Without link information (`linkedHosts` unset), every addon counts, as in
|
|
264
|
+
* `checkPrebuilds`.
|
|
265
|
+
*/
|
|
266
|
+
function addonsLinkedOn(addons, hosts) {
|
|
267
|
+
return addons.filter((addon) => addon.linkedHosts === undefined || addon.linkedHosts.some((host) => hosts.includes(host)));
|
|
268
|
+
}
|
|
269
|
+
function enginesPackages(records) {
|
|
270
|
+
const byId = new Map();
|
|
271
|
+
for (const record of records) {
|
|
272
|
+
if (record.isAddon || record.enginesBare === undefined)
|
|
273
|
+
continue;
|
|
274
|
+
const id = `${record.name}@${record.version ?? 'unknown'}`;
|
|
275
|
+
if (byId.has(id))
|
|
276
|
+
continue;
|
|
277
|
+
const pkg = { name: record.name, enginesBare: record.enginesBare };
|
|
278
|
+
if (record.version !== undefined)
|
|
279
|
+
pkg.version = record.version;
|
|
280
|
+
byId.set(id, pkg);
|
|
281
|
+
}
|
|
282
|
+
return [...byId.values()];
|
|
283
|
+
}
|
|
284
|
+
/**
|
|
285
|
+
* Mobile hosts run the Bare build inside react-native-bare-kit; desktop hosts
|
|
286
|
+
* run `bare-runtime` (or `bare`). An explicit version applies to every host.
|
|
287
|
+
* Without react-native-bare-kit installed, mobile hosts fall back to the
|
|
288
|
+
* desktop detection so projects that only bundle for mobile keep a runtime.
|
|
289
|
+
*/
|
|
290
|
+
async function resolveRuntimeGroups(options) {
|
|
291
|
+
const { projectRoot, hosts, explicit } = options;
|
|
292
|
+
if (explicit !== null) {
|
|
293
|
+
return [
|
|
294
|
+
{
|
|
295
|
+
hosts,
|
|
296
|
+
resolution: await resolveBareRuntime({
|
|
297
|
+
projectRoot,
|
|
298
|
+
explicitVersion: explicit.version,
|
|
299
|
+
explicitSource: explicit.source
|
|
300
|
+
})
|
|
301
|
+
}
|
|
302
|
+
];
|
|
303
|
+
}
|
|
304
|
+
const mobileHosts = hosts.filter(isMobileHost);
|
|
305
|
+
const desktopHosts = hosts.filter((host) => !isMobileHost(host));
|
|
306
|
+
const groups = [];
|
|
307
|
+
if (mobileHosts.length > 0) {
|
|
308
|
+
groups.push({
|
|
309
|
+
hosts: mobileHosts,
|
|
310
|
+
resolution: isReactNativeBareKitInstalled(projectRoot)
|
|
311
|
+
? await resolveMobileBareRuntime({
|
|
312
|
+
projectRoot,
|
|
313
|
+
network: options.network,
|
|
314
|
+
onProgress: options.onProgress,
|
|
315
|
+
fetchText: options.fetchText
|
|
316
|
+
})
|
|
317
|
+
: await resolveBareRuntime({ projectRoot })
|
|
318
|
+
});
|
|
319
|
+
}
|
|
320
|
+
if (desktopHosts.length > 0) {
|
|
321
|
+
groups.push({ hosts: desktopHosts, resolution: await resolveBareRuntime({ projectRoot }) });
|
|
322
|
+
}
|
|
323
|
+
return groups;
|
|
203
324
|
}
|
|
204
325
|
function buildInvalidPackageJsonIssues(records) {
|
|
205
326
|
return records.map((record) => {
|
|
@@ -262,6 +383,9 @@ export function formatVerifyBundleResult(result) {
|
|
|
262
383
|
sections.push('');
|
|
263
384
|
sections.push(...formatMissingPrebuilds(result.issues));
|
|
264
385
|
sections.push(...formatAbiMismatches(result.issues));
|
|
386
|
+
sections.push(...formatEnginesMismatches(result.issues));
|
|
387
|
+
for (const advice of result.advice ?? [])
|
|
388
|
+
sections.push(...formatEnginesAdvice(advice));
|
|
265
389
|
sections.push(...formatInvalidRuntimeVersions(result.issues));
|
|
266
390
|
sections.push(...formatMalformedEnginesBare(result.issues));
|
|
267
391
|
sections.push(...formatConfigLoadFailed(result.issues));
|
|
@@ -288,7 +412,9 @@ function formatMissingPrebuilds(issues) {
|
|
|
288
412
|
return [];
|
|
289
413
|
const lines = [' Missing prebuild:'];
|
|
290
414
|
for (const issue of matches) {
|
|
291
|
-
|
|
415
|
+
const pin = issue.platformPackage;
|
|
416
|
+
const needs = pin === undefined ? '' : ` (needs "${pin.name}": "${pin.version}" in package.json)`;
|
|
417
|
+
lines.push(` - ${issue.addon} for ${issue.host}${needs}`);
|
|
292
418
|
}
|
|
293
419
|
lines.push('');
|
|
294
420
|
return lines;
|
|
@@ -305,6 +431,18 @@ function formatAbiMismatches(issues) {
|
|
|
305
431
|
lines.push('');
|
|
306
432
|
return lines;
|
|
307
433
|
}
|
|
434
|
+
function formatEnginesMismatches(issues) {
|
|
435
|
+
const matches = issues.filter((issue) => issue.code === 'engines-mismatch');
|
|
436
|
+
if (matches.length === 0)
|
|
437
|
+
return [];
|
|
438
|
+
const lines = [' engines.bare mismatch:'];
|
|
439
|
+
for (const issue of matches) {
|
|
440
|
+
lines.push(` - ${issue.package} requires bare ${issue.enginesBare}, ` +
|
|
441
|
+
`runtime is ${issue.runtimeVersion}`);
|
|
442
|
+
}
|
|
443
|
+
lines.push('');
|
|
444
|
+
return lines;
|
|
445
|
+
}
|
|
308
446
|
function formatUnknownRuntime(issues) {
|
|
309
447
|
const matches = issues.filter((issue) => issue.code === 'unknown-runtime-version');
|
|
310
448
|
if (matches.length === 0)
|