@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.
- package/NOTICE +130 -62
- 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
|
@@ -18,26 +18,38 @@ function buildTranscribeRequest(params, requestId) {
|
|
|
18
18
|
};
|
|
19
19
|
}
|
|
20
20
|
export function transcribe(params, options) {
|
|
21
|
+
return createTranscribeCall(params, options);
|
|
22
|
+
}
|
|
23
|
+
export function createTranscribeCall(params, options, responseStream = stream) {
|
|
21
24
|
// Client-generated id surfaced synchronously on the returned promise
|
|
22
25
|
// ā same shape as `loadModel` / `downloadAsset` / `completion`. The
|
|
23
26
|
// CLI cancel bridge in `qvac serve` binds `req.on('close')` to
|
|
24
27
|
// `cancel({ requestId })` immediately after the call returns so a
|
|
25
28
|
// client disconnect aborts the in-flight transcription.
|
|
26
29
|
const requestId = generateClientRequestId();
|
|
27
|
-
|
|
28
|
-
|
|
30
|
+
let resolveStats = () => { };
|
|
31
|
+
let rejectStats = () => { };
|
|
32
|
+
const stats = new Promise((resolve, reject) => {
|
|
33
|
+
resolveStats = resolve;
|
|
34
|
+
rejectStats = reject;
|
|
35
|
+
});
|
|
36
|
+
stats.catch(() => { });
|
|
37
|
+
const inner = runTranscribe(params, requestId, options, resolveStats, responseStream);
|
|
38
|
+
inner.then(() => resolveStats(undefined), rejectStats);
|
|
39
|
+
return decoratePromise(inner, { requestId, stats });
|
|
29
40
|
}
|
|
30
|
-
async function runTranscribe(params, requestId, options) {
|
|
41
|
+
async function runTranscribe(params, requestId, options, onStats, responseStream) {
|
|
31
42
|
const request = buildTranscribeRequest(params, requestId);
|
|
32
43
|
if (params.metadata === true) {
|
|
33
44
|
const segments = [];
|
|
34
|
-
for await (const response of
|
|
45
|
+
for await (const response of responseStream(request, options)) {
|
|
35
46
|
if (response.type === 'transcribe') {
|
|
36
47
|
const parsed = transcribeResponseSchema.parse(response);
|
|
37
48
|
if (parsed.segment) {
|
|
38
49
|
segments.push(parsed.segment);
|
|
39
50
|
}
|
|
40
51
|
if (parsed.done) {
|
|
52
|
+
onStats(parsed.stats);
|
|
41
53
|
break;
|
|
42
54
|
}
|
|
43
55
|
}
|
|
@@ -45,13 +57,14 @@ async function runTranscribe(params, requestId, options) {
|
|
|
45
57
|
return segments;
|
|
46
58
|
}
|
|
47
59
|
let fullText = '';
|
|
48
|
-
for await (const response of
|
|
60
|
+
for await (const response of responseStream(request, options)) {
|
|
49
61
|
if (response.type === 'transcribe') {
|
|
50
62
|
const parsed = transcribeResponseSchema.parse(response);
|
|
51
63
|
if (parsed.text) {
|
|
52
64
|
fullText += parsed.text;
|
|
53
65
|
}
|
|
54
66
|
if (parsed.done) {
|
|
67
|
+
onStats(parsed.stats);
|
|
55
68
|
break;
|
|
56
69
|
}
|
|
57
70
|
}
|
|
@@ -144,16 +157,47 @@ export async function createTranscribeStreamSession(params, options, process, se
|
|
|
144
157
|
statsSettled = true;
|
|
145
158
|
rejectStatsPromise(error);
|
|
146
159
|
}
|
|
147
|
-
|
|
148
|
-
|
|
160
|
+
// Settled from the same terminal frame as `stats`, and on the same paths:
|
|
161
|
+
// resolved empty when the stream closes without one, rejected on error.
|
|
162
|
+
let diagnosticsSettled = false;
|
|
163
|
+
let resolveDiagnosticsPromise = () => { };
|
|
164
|
+
let rejectDiagnosticsPromise = () => { };
|
|
165
|
+
const diagnostics = new Promise((resolve, reject) => {
|
|
166
|
+
resolveDiagnosticsPromise = resolve;
|
|
167
|
+
rejectDiagnosticsPromise = reject;
|
|
168
|
+
});
|
|
169
|
+
diagnostics.catch(() => { });
|
|
170
|
+
function resolveDiagnostics(value) {
|
|
171
|
+
if (diagnosticsSettled)
|
|
172
|
+
return;
|
|
173
|
+
diagnosticsSettled = true;
|
|
174
|
+
resolveDiagnosticsPromise(value);
|
|
175
|
+
}
|
|
176
|
+
function rejectDiagnostics(error) {
|
|
177
|
+
if (diagnosticsSettled)
|
|
178
|
+
return;
|
|
179
|
+
diagnosticsSettled = true;
|
|
180
|
+
rejectDiagnosticsPromise(error);
|
|
181
|
+
}
|
|
182
|
+
function resolveTerminal(statsValue, diagnosticsValue) {
|
|
183
|
+
resolveStats(statsValue);
|
|
184
|
+
resolveDiagnostics(diagnosticsValue);
|
|
185
|
+
}
|
|
186
|
+
function resolveEmptyTerminal() {
|
|
187
|
+
resolveTerminal(undefined, undefined);
|
|
188
|
+
}
|
|
189
|
+
function rejectTerminal(error) {
|
|
190
|
+
rejectStats(error);
|
|
191
|
+
rejectDiagnostics(error);
|
|
149
192
|
}
|
|
150
193
|
function processResponse(line) {
|
|
151
|
-
return process(line,
|
|
194
|
+
return process(line, resolveTerminal);
|
|
152
195
|
}
|
|
153
|
-
const responses = parseLines(responseStream, processResponse,
|
|
196
|
+
const responses = parseLines(responseStream, processResponse, resolveEmptyTerminal, rejectTerminal);
|
|
154
197
|
let consumed = false;
|
|
155
198
|
return {
|
|
156
199
|
stats,
|
|
200
|
+
diagnostics,
|
|
157
201
|
write(audioChunk) {
|
|
158
202
|
requestStream.write(audioChunk);
|
|
159
203
|
},
|
|
@@ -161,7 +205,7 @@ export async function createTranscribeStreamSession(params, options, process, se
|
|
|
161
205
|
requestStream.end();
|
|
162
206
|
},
|
|
163
207
|
destroy() {
|
|
164
|
-
|
|
208
|
+
resolveEmptyTerminal();
|
|
165
209
|
requestStream.destroy();
|
|
166
210
|
responseStream.destroy();
|
|
167
211
|
},
|
|
@@ -182,7 +226,7 @@ function transcribeStreamDuplexMetadata(params, options) {
|
|
|
182
226
|
}
|
|
183
227
|
function transcribeStreamDuplexConversation(params, options) {
|
|
184
228
|
const wantsMetadata = params.metadata === true;
|
|
185
|
-
return createTranscribeStreamSession(params, options, (line,
|
|
229
|
+
return createTranscribeStreamSession(params, options, (line, onTerminal) => processLineConversation(line, wantsMetadata, onTerminal), 'TranscribeStreamConversationSession');
|
|
186
230
|
}
|
|
187
231
|
/**
|
|
188
232
|
* Line-delimited parser: reads newline-separated frames from a duplex
|
|
@@ -241,31 +285,32 @@ function parseResponseLine(line) {
|
|
|
241
285
|
* `undefined` for frames the caller should skip, or the value extracted from
|
|
242
286
|
* the frame.
|
|
243
287
|
*/
|
|
244
|
-
function processWith(line, extract,
|
|
288
|
+
function processWith(line, extract, onTerminal) {
|
|
245
289
|
const response = parseResponseLine(line);
|
|
246
290
|
if (response === null)
|
|
247
291
|
return undefined;
|
|
248
292
|
if (response.error)
|
|
249
293
|
throw new TranscriptionFailedError(response.error);
|
|
250
294
|
if (response.done) {
|
|
251
|
-
|
|
295
|
+
onTerminal(response.stats, response.diagnostics);
|
|
252
296
|
return null;
|
|
253
297
|
}
|
|
254
298
|
return extract(response);
|
|
255
299
|
}
|
|
256
|
-
export function processLine(line,
|
|
257
|
-
return processWith(line, (response) => (response.text?.trim() ? response.text : undefined),
|
|
300
|
+
export function processLine(line, onTerminal) {
|
|
301
|
+
return processWith(line, (response) => (response.text?.trim() ? response.text : undefined), onTerminal);
|
|
258
302
|
}
|
|
259
|
-
function processLineMetadata(line,
|
|
260
|
-
return processWith(line, (response) => response.segment,
|
|
303
|
+
function processLineMetadata(line, onTerminal) {
|
|
304
|
+
return processWith(line, (response) => response.segment, onTerminal);
|
|
261
305
|
}
|
|
262
|
-
function processLineConversation(line, wantsMetadata,
|
|
306
|
+
export function processLineConversation(line, wantsMetadata, onTerminal) {
|
|
263
307
|
return processWith(line, (response) => {
|
|
264
308
|
if (response.vad) {
|
|
265
309
|
return {
|
|
266
310
|
type: 'vad',
|
|
267
311
|
speaking: response.vad.speaking,
|
|
268
|
-
probability: response.vad.probability
|
|
312
|
+
probability: response.vad.probability,
|
|
313
|
+
...(response.vad.source && { source: response.vad.source })
|
|
269
314
|
};
|
|
270
315
|
}
|
|
271
316
|
if (response.endOfTurn) {
|
|
@@ -291,5 +336,5 @@ function processLineConversation(line, wantsMetadata, onStats) {
|
|
|
291
336
|
return { type: 'text', text: response.text };
|
|
292
337
|
}
|
|
293
338
|
return undefined;
|
|
294
|
-
},
|
|
339
|
+
}, onTerminal);
|
|
295
340
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { ContextOverflowError, RequestIdConflictError, RequestNotFoundError, RequestRejectedByPolicyError, TranslationFailedError } from '../../utils/errors-server.js';
|
|
1
|
+
import { RpcServerOperationError, InferenceCancelledError, ContextOverflowError, RequestIdConflictError, RequestNotFoundError, RequestRejectedByPolicyError, TranslationFailedError } from '../../utils/errors-server.js';
|
|
2
2
|
export class RPCError extends Error {
|
|
3
3
|
timestamp;
|
|
4
4
|
remoteStack;
|
|
@@ -93,14 +93,18 @@ function readOptionalStringField(fields, key) {
|
|
|
93
93
|
* be re-exported from `@qvac/sdk` so consumers can `import` it.
|
|
94
94
|
* Forgetting either side means `instanceof` regresses for that class.
|
|
95
95
|
*
|
|
96
|
-
*
|
|
97
|
-
*
|
|
98
|
-
*
|
|
99
|
-
* envelope, and adding a reconstructor for one would create a
|
|
100
|
-
* parallel construction path that fires whenever the server happens
|
|
101
|
-
* to throw the same class name.
|
|
96
|
+
* Completion aggregators construct cancellation errors locally with partial
|
|
97
|
+
* output. RPC control operations also throw them in the worker, so cancellation
|
|
98
|
+
* errors support both paths.
|
|
102
99
|
*/
|
|
103
100
|
const RECONSTRUCTORS = {
|
|
101
|
+
INFERENCE_CANCELLED: (response) => {
|
|
102
|
+
const partial = response.typedFields?.['partial'];
|
|
103
|
+
return new InferenceCancelledError(readStringField(response.typedFields, 'requestId', ''), partial && typeof partial === 'object' && !Array.isArray(partial)
|
|
104
|
+
? partial
|
|
105
|
+
: {}, response.cause);
|
|
106
|
+
},
|
|
107
|
+
RPC_SERVER_OPERATION_FAILED: (response) => new RpcServerOperationError(readStringField(response.typedFields, 'operation', 'rpcServer'), readStringField(response.typedFields, 'details', response.message), response.cause),
|
|
104
108
|
REQUEST_ID_CONFLICT: (response) => {
|
|
105
109
|
return new RequestIdConflictError(readStringField(response.typedFields, 'requestId', ''), response.cause);
|
|
106
110
|
},
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
export declare function generateWorkerEntry(pluginSpecifiers: string[], sdkName: string, resolveImport?: (specifier: string) => string): string;
|
|
2
|
-
export declare function generateWorkerEntries(pluginSpecifiers: string[], sdkName: string, resolveBundleImport: (specifier: string) => string): {
|
|
1
|
+
export declare function generateWorkerEntry(pluginSpecifiers: string[], sdkName: string, resolveImport?: (specifier: string) => string, rpcServerProvider?: string): string;
|
|
2
|
+
export declare function generateWorkerEntries(pluginSpecifiers: string[], sdkName: string, resolveBundleImport: (specifier: string) => string, rpcServerProvider?: string): {
|
|
3
3
|
runtimeEntry: string;
|
|
4
4
|
bundleEntry: string;
|
|
5
5
|
};
|
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
import { parseBuiltinSpecifier } from './plugins.js';
|
|
2
|
-
export function generateWorkerEntry(pluginSpecifiers, sdkName, resolveImport = (specifier) => specifier) {
|
|
2
|
+
export function generateWorkerEntry(pluginSpecifiers, sdkName, resolveImport = (specifier) => specifier, rpcServerProvider) {
|
|
3
3
|
const imports = [];
|
|
4
4
|
const registrations = [];
|
|
5
5
|
let varIndex = 0;
|
|
6
|
+
if (rpcServerProvider) {
|
|
7
|
+
imports.push(`import { registerRpcServerProvider } from ${JSON.stringify(resolveImport(`${sdkName}/rpc-server-provider`))};`, `import rpcServerProvider from ${JSON.stringify(resolveImport(rpcServerProvider))};`);
|
|
8
|
+
registrations.push('registerRpcServerProvider(rpcServerProvider);');
|
|
9
|
+
}
|
|
6
10
|
for (const specifier of pluginSpecifiers) {
|
|
7
11
|
const builtin = parseBuiltinSpecifier(specifier, sdkName);
|
|
8
12
|
if (builtin) {
|
|
@@ -46,9 +50,9 @@ if (hasRPCConfig) {
|
|
|
46
50
|
}
|
|
47
51
|
`;
|
|
48
52
|
}
|
|
49
|
-
export function generateWorkerEntries(pluginSpecifiers, sdkName, resolveBundleImport) {
|
|
53
|
+
export function generateWorkerEntries(pluginSpecifiers, sdkName, resolveBundleImport, rpcServerProvider) {
|
|
50
54
|
return {
|
|
51
|
-
runtimeEntry: generateWorkerEntry(pluginSpecifiers, sdkName),
|
|
52
|
-
bundleEntry: generateWorkerEntry(pluginSpecifiers, sdkName, resolveBundleImport)
|
|
55
|
+
runtimeEntry: generateWorkerEntry(pluginSpecifiers, sdkName, undefined, rpcServerProvider),
|
|
56
|
+
bundleEntry: generateWorkerEntry(pluginSpecifiers, sdkName, resolveBundleImport, rpcServerProvider)
|
|
53
57
|
};
|
|
54
58
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type HostPrebuildPackage } from '../host-prebuilds/index.js';
|
|
1
2
|
export interface BundleSdkOptions {
|
|
2
3
|
projectRoot?: string | undefined;
|
|
3
4
|
configPath?: string | undefined;
|
|
@@ -6,6 +7,23 @@ export interface BundleSdkOptions {
|
|
|
6
7
|
defer?: string[] | undefined;
|
|
7
8
|
quiet?: boolean | undefined;
|
|
8
9
|
verbose?: boolean | undefined;
|
|
10
|
+
/**
|
|
11
|
+
* Install the addon platform packages the bundle needs for its mobile hosts
|
|
12
|
+
* with the project's package manager (see `ensureHostPrebuilds`), then
|
|
13
|
+
* bundle again. Off by default: without it, bundling never changes
|
|
14
|
+
* package.json or node_modules. When the install is refused, the bundle and
|
|
15
|
+
* its manifest are still written before `HostPrebuildsInstallRefusedError`
|
|
16
|
+
* is thrown.
|
|
17
|
+
*/
|
|
18
|
+
installMissingPrebuilds?: boolean | undefined;
|
|
19
|
+
/**
|
|
20
|
+
* Check the bundled packages' engines.bare against the Bare runtime of each
|
|
21
|
+
* host and warn on a mismatch. Defaults to true; callers that run
|
|
22
|
+
* `verifyBundle` on the result can turn it off.
|
|
23
|
+
*/
|
|
24
|
+
checkEngines?: boolean | undefined;
|
|
25
|
+
/** Allow network lookups during the engines check. Defaults to true. */
|
|
26
|
+
network?: boolean | undefined;
|
|
9
27
|
}
|
|
10
28
|
export interface BundleSdkResult {
|
|
11
29
|
bundlePath: string;
|
|
@@ -15,6 +33,8 @@ export interface BundleSdkResult {
|
|
|
15
33
|
worker: string;
|
|
16
34
|
};
|
|
17
35
|
manifestPath: string;
|
|
36
|
+
/** Platform packages `installMissingPrebuilds` installed; empty when it is off. */
|
|
37
|
+
installedPrebuilds: HostPrebuildPackage[];
|
|
18
38
|
}
|
|
19
39
|
export declare function bundleSdk(options?: BundleSdkOptions): Promise<BundleSdkResult>;
|
|
20
40
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -3,13 +3,18 @@ import path from 'node:path';
|
|
|
3
3
|
import { createRequire } from 'node:module';
|
|
4
4
|
import { DEFAULT_HOSTS, DEFAULT_SDK_NAME } from './constants.js';
|
|
5
5
|
import { CONFIG_CANDIDATES, resolveConfigForProject } from '../../client/config-loader/resolve-config.node.js';
|
|
6
|
-
import {
|
|
7
|
-
import { BareImportsMapNotFoundError } from '../../utils/errors-client.js';
|
|
6
|
+
import { createCommandLogger } from '../command-logger.js';
|
|
7
|
+
import { BareImportsMapNotFoundError, HostPrebuildsInstallRefusedError } from '../../utils/errors-client.js';
|
|
8
8
|
import { resolvePluginSpecifiers, parseBuiltinSpecifier } from './plugins.js';
|
|
9
9
|
import { generateWorkerEntries } from './entry-gen.js';
|
|
10
10
|
import { runBarePack } from './bare-pack.js';
|
|
11
11
|
import { generateAddonsManifest } from './manifest.js';
|
|
12
12
|
import { createSdkImportResolver } from './resolve-sdk-import.js';
|
|
13
|
+
import { installMissingHostPrebuilds } from '../host-prebuilds/index.js';
|
|
14
|
+
import { collectAddonsFromBundle } from '../verify/bundle-source.js';
|
|
15
|
+
import { verifyBundle } from '../verify/index.js';
|
|
16
|
+
import { formatRuntimeSource } from '../verify/abi.js';
|
|
17
|
+
import { formatEnginesAdvice } from '../verify/engines-advice.js';
|
|
13
18
|
const require = createRequire(import.meta.url);
|
|
14
19
|
function resolveSdkPath(projectRoot, explicitSdkPath) {
|
|
15
20
|
if (explicitSdkPath) {
|
|
@@ -49,14 +54,43 @@ function resolveImportsMapPath(sdkPath, sdkName) {
|
|
|
49
54
|
}
|
|
50
55
|
throw new BareImportsMapNotFoundError(sdkName, importsMapPath);
|
|
51
56
|
}
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
57
|
+
const ENGINES_ISSUE_CODES = new Set(['abi-mismatch', 'engines-mismatch']);
|
|
58
|
+
async function checkBundleEngines(options) {
|
|
59
|
+
const { projectRoot, bundlePath, hosts, configPath, network, logger } = options;
|
|
60
|
+
logger.info('\nš Checking engines.bare against the Bare runtime of each host...');
|
|
61
|
+
const result = await verifyBundle({
|
|
62
|
+
projectRoot,
|
|
63
|
+
addonsSource: bundlePath,
|
|
64
|
+
hosts,
|
|
65
|
+
...(configPath !== undefined ? { configPath } : {}),
|
|
66
|
+
...(network !== undefined ? { network } : {}),
|
|
67
|
+
onProgress: (message) => logger.info(` ${message}`)
|
|
68
|
+
});
|
|
69
|
+
const checkedHosts = [];
|
|
70
|
+
for (const group of result.runtimes ?? []) {
|
|
71
|
+
const label = group.hosts.join(', ');
|
|
72
|
+
if (group.resolution.resolved) {
|
|
73
|
+
checkedHosts.push(...group.hosts);
|
|
74
|
+
logger.info(` ${label}: Bare ${group.resolution.runtime.version} (from ${formatRuntimeSource(group.resolution.runtime)})`);
|
|
75
|
+
}
|
|
76
|
+
else {
|
|
77
|
+
logger.warn(`engines.bare not checked for ${label}: ${group.resolution.error.reason}`);
|
|
78
|
+
}
|
|
55
79
|
}
|
|
56
|
-
|
|
57
|
-
|
|
80
|
+
const mismatches = result.issues.filter((issue) => ENGINES_ISSUE_CODES.has(issue.code) && issue.level === 'error');
|
|
81
|
+
if (mismatches.length === 0) {
|
|
82
|
+
if (checkedHosts.length > 0) {
|
|
83
|
+
logger.info(` No engines.bare mismatches for ${checkedHosts.join(', ')}`);
|
|
84
|
+
}
|
|
85
|
+
return;
|
|
58
86
|
}
|
|
59
|
-
|
|
87
|
+
const lines = ['The bundle contains packages that require a newer Bare runtime:'];
|
|
88
|
+
for (const issue of mismatches)
|
|
89
|
+
lines.push(` - ${issue.message}`);
|
|
90
|
+
lines.push('');
|
|
91
|
+
for (const advice of result.advice ?? [])
|
|
92
|
+
lines.push(...formatEnginesAdvice(advice));
|
|
93
|
+
logger.warn(lines.join('\n').trimEnd());
|
|
60
94
|
}
|
|
61
95
|
export async function bundleSdk(options = {}) {
|
|
62
96
|
const startTime = Date.now();
|
|
@@ -94,7 +128,7 @@ export async function bundleSdk(options = {}) {
|
|
|
94
128
|
await fsp.mkdir(outputDir, { recursive: true });
|
|
95
129
|
logger.info('\nš Generating worker entry...');
|
|
96
130
|
const resolveSdkImport = createSdkImportResolver(sdkPath, sdkName);
|
|
97
|
-
const { runtimeEntry, bundleEntry } = generateWorkerEntries(pluginSpecifiers, sdkName, resolveSdkImport);
|
|
131
|
+
const { runtimeEntry, bundleEntry } = generateWorkerEntries(pluginSpecifiers, sdkName, resolveSdkImport, config.rpcServerProvider);
|
|
98
132
|
await fsp.writeFile(entryPath, runtimeEntry, 'utf8');
|
|
99
133
|
logger.info(` Created: ${path.relative(projectRoot, entryPath)}`);
|
|
100
134
|
logger.info(` Using: ${path.relative(projectRoot, importsMapPath)}`);
|
|
@@ -103,9 +137,11 @@ export async function bundleSdk(options = {}) {
|
|
|
103
137
|
if (deferModules.length > 0) {
|
|
104
138
|
logger.debug(` Deferred: ${deferModules.join(', ')}`);
|
|
105
139
|
}
|
|
140
|
+
let installedPrebuilds = [];
|
|
141
|
+
let installRefused;
|
|
106
142
|
try {
|
|
107
143
|
await fsp.writeFile(bundleEntryPath, bundleEntry, 'utf8');
|
|
108
|
-
|
|
144
|
+
const barePackOptions = {
|
|
109
145
|
entryPath: bundleEntryPath,
|
|
110
146
|
outputPath: bundlePath,
|
|
111
147
|
hosts,
|
|
@@ -113,7 +149,34 @@ export async function bundleSdk(options = {}) {
|
|
|
113
149
|
deferModules,
|
|
114
150
|
quiet: options.quiet === true,
|
|
115
151
|
logger
|
|
116
|
-
}
|
|
152
|
+
};
|
|
153
|
+
await runBarePack(barePackOptions);
|
|
154
|
+
if (options.installMissingPrebuilds === true) {
|
|
155
|
+
try {
|
|
156
|
+
const { installed } = await installMissingHostPrebuilds({
|
|
157
|
+
projectRoot,
|
|
158
|
+
hosts,
|
|
159
|
+
addons: await collectAddonsFromBundle({ bundlePath, projectRoot, hosts }),
|
|
160
|
+
quiet: options.quiet === true,
|
|
161
|
+
logger
|
|
162
|
+
});
|
|
163
|
+
installedPrebuilds = installed;
|
|
164
|
+
// Where a platform package was missing, bare-pack resolved the addon's
|
|
165
|
+
// `#host-addon` import to its fallback module; bundle again to pick up
|
|
166
|
+
// the installed package.
|
|
167
|
+
if (installed.length > 0) {
|
|
168
|
+
logger.info('\nšØ Bundling again with the installed platform packages...');
|
|
169
|
+
await runBarePack(barePackOptions);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
catch (error) {
|
|
173
|
+
if (!(error instanceof HostPrebuildsInstallRefusedError))
|
|
174
|
+
throw error;
|
|
175
|
+
// A refusal happens before anything is installed, so the bundle
|
|
176
|
+
// already written is final and only its manifest is left to write.
|
|
177
|
+
installRefused = error;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
117
180
|
}
|
|
118
181
|
finally {
|
|
119
182
|
await fsp.rm(bundleEntryPath, { force: true });
|
|
@@ -128,6 +191,18 @@ export async function bundleSdk(options = {}) {
|
|
|
128
191
|
projectRoot,
|
|
129
192
|
logger
|
|
130
193
|
});
|
|
194
|
+
if (options.checkEngines !== false) {
|
|
195
|
+
await checkBundleEngines({
|
|
196
|
+
projectRoot,
|
|
197
|
+
bundlePath,
|
|
198
|
+
hosts,
|
|
199
|
+
configPath: configPath ?? undefined,
|
|
200
|
+
network: options.network,
|
|
201
|
+
logger
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
if (installRefused !== undefined)
|
|
205
|
+
throw installRefused;
|
|
131
206
|
const elapsed = ((Date.now() - startTime) / 1000).toFixed(2);
|
|
132
207
|
logger.info(`\nš Done in ${elapsed}s!\n`);
|
|
133
208
|
logger.info('Generated files:');
|
|
@@ -143,6 +218,7 @@ export async function bundleSdk(options = {}) {
|
|
|
143
218
|
entryPaths: {
|
|
144
219
|
worker: entryPath
|
|
145
220
|
},
|
|
146
|
-
manifestPath: manifestResult.manifestPath
|
|
221
|
+
manifestPath: manifestResult.manifestPath,
|
|
222
|
+
installedPrebuilds
|
|
147
223
|
};
|
|
148
224
|
}
|
|
@@ -17,7 +17,7 @@ export function parseBuiltinSpecifier(specifier, sdkName) {
|
|
|
17
17
|
}
|
|
18
18
|
export function resolvePluginSpecifiers(config, sdkName, logger) {
|
|
19
19
|
let plugins = config.plugins ?? [];
|
|
20
|
-
if (plugins.length === 0) {
|
|
20
|
+
if (plugins.length === 0 && !(config.rpcServerProvider && config.plugins !== undefined)) {
|
|
21
21
|
const allBuiltins = BUILTIN_SUFFIXES.map((suffix) => buildBuiltinSpecifier(sdkName, suffix));
|
|
22
22
|
logger.warn('No plugins specified ā bundling ALL built-in plugins.');
|
|
23
23
|
logger.info(" For smaller bundles, add a 'plugins' array to qvac.config.*\n");
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export interface CommandLoggerOptions {
|
|
2
|
+
quiet?: boolean | undefined;
|
|
3
|
+
verbose?: boolean | undefined;
|
|
4
|
+
}
|
|
5
|
+
export declare function createCommandLogger(options: CommandLoggerOptions): import("../logging/index.js").Logger;
|
|
6
|
+
//# sourceMappingURL=command-logger.d.ts.map
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { getClientLogger } from '../logging/index.js';
|
|
2
|
+
export function createCommandLogger(options) {
|
|
3
|
+
if (options.quiet) {
|
|
4
|
+
return getClientLogger({ level: 'error', enableConsole: false });
|
|
5
|
+
}
|
|
6
|
+
// The client logger keeps console output off unless asked; a command's
|
|
7
|
+
// progress and warnings are meant for the person running it.
|
|
8
|
+
if (options.verbose) {
|
|
9
|
+
return getClientLogger({ level: 'debug', enableConsole: true });
|
|
10
|
+
}
|
|
11
|
+
return getClientLogger({ enableConsole: true });
|
|
12
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import type { Logger } from '../../logging/types.js';
|
|
2
|
+
import { type NativeAddon } from '../verify/addon-source.js';
|
|
3
|
+
import { type PackageManagerName } from './package-manager.js';
|
|
4
|
+
export type { PackageManagerName } from './package-manager.js';
|
|
5
|
+
export interface EnsureHostPrebuildsOptions {
|
|
6
|
+
/** The package whose package.json receives the pins; its package manager installs them. */
|
|
7
|
+
projectRoot: string;
|
|
8
|
+
/** Bare hosts to cover. Only mobile hosts (`android-*`, `ios-*`) can need an install. */
|
|
9
|
+
hosts: string[];
|
|
10
|
+
/**
|
|
11
|
+
* Addon package names to cover. Defaults to every addon installed for the
|
|
12
|
+
* project: in its own node_modules or in that of a workspace root listing it.
|
|
13
|
+
*/
|
|
14
|
+
addons?: string[] | undefined;
|
|
15
|
+
/** Install with this package manager instead of detecting the project's own. */
|
|
16
|
+
packageManager?: PackageManagerName | undefined;
|
|
17
|
+
quiet?: boolean | undefined;
|
|
18
|
+
verbose?: boolean | undefined;
|
|
19
|
+
}
|
|
20
|
+
export interface HostPrebuildPackage {
|
|
21
|
+
/** The platform package, e.g. `@qvac/tts-ggml-android-arm64`. */
|
|
22
|
+
name: string;
|
|
23
|
+
/** Always the addon's own version: platform packages are version-locked to it. */
|
|
24
|
+
version: string;
|
|
25
|
+
/** The addon the package ships prebuilds for. */
|
|
26
|
+
addon: string;
|
|
27
|
+
/** The requested hosts the package covers. */
|
|
28
|
+
hosts: string[];
|
|
29
|
+
}
|
|
30
|
+
export interface EnsureHostPrebuildsResult {
|
|
31
|
+
/** The packages this call installed; empty when every prebuild already resolved. */
|
|
32
|
+
installed: HostPrebuildPackage[];
|
|
33
|
+
/** The package manager that installed them, or null when nothing was missing. */
|
|
34
|
+
packageManager: PackageManagerName | null;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Installs the per-platform prebuild packages that addons need for mobile
|
|
38
|
+
* hosts and that the project does not have yet.
|
|
39
|
+
*
|
|
40
|
+
* A split addon names one platform package per host in the `#host-addon` map
|
|
41
|
+
* of its package.json (`<addon>-ios` covers every iOS host). Desktop platform
|
|
42
|
+
* packages install as the addon's os/cpu-filtered optionalDependencies, but a
|
|
43
|
+
* build host never reports a mobile os, so mobile ones have to be declared.
|
|
44
|
+
* This declares the missing ones in package.json, pinned to each addon's
|
|
45
|
+
* exact version, using the project's own package manager.
|
|
46
|
+
*
|
|
47
|
+
* A host whose prebuild already resolves is skipped: a local
|
|
48
|
+
* `prebuilds/<host>` in the addon (source builds) or its platform package at
|
|
49
|
+
* the addon's version. Throws `HostPrebuildsInstallRefusedError` when no
|
|
50
|
+
* supported package manager (npm 7+, pnpm, bun, Yarn Berry) is found, and
|
|
51
|
+
* `HostPrebuildsInstallFailedError` when the install does not produce the
|
|
52
|
+
* packages.
|
|
53
|
+
*/
|
|
54
|
+
export declare function ensureHostPrebuilds(options: EnsureHostPrebuildsOptions): Promise<EnsureHostPrebuildsResult>;
|
|
55
|
+
export interface InstallMissingHostPrebuildsOptions {
|
|
56
|
+
projectRoot: string;
|
|
57
|
+
hosts: string[];
|
|
58
|
+
addons: NativeAddon[];
|
|
59
|
+
packageManager?: PackageManagerName | undefined;
|
|
60
|
+
quiet: boolean;
|
|
61
|
+
logger: Logger;
|
|
62
|
+
}
|
|
63
|
+
/** `ensureHostPrebuilds` for addons the caller has already located. */
|
|
64
|
+
export declare function installMissingHostPrebuilds(options: InstallMissingHostPrebuildsOptions): Promise<EnsureHostPrebuildsResult>;
|
|
65
|
+
/**
|
|
66
|
+
* The platform packages `addons` still need for the mobile hosts in `hosts`,
|
|
67
|
+
* one entry per package. Throws when two installed versions of one addon need
|
|
68
|
+
* the same platform package, since only one version of it can be installed.
|
|
69
|
+
*/
|
|
70
|
+
export declare function findMissingHostPrebuilds(addons: NativeAddon[], hosts: string[]): Promise<HostPrebuildPackage[]>;
|
|
71
|
+
//# sourceMappingURL=index.d.ts.map
|