@qvac/sdk 0.20.1 → 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 +76 -13
- package/README.md +39 -5
- 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 +5 -4
- package/dist/src/client/api/assess-model-fit.js +24 -7
- 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 +30 -25
- 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,278 @@
|
|
|
1
|
+
import { spawn } from 'node:child_process';
|
|
2
|
+
import { promises as fsp } from 'node:fs';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import semver from 'semver';
|
|
5
|
+
const PACKAGE_MANAGERS = ['npm', 'pnpm', 'bun', 'yarn'];
|
|
6
|
+
const LOCKFILES = [
|
|
7
|
+
['package-lock.json', 'npm'],
|
|
8
|
+
['npm-shrinkwrap.json', 'npm'],
|
|
9
|
+
['pnpm-lock.yaml', 'pnpm'],
|
|
10
|
+
['bun.lock', 'bun'],
|
|
11
|
+
['bun.lockb', 'bun'],
|
|
12
|
+
['yarn.lock', 'yarn']
|
|
13
|
+
];
|
|
14
|
+
/**
|
|
15
|
+
* Files a package manager writes into the node_modules it installs. They name
|
|
16
|
+
* the tool that built the tree even where the project keeps no lockfile. Bun's
|
|
17
|
+
* default layout writes none.
|
|
18
|
+
*/
|
|
19
|
+
const INSTALL_MARKERS = [
|
|
20
|
+
['.package-lock.json', 'npm'],
|
|
21
|
+
['.modules.yaml', 'pnpm'],
|
|
22
|
+
['.yarn-state.yml', 'yarn'],
|
|
23
|
+
['.yarn-integrity', 'yarn']
|
|
24
|
+
];
|
|
25
|
+
/**
|
|
26
|
+
* The package manager that owns `projectRoot`, from the project's own
|
|
27
|
+
* `packageManager` field, lockfile, or node_modules install files. A project
|
|
28
|
+
* with none of those is a workspace member only if the nearest directory above
|
|
29
|
+
* it that has them is a workspace root listing it; any other enclosing project
|
|
30
|
+
* belongs to someone else, and its package manager is not this one's.
|
|
31
|
+
*/
|
|
32
|
+
export async function detectPackageManager(projectRoot) {
|
|
33
|
+
const start = path.resolve(projectRoot);
|
|
34
|
+
const own = await readInstallEvidence(start);
|
|
35
|
+
if (hasEvidence(own))
|
|
36
|
+
return decidePackageManager(start, own);
|
|
37
|
+
let dir = start;
|
|
38
|
+
for (;;) {
|
|
39
|
+
const parent = path.dirname(dir);
|
|
40
|
+
if (parent === dir) {
|
|
41
|
+
return {
|
|
42
|
+
manager: null,
|
|
43
|
+
reason: `no lockfile or packageManager field found in ${start} or its parent directories`
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
dir = parent;
|
|
47
|
+
const evidence = await readInstallEvidence(dir);
|
|
48
|
+
if (!hasEvidence(evidence))
|
|
49
|
+
continue;
|
|
50
|
+
if (!(await isWorkspaceMember(dir, start))) {
|
|
51
|
+
return {
|
|
52
|
+
manager: null,
|
|
53
|
+
reason: `${start} has no lockfile of its own, and ${dir}, which has one, ` +
|
|
54
|
+
'is not a workspace root that lists it'
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
return decidePackageManager(dir, evidence);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
export function isPackageManagerName(value) {
|
|
61
|
+
return PACKAGE_MANAGERS.includes(value);
|
|
62
|
+
}
|
|
63
|
+
function hasEvidence(evidence) {
|
|
64
|
+
return evidence.declared !== null || evidence.found.length > 0;
|
|
65
|
+
}
|
|
66
|
+
/** A declared `packageManager` decides; otherwise every lockfile and install file must agree. */
|
|
67
|
+
function decidePackageManager(dir, evidence) {
|
|
68
|
+
const { declared, found } = evidence;
|
|
69
|
+
if (declared !== null) {
|
|
70
|
+
const name = declared.split('@')[0] ?? '';
|
|
71
|
+
if (!isPackageManagerName(name)) {
|
|
72
|
+
return {
|
|
73
|
+
manager: null,
|
|
74
|
+
reason: `package.json in ${dir} declares packageManager "${declared}", ` +
|
|
75
|
+
'which is not npm, pnpm, bun, or Yarn'
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
return {
|
|
79
|
+
manager: name,
|
|
80
|
+
source: `packageManager "${declared}" in ${path.join(dir, 'package.json')}`
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
const managers = [...new Set(found.map((entry) => entry.manager))];
|
|
84
|
+
const [first] = found;
|
|
85
|
+
if (managers.length === 1 && first !== undefined) {
|
|
86
|
+
return { manager: first.manager, source: first.source };
|
|
87
|
+
}
|
|
88
|
+
return {
|
|
89
|
+
manager: null,
|
|
90
|
+
reason: `${dir} has install files from ${managers.join(', ')} ` +
|
|
91
|
+
`(${found.map((entry) => path.relative(dir, entry.source)).join(', ')}); ` +
|
|
92
|
+
'set the packageManager field in package.json to pick one'
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
async function readInstallEvidence(dir) {
|
|
96
|
+
const found = [];
|
|
97
|
+
for (const [file, manager] of LOCKFILES) {
|
|
98
|
+
const source = path.join(dir, file);
|
|
99
|
+
if (await isFile(source))
|
|
100
|
+
found.push({ manager, source });
|
|
101
|
+
}
|
|
102
|
+
for (const [file, manager] of INSTALL_MARKERS) {
|
|
103
|
+
const source = path.join(dir, 'node_modules', file);
|
|
104
|
+
if (await isFile(source))
|
|
105
|
+
found.push({ manager, source });
|
|
106
|
+
}
|
|
107
|
+
const manifest = await readPackageJson(dir);
|
|
108
|
+
const field = manifest?.['packageManager'];
|
|
109
|
+
return { declared: typeof field === 'string' && field.length > 0 ? field : null, found };
|
|
110
|
+
}
|
|
111
|
+
async function isFile(filePath) {
|
|
112
|
+
try {
|
|
113
|
+
return (await fsp.stat(filePath)).isFile();
|
|
114
|
+
}
|
|
115
|
+
catch {
|
|
116
|
+
return false;
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
async function readPackageJson(dir) {
|
|
120
|
+
try {
|
|
121
|
+
const parsed = JSON.parse(await fsp.readFile(path.join(dir, 'package.json'), 'utf8'));
|
|
122
|
+
if (typeof parsed !== 'object' || parsed === null || Array.isArray(parsed))
|
|
123
|
+
return null;
|
|
124
|
+
return parsed;
|
|
125
|
+
}
|
|
126
|
+
catch {
|
|
127
|
+
return null;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Whether the workspace globs declared at `rootDir` (package.json `workspaces`
|
|
132
|
+
* for npm, Yarn, and bun; `pnpm-workspace.yaml` for pnpm) include `memberDir`.
|
|
133
|
+
*/
|
|
134
|
+
export async function isWorkspaceMember(rootDir, memberDir) {
|
|
135
|
+
const relative = path.relative(rootDir, memberDir).split(path.sep).join('/');
|
|
136
|
+
let included = false;
|
|
137
|
+
for (const pattern of await readWorkspacePatterns(rootDir)) {
|
|
138
|
+
const negated = pattern.startsWith('!');
|
|
139
|
+
const glob = (negated ? pattern.slice(1) : pattern).replace(/^\.\//, '').replace(/\/+$/, '');
|
|
140
|
+
if (globToRegExp(glob).test(relative))
|
|
141
|
+
included = !negated;
|
|
142
|
+
}
|
|
143
|
+
return included;
|
|
144
|
+
}
|
|
145
|
+
async function readWorkspacePatterns(dir) {
|
|
146
|
+
const patterns = [];
|
|
147
|
+
const workspaces = (await readPackageJson(dir))?.['workspaces'];
|
|
148
|
+
const list = typeof workspaces === 'object' && workspaces !== null && !Array.isArray(workspaces)
|
|
149
|
+
? workspaces.packages
|
|
150
|
+
: workspaces;
|
|
151
|
+
if (Array.isArray(list)) {
|
|
152
|
+
patterns.push(...list.filter((entry) => typeof entry === 'string'));
|
|
153
|
+
}
|
|
154
|
+
try {
|
|
155
|
+
const yaml = await fsp.readFile(path.join(dir, 'pnpm-workspace.yaml'), 'utf8');
|
|
156
|
+
patterns.push(...parsePnpmWorkspacePackages(yaml));
|
|
157
|
+
}
|
|
158
|
+
catch {
|
|
159
|
+
// Not a pnpm workspace.
|
|
160
|
+
}
|
|
161
|
+
return patterns;
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* The `packages` list of a pnpm-workspace.yaml, in block (`- 'apps/*'`) or
|
|
165
|
+
* flow (`packages: ['apps/*']`) form. The SDK has no YAML parser, and the
|
|
166
|
+
* file's other keys are irrelevant here.
|
|
167
|
+
*/
|
|
168
|
+
export function parsePnpmWorkspacePackages(yaml) {
|
|
169
|
+
const patterns = [];
|
|
170
|
+
let inPackages = false;
|
|
171
|
+
for (const rawLine of yaml.split(/\r?\n/)) {
|
|
172
|
+
const line = rawLine.replace(/\s+#.*$/, '');
|
|
173
|
+
const flow = /^packages\s*:\s*\[(.*)\]\s*$/.exec(line);
|
|
174
|
+
if (flow !== null) {
|
|
175
|
+
patterns.push(...(flow[1] ?? '').split(',').map(unquote).filter(Boolean));
|
|
176
|
+
break;
|
|
177
|
+
}
|
|
178
|
+
if (/^packages\s*:\s*$/.test(line)) {
|
|
179
|
+
inPackages = true;
|
|
180
|
+
continue;
|
|
181
|
+
}
|
|
182
|
+
if (!inPackages)
|
|
183
|
+
continue;
|
|
184
|
+
if (/^\S/.test(line))
|
|
185
|
+
break;
|
|
186
|
+
const item = /^\s*-\s*(.+?)\s*$/.exec(line);
|
|
187
|
+
if (item !== null)
|
|
188
|
+
patterns.push(unquote(item[1] ?? ''));
|
|
189
|
+
}
|
|
190
|
+
return patterns;
|
|
191
|
+
}
|
|
192
|
+
function unquote(value) {
|
|
193
|
+
return value.trim().replace(/^(['"])(.*)\1$/, '$2');
|
|
194
|
+
}
|
|
195
|
+
/** `*` matches within one path segment, `**` across segments. */
|
|
196
|
+
function globToRegExp(glob) {
|
|
197
|
+
let source = '';
|
|
198
|
+
for (let i = 0; i < glob.length; i++) {
|
|
199
|
+
const char = glob[i] ?? '';
|
|
200
|
+
if (char === '*' && glob[i + 1] === '*') {
|
|
201
|
+
const slash = glob[i + 2] === '/';
|
|
202
|
+
source += slash ? '(?:.*/)?' : '.*';
|
|
203
|
+
i += slash ? 2 : 1;
|
|
204
|
+
}
|
|
205
|
+
else if (char === '*') {
|
|
206
|
+
source += '[^/]*';
|
|
207
|
+
}
|
|
208
|
+
else if (char === '?') {
|
|
209
|
+
source += '[^/]';
|
|
210
|
+
}
|
|
211
|
+
else {
|
|
212
|
+
source += char.replace(/[.+^${}()|[\]\\]/g, '\\$&');
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
return new RegExp(`^${source}$`);
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* Why `manager` cannot install in `cwd`, or null when it can. The supported
|
|
219
|
+
* set matches the installers the split addons document: npm 7+, pnpm, bun,
|
|
220
|
+
* and Yarn Berry.
|
|
221
|
+
*/
|
|
222
|
+
export async function checkPackageManagerSupport(manager, cwd) {
|
|
223
|
+
const result = await runPackageManager(manager, ['--version'], { cwd, quiet: true });
|
|
224
|
+
if (result.error !== undefined || result.code !== 0) {
|
|
225
|
+
return `\`${manager} --version\` failed; is ${manager} installed and on PATH?`;
|
|
226
|
+
}
|
|
227
|
+
const version = semver.coerce(result.stdout.trim())?.version;
|
|
228
|
+
if (version === undefined)
|
|
229
|
+
return null;
|
|
230
|
+
if (manager === 'npm' && semver.lt(version, '7.0.0')) {
|
|
231
|
+
return `npm ${version} is too old; npm 7 or later is required`;
|
|
232
|
+
}
|
|
233
|
+
if (manager === 'yarn' && semver.lt(version, '2.0.0')) {
|
|
234
|
+
return `Yarn ${version} (Yarn Classic) is not supported; use Yarn Berry (2 or later)`;
|
|
235
|
+
}
|
|
236
|
+
return null;
|
|
237
|
+
}
|
|
238
|
+
/** Arguments that add `specs` as exact-version dependencies of the package in cwd. */
|
|
239
|
+
export function installArgs(manager, specs) {
|
|
240
|
+
switch (manager) {
|
|
241
|
+
case 'npm':
|
|
242
|
+
return ['install', '--save-exact', ...specs];
|
|
243
|
+
case 'pnpm':
|
|
244
|
+
return ['add', '--save-exact', ...specs];
|
|
245
|
+
case 'bun':
|
|
246
|
+
case 'yarn':
|
|
247
|
+
return ['add', '--exact', ...specs];
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
/**
|
|
251
|
+
* Quiet runs capture stdout and stderr; other runs stream them to this
|
|
252
|
+
* process. Windows resolves the package managers' `.cmd` shims through the
|
|
253
|
+
* shell, which does not escape arguments, so callers must pass only
|
|
254
|
+
* validated ones.
|
|
255
|
+
*/
|
|
256
|
+
export function runPackageManager(manager, args, options) {
|
|
257
|
+
return new Promise((resolve) => {
|
|
258
|
+
let stdout = '';
|
|
259
|
+
let stderr = '';
|
|
260
|
+
const spawnOptions = {
|
|
261
|
+
cwd: options.cwd,
|
|
262
|
+
stdio: options.quiet ? ['ignore', 'pipe', 'pipe'] : 'inherit'
|
|
263
|
+
};
|
|
264
|
+
const proc = process.platform === 'win32'
|
|
265
|
+
? spawn([manager, ...args].join(' '), { ...spawnOptions, shell: true })
|
|
266
|
+
: spawn(manager, args, spawnOptions);
|
|
267
|
+
proc.stdout?.setEncoding('utf8');
|
|
268
|
+
proc.stdout?.on('data', (chunk) => {
|
|
269
|
+
stdout += chunk;
|
|
270
|
+
});
|
|
271
|
+
proc.stderr?.setEncoding('utf8');
|
|
272
|
+
proc.stderr?.on('data', (chunk) => {
|
|
273
|
+
stderr += chunk;
|
|
274
|
+
});
|
|
275
|
+
proc.on('error', (error) => resolve({ code: null, stdout, stderr, error }));
|
|
276
|
+
proc.on('close', (code) => resolve({ code, stdout, stderr }));
|
|
277
|
+
});
|
|
278
|
+
}
|
|
@@ -1,5 +1,14 @@
|
|
|
1
1
|
export { bundleSdk } from './bundle/index.js';
|
|
2
2
|
export type { BundleSdkOptions, BundleSdkResult } from './bundle/index.js';
|
|
3
|
+
export { ensureHostPrebuilds } from './host-prebuilds/index.js';
|
|
4
|
+
export type { EnsureHostPrebuildsOptions, EnsureHostPrebuildsResult, HostPrebuildPackage, PackageManagerName } from './host-prebuilds/index.js';
|
|
3
5
|
export { verifyBundle, hasErrors, hasWarnings, formatVerifyBundleResult } from './verify/index.js';
|
|
4
|
-
export type { VerifyBundleOptions, VerifyBundleResult, VerifyBundleIssue } from './verify/index.js';
|
|
6
|
+
export type { VerifyBundleOptions, VerifyBundleResult, VerifyBundleIssue, RuntimeGroup } from './verify/index.js';
|
|
7
|
+
export { HostPrebuildsInstallFailedError, HostPrebuildsInstallRefusedError } from '../utils/errors-client.js';
|
|
8
|
+
export { formatRuntimeSource } from './verify/abi.js';
|
|
9
|
+
export type { BareRuntime, BareRuntimeResolution } from './verify/abi.js';
|
|
10
|
+
export { isReactNativeBareKitInstalled } from './verify/bare-kit-runtime.js';
|
|
11
|
+
export { isMobileHost } from './verify/prebuilds.js';
|
|
12
|
+
export { formatEnginesAdvice } from './verify/engines-advice.js';
|
|
13
|
+
export type { EnginesAdvice, EnginesOverride, EnginesUpgrade } from './verify/engines-advice.js';
|
|
5
14
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1,2 +1,8 @@
|
|
|
1
1
|
export { bundleSdk } from './bundle/index.js';
|
|
2
|
+
export { ensureHostPrebuilds } from './host-prebuilds/index.js';
|
|
2
3
|
export { verifyBundle, hasErrors, hasWarnings, formatVerifyBundleResult } from './verify/index.js';
|
|
4
|
+
export { HostPrebuildsInstallFailedError, HostPrebuildsInstallRefusedError } from '../utils/errors-client.js';
|
|
5
|
+
export { formatRuntimeSource } from './verify/abi.js';
|
|
6
|
+
export { isReactNativeBareKitInstalled } from './verify/bare-kit-runtime.js';
|
|
7
|
+
export { isMobileHost } from './verify/prebuilds.js';
|
|
8
|
+
export { formatEnginesAdvice } from './verify/engines-advice.js';
|
|
@@ -1,7 +1,10 @@
|
|
|
1
1
|
import { type NativeAddon } from './addon-source.js';
|
|
2
2
|
export interface BareRuntime {
|
|
3
3
|
version: string;
|
|
4
|
-
source: 'flag' | 'config' | 'bare-runtime' | 'bare';
|
|
4
|
+
source: 'flag' | 'config' | 'bare-runtime' | 'bare' | 'react-native-bare-kit';
|
|
5
|
+
/** Installed version of the package named by `source`, when it differs from `version`. */
|
|
6
|
+
packageVersion?: string;
|
|
7
|
+
detail?: string;
|
|
5
8
|
}
|
|
6
9
|
export interface UnresolvedBareRuntime {
|
|
7
10
|
reason: string;
|
|
@@ -27,6 +30,15 @@ export interface AbiMismatchIssue {
|
|
|
27
30
|
enginesBare: string;
|
|
28
31
|
runtimeVersion: string;
|
|
29
32
|
}
|
|
33
|
+
/** A bundled package that is not an addon but still declares engines.bare. */
|
|
34
|
+
export interface EnginesMismatchIssue {
|
|
35
|
+
code: 'engines-mismatch';
|
|
36
|
+
level: 'error';
|
|
37
|
+
package: string;
|
|
38
|
+
message: string;
|
|
39
|
+
enginesBare: string;
|
|
40
|
+
runtimeVersion: string;
|
|
41
|
+
}
|
|
30
42
|
export interface UnknownRuntimeIssue {
|
|
31
43
|
code: 'unknown-runtime-version';
|
|
32
44
|
level: 'warning';
|
|
@@ -40,13 +52,21 @@ export interface MalformedEnginesBareIssue {
|
|
|
40
52
|
enginesBare: string;
|
|
41
53
|
message: string;
|
|
42
54
|
}
|
|
43
|
-
export type AbiIssue = AbiMismatchIssue | UnknownRuntimeIssue | MalformedEnginesBareIssue;
|
|
55
|
+
export type AbiIssue = AbiMismatchIssue | EnginesMismatchIssue | UnknownRuntimeIssue | MalformedEnginesBareIssue;
|
|
44
56
|
export interface CheckAbiOptions {
|
|
45
57
|
addons: NativeAddon[];
|
|
46
58
|
runtime: BareRuntimeResolution;
|
|
59
|
+
/** Non-addon packages that declare engines.bare. */
|
|
60
|
+
packages?: EnginesPackage[] | undefined;
|
|
61
|
+
}
|
|
62
|
+
export interface EnginesPackage {
|
|
63
|
+
name: string;
|
|
64
|
+
version?: string;
|
|
65
|
+
enginesBare: string;
|
|
47
66
|
}
|
|
48
67
|
export declare function resolveBareRuntime(options: ResolveBareRuntimeOptions): Promise<BareRuntimeResolution>;
|
|
49
68
|
export declare function normalizeVersion(value: string): string | null;
|
|
50
69
|
export declare function formatConfigLabel(projectRoot: string, configPath?: string): string;
|
|
70
|
+
export declare function formatRuntimeSource(runtime: BareRuntime): string;
|
|
51
71
|
export declare function checkAbi(options: CheckAbiOptions): AbiIssue[];
|
|
52
72
|
//# sourceMappingURL=abi.d.ts.map
|
|
@@ -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
|
|
76
|
-
|
|
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
|
|
81
|
-
|
|
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:
|
|
89
|
-
enginesBare: range,
|
|
90
|
-
message: `${
|
|
91
|
-
|
|
92
|
-
'Report this to the
|
|
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(
|
|
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
|
-
`
|
|
106
|
-
'
|
|
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
|
-
|
|
112
|
-
|
|
119
|
+
const { version } = runtime.runtime;
|
|
120
|
+
for (const entry of checkable) {
|
|
121
|
+
if (semver.satisfies(version, entry.range))
|
|
113
122
|
continue;
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
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
|
|
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
|
|
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
|