@qvac/sdk 0.11.0 → 0.12.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (211) hide show
  1. package/NOTICE +1423 -43
  2. package/README.md +2 -0
  3. package/dist/client/api/classify.d.ts +23 -0
  4. package/dist/client/api/classify.js +43 -0
  5. package/dist/client/api/get-model-info.d.ts +1 -1
  6. package/dist/client/api/index.d.ts +4 -0
  7. package/dist/client/api/index.js +4 -0
  8. package/dist/client/api/load-model.js +24 -1
  9. package/dist/client/api/transcribe.d.ts +3 -0
  10. package/dist/client/api/transcribe.js +13 -2
  11. package/dist/client/api/video.d.ts +64 -0
  12. package/dist/client/api/video.js +147 -0
  13. package/dist/client/api/vla-helpers.d.ts +45 -0
  14. package/dist/client/api/vla-helpers.js +130 -0
  15. package/dist/client/api/vla.d.ts +65 -0
  16. package/dist/client/api/vla.js +109 -0
  17. package/dist/client/config-loader/resolve-config.node.d.ts +16 -0
  18. package/dist/client/config-loader/resolve-config.node.js +77 -23
  19. package/dist/client/plugins-factory.d.ts +8 -0
  20. package/dist/client/plugins-factory.js +10 -0
  21. package/dist/client/rpc/bare-client.d.ts +1 -0
  22. package/dist/client/rpc/bare-client.js +66 -66
  23. package/dist/client/rpc/ensure-worker-ready.d.ts +9 -0
  24. package/dist/client/rpc/ensure-worker-ready.js +17 -0
  25. package/dist/client/rpc/expo-rpc-client.d.ts +1 -0
  26. package/dist/client/rpc/expo-rpc-client.js +4 -0
  27. package/dist/client/rpc/node-rpc-client.d.ts +1 -0
  28. package/dist/client/rpc/node-rpc-client.js +97 -5
  29. package/dist/client/rpc/rpc-client.js +115 -8
  30. package/dist/client/rpc/rpc-error.js +14 -1
  31. package/dist/commands/bundle/bare-pack.d.ts +13 -0
  32. package/dist/commands/bundle/bare-pack.js +54 -0
  33. package/dist/commands/bundle/constants.d.ts +7 -0
  34. package/dist/commands/bundle/constants.js +23 -0
  35. package/dist/commands/bundle/entry-gen.d.ts +2 -0
  36. package/dist/commands/bundle/entry-gen.js +48 -0
  37. package/dist/commands/bundle/index.d.ts +20 -0
  38. package/dist/commands/bundle/index.js +141 -0
  39. package/dist/commands/bundle/manifest.d.ts +21 -0
  40. package/dist/commands/bundle/manifest.js +193 -0
  41. package/dist/commands/bundle/plugins.d.ts +9 -0
  42. package/dist/commands/bundle/plugins.js +51 -0
  43. package/dist/commands/index.d.ts +5 -0
  44. package/dist/commands/index.js +2 -0
  45. package/dist/commands/verify/abi.d.ts +52 -0
  46. package/dist/commands/verify/abi.js +125 -0
  47. package/dist/commands/verify/addon-source.d.ts +43 -0
  48. package/dist/commands/verify/addon-source.js +75 -0
  49. package/dist/commands/verify/bundle-source.d.ts +12 -0
  50. package/dist/commands/verify/bundle-source.js +53 -0
  51. package/dist/commands/verify/index.d.ts +59 -0
  52. package/dist/commands/verify/index.js +371 -0
  53. package/dist/commands/verify/node-modules-source.d.ts +11 -0
  54. package/dist/commands/verify/node-modules-source.js +76 -0
  55. package/dist/commands/verify/prebuilds.d.ts +15 -0
  56. package/dist/commands/verify/prebuilds.js +39 -0
  57. package/dist/examples/classification/classify-image.d.ts +2 -0
  58. package/dist/examples/classification/classify-image.js +23 -0
  59. package/dist/examples/diffusion-txt2vid.d.ts +2 -0
  60. package/dist/examples/diffusion-txt2vid.js +81 -0
  61. package/dist/examples/plugins.js +3 -7
  62. package/dist/examples/tools/llamacpp-tools-gemma4.js +2 -5
  63. package/dist/examples/tools/llamacpp-tools-qwen35.js +2 -3
  64. package/dist/examples/transcription/parakeet-ctc-filesystem.js +18 -12
  65. package/dist/examples/transcription/parakeet-microphone-record.js +7 -12
  66. package/dist/examples/transcription/parakeet-microphone-stream.d.ts +2 -0
  67. package/dist/examples/transcription/parakeet-microphone-stream.js +79 -0
  68. package/dist/examples/transcription/parakeet-sortformer-streaming.d.ts +2 -0
  69. package/dist/examples/transcription/parakeet-sortformer-streaming.js +121 -0
  70. package/dist/examples/transcription/parakeet-sortformer.js +58 -55
  71. package/dist/examples/transcription/parakeet-tdt-filesystem.js +18 -15
  72. package/dist/examples/transcription/whispercpp-microphone-conversation.js +6 -1
  73. package/dist/examples/tts/chatterbox.js +7 -16
  74. package/dist/examples/tts/llm-to-tts-streaming.js +3 -10
  75. package/dist/examples/tts/supertonic-multilingual.js +4 -12
  76. package/dist/examples/tts/supertonic.js +5 -12
  77. package/dist/examples/vla-smolvla.d.ts +2 -0
  78. package/dist/examples/vla-smolvla.js +75 -0
  79. package/dist/examples/voice-assistant/voice-assistant.js +3 -10
  80. package/dist/expo/plugins/find-in-ancestor-node-modules.d.ts +14 -0
  81. package/dist/expo/plugins/find-in-ancestor-node-modules.js +24 -0
  82. package/dist/expo/plugins/get-project-root.d.ts +22 -0
  83. package/dist/expo/plugins/get-project-root.js +23 -0
  84. package/dist/expo/plugins/index.d.ts +4 -0
  85. package/dist/expo/plugins/index.js +4 -0
  86. package/dist/expo/plugins/resolve-sdk-package-dir.d.ts +9 -2
  87. package/dist/expo/plugins/resolve-sdk-package-dir.js +38 -11
  88. package/dist/expo/plugins/withDeviceInfo.js +2 -1
  89. package/dist/expo/plugins/withMobileBundle.d.ts +2 -17
  90. package/dist/expo/plugins/withMobileBundle.js +31 -85
  91. package/dist/index.d.ts +5 -3
  92. package/dist/index.js +9 -3
  93. package/dist/models/registry/models.d.ts +3711 -368
  94. package/dist/models/registry/models.js +7066 -3562
  95. package/dist/models/update-models/naming.js +22 -8
  96. package/dist/pear/pre.js +6 -2
  97. package/dist/schemas/cancel.d.ts +5 -0
  98. package/dist/schemas/cancel.js +1 -0
  99. package/dist/schemas/classification.d.ts +53 -0
  100. package/dist/schemas/classification.js +33 -0
  101. package/dist/schemas/common.d.ts +1001 -1739
  102. package/dist/schemas/common.js +6 -1
  103. package/dist/schemas/completion-event.d.ts +3 -0
  104. package/dist/schemas/completion-event.js +1 -0
  105. package/dist/schemas/completion-stream.d.ts +1 -0
  106. package/dist/schemas/download-asset.d.ts +13 -3
  107. package/dist/schemas/engine-addon-map.d.ts +3 -0
  108. package/dist/schemas/engine-addon-map.js +18 -5
  109. package/dist/schemas/get-model-info.d.ts +4 -0
  110. package/dist/schemas/get-model-info.js +2 -0
  111. package/dist/schemas/index.d.ts +3 -0
  112. package/dist/schemas/index.js +3 -0
  113. package/dist/schemas/llamacpp-config.d.ts +12 -2
  114. package/dist/schemas/load-model.d.ts +6152 -10764
  115. package/dist/schemas/load-model.js +75 -7
  116. package/dist/schemas/model-src-utils.d.ts +22 -2
  117. package/dist/schemas/model-types.d.ts +46 -6
  118. package/dist/schemas/model-types.js +28 -5
  119. package/dist/schemas/ocr.d.ts +5 -0
  120. package/dist/schemas/plugin.d.ts +20 -5
  121. package/dist/schemas/plugin.js +21 -4
  122. package/dist/schemas/registry.d.ts +44 -0
  123. package/dist/schemas/registry.js +5 -0
  124. package/dist/schemas/reload-config.d.ts +22 -2
  125. package/dist/schemas/sdcpp-config.d.ts +316 -1
  126. package/dist/schemas/sdcpp-config.js +232 -33
  127. package/dist/schemas/sdk-config.d.ts +654 -1324
  128. package/dist/schemas/sdk-config.js +16 -1
  129. package/dist/schemas/sdk-errors-client.d.ts +7 -0
  130. package/dist/schemas/sdk-errors-client.js +36 -1
  131. package/dist/schemas/sdk-errors-server.d.ts +3 -1
  132. package/dist/schemas/sdk-errors-server.js +20 -5
  133. package/dist/schemas/text-to-speech.d.ts +79 -696
  134. package/dist/schemas/text-to-speech.js +46 -19
  135. package/dist/schemas/transcription-config.d.ts +37 -226
  136. package/dist/schemas/transcription-config.js +76 -15
  137. package/dist/schemas/transcription.d.ts +63 -11
  138. package/dist/schemas/transcription.js +56 -2
  139. package/dist/schemas/translation-config.d.ts +60 -10
  140. package/dist/schemas/vla.d.ts +87 -0
  141. package/dist/schemas/vla.js +108 -0
  142. package/dist/scripts/run-unit-tests.js +8 -2
  143. package/dist/server/bare/ops/transcribe.d.ts +2 -1
  144. package/dist/server/bare/ops/transcribe.js +59 -34
  145. package/dist/server/bare/plugins/ggml-classification/ops/classify.d.ts +6 -0
  146. package/dist/server/bare/plugins/ggml-classification/ops/classify.js +30 -0
  147. package/dist/server/bare/plugins/ggml-classification/plugin.d.ts +32 -0
  148. package/dist/server/bare/plugins/ggml-classification/plugin.js +55 -0
  149. package/dist/server/bare/plugins/ggml-vla/ops/vla-hparams.d.ts +3 -0
  150. package/dist/server/bare/plugins/ggml-vla/ops/vla-hparams.js +12 -0
  151. package/dist/server/bare/plugins/ggml-vla/ops/vla-run.d.ts +3 -0
  152. package/dist/server/bare/plugins/ggml-vla/ops/vla-run.js +75 -0
  153. package/dist/server/bare/plugins/ggml-vla/plugin.d.ts +54 -0
  154. package/dist/server/bare/plugins/ggml-vla/plugin.js +57 -0
  155. package/dist/server/bare/plugins/index.d.ts +3 -1
  156. package/dist/server/bare/plugins/index.js +3 -1
  157. package/dist/server/bare/plugins/llamacpp-completion/ops/completion-stream.js +3 -0
  158. package/dist/server/bare/plugins/llamacpp-completion/ops/context-overflow.d.ts +29 -0
  159. package/dist/server/bare/plugins/llamacpp-completion/ops/context-overflow.js +65 -0
  160. package/dist/server/bare/plugins/llamacpp-completion/plugin.d.ts +6 -0
  161. package/dist/server/bare/plugins/llamacpp-completion/plugin.js +26 -0
  162. package/dist/server/bare/plugins/nmtcpp-translation/plugin.d.ts +25 -0
  163. package/dist/server/bare/plugins/onnx-ocr/plugin.d.ts +5 -0
  164. package/dist/server/bare/plugins/parakeet-transcription/plugin.d.ts +67 -246
  165. package/dist/server/bare/plugins/parakeet-transcription/plugin.js +66 -97
  166. package/dist/server/bare/plugins/sdcpp-generation/ops/video.d.ts +3 -0
  167. package/dist/server/bare/plugins/sdcpp-generation/ops/video.js +199 -0
  168. package/dist/server/bare/plugins/sdcpp-generation/plugin.d.ts +200 -2
  169. package/dist/server/bare/plugins/sdcpp-generation/plugin.js +61 -8
  170. package/dist/server/bare/plugins/{onnx-tts → tts-ggml}/ops/text-to-speech-stream.js +2 -15
  171. package/dist/server/bare/plugins/{onnx-tts → tts-ggml}/ops/text-to-speech.js +2 -1
  172. package/dist/server/bare/plugins/tts-ggml/plugin.d.ts +75 -0
  173. package/dist/server/bare/plugins/tts-ggml/plugin.js +189 -0
  174. package/dist/server/bare/plugins/whispercpp-transcription/plugin.d.ts +29 -4
  175. package/dist/server/bare/plugins/whispercpp-transcription/plugin.js +12 -1
  176. package/dist/server/bare/registry/model-config-utils.js +7 -0
  177. package/dist/server/bare/runtime/request-context.d.ts +1 -1
  178. package/dist/server/bare/runtime-lifecycle.js +9 -9
  179. package/dist/server/bare/types/addon-responses.d.ts +1 -0
  180. package/dist/server/env.js +4 -1
  181. package/dist/server/plugins/index.d.ts +1 -1
  182. package/dist/server/plugins/index.js +1 -1
  183. package/dist/server/plugins/registry.d.ts +1 -0
  184. package/dist/server/plugins/registry.js +5 -0
  185. package/dist/server/rpc/handler-registry.js +4 -0
  186. package/dist/server/rpc/handler-selection.d.ts +9 -0
  187. package/dist/server/rpc/handler-selection.js +14 -0
  188. package/dist/server/rpc/handler-utils.js +5 -13
  189. package/dist/server/rpc/handlers/classify.d.ts +3 -0
  190. package/dist/server/rpc/handlers/classify.js +4 -0
  191. package/dist/server/rpc/handlers/index.d.ts +2 -0
  192. package/dist/server/rpc/handlers/index.js +2 -0
  193. package/dist/server/rpc/handlers/load-model/handler.js +4 -1
  194. package/dist/server/rpc/handlers/load-model/resolve.js +9 -0
  195. package/dist/server/rpc/handlers/video-stream.d.ts +3 -0
  196. package/dist/server/rpc/handlers/video-stream.js +4 -0
  197. package/dist/server/rpc/profiling/operation-metrics.js +23 -0
  198. package/dist/server/utils/config-transform.js +1 -1
  199. package/dist/server/utils/tools/parsers/qwen35.js +7 -3
  200. package/dist/server/worker.js +14 -11
  201. package/dist/utils/errors-client.d.ts +23 -0
  202. package/dist/utils/errors-client.js +40 -0
  203. package/dist/utils/errors-server.d.ts +30 -2
  204. package/dist/utils/errors-server.js +51 -3
  205. package/package.json +66 -80
  206. package/dist/server/bare/plugins/onnx-tts/plugin.d.ts +0 -490
  207. package/dist/server/bare/plugins/onnx-tts/plugin.js +0 -272
  208. package/dist/server/bare/plugins/onnx-tts/wav-helper.d.ts +0 -14
  209. package/dist/server/bare/plugins/onnx-tts/wav-helper.js +0 -107
  210. /package/dist/server/bare/plugins/{onnx-tts → tts-ggml}/ops/text-to-speech-stream.d.ts +0 -0
  211. /package/dist/server/bare/plugins/{onnx-tts → tts-ggml}/ops/text-to-speech.d.ts +0 -0
@@ -0,0 +1,141 @@
1
+ import fs, { promises as fsp } from "node:fs";
2
+ import path from "node:path";
3
+ import { createRequire } from "node:module";
4
+ import { DEFAULT_HOSTS, DEFAULT_SDK_NAME } from "./constants.js";
5
+ import { CONFIG_CANDIDATES, resolveConfigForProject, } from "../../client/config-loader/resolve-config.node.js";
6
+ import { getClientLogger } from "../../logging/index.js";
7
+ import { BareImportsMapNotFoundError } from "../../utils/errors-client.js";
8
+ import { resolvePluginSpecifiers, parseBuiltinSpecifier, } from "./plugins.js";
9
+ import { generateWorkerEntry } from "./entry-gen.js";
10
+ import { runBarePack } from "./bare-pack.js";
11
+ import { generateAddonsManifest } from "./manifest.js";
12
+ const require = createRequire(import.meta.url);
13
+ function resolveSdkPath(projectRoot, explicitSdkPath) {
14
+ if (explicitSdkPath) {
15
+ return path.isAbsolute(explicitSdkPath)
16
+ ? explicitSdkPath
17
+ : path.join(projectRoot, explicitSdkPath);
18
+ }
19
+ try {
20
+ const pkgJsonPath = require.resolve("@qvac/sdk/package.json", {
21
+ paths: [projectRoot],
22
+ });
23
+ return path.dirname(pkgJsonPath);
24
+ }
25
+ catch {
26
+ return path.join(projectRoot, "node_modules", "@qvac", "sdk");
27
+ }
28
+ }
29
+ async function resolveSdkName(sdkPath) {
30
+ const sdkPackageJsonPath = path.join(sdkPath, "package.json");
31
+ try {
32
+ if (fs.existsSync(sdkPackageJsonPath)) {
33
+ const content = await fsp.readFile(sdkPackageJsonPath, "utf8");
34
+ const pkg = JSON.parse(content);
35
+ if (pkg.name)
36
+ return pkg.name;
37
+ }
38
+ }
39
+ catch {
40
+ // Fall through to default
41
+ }
42
+ return DEFAULT_SDK_NAME;
43
+ }
44
+ function resolveImportsMapPath(sdkPath, sdkName) {
45
+ const importsMapPath = path.join(sdkPath, "bare-imports.json");
46
+ if (fs.existsSync(importsMapPath)) {
47
+ return importsMapPath;
48
+ }
49
+ throw new BareImportsMapNotFoundError(sdkName, importsMapPath);
50
+ }
51
+ function createCommandLogger(options) {
52
+ if (options.quiet) {
53
+ return getClientLogger({ level: "error", enableConsole: false });
54
+ }
55
+ if (options.verbose) {
56
+ return getClientLogger({ level: "debug" });
57
+ }
58
+ return getClientLogger();
59
+ }
60
+ export async function bundleSdk(options = {}) {
61
+ const startTime = Date.now();
62
+ const projectRoot = options.projectRoot ?? process.cwd();
63
+ const outputDir = path.join(projectRoot, "qvac");
64
+ const entryPath = path.join(outputDir, "worker.entry.mjs");
65
+ const bundlePath = path.join(outputDir, "worker.bundle.js");
66
+ const logger = createCommandLogger(options);
67
+ logger.info("🔧 QVAC SDK Worker Bundler\n");
68
+ const { configPath, config } = await resolveConfigForProject(projectRoot, options.configPath);
69
+ if (configPath) {
70
+ logger.info(`📄 Config: ${path.relative(projectRoot, configPath)}`);
71
+ }
72
+ else {
73
+ logger.info("📄 Config: (none)");
74
+ logger.warn("No config file found — continuing with defaults.");
75
+ logger.info(" To customize bundling, create one of:\n" +
76
+ CONFIG_CANDIDATES.map((c) => ` - ${c}`).join("\n") +
77
+ "\n");
78
+ }
79
+ const sdkPath = resolveSdkPath(projectRoot, options.sdkPath);
80
+ const sdkName = await resolveSdkName(sdkPath);
81
+ logger.info(`📦 SDK: ${sdkName}`);
82
+ logger.debug(` Path: ${sdkPath}`);
83
+ const importsMapPath = resolveImportsMapPath(sdkPath, sdkName);
84
+ const pluginSpecifiers = resolvePluginSpecifiers(config, sdkName, logger);
85
+ logger.info(`\n📦 Plugins to include (${pluginSpecifiers.length}):`);
86
+ for (const spec of pluginSpecifiers) {
87
+ const label = parseBuiltinSpecifier(spec, sdkName)
88
+ ? "✓ built-in"
89
+ : "⊕ custom";
90
+ logger.info(` ${label}: ${spec}`);
91
+ }
92
+ const hosts = options.hosts && options.hosts.length > 0 ? options.hosts : DEFAULT_HOSTS;
93
+ const deferModules = options.defer ?? [];
94
+ await fsp.mkdir(outputDir, { recursive: true });
95
+ logger.info("\n📝 Generating worker entry...");
96
+ const workerEntry = generateWorkerEntry(pluginSpecifiers, sdkName);
97
+ await fsp.writeFile(entryPath, workerEntry, "utf8");
98
+ logger.info(` Created: ${path.relative(projectRoot, entryPath)}`);
99
+ logger.info(` Using: ${path.relative(projectRoot, importsMapPath)}`);
100
+ logger.info("\n🔨 Bundling with bare-pack...");
101
+ logger.debug(` Hosts: ${hosts.join(", ")}`);
102
+ if (deferModules.length > 0) {
103
+ logger.debug(` Deferred: ${deferModules.join(", ")}`);
104
+ }
105
+ await runBarePack({
106
+ entryPath,
107
+ outputPath: bundlePath,
108
+ hosts,
109
+ importsMapPath,
110
+ deferModules,
111
+ quiet: options.quiet === true,
112
+ logger,
113
+ });
114
+ const stats = await fsp.stat(bundlePath);
115
+ const sizeKB = (stats.size / 1024).toFixed(1);
116
+ logger.info(`\n✅ Bundle created: ${path.relative(projectRoot, bundlePath)}`);
117
+ logger.info(` Size: ${sizeKB} KB`);
118
+ const manifestResult = await generateAddonsManifest({
119
+ bundlePath,
120
+ outputDir,
121
+ projectRoot,
122
+ logger,
123
+ });
124
+ const elapsed = ((Date.now() - startTime) / 1000).toFixed(2);
125
+ logger.info(`\n🎉 Done in ${elapsed}s!\n`);
126
+ logger.info("Generated files:");
127
+ logger.info(" - qvac/worker.entry.mjs (standalone worker with RPC + lifecycle)");
128
+ logger.info(" - qvac/worker.bundle.js (mobile bundle for Expo/React Native BareKit)");
129
+ logger.info(" - qvac/addons.manifest.json\n");
130
+ logger.info("Mobile: Expo plugin auto-configures worker.bundle.js");
131
+ logger.info("Standalone: Import qvac/worker.entry.mjs for full worker with RPC\n");
132
+ return {
133
+ bundlePath,
134
+ plugins: pluginSpecifiers,
135
+ addons: manifestResult.addons,
136
+ entryPaths: {
137
+ worker: entryPath,
138
+ },
139
+ manifestPath: manifestResult.manifestPath,
140
+ };
141
+ }
@@ -0,0 +1,21 @@
1
+ import type { Logger } from "../../logging/types";
2
+ interface BarePackHeader {
3
+ id?: string;
4
+ resolutions?: Record<string, unknown>;
5
+ }
6
+ interface GenerateAddonsManifestOptions {
7
+ bundlePath: string;
8
+ outputDir: string;
9
+ projectRoot: string;
10
+ logger: Logger;
11
+ }
12
+ interface GenerateAddonsManifestResult {
13
+ manifestPath: string;
14
+ addons: string[];
15
+ }
16
+ export declare function extractPackedString(bundleJsText: string): string;
17
+ export declare function extractBarePackHeader(packed: string): BarePackHeader;
18
+ export declare function buildNestedPathIndex(resolutions: Record<string, unknown>, projectRoot: string): Map<string, Set<string>>;
19
+ export declare function generateAddonsManifest(options: GenerateAddonsManifestOptions): Promise<GenerateAddonsManifestResult>;
20
+ export {};
21
+ //# sourceMappingURL=manifest.d.ts.map
@@ -0,0 +1,193 @@
1
+ import fs, { promises as fsp } from "node:fs";
2
+ import path from "node:path";
3
+ export function extractPackedString(bundleJsText) {
4
+ const idx = bundleJsText.indexOf("module.exports");
5
+ if (idx === -1) {
6
+ throw new Error("bundle does not contain 'module.exports'");
7
+ }
8
+ const eq = bundleJsText.indexOf("=", idx);
9
+ if (eq === -1) {
10
+ throw new Error("could not find '=' after module.exports");
11
+ }
12
+ let i = eq + 1;
13
+ while (i < bundleJsText.length && /\s/.test(bundleJsText[i] ?? ""))
14
+ i++;
15
+ const quote = bundleJsText[i];
16
+ if (quote !== '"' && quote !== "'") {
17
+ throw new Error("export value is not a string literal");
18
+ }
19
+ i++;
20
+ let out = "";
21
+ let esc = false;
22
+ for (; i < bundleJsText.length; i++) {
23
+ const ch = bundleJsText[i];
24
+ if (esc) {
25
+ switch (ch) {
26
+ case "n":
27
+ out += "\n";
28
+ break;
29
+ case "r":
30
+ out += "\r";
31
+ break;
32
+ case "t":
33
+ out += "\t";
34
+ break;
35
+ case "b":
36
+ out += "\b";
37
+ break;
38
+ case "f":
39
+ out += "\f";
40
+ break;
41
+ case "v":
42
+ out += "\v";
43
+ break;
44
+ case "\\":
45
+ out += "\\";
46
+ break;
47
+ case '"':
48
+ out += '"';
49
+ break;
50
+ case "'":
51
+ out += "'";
52
+ break;
53
+ case "x": {
54
+ const hex = bundleJsText.slice(i + 1, i + 3);
55
+ if (!/^[0-9a-fA-F]{2}$/.test(hex))
56
+ throw new Error("bad \\x escape");
57
+ out += String.fromCharCode(parseInt(hex, 16));
58
+ i += 2;
59
+ break;
60
+ }
61
+ case "u": {
62
+ const hex = bundleJsText.slice(i + 1, i + 5);
63
+ if (!/^[0-9a-fA-F]{4}$/.test(hex))
64
+ throw new Error("bad \\u escape");
65
+ out += String.fromCharCode(parseInt(hex, 16));
66
+ i += 4;
67
+ break;
68
+ }
69
+ default:
70
+ out += ch;
71
+ }
72
+ esc = false;
73
+ continue;
74
+ }
75
+ if (ch === "\\") {
76
+ esc = true;
77
+ continue;
78
+ }
79
+ if (ch === quote)
80
+ break;
81
+ out += ch;
82
+ }
83
+ if (i >= bundleJsText.length) {
84
+ throw new Error("unterminated string literal");
85
+ }
86
+ return out;
87
+ }
88
+ export function extractBarePackHeader(packed) {
89
+ const firstNL = packed.indexOf("\n");
90
+ if (firstNL === -1) {
91
+ throw new Error("packed string missing first newline separator");
92
+ }
93
+ const jsonStart = packed.indexOf("{", firstNL + 1);
94
+ if (jsonStart === -1) {
95
+ throw new Error("could not find header JSON start in packed string");
96
+ }
97
+ let i = jsonStart;
98
+ let depth = 0;
99
+ let inStr = false;
100
+ let esc = false;
101
+ for (; i < packed.length; i++) {
102
+ const ch = packed[i];
103
+ if (inStr) {
104
+ if (esc)
105
+ esc = false;
106
+ else if (ch === "\\")
107
+ esc = true;
108
+ else if (ch === '"')
109
+ inStr = false;
110
+ continue;
111
+ }
112
+ if (ch === '"')
113
+ inStr = true;
114
+ else if (ch === "{")
115
+ depth++;
116
+ else if (ch === "}") {
117
+ depth--;
118
+ if (depth === 0) {
119
+ i++;
120
+ break;
121
+ }
122
+ }
123
+ }
124
+ if (depth !== 0) {
125
+ throw new Error("unbalanced braces while extracting header JSON");
126
+ }
127
+ return JSON.parse(packed.slice(jsonStart, i));
128
+ }
129
+ const NODE_MODULES_RE = /\/node_modules\/(@[^/]+\/[^/]+|[^/]+)(?=\/)/g;
130
+ export function buildNestedPathIndex(resolutions, projectRoot) {
131
+ const index = new Map();
132
+ for (const key of Object.keys(resolutions)) {
133
+ for (const match of key.matchAll(NODE_MODULES_RE)) {
134
+ const pkgName = match[1];
135
+ if (!pkgName)
136
+ continue;
137
+ const idx = match.index;
138
+ if (idx === undefined)
139
+ continue;
140
+ const marker = `/node_modules/${pkgName}/`;
141
+ const candidate = path.join(projectRoot, key.slice(1, idx + marker.length), "package.json");
142
+ let set = index.get(pkgName);
143
+ if (!set) {
144
+ set = new Set();
145
+ index.set(pkgName, set);
146
+ }
147
+ set.add(candidate);
148
+ }
149
+ }
150
+ return index;
151
+ }
152
+ export async function generateAddonsManifest(options) {
153
+ const { bundlePath, outputDir, projectRoot, logger } = options;
154
+ logger.info("\n📦 Generating addons manifest...");
155
+ const bundleJsText = await fsp.readFile(bundlePath, "utf8");
156
+ const packed = extractPackedString(bundleJsText);
157
+ const header = extractBarePackHeader(packed);
158
+ const resolutions = header.resolutions ?? {};
159
+ const pathsByPackage = buildNestedPathIndex(resolutions, projectRoot);
160
+ const addons = [];
161
+ for (const [pkgName, candidates] of pathsByPackage) {
162
+ let pkgJson = null;
163
+ for (const candidate of candidates) {
164
+ try {
165
+ if (fs.existsSync(candidate)) {
166
+ pkgJson = JSON.parse(await fsp.readFile(candidate, "utf8"));
167
+ break;
168
+ }
169
+ }
170
+ catch (err) {
171
+ logger.warn(` Could not read ${candidate}: ${err.message}`);
172
+ }
173
+ }
174
+ if (pkgJson?.addon === true) {
175
+ addons.push(pkgName);
176
+ }
177
+ }
178
+ addons.sort();
179
+ const bundleId = typeof header.id === "string" && header.id.length > 0
180
+ ? header.id
181
+ : "unknown";
182
+ const manifest = {
183
+ version: 1,
184
+ bundleId,
185
+ addons,
186
+ };
187
+ const manifestPath = path.join(outputDir, "addons.manifest.json");
188
+ await fsp.writeFile(manifestPath, JSON.stringify(manifest, null, 2) + "\n");
189
+ logger.info(` Found ${pathsByPackage.size} packages in bundle graph`);
190
+ logger.info(` Identified ${addons.length} native addons: ${addons.join(", ") || "(none)"}`);
191
+ logger.info(` Wrote ${manifestPath}`);
192
+ return { manifestPath, addons };
193
+ }
@@ -0,0 +1,9 @@
1
+ import type { Logger } from "../../logging/types";
2
+ import type { QvacConfig } from "../../schemas/sdk-config";
3
+ export declare function buildBuiltinSpecifier(sdkName: string, suffix: string): string;
4
+ export declare function parseBuiltinSpecifier(specifier: string, sdkName: string): {
5
+ suffix: string;
6
+ exportName: string;
7
+ } | null;
8
+ export declare function resolvePluginSpecifiers(config: QvacConfig, sdkName: string, logger: Logger): string[];
9
+ //# sourceMappingURL=plugins.d.ts.map
@@ -0,0 +1,51 @@
1
+ import { BUILTIN_PLUGINS, BUILTIN_SUFFIXES } from "./constants.js";
2
+ import { InvalidPluginSpecifierError } from "../../utils/errors-client.js";
3
+ export function buildBuiltinSpecifier(sdkName, suffix) {
4
+ return `${sdkName}/${suffix}/plugin`;
5
+ }
6
+ export function parseBuiltinSpecifier(specifier, sdkName) {
7
+ const prefix = `${sdkName}/`;
8
+ const pluginSuffix = "/plugin";
9
+ if (specifier.startsWith(prefix) && specifier.endsWith(pluginSuffix)) {
10
+ const middle = specifier.slice(prefix.length, -pluginSuffix.length);
11
+ const info = BUILTIN_PLUGINS[middle];
12
+ if (!middle.includes("/") && info) {
13
+ return { suffix: middle, exportName: info.exportName };
14
+ }
15
+ }
16
+ return null;
17
+ }
18
+ export function resolvePluginSpecifiers(config, sdkName, logger) {
19
+ let plugins = config.plugins ?? [];
20
+ if (plugins.length === 0) {
21
+ const allBuiltins = BUILTIN_SUFFIXES.map((suffix) => buildBuiltinSpecifier(sdkName, suffix));
22
+ logger.warn("No plugins specified — bundling ALL built-in plugins.");
23
+ logger.info(" For smaller bundles, add a 'plugins' array to qvac.config.*\n");
24
+ plugins = allBuiltins;
25
+ }
26
+ const uniquePlugins = [...new Set(plugins)];
27
+ const resolved = [];
28
+ const customPlugins = [];
29
+ const errors = [];
30
+ for (const specifier of uniquePlugins) {
31
+ const builtin = parseBuiltinSpecifier(specifier, sdkName);
32
+ if (builtin) {
33
+ resolved.push(specifier);
34
+ }
35
+ else {
36
+ if (!specifier.endsWith("/plugin")) {
37
+ errors.push(specifier);
38
+ }
39
+ else {
40
+ customPlugins.push(specifier);
41
+ }
42
+ }
43
+ }
44
+ if (errors.length > 0) {
45
+ throw new InvalidPluginSpecifierError(errors);
46
+ }
47
+ if (customPlugins.length > 0) {
48
+ logger.info(`📦 Custom plugins: ${customPlugins.join(", ")}`);
49
+ }
50
+ return [...resolved, ...customPlugins];
51
+ }
@@ -0,0 +1,5 @@
1
+ export { bundleSdk } from "./bundle/index";
2
+ export type { BundleSdkOptions, BundleSdkResult } from "./bundle/index";
3
+ export { verifyBundle, hasErrors, hasWarnings, formatVerifyBundleResult, } from "./verify/index";
4
+ export type { VerifyBundleOptions, VerifyBundleResult, VerifyBundleIssue, } from "./verify/index";
5
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1,2 @@
1
+ export { bundleSdk } from "./bundle/index.js";
2
+ export { verifyBundle, hasErrors, hasWarnings, formatVerifyBundleResult, } from "./verify/index.js";
@@ -0,0 +1,52 @@
1
+ import { type NativeAddon } from "./addon-source";
2
+ export interface BareRuntime {
3
+ version: string;
4
+ source: "flag" | "config" | "bare-runtime" | "bare";
5
+ }
6
+ export interface UnresolvedBareRuntime {
7
+ reason: string;
8
+ triedPaths: string[];
9
+ }
10
+ export interface ResolveBareRuntimeOptions {
11
+ projectRoot: string;
12
+ explicitVersion?: string;
13
+ explicitSource?: "flag" | "config";
14
+ }
15
+ export type BareRuntimeResolution = {
16
+ resolved: true;
17
+ runtime: BareRuntime;
18
+ } | {
19
+ resolved: false;
20
+ error: UnresolvedBareRuntime;
21
+ };
22
+ export interface AbiMismatchIssue {
23
+ code: "abi-mismatch";
24
+ level: "error";
25
+ addon: string;
26
+ message: string;
27
+ enginesBare: string;
28
+ runtimeVersion: string;
29
+ }
30
+ export interface UnknownRuntimeIssue {
31
+ code: "unknown-runtime-version";
32
+ level: "warning";
33
+ message: string;
34
+ triedPaths: string[];
35
+ }
36
+ export interface MalformedEnginesBareIssue {
37
+ code: "malformed-engines-bare";
38
+ level: "warning";
39
+ addon: string;
40
+ enginesBare: string;
41
+ message: string;
42
+ }
43
+ export type AbiIssue = AbiMismatchIssue | UnknownRuntimeIssue | MalformedEnginesBareIssue;
44
+ export interface CheckAbiOptions {
45
+ addons: NativeAddon[];
46
+ runtime: BareRuntimeResolution;
47
+ }
48
+ export declare function resolveBareRuntime(options: ResolveBareRuntimeOptions): Promise<BareRuntimeResolution>;
49
+ export declare function normalizeVersion(value: string): string | null;
50
+ export declare function formatConfigLabel(projectRoot: string, configPath?: string): string;
51
+ export declare function checkAbi(options: CheckAbiOptions): AbiIssue[];
52
+ //# sourceMappingURL=abi.d.ts.map
@@ -0,0 +1,125 @@
1
+ import { promises as fsp } from "node:fs";
2
+ import path from "node:path";
3
+ import semver from "semver";
4
+ import { formatAddonId } from "./addon-source.js";
5
+ const RUNTIME_PACKAGES = [
6
+ { source: "bare-runtime", packageName: "bare-runtime" },
7
+ { source: "bare", packageName: "bare" },
8
+ ];
9
+ export async function resolveBareRuntime(options) {
10
+ if (options.explicitVersion) {
11
+ // Caller (verifyBundle) pre-validates explicitVersion via normalizeVersion.
12
+ return {
13
+ resolved: true,
14
+ runtime: {
15
+ version: normalizeVersion(options.explicitVersion),
16
+ source: options.explicitSource ?? "flag",
17
+ },
18
+ };
19
+ }
20
+ const tried = [];
21
+ for (const candidate of RUNTIME_PACKAGES) {
22
+ const pkgJsonPath = path.join(options.projectRoot, "node_modules", candidate.packageName, "package.json");
23
+ tried.push(pkgJsonPath);
24
+ const version = await tryReadRuntimeVersion(pkgJsonPath);
25
+ if (version) {
26
+ return {
27
+ resolved: true,
28
+ runtime: { version, source: candidate.source },
29
+ };
30
+ }
31
+ }
32
+ return {
33
+ resolved: false,
34
+ error: {
35
+ reason: "Unable to detect installed Bare runtime version",
36
+ triedPaths: tried,
37
+ },
38
+ };
39
+ }
40
+ async function tryReadRuntimeVersion(pkgJsonPath) {
41
+ let raw;
42
+ try {
43
+ raw = await fsp.readFile(pkgJsonPath, "utf8");
44
+ }
45
+ catch {
46
+ return null;
47
+ }
48
+ let parsed;
49
+ try {
50
+ parsed = JSON.parse(raw);
51
+ }
52
+ catch {
53
+ return null;
54
+ }
55
+ if (typeof parsed !== "object" || parsed === null || Array.isArray(parsed)) {
56
+ return null;
57
+ }
58
+ const version = parsed["version"];
59
+ return typeof version === "string" ? normalizeVersion(version) : null;
60
+ }
61
+ export function normalizeVersion(value) {
62
+ const coerced = semver.coerce(value, { includePrerelease: true });
63
+ return coerced ? coerced.version : null;
64
+ }
65
+ export function formatConfigLabel(projectRoot, configPath) {
66
+ if (!configPath)
67
+ return "qvac.config";
68
+ const rel = path.relative(projectRoot, configPath);
69
+ if (!rel || rel.startsWith("..") || path.isAbsolute(rel))
70
+ return configPath;
71
+ return rel;
72
+ }
73
+ export function checkAbi(options) {
74
+ const { addons, runtime } = options;
75
+ const addonsWithEngines = addons.filter((addon) => addon.enginesBare !== undefined);
76
+ if (addonsWithEngines.length === 0)
77
+ return [];
78
+ const issues = [];
79
+ const checkable = [];
80
+ for (const addon of addonsWithEngines) {
81
+ const range = addon.enginesBare;
82
+ if (!range)
83
+ continue;
84
+ if (!semver.validRange(range)) {
85
+ issues.push({
86
+ code: "malformed-engines-bare",
87
+ level: "warning",
88
+ addon: formatAddonId(addon),
89
+ enginesBare: range,
90
+ message: `${formatAddonId(addon)} declares engines.bare "${range}", which is ` +
91
+ "not a valid semver range. ABI check skipped for this addon. " +
92
+ "Report this to the addon maintainer.",
93
+ });
94
+ continue;
95
+ }
96
+ checkable.push({ addon, range });
97
+ }
98
+ if (checkable.length === 0)
99
+ return issues;
100
+ if (!runtime.resolved) {
101
+ issues.push({
102
+ code: "unknown-runtime-version",
103
+ level: "warning",
104
+ message: `${runtime.error.reason}. ABI checks skipped for ${checkable.length} ` +
105
+ `addon${checkable.length === 1 ? "" : "s"}. ` +
106
+ "Pass bareRuntimeVersion to enable strict ABI verification.",
107
+ triedPaths: runtime.error.triedPaths,
108
+ });
109
+ return issues;
110
+ }
111
+ for (const { addon, range } of checkable) {
112
+ if (semver.satisfies(runtime.runtime.version, range))
113
+ continue;
114
+ issues.push({
115
+ code: "abi-mismatch",
116
+ level: "error",
117
+ addon: formatAddonId(addon),
118
+ enginesBare: range,
119
+ runtimeVersion: runtime.runtime.version,
120
+ message: `${formatAddonId(addon)} requires bare ${range}, ` +
121
+ `runtime is ${runtime.runtime.version} (from ${runtime.runtime.source}).`,
122
+ });
123
+ }
124
+ return issues;
125
+ }
@@ -0,0 +1,43 @@
1
+ export type AddonSourceKind = "bare-pack-bundle" | "node-modules";
2
+ export interface NativeAddon {
3
+ name: string;
4
+ version?: string;
5
+ packageJsonPath: string;
6
+ packageRoot: string;
7
+ enginesBare?: string;
8
+ }
9
+ export interface AddonPackageJson {
10
+ name?: string;
11
+ version?: string;
12
+ addon?: boolean;
13
+ engines?: {
14
+ bare?: string;
15
+ };
16
+ }
17
+ export interface ReadAddonPackageJsonOptions {
18
+ packageJsonPath: string;
19
+ expectedName?: string;
20
+ }
21
+ export interface InvalidPackageJsonRecord {
22
+ packageJsonPath: string;
23
+ expectedName?: string;
24
+ reason: string;
25
+ }
26
+ export interface ReadAddonPackageJsonResult {
27
+ found: boolean;
28
+ isAddon: boolean;
29
+ invalid?: InvalidPackageJsonRecord;
30
+ addon?: NativeAddon;
31
+ }
32
+ export declare function readAddonPackageJson(options: ReadAddonPackageJsonOptions): Promise<ReadAddonPackageJsonResult>;
33
+ export interface CollectDiagnostics {
34
+ invalidPackageJsons: InvalidPackageJsonRecord[];
35
+ emptyResolutions: boolean;
36
+ }
37
+ export declare function createCollectDiagnostics(): CollectDiagnostics;
38
+ export declare function formatAddonId(addon: {
39
+ name: string;
40
+ version?: string;
41
+ }): string;
42
+ export declare function deduplicateAddons(addons: NativeAddon[]): NativeAddon[];
43
+ //# sourceMappingURL=addon-source.d.ts.map