@hakobu/hakobu 1.0.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.
Files changed (284) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +673 -0
  3. package/dictionary/angular-bridge.js +3 -0
  4. package/dictionary/any-promise.js +3 -0
  5. package/dictionary/async.js +3 -0
  6. package/dictionary/aws-sdk.js +7 -0
  7. package/dictionary/babel-core.js +3 -0
  8. package/dictionary/batch.js +3 -0
  9. package/dictionary/bcrypt.js +3 -0
  10. package/dictionary/better-sqlite3.js +3 -0
  11. package/dictionary/bignum.js +3 -0
  12. package/dictionary/bindings.js +3 -0
  13. package/dictionary/blessed.js +8 -0
  14. package/dictionary/body-parser.js +9 -0
  15. package/dictionary/browserify.js +7 -0
  16. package/dictionary/bson.js +3 -0
  17. package/dictionary/buffermaker.js +7 -0
  18. package/dictionary/bunyan.js +9 -0
  19. package/dictionary/busboy.js +7 -0
  20. package/dictionary/bytes.js +3 -0
  21. package/dictionary/callsites.js +3 -0
  22. package/dictionary/chokidar.js +3 -0
  23. package/dictionary/coffee-script.js +7 -0
  24. package/dictionary/colors.js +3 -0
  25. package/dictionary/compression.js +3 -0
  26. package/dictionary/compressjs.js +7 -0
  27. package/dictionary/connect-mongo.js +3 -0
  28. package/dictionary/connect-mongodb.js +3 -0
  29. package/dictionary/connect-redis.js +3 -0
  30. package/dictionary/connect.js +10 -0
  31. package/dictionary/consolidate.js +3 -0
  32. package/dictionary/cookie-parser.js +3 -0
  33. package/dictionary/cookie.js +3 -0
  34. package/dictionary/cors.js +3 -0
  35. package/dictionary/cron.js +3 -0
  36. package/dictionary/cross-env.js +11 -0
  37. package/dictionary/cross-spawn-async.js +3 -0
  38. package/dictionary/curve25519.js +3 -0
  39. package/dictionary/data-preflight.js +7 -0
  40. package/dictionary/debug.js +3 -0
  41. package/dictionary/denymount.js +3 -0
  42. package/dictionary/diff.js +3 -0
  43. package/dictionary/drivelist.js +22 -0
  44. package/dictionary/ed25519.js +3 -0
  45. package/dictionary/ejs.js +3 -0
  46. package/dictionary/elasticsearch.js +3 -0
  47. package/dictionary/electron.js +17 -0
  48. package/dictionary/emailjs.js +3 -0
  49. package/dictionary/engine.io.js +3 -0
  50. package/dictionary/epoll.js +3 -0
  51. package/dictionary/errorhandler.js +7 -0
  52. package/dictionary/errors.js +7 -0
  53. package/dictionary/eslint.js +7 -0
  54. package/dictionary/etcher-image-write.js +3 -0
  55. package/dictionary/exceljs.js +21 -0
  56. package/dictionary/exiftool.exe.js +13 -0
  57. package/dictionary/exiftool.pl.js +13 -0
  58. package/dictionary/express-load.js +12 -0
  59. package/dictionary/express-session.js +3 -0
  60. package/dictionary/express.js +14 -0
  61. package/dictionary/extender.js +11 -0
  62. package/dictionary/extsprintf.js +3 -0
  63. package/dictionary/faye-websocket.js +3 -0
  64. package/dictionary/feathers.js +3 -0
  65. package/dictionary/findup-sync.js +3 -0
  66. package/dictionary/floordate.js +3 -0
  67. package/dictionary/fmt.js +3 -0
  68. package/dictionary/formidable.js +3 -0
  69. package/dictionary/fs-extra.js +3 -0
  70. package/dictionary/fsevents.js +3 -0
  71. package/dictionary/geoip-lite.js +7 -0
  72. package/dictionary/github.js +7 -0
  73. package/dictionary/gm.js +3 -0
  74. package/dictionary/google-closure-compiler-java.js +13 -0
  75. package/dictionary/google-closure-compiler.js +13 -0
  76. package/dictionary/googleapis.js +7 -0
  77. package/dictionary/got.js +3 -0
  78. package/dictionary/graceful-fs.js +19 -0
  79. package/dictionary/grpc.js +11 -0
  80. package/dictionary/gulp.js +3 -0
  81. package/dictionary/hap-nodejs.js +3 -0
  82. package/dictionary/heapdump.js +3 -0
  83. package/dictionary/hoek.js +3 -0
  84. package/dictionary/homebridge.js +3 -0
  85. package/dictionary/http-proxy.js +3 -0
  86. package/dictionary/http-server.js +3 -0
  87. package/dictionary/image-size.js +3 -0
  88. package/dictionary/indexof.js +3 -0
  89. package/dictionary/inquirer.js +3 -0
  90. package/dictionary/j.js +16 -0
  91. package/dictionary/jade.js +3 -0
  92. package/dictionary/jsdom.js +3 -0
  93. package/dictionary/json-stringify-date.js +3 -0
  94. package/dictionary/json-stringify-safe.js +3 -0
  95. package/dictionary/jsonwebtoken.js +3 -0
  96. package/dictionary/kerberos.js +3 -0
  97. package/dictionary/knex.js +7 -0
  98. package/dictionary/later.js +7 -0
  99. package/dictionary/level.js +3 -0
  100. package/dictionary/leveldown.js +10 -0
  101. package/dictionary/levelup.js +3 -0
  102. package/dictionary/liftoff.js +12 -0
  103. package/dictionary/lodash.js +3 -0
  104. package/dictionary/log4js.js +7 -0
  105. package/dictionary/logform.js +7 -0
  106. package/dictionary/machinepack-urls.js +7 -0
  107. package/dictionary/markdown.js +3 -0
  108. package/dictionary/mdns.js +6 -0
  109. package/dictionary/method-override.js +3 -0
  110. package/dictionary/microjob.js +16 -0
  111. package/dictionary/mime-types.js +3 -0
  112. package/dictionary/mime.js +3 -0
  113. package/dictionary/minimatch.js +3 -0
  114. package/dictionary/minstache.js +3 -0
  115. package/dictionary/module-deps.js +3 -0
  116. package/dictionary/moment-timezone.js +3 -0
  117. package/dictionary/moment.js +7 -0
  118. package/dictionary/mongodb-core.js +22 -0
  119. package/dictionary/mongodb.js +7 -0
  120. package/dictionary/mongoose.js +7 -0
  121. package/dictionary/mongoskin.js +7 -0
  122. package/dictionary/ms.js +3 -0
  123. package/dictionary/msgpack.js +3 -0
  124. package/dictionary/multer.js +3 -0
  125. package/dictionary/muri.js +3 -0
  126. package/dictionary/native-or-bluebird.js +3 -0
  127. package/dictionary/natives.js +3 -0
  128. package/dictionary/nconf.js +7 -0
  129. package/dictionary/nedb.js +3 -0
  130. package/dictionary/negotiator.js +7 -0
  131. package/dictionary/newrelic.js +3 -0
  132. package/dictionary/nib.js +3 -0
  133. package/dictionary/nightmare.js +18 -0
  134. package/dictionary/node-forge.js +7 -0
  135. package/dictionary/node-libcurl.js +3 -0
  136. package/dictionary/node-notifier.js +30 -0
  137. package/dictionary/node-pre-gyp.js +7 -0
  138. package/dictionary/node-redis-pubsub.js +3 -0
  139. package/dictionary/node-sass.js +3 -0
  140. package/dictionary/node-uuid.js +3 -0
  141. package/dictionary/node-xlsx.js +3 -0
  142. package/dictionary/node-zookeeper-client.js +7 -0
  143. package/dictionary/nodegit.js +7 -0
  144. package/dictionary/nodemailer-sendmail-transport.js +3 -0
  145. package/dictionary/nodemailer.js +3 -0
  146. package/dictionary/npm-registry-client.js +7 -0
  147. package/dictionary/npm.js +7 -0
  148. package/dictionary/nssocket.js +3 -0
  149. package/dictionary/oauth2orize.js +7 -0
  150. package/dictionary/octobat.js +3 -0
  151. package/dictionary/open.js +13 -0
  152. package/dictionary/opn.js +4 -0
  153. package/dictionary/optimist.js +3 -0
  154. package/dictionary/passport-local.js +3 -0
  155. package/dictionary/passport.js +3 -0
  156. package/dictionary/pg-cursor.js +3 -0
  157. package/dictionary/pg-query-stream.js +3 -0
  158. package/dictionary/pg-types.js +7 -0
  159. package/dictionary/pg.js +7 -0
  160. package/dictionary/pg.js.js +7 -0
  161. package/dictionary/pgpass.js +7 -0
  162. package/dictionary/phantom.js +19 -0
  163. package/dictionary/phantomjs-prebuilt.js +16 -0
  164. package/dictionary/pkginfo.js +3 -0
  165. package/dictionary/pm2.js +7 -0
  166. package/dictionary/pmx.js +3 -0
  167. package/dictionary/pouchdb.js +3 -0
  168. package/dictionary/primus-emitter.js +3 -0
  169. package/dictionary/primus-spark-latency.js +3 -0
  170. package/dictionary/primus.js +3 -0
  171. package/dictionary/publicsuffixlist.js +15 -0
  172. package/dictionary/pug.js +3 -0
  173. package/dictionary/punt.js +3 -0
  174. package/dictionary/puppeteer.js +13 -0
  175. package/dictionary/pwd.js +3 -0
  176. package/dictionary/q.js +3 -0
  177. package/dictionary/raven.js +3 -0
  178. package/dictionary/rc.js +12 -0
  179. package/dictionary/readable-stream.js +3 -0
  180. package/dictionary/rechoir.js +3 -0
  181. package/dictionary/redis-parser.js +3 -0
  182. package/dictionary/redis.js +3 -0
  183. package/dictionary/regression.js +3 -0
  184. package/dictionary/reload.js +7 -0
  185. package/dictionary/request.js +3 -0
  186. package/dictionary/require-uncached.js +3 -0
  187. package/dictionary/require_optional.js +3 -0
  188. package/dictionary/s3.js +3 -0
  189. package/dictionary/safe_datejs.js +3 -0
  190. package/dictionary/sails.js +33 -0
  191. package/dictionary/sax.js +3 -0
  192. package/dictionary/scrypt.js +3 -0
  193. package/dictionary/semver.js +3 -0
  194. package/dictionary/sequelize.js +7 -0
  195. package/dictionary/serialport.js +3 -0
  196. package/dictionary/sha3.js +3 -0
  197. package/dictionary/sharp.js +11 -0
  198. package/dictionary/shelljs.js +7 -0
  199. package/dictionary/sinon.js +3 -0
  200. package/dictionary/socket.io-client.js +13 -0
  201. package/dictionary/socket.io.js +12 -0
  202. package/dictionary/sqip.js +7 -0
  203. package/dictionary/sqlite3.js +7 -0
  204. package/dictionary/steam-crypto.js +7 -0
  205. package/dictionary/steam-resources.js +19 -0
  206. package/dictionary/steam.js +3 -0
  207. package/dictionary/stripe-webhook-middleware.js +3 -0
  208. package/dictionary/stripe.js +3 -0
  209. package/dictionary/strong-globalize.js +3 -0
  210. package/dictionary/stylus.js +14 -0
  211. package/dictionary/supervisor.js +3 -0
  212. package/dictionary/svgo.js +8 -0
  213. package/dictionary/tabtab.js +3 -0
  214. package/dictionary/tesseract.js.js +7 -0
  215. package/dictionary/thread-stream.js +7 -0
  216. package/dictionary/throng.js +3 -0
  217. package/dictionary/time.js +3 -0
  218. package/dictionary/tinify.js +7 -0
  219. package/dictionary/tiny-worker.js +7 -0
  220. package/dictionary/tmp.js +3 -0
  221. package/dictionary/transformers.js +3 -0
  222. package/dictionary/uglify-js.js +9 -0
  223. package/dictionary/umd.js +19 -0
  224. package/dictionary/underscore.js +3 -0
  225. package/dictionary/union.js +3 -0
  226. package/dictionary/update-notifier.js +3 -0
  227. package/dictionary/usage.js +7 -0
  228. package/dictionary/v8flags.js +13 -0
  229. package/dictionary/verror.js +3 -0
  230. package/dictionary/voc.js +3 -0
  231. package/dictionary/webdriverio.js +7 -0
  232. package/dictionary/winston-uber.js +7 -0
  233. package/dictionary/winston.js +7 -0
  234. package/dictionary/ws.js +3 -0
  235. package/dictionary/xlsx.js +16 -0
  236. package/dictionary/xml2js.js +3 -0
  237. package/dictionary/yargs.js +3 -0
  238. package/dictionary/zeromq.js +13 -0
  239. package/lib-es5/addon-extract.js +164 -0
  240. package/lib-es5/analyzer.js +687 -0
  241. package/lib-es5/app-bundle.js +133 -0
  242. package/lib-es5/appdir.js +265 -0
  243. package/lib-es5/bin.js +304 -0
  244. package/lib-es5/bootstrap.js +179 -0
  245. package/lib-es5/bundler.js +496 -0
  246. package/lib-es5/chmod.js +15 -0
  247. package/lib-es5/colors.js +12 -0
  248. package/lib-es5/commands.js +376 -0
  249. package/lib-es5/common.js +328 -0
  250. package/lib-es5/compress_type.js +10 -0
  251. package/lib-es5/config.js +291 -0
  252. package/lib-es5/detector.js +421 -0
  253. package/lib-es5/esm-hooks.js +366 -0
  254. package/lib-es5/esm-resolver.js +292 -0
  255. package/lib-es5/esm-transformer.js +378 -0
  256. package/lib-es5/exports-resolver.js +184 -0
  257. package/lib-es5/external-artifacts.js +170 -0
  258. package/lib-es5/fabricator.js +137 -0
  259. package/lib-es5/follow.js +190 -0
  260. package/lib-es5/help.js +52 -0
  261. package/lib-es5/index.d.ts +2 -0
  262. package/lib-es5/index.js +552 -0
  263. package/lib-es5/log.js +7 -0
  264. package/lib-es5/mach-o.js +262 -0
  265. package/lib-es5/manifest.js +21 -0
  266. package/lib-es5/options.js +19 -0
  267. package/lib-es5/packager.js +1036 -0
  268. package/lib-es5/packer.js +137 -0
  269. package/lib-es5/pe-metadata.js +130 -0
  270. package/lib-es5/producer.js +378 -0
  271. package/lib-es5/refiner.js +87 -0
  272. package/lib-es5/resolver.js +142 -0
  273. package/lib-es5/runtime-diagnostics.js +172 -0
  274. package/lib-es5/sea.js +307 -0
  275. package/lib-es5/snapshot-fs-patch.js +396 -0
  276. package/lib-es5/snapshot-fs.js +255 -0
  277. package/lib-es5/snapshot-index.js +135 -0
  278. package/lib-es5/snapshot-path.js +168 -0
  279. package/lib-es5/types.js +9 -0
  280. package/lib-es5/walker.js +1019 -0
  281. package/lib-es5/windows-sign.js +139 -0
  282. package/package.json +99 -0
  283. package/prelude/bootstrap.js +2263 -0
  284. package/prelude/diagnostic.js +147 -0
@@ -0,0 +1,1036 @@
1
+ "use strict";
2
+ /**
3
+ * Hakobu Packager
4
+ *
5
+ * End-to-end packaging: project → analysis → executable.
6
+ *
7
+ * Uses the new manifest/analyzer for project analysis, then bridges
8
+ * into the inherited producer/packer for binary assembly. This is the
9
+ * pragmatic approach: the new analysis layers feed into the proven
10
+ * binary injection mechanism.
11
+ */
12
+ var __importDefault = (this && this.__importDefault) || function (mod) {
13
+ return (mod && mod.__esModule) ? mod : { "default": mod };
14
+ };
15
+ Object.defineProperty(exports, "__esModule", { value: true });
16
+ exports.packageApp = exports.packageMultiple = void 0;
17
+ const fs_1 = __importDefault(require("fs"));
18
+ const os_1 = __importDefault(require("os"));
19
+ const path_1 = __importDefault(require("path"));
20
+ const child_process_1 = require("child_process");
21
+ const hakobu_fetch_1 = require("@hakobu/hakobu-fetch");
22
+ const analyzer_1 = require("./analyzer");
23
+ const bundler_1 = require("./bundler");
24
+ const fabricator_1 = require("./fabricator");
25
+ const log_1 = require("./log");
26
+ const common_1 = require("./common");
27
+ const packer_1 = __importDefault(require("./packer"));
28
+ const producer_1 = __importDefault(require("./producer"));
29
+ const compress_type_1 = require("./compress_type");
30
+ const chmod_1 = require("./chmod");
31
+ const mach_o_1 = require("./mach-o");
32
+ const windows_sign_1 = require("./windows-sign");
33
+ const pe_metadata_1 = require("./pe-metadata");
34
+ const app_bundle_1 = require("./app-bundle");
35
+ const appdir_1 = require("./appdir");
36
+ function prepareBaseBinary(targetSpec, binaryPath) {
37
+ if (targetSpec.platform !== 'macos') {
38
+ return { effectiveBinaryPath: binaryPath, cleanup: () => { } };
39
+ }
40
+ const tmpDir = fs_1.default.mkdtempSync(path_1.default.join(os_1.default.tmpdir(), 'hakobu-base-'));
41
+ const stripped = path_1.default.join(tmpDir, path_1.default.basename(binaryPath) + '.unsigned');
42
+ fs_1.default.copyFileSync(binaryPath, stripped);
43
+ try {
44
+ (0, child_process_1.execFileSync)('codesign', ['--remove-signature', stripped], { stdio: 'pipe' });
45
+ }
46
+ catch {
47
+ // Some cache entries are already unsigned; stripping is best-effort.
48
+ }
49
+ return {
50
+ effectiveBinaryPath: stripped,
51
+ cleanup: () => {
52
+ try {
53
+ fs_1.default.rmSync(tmpDir, { recursive: true, force: true });
54
+ }
55
+ catch { }
56
+ },
57
+ };
58
+ }
59
+ // ─────────────────────────────────────────────────────────────────────
60
+ // Multi-target packaging
61
+ // ─────────────────────────────────────────────────────────────────────
62
+ const ALL_TARGETS = [
63
+ 'node24-linux-x64', 'node24-linux-arm64', 'node24-win-x64', 'node24-win-arm64',
64
+ 'node24-macos-arm64', 'node24-macos-x64', 'node24-linuxstatic-x64',
65
+ ];
66
+ async function packageMultiple(options) {
67
+ const { projectRoot } = options;
68
+ const outputDir = path_1.default.resolve(options.outputDir || '.');
69
+ // Expand 'all' target
70
+ const targetSpecs = options.targets.flatMap(t => t === 'all' ? ALL_TARGETS : t.split(',')).filter(Boolean);
71
+ if (targetSpecs.length === 0) {
72
+ throw new Error('No targets specified.');
73
+ }
74
+ // Single target → delegate to packageApp for backward compat
75
+ if (targetSpecs.length === 1) {
76
+ const result = await packageApp({
77
+ ...options,
78
+ target: targetSpecs[0],
79
+ output: path_1.default.join(outputDir, defaultOutputName(appIdFromProject(projectRoot), parseTarget(targetSpecs[0]))),
80
+ });
81
+ return [{
82
+ target: result.target,
83
+ status: 'success',
84
+ outputPath: result.outputPath,
85
+ fileCount: result.fileCount,
86
+ }];
87
+ }
88
+ log_1.log.info(`Multi-target packaging: ${targetSpecs.length} targets`);
89
+ // ── Shared step: bundle (if requested) ──
90
+ let effectiveRoot = projectRoot;
91
+ let effectiveOptions = { ...options };
92
+ let bundleOutput = null;
93
+ if (options.bundle) {
94
+ log_1.log.info('Bundling project (shared across all targets)...');
95
+ const bundlerName = typeof options.bundle === 'string' ? options.bundle : 'rolldown';
96
+ const adapter = (0, bundler_1.getAdapter)(bundlerName);
97
+ const entry = options.entry || resolveEntryForBundle(projectRoot);
98
+ const appName = appIdFromProject(projectRoot);
99
+ bundleOutput = await adapter.bundle({
100
+ projectRoot, entry,
101
+ external: options.bundleExternal,
102
+ appName,
103
+ });
104
+ for (const w of bundleOutput.warnings) {
105
+ log_1.log.warn(`[bundle] ${w.message}`);
106
+ }
107
+ effectiveRoot = bundleOutput.projectRoot;
108
+ const bundleAssets = [
109
+ ...(options.assets || []),
110
+ ...bundleOutput.mapFiles,
111
+ ];
112
+ effectiveOptions = {
113
+ ...effectiveOptions,
114
+ entry: undefined,
115
+ assets: bundleAssets.length > 0 ? bundleAssets : undefined,
116
+ };
117
+ }
118
+ // ── Shared step: analyze ──
119
+ log_1.log.info('Analyzing project (shared across all targets)...');
120
+ const manifest = await (0, analyzer_1.analyze)({
121
+ projectRoot: effectiveRoot,
122
+ entry: effectiveOptions.entry,
123
+ assets: effectiveOptions.assets,
124
+ externals: effectiveOptions.externals,
125
+ });
126
+ log_1.log.info(` entry: ${manifest.entry.snapshotPath} (${manifest.entry.format})`);
127
+ log_1.log.info(` files: ${Object.keys(manifest.files).length}`);
128
+ // ── Pre-fetch: download all base binaries in parallel ──
129
+ // Each target has a unique platform-arch, so no cache file races.
130
+ const parsedTargets = targetSpecs.map(spec => ({
131
+ spec,
132
+ ...parseTarget(spec),
133
+ }));
134
+ log_1.log.info(`\nFetching ${parsedTargets.length} base binaries...`);
135
+ const fetchResults = await Promise.allSettled(parsedTargets.map(t => (0, hakobu_fetch_1.need)({ nodeRange: t.nodeRange, platform: t.platform, arch: t.arch, forceBuild: options.forceBuild })
136
+ .then(binaryPath => {
137
+ log_1.log.info(` fetched: ${t.platform}-${t.arch}`);
138
+ return binaryPath;
139
+ })));
140
+ // Map fetch results by spec for lookup during per-target assembly
141
+ const fetchedBinaries = new Map();
142
+ for (let i = 0; i < parsedTargets.length; i++) {
143
+ const result = fetchResults[i];
144
+ if (result.status === 'fulfilled') {
145
+ fetchedBinaries.set(parsedTargets[i].spec, result.value);
146
+ }
147
+ }
148
+ // ── Per-target: pack, produce ──
149
+ fs_1.default.mkdirSync(outputDir, { recursive: true });
150
+ const results = [];
151
+ for (const spec of targetSpecs) {
152
+ const targetSpec = parseTarget(spec);
153
+ const outputName = defaultOutputName(manifest.appId, targetSpec);
154
+ const outputPath = path_1.default.join(outputDir, outputName);
155
+ log_1.log.info(`\n [${targetSpec.platform}-${targetSpec.arch}]`);
156
+ // Check if fetch succeeded for this target
157
+ const prefetchedBinary = fetchedBinaries.get(spec);
158
+ if (!prefetchedBinary) {
159
+ const fetchResult = fetchResults[targetSpecs.indexOf(spec)];
160
+ const fetchError = fetchResult.status === 'rejected' ? fetchResult.reason?.message : 'unknown';
161
+ results.push({
162
+ target: targetSpec,
163
+ status: 'failed',
164
+ outputPath,
165
+ fileCount: 0,
166
+ error: `Base binary fetch failed: ${fetchError}`,
167
+ });
168
+ continue;
169
+ }
170
+ try {
171
+ const result = await packageAppForTarget(effectiveRoot, manifest, targetSpec, outputPath, effectiveOptions);
172
+ const sizeMB = fs_1.default.existsSync(result.outputPath)
173
+ ? (fs_1.default.statSync(result.outputPath).size / 1024 / 1024).toFixed(0) + ' MB'
174
+ : '';
175
+ results.push({
176
+ target: targetSpec,
177
+ status: 'success',
178
+ outputPath: result.outputPath,
179
+ fileCount: result.fileCount,
180
+ sizeMB,
181
+ });
182
+ }
183
+ catch (err) {
184
+ results.push({
185
+ target: targetSpec,
186
+ status: 'failed',
187
+ outputPath,
188
+ fileCount: 0,
189
+ error: err.message,
190
+ });
191
+ }
192
+ }
193
+ // Clean up bundle
194
+ if (bundleOutput)
195
+ bundleOutput.cleanup();
196
+ // Summary table
197
+ log_1.log.info('\n=== Packaging Results ===\n');
198
+ for (const r of results) {
199
+ const label = `${r.target.platform}-${r.target.arch}`;
200
+ if (r.status === 'success') {
201
+ log_1.log.info(` OK ${label.padEnd(20)} → ${r.outputPath} (${r.sizeMB})`);
202
+ }
203
+ else {
204
+ log_1.log.error(` FAIL ${label.padEnd(20)} ${r.error}`);
205
+ }
206
+ }
207
+ const ok = results.filter(r => r.status === 'success').length;
208
+ const fail = results.filter(r => r.status === 'failed').length;
209
+ log_1.log.info(`\n${ok} succeeded, ${fail} failed`);
210
+ return results;
211
+ }
212
+ exports.packageMultiple = packageMultiple;
213
+ /**
214
+ * Package a single target using a pre-analyzed manifest.
215
+ * This is the per-target inner loop for multi-target packaging.
216
+ */
217
+ async function packageAppForTarget(projectRoot, manifest, targetSpec, outputPath, options) {
218
+ // Fetch base binary
219
+ const binaryPath = await (0, hakobu_fetch_1.need)({
220
+ nodeRange: targetSpec.nodeRange,
221
+ platform: targetSpec.platform,
222
+ arch: targetSpec.arch,
223
+ forceBuild: options.forceBuild,
224
+ });
225
+ const preparedBase = prepareBaseBinary(targetSpec, binaryPath);
226
+ try {
227
+ // Build payload
228
+ const { records, entrypoint, symLinks } = manifestToRecords(manifest, options.bytecode);
229
+ const slash = targetSpec.platform === 'win' ? '\\' : '/';
230
+ const backpack = (0, packer_1.default)({ records, entrypoint, bytecode: !!options.bytecode, symLinks });
231
+ // In app-bundle/appdir mode, write the raw executable to a temp path
232
+ const usesTempOutput = (options.appBundle && targetSpec.platform === 'macos')
233
+ || (options.appDir && (0, appdir_1.isLinuxPlatform)(targetSpec.platform));
234
+ const producerOutput = usesTempOutput
235
+ ? path_1.default.join(os_1.default.tmpdir(), `hakobu-wrap-${manifest.appId}-${Date.now()}`)
236
+ : outputPath;
237
+ fs_1.default.mkdirSync(path_1.default.dirname(path_1.default.resolve(producerOutput)), { recursive: true });
238
+ const target = {
239
+ nodeRange: targetSpec.nodeRange,
240
+ platform: targetSpec.platform,
241
+ arch: targetSpec.arch,
242
+ binaryPath: preparedBase.effectiveBinaryPath,
243
+ output: path_1.default.resolve(producerOutput),
244
+ fabricator: {
245
+ nodeRange: targetSpec.nodeRange,
246
+ platform: hakobu_fetch_1.system.hostPlatform,
247
+ arch: hakobu_fetch_1.system.hostArch,
248
+ // For bytecode compilation, the fabricator must use the patched base binary
249
+ // (which has sourceless: true support). For source-only mode, it doesn't matter
250
+ // because STORE_BLOB stripes are removed by the packer.
251
+ binaryPath: options.bytecode ? binaryPath : process.execPath,
252
+ output: '',
253
+ fabricator: null,
254
+ },
255
+ };
256
+ log_1.log.debug(`Producer input:`, [
257
+ ` target: ${JSON.stringify(target.output)}`,
258
+ ` bakes: ${JSON.stringify(options.options || [])}`,
259
+ ` compress: ${options.compress || 'none'}`,
260
+ ` stripes: ${backpack.stripes.length}`,
261
+ ]);
262
+ await (0, producer_1.default)({
263
+ backpack, bakes: options.options || [], slash, target, symLinks,
264
+ doCompress: resolveCompressType(options.compress), nativeBuild: false,
265
+ });
266
+ // Post-production
267
+ let finalOutputPath = path_1.default.resolve(outputPath);
268
+ if (targetSpec.platform === 'macos') {
269
+ // Mach-O patch is always needed (fixes __LINKEDIT after payload injection)
270
+ const buf = (0, mach_o_1.patchMachOExecutable)(fs_1.default.readFileSync(target.output));
271
+ fs_1.default.writeFileSync(target.output, buf);
272
+ await (0, chmod_1.plusx)(target.output);
273
+ if (options.appBundle) {
274
+ // Bundle mode: wrap first, then sign/notarize the bundle
275
+ finalOutputPath = (0, app_bundle_1.createAppBundle)({
276
+ executablePath: target.output,
277
+ outputPath: outputPath,
278
+ appName: manifest.appId,
279
+ macos: options.macos,
280
+ });
281
+ try {
282
+ (0, mach_o_1.signAppBundle)(finalOutputPath, options.signIdentity);
283
+ }
284
+ catch { }
285
+ if (options.notarize) {
286
+ await (0, mach_o_1.notarizeAppBundle)({ executable: finalOutputPath });
287
+ }
288
+ }
289
+ else {
290
+ // Raw executable mode: sign/notarize the executable directly
291
+ try {
292
+ (0, mach_o_1.signMachOExecutable)(target.output, options.signIdentity);
293
+ }
294
+ catch { }
295
+ if (options.notarize) {
296
+ await (0, mach_o_1.notarizeMachOExecutable)({ executable: target.output });
297
+ }
298
+ }
299
+ }
300
+ else if (targetSpec.platform === 'win') {
301
+ // Metadata injection must happen BEFORE signing
302
+ if (options.metadata) {
303
+ await (0, pe_metadata_1.injectPeMetadata)(target.output, options.metadata);
304
+ }
305
+ if ((0, windows_sign_1.hasWindowsSigningCredentials)(options.winCertPath)) {
306
+ (0, windows_sign_1.signWindowsExecutable)({
307
+ executable: target.output,
308
+ certPath: options.winCertPath,
309
+ certPassword: options.winCertPassword,
310
+ });
311
+ }
312
+ }
313
+ else {
314
+ await (0, chmod_1.plusx)(target.output);
315
+ // AppDir wrapping (Linux only, opt-in)
316
+ if (options.appDir && (0, appdir_1.isLinuxPlatform)(targetSpec.platform)) {
317
+ const appDirPath = (0, appdir_1.createAppDir)({
318
+ executablePath: target.output,
319
+ outputPath: outputPath,
320
+ appName: manifest.appId,
321
+ linux: options.linux,
322
+ });
323
+ if (options.appImage) {
324
+ // AppImage: build from AppDir, then clean up the AppDir
325
+ finalOutputPath = (0, appdir_1.createAppImage)({
326
+ appDirPath,
327
+ outputPath: outputPath,
328
+ arch: targetSpec.arch,
329
+ });
330
+ try {
331
+ fs_1.default.rmSync(appDirPath, { recursive: true, force: true });
332
+ }
333
+ catch { }
334
+ }
335
+ else {
336
+ finalOutputPath = appDirPath;
337
+ }
338
+ }
339
+ }
340
+ // Kill fabricator child processes (bytecode compilation spawns long-lived workers)
341
+ (0, fabricator_1.shutdown)();
342
+ return {
343
+ outputPath: finalOutputPath,
344
+ manifest,
345
+ fileCount: Object.keys(manifest.files).length,
346
+ target: targetSpec,
347
+ };
348
+ }
349
+ finally {
350
+ preparedBase.cleanup();
351
+ }
352
+ }
353
+ function appIdFromProject(projectRoot) {
354
+ const pkgJsonPath = path_1.default.join(projectRoot, 'package.json');
355
+ if (fs_1.default.existsSync(pkgJsonPath)) {
356
+ try {
357
+ const pkg = JSON.parse(fs_1.default.readFileSync(pkgJsonPath, 'utf8'));
358
+ return pkg.name || 'app';
359
+ }
360
+ catch { }
361
+ }
362
+ return 'app';
363
+ }
364
+ function defaultOutputName(appId, target) {
365
+ const ext = target.platform === 'win' ? '.exe' : '';
366
+ return `${appId}-${target.platform}-${target.arch}${ext}`;
367
+ }
368
+ // ─────────────────────────────────────────────────────────────────────
369
+ // Core package function (single target — unchanged)
370
+ // ─────────────────────────────────────────────────────────────────────
371
+ async function packageApp(options) {
372
+ // ── App bundle validation ──
373
+ if (options.appBundle) {
374
+ const targetSpec = parseTarget(options.target || '');
375
+ if (targetSpec.platform !== 'macos') {
376
+ throw new Error(`--app-bundle is only supported for macOS targets (got ${targetSpec.platform}).\n` +
377
+ 'macOS .app bundles require a Mach-O executable.');
378
+ }
379
+ }
380
+ // ── AppImage implies AppDir ──
381
+ if (options.appImage) {
382
+ options.appDir = true;
383
+ }
384
+ // ── AppDir validation ──
385
+ if (options.appDir) {
386
+ const targetSpec = parseTarget(options.target || '');
387
+ if (!(0, appdir_1.isLinuxPlatform)(targetSpec.platform)) {
388
+ throw new Error(`--appdir is only supported for Linux targets (got ${targetSpec.platform}).\n` +
389
+ 'AppDir requires an ELF executable.');
390
+ }
391
+ }
392
+ // ── Bytecode mode validation ──
393
+ if (options.bytecode && options.bundle) {
394
+ throw new Error('Bytecode mode (--bytecode) cannot be combined with bundle mode (--bundle).\n' +
395
+ 'Bundle mode produces ESM output which is not compatible with V8 bytecode compilation.\n' +
396
+ 'Use one or the other, not both.');
397
+ }
398
+ let { projectRoot } = options;
399
+ let bundleOutput = null;
400
+ // ── 0. Bundle mode (optional pre-processing) ──
401
+ if (options.bundle) {
402
+ log_1.log.info('Bundling project...');
403
+ const bundlerName = typeof options.bundle === 'string' ? options.bundle : 'rolldown';
404
+ const adapter = (0, bundler_1.getAdapter)(bundlerName);
405
+ // Determine entry for bundling
406
+ const entry = options.entry || resolveEntryForBundle(projectRoot);
407
+ // Determine app name from package.json
408
+ let appName = 'app';
409
+ const pkgJsonPath = path_1.default.join(projectRoot, 'package.json');
410
+ if (fs_1.default.existsSync(pkgJsonPath)) {
411
+ try {
412
+ const pkg = JSON.parse(fs_1.default.readFileSync(pkgJsonPath, 'utf8'));
413
+ appName = pkg.name || 'app';
414
+ }
415
+ catch { }
416
+ }
417
+ bundleOutput = await adapter.bundle({
418
+ projectRoot,
419
+ entry,
420
+ external: options.bundleExternal,
421
+ appName,
422
+ });
423
+ for (const w of bundleOutput.warnings) {
424
+ log_1.log.warn(`[bundle] ${w.message}`);
425
+ }
426
+ // Switch to the bundled project for the rest of the pipeline
427
+ projectRoot = bundleOutput.projectRoot;
428
+ // Clear entry override — the bundle's package.json has the right main
429
+ // Include source map files as assets so they end up in the snapshot
430
+ const bundleAssets = [
431
+ ...(options.assets || []),
432
+ ...bundleOutput.mapFiles,
433
+ ];
434
+ options = { ...options, entry: undefined, assets: bundleAssets.length > 0 ? bundleAssets : undefined };
435
+ }
436
+ try {
437
+ return await packageAppInner(projectRoot, options, bundleOutput);
438
+ }
439
+ finally {
440
+ // Clean up bundle temp directory
441
+ if (bundleOutput)
442
+ bundleOutput.cleanup();
443
+ }
444
+ }
445
+ exports.packageApp = packageApp;
446
+ function resolveEntryForBundle(projectRoot) {
447
+ const pkgJsonPath = path_1.default.join(projectRoot, 'package.json');
448
+ if (fs_1.default.existsSync(pkgJsonPath)) {
449
+ try {
450
+ const pkg = JSON.parse(fs_1.default.readFileSync(pkgJsonPath, 'utf8'));
451
+ if (pkg.main)
452
+ return pkg.main;
453
+ if (pkg.module)
454
+ return pkg.module;
455
+ }
456
+ catch { }
457
+ }
458
+ // Fallback: common entry patterns
459
+ for (const candidate of ['src/index.ts', 'src/index.js', 'index.ts', 'index.js']) {
460
+ if (fs_1.default.existsSync(path_1.default.join(projectRoot, candidate)))
461
+ return candidate;
462
+ }
463
+ throw new Error('Cannot determine entry for bundling. Specify --entry.');
464
+ }
465
+ async function packageAppInner(projectRoot, options, bundleOutput) {
466
+ log_1.log.info('Analyzing project...');
467
+ // ── 1. Analyze using new manifest pipeline ──
468
+ const manifest = await (0, analyzer_1.analyze)({
469
+ projectRoot,
470
+ entry: options.entry,
471
+ assets: options.assets,
472
+ externals: options.externals,
473
+ });
474
+ log_1.log.info(` entry: ${manifest.entry.snapshotPath} (${manifest.entry.format})`);
475
+ log_1.log.info(` files: ${Object.keys(manifest.files).length}`);
476
+ log_1.log.debug('Manifest details:', [
477
+ ` projectRoot: ${projectRoot}`,
478
+ ` appId: ${manifest.appId}`,
479
+ ` file count: ${Object.keys(manifest.files).length}`,
480
+ ` warnings: ${manifest.warnings.length}`,
481
+ ]);
482
+ if (manifest.warnings.length > 0) {
483
+ for (const w of manifest.warnings) {
484
+ if (w.severity === 'error') {
485
+ log_1.log.error(`[${w.category}] ${w.message}`);
486
+ }
487
+ else if (w.severity === 'warning') {
488
+ log_1.log.warn(`[${w.category}] ${w.message}`);
489
+ }
490
+ if (w.suggestion) {
491
+ log_1.log.info(` → ${w.suggestion}`);
492
+ }
493
+ }
494
+ }
495
+ // ── 2. Parse target ──
496
+ const targetSpec = parseTarget(options.target);
497
+ log_1.log.info(`Target: ${targetSpec.nodeRange}-${targetSpec.platform}-${targetSpec.arch}`);
498
+ // ── 3. Fetch base binary ──
499
+ log_1.log.info('Fetching base binary...');
500
+ const binaryPath = await (0, hakobu_fetch_1.need)({
501
+ nodeRange: targetSpec.nodeRange,
502
+ platform: targetSpec.platform,
503
+ arch: targetSpec.arch,
504
+ forceBuild: options.forceBuild,
505
+ });
506
+ log_1.log.info(` base: ${binaryPath}`);
507
+ // ── 3b. Strip macOS code signature before payload injection ──
508
+ // The producer appends data past __LINKEDIT, which invalidates the adhoc
509
+ // signature and makes subsequent codesign operations fail. Stripping the
510
+ // signature first lets us patch + re-sign cleanly after production.
511
+ const preparedBase = prepareBaseBinary(targetSpec, binaryPath);
512
+ try {
513
+ // ── 4. Bridge: manifest → inherited FileRecords + Stripe format ──
514
+ log_1.log.info('Building payload...');
515
+ const { records, entrypoint, symLinks } = manifestToRecords(manifest, options.bytecode);
516
+ // ── 5. Pack using inherited packer ──
517
+ const slash = targetSpec.platform === 'win' ? '\\' : '/';
518
+ const backpack = (0, packer_1.default)({
519
+ records,
520
+ entrypoint,
521
+ bytecode: !!options.bytecode,
522
+ symLinks,
523
+ });
524
+ // ── 6. Build target object for producer ──
525
+ const requestedOutput = options.output || defaultOutputPath(manifest.appId, targetSpec);
526
+ // In app-bundle/appdir mode, the producer writes to a temp file; wrapper moves it in
527
+ const usesTempOutput = (options.appBundle && targetSpec.platform === 'macos')
528
+ || (options.appDir && (0, appdir_1.isLinuxPlatform)(targetSpec.platform));
529
+ const outputPath = usesTempOutput
530
+ ? path_1.default.join(os_1.default.tmpdir(), `hakobu-wrap-${manifest.appId}-${Date.now()}`)
531
+ : requestedOutput;
532
+ fs_1.default.mkdirSync(path_1.default.dirname(path_1.default.resolve(outputPath)), { recursive: true });
533
+ const target = {
534
+ nodeRange: targetSpec.nodeRange,
535
+ platform: targetSpec.platform,
536
+ arch: targetSpec.arch,
537
+ binaryPath: preparedBase.effectiveBinaryPath,
538
+ output: path_1.default.resolve(outputPath),
539
+ fabricator: {
540
+ nodeRange: targetSpec.nodeRange,
541
+ platform: hakobu_fetch_1.system.hostPlatform,
542
+ arch: hakobu_fetch_1.system.hostArch,
543
+ binaryPath: options.bytecode ? binaryPath : process.execPath,
544
+ output: '',
545
+ fabricator: null,
546
+ },
547
+ };
548
+ // ── 7. Produce executable using inherited producer ──
549
+ log_1.log.info(`Writing ${outputPath}...`);
550
+ log_1.log.debug('Producer input:', [
551
+ ` output: ${path_1.default.resolve(outputPath)}`,
552
+ ` bakes: ${JSON.stringify(options.options || [])}`,
553
+ ` compress: ${options.compress || 'none'}`,
554
+ ` bytecode: ${!!options.bytecode}`,
555
+ ` stripes: ${backpack.stripes.length}`,
556
+ ]);
557
+ await (0, producer_1.default)({
558
+ backpack,
559
+ bakes: options.options || [],
560
+ slash,
561
+ target,
562
+ symLinks,
563
+ doCompress: resolveCompressType(options.compress),
564
+ nativeBuild: false,
565
+ });
566
+ // ── 8. Post-production: signing + chmod ──
567
+ log_1.log.debug(`Post-production: platform=${targetSpec.platform}, appBundle=${!!options.appBundle}, appDir=${!!options.appDir}`);
568
+ let finalOutputPath = path_1.default.resolve(requestedOutput);
569
+ if (targetSpec.platform === 'macos') {
570
+ // Base was pre-stripped in step 3b, so __LINKEDIT patch + fresh sign works cleanly
571
+ const buf = (0, mach_o_1.patchMachOExecutable)(fs_1.default.readFileSync(target.output));
572
+ fs_1.default.writeFileSync(target.output, buf);
573
+ await (0, chmod_1.plusx)(target.output);
574
+ if (options.appBundle) {
575
+ // Bundle mode: wrap first, then sign/notarize the bundle
576
+ finalOutputPath = (0, app_bundle_1.createAppBundle)({
577
+ executablePath: target.output,
578
+ outputPath: requestedOutput,
579
+ appName: manifest.appId,
580
+ macos: options.macos,
581
+ });
582
+ try {
583
+ (0, mach_o_1.signAppBundle)(finalOutputPath, options.signIdentity);
584
+ }
585
+ catch {
586
+ if (targetSpec.arch === 'arm64') {
587
+ log_1.log.warn('Unable to sign the macOS app bundle — it may not run on ARM64.');
588
+ }
589
+ }
590
+ if (options.notarize) {
591
+ await (0, mach_o_1.notarizeAppBundle)({ executable: finalOutputPath });
592
+ }
593
+ }
594
+ else {
595
+ // Raw executable mode: sign/notarize the executable directly
596
+ try {
597
+ (0, mach_o_1.signMachOExecutable)(target.output, options.signIdentity);
598
+ }
599
+ catch {
600
+ if (targetSpec.arch === 'arm64') {
601
+ log_1.log.warn('Unable to sign the macOS executable — it may not run on ARM64.');
602
+ }
603
+ }
604
+ if (options.notarize) {
605
+ await (0, mach_o_1.notarizeMachOExecutable)({ executable: target.output });
606
+ }
607
+ }
608
+ }
609
+ else if (targetSpec.platform === 'win') {
610
+ // Metadata injection must happen BEFORE signing
611
+ if (options.metadata) {
612
+ await (0, pe_metadata_1.injectPeMetadata)(target.output, options.metadata);
613
+ }
614
+ if ((0, windows_sign_1.hasWindowsSigningCredentials)(options.winCertPath)) {
615
+ (0, windows_sign_1.signWindowsExecutable)({
616
+ executable: target.output,
617
+ certPath: options.winCertPath,
618
+ certPassword: options.winCertPassword,
619
+ });
620
+ }
621
+ }
622
+ else {
623
+ await (0, chmod_1.plusx)(target.output);
624
+ // AppDir wrapping (Linux only, opt-in)
625
+ if (options.appDir && (0, appdir_1.isLinuxPlatform)(targetSpec.platform)) {
626
+ const appDirPath = (0, appdir_1.createAppDir)({
627
+ executablePath: target.output,
628
+ outputPath: requestedOutput,
629
+ appName: manifest.appId,
630
+ linux: options.linux,
631
+ });
632
+ if (options.appImage) {
633
+ finalOutputPath = (0, appdir_1.createAppImage)({
634
+ appDirPath,
635
+ outputPath: requestedOutput,
636
+ arch: targetSpec.arch,
637
+ });
638
+ try {
639
+ fs_1.default.rmSync(appDirPath, { recursive: true, force: true });
640
+ }
641
+ catch { }
642
+ }
643
+ else {
644
+ finalOutputPath = appDirPath;
645
+ }
646
+ }
647
+ }
648
+ (0, fabricator_1.shutdown)();
649
+ log_1.log.info(`Done. Packaged ${Object.keys(manifest.files).length} files → ${finalOutputPath}`);
650
+ return {
651
+ outputPath: finalOutputPath,
652
+ manifest,
653
+ fileCount: Object.keys(manifest.files).length,
654
+ target: targetSpec,
655
+ };
656
+ }
657
+ finally {
658
+ preparedBase.cleanup();
659
+ }
660
+ }
661
+ // ─────────────────────────────────────────────────────────────────────
662
+ // Bridge: manifest → inherited FileRecords
663
+ // ─────────────────────────────────────────────────────────────────────
664
+ function manifestToRecords(manifest, bytecode) {
665
+ const records = {};
666
+ const dirContents = new Map();
667
+ const isEsmEntry = manifest.entry.format === 'esm';
668
+ // Add all manifest files to records
669
+ for (const [snapshotPath, file] of Object.entries(manifest.files)) {
670
+ const absPath = file.absolutePath;
671
+ const content = fs_1.default.readFileSync(absPath);
672
+ const record = {
673
+ file: absPath,
674
+ body: content,
675
+ [common_1.STORE_CONTENT]: content,
676
+ [common_1.STORE_STAT]: {
677
+ size: content.length,
678
+ isFileValue: true,
679
+ isDirectoryValue: false,
680
+ isSocketValue: false,
681
+ isSymbolicLinkValue: false,
682
+ },
683
+ };
684
+ // Bytecode mode: add STORE_BLOB for CJS scripts.
685
+ // The fabricator will compile the source to V8 cached data.
686
+ // ESM scripts are NOT bytecode-compiled (vm.Script is CJS-only).
687
+ if (bytecode && file.kind === 'script' && file.format === 'cjs') {
688
+ record[common_1.STORE_BLOB] = content;
689
+ }
690
+ records[absPath] = record;
691
+ // Build the full directory tree — not just direct parents, but all
692
+ // intermediate dirs up to the project root. This is needed for CJS
693
+ // node_modules resolution: require('pkg') walks up directories
694
+ // checking node_modules/pkg, so the VFS must have directory entries
695
+ // at every level.
696
+ let dir = path_1.default.dirname(absPath);
697
+ if (!dirContents.has(dir))
698
+ dirContents.set(dir, []);
699
+ dirContents.get(dir).push(path_1.default.basename(absPath));
700
+ // Walk up and register intermediate directories as children of their parents
701
+ const projectRoot = fs_1.default.realpathSync(manifest.projectRoot || path_1.default.dirname(manifest.entry.absolutePath));
702
+ while (dir !== projectRoot && dir !== path_1.default.dirname(dir)) {
703
+ const parent = path_1.default.dirname(dir);
704
+ if (!dirContents.has(parent))
705
+ dirContents.set(parent, []);
706
+ const dirBasename = path_1.default.basename(dir);
707
+ if (!dirContents.get(parent).includes(dirBasename)) {
708
+ dirContents.get(parent).push(dirBasename);
709
+ }
710
+ dir = parent;
711
+ }
712
+ }
713
+ // Inject CJS shim that registers ESM hooks for snapshot-aware resolution.
714
+ // Always needed: CJS entries may use import() to load ESM dependencies,
715
+ // and ESM entries need the hooks for all import resolution.
716
+ let entrypoint = manifest.entry.absolutePath;
717
+ const { shimPath, shimContent, shimDir } = buildEsmBridge(manifest, isEsmEntry);
718
+ records[shimPath] = {
719
+ file: shimPath,
720
+ body: shimContent,
721
+ [common_1.STORE_CONTENT]: shimContent,
722
+ [common_1.STORE_STAT]: {
723
+ size: shimContent.length,
724
+ isFileValue: true,
725
+ isDirectoryValue: false,
726
+ isSocketValue: false,
727
+ isSymbolicLinkValue: false,
728
+ },
729
+ };
730
+ entrypoint = shimPath;
731
+ // Add shim to its directory listing
732
+ if (!dirContents.has(shimDir))
733
+ dirContents.set(shimDir, []);
734
+ if (!dirContents.get(shimDir).includes(path_1.default.basename(shimPath))) {
735
+ dirContents.get(shimDir).push(path_1.default.basename(shimPath));
736
+ }
737
+ // Add directory records with STORE_LINKS
738
+ for (const [dir, files] of dirContents) {
739
+ if (!records[dir]) {
740
+ records[dir] = {
741
+ file: dir,
742
+ [common_1.STORE_LINKS]: files,
743
+ [common_1.STORE_STAT]: {
744
+ size: 0,
745
+ isFileValue: false,
746
+ isDirectoryValue: true,
747
+ isSocketValue: false,
748
+ isSymbolicLinkValue: false,
749
+ },
750
+ };
751
+ }
752
+ }
753
+ return { records, entrypoint, symLinks: {} };
754
+ }
755
+ // ─────────────────────────────────────────────────────────────────────
756
+ // ESM Bridge
757
+ // ─────────────────────────────────────────────────────────────────────
758
+ /**
759
+ * Build a CJS shim that registers ESM hooks and loads the real entry.
760
+ *
761
+ * Always injected (not just for ESM entries) because CJS code may use
762
+ * import() to load ESM dependencies — those calls need the snapshot-aware
763
+ * ESM resolver hooks to be registered first.
764
+ *
765
+ * For ESM entries: registers hooks + import()s the real entry
766
+ * For CJS entries: registers hooks + require()s the real entry
767
+ */
768
+ function buildEsmBridge(manifest, isEsm = true) {
769
+ const entryAbsPath = manifest.entry.absolutePath;
770
+ const shimDir = path_1.default.dirname(entryAbsPath);
771
+ const shimPath = path_1.default.join(shimDir, '__hakobu_esm_shim__.cjs');
772
+ // Collect package.json paths for module format detection at runtime
773
+ const pkgJsonAbsPaths = Object.values(manifest.files)
774
+ .filter(f => f.kind === 'package-json')
775
+ .map(f => f.absolutePath);
776
+ const shimSource = `'use strict';
777
+ // Hakobu ESM Bridge — bootstraps ESM loading from the inherited CJS VFS
778
+
779
+ // Enable source maps before any module loading. The patched base binary is
780
+ // built with --without-node-options which ignores NODE_OPTIONS, so
781
+ // --enable-source-maps via env has no effect. This programmatic call
782
+ // ensures source maps work when .map files are present in the snapshot.
783
+ if (typeof process.setSourceMapsEnabled === 'function') {
784
+ process.setSourceMapsEnabled(true);
785
+ }
786
+
787
+ var { registerHooks } = require('node:module');
788
+ var fs = require('fs');
789
+ var pathMod = require('path');
790
+ var { pathToFileURL, fileURLToPath } = require('url');
791
+
792
+ // Platform detection: Windows uses C:\\snapshot, POSIX uses /snapshot
793
+ var isWin = process.platform === 'win32';
794
+ var snapRoot = isWin ? 'C:\\\\snapshot' : '/snapshot';
795
+ var sep = isWin ? '\\\\' : '/';
796
+
797
+ // Normalize a snapshot path to POSIX for URL/map keys (internal canonical form)
798
+ function toCanonical(p) {
799
+ if (isWin && p.startsWith('C:\\\\snapshot')) return p.slice(2).replace(/\\\\/g, '/');
800
+ return p;
801
+ }
802
+
803
+ // Convert canonical back to native snapshot path for fs operations
804
+ function toNative(p) {
805
+ if (isWin && p.startsWith('/snapshot')) return 'C:' + p.replace(/\\//g, '\\\\');
806
+ return p;
807
+ }
808
+
809
+ // Read package.json data for module type detection (using patched fs)
810
+ // absPath is a host absolute path (e.g. /home/user/project/package.json or D:\\a\\project\\package.json)
811
+ // Convert to canonical snapshot path: strip drive letter, normalize to POSIX, prepend /snapshot
812
+ var pkgJsons = {};
813
+ ${JSON.stringify(pkgJsonAbsPaths)}.forEach(function(absPath) {
814
+ var posix = absPath.replace(/\\\\/g, '/');
815
+ if (/^[A-Z]:/i.test(posix)) posix = posix.slice(2);
816
+ var canonical = '/snapshot' + posix;
817
+ var native = toNative(canonical);
818
+ try { pkgJsons[canonical] = JSON.parse(fs.readFileSync(native, 'utf8')); } catch {}
819
+ });
820
+
821
+ function isSnapshotUrl(url) {
822
+ if (url.startsWith('file:///snapshot/')) return true;
823
+ // Windows: file:///C:/snapshot/
824
+ if (isWin && /^file:\\/\\/\\/[A-Z]:\\/snapshot\\//i.test(url)) return true;
825
+ return false;
826
+ }
827
+
828
+ function urlToCanonical(url) {
829
+ var p = fileURLToPath(url);
830
+ return toCanonical(p);
831
+ }
832
+
833
+ function canonicalToUrl(canonical) {
834
+ return pathToFileURL(toNative(canonical)).href;
835
+ }
836
+
837
+ function getModuleFormat(canonical) {
838
+ if (canonical.endsWith('.mjs')) return 'module';
839
+ if (canonical.endsWith('.cjs')) return 'commonjs';
840
+ if (canonical.endsWith('.json')) return 'json';
841
+ var dir = canonical;
842
+ while (dir !== '/') {
843
+ dir = dir.substring(0, dir.lastIndexOf('/')) || '/';
844
+ var pkgPath = dir + '/package.json';
845
+ if (pkgJsons[pkgPath]) return pkgJsons[pkgPath].type === 'module' ? 'module' : 'commonjs';
846
+ }
847
+ return 'commonjs';
848
+ }
849
+
850
+ function snapshotExists(canonical) {
851
+ try { return fs.existsSync(toNative(canonical)); } catch { return false; }
852
+ }
853
+
854
+ function resolveFromSnapshot(specifier, parentCanonical) {
855
+ var parentDir = parentCanonical.substring(0, parentCanonical.lastIndexOf('/'));
856
+ var resolved;
857
+ if (specifier.startsWith('./') || specifier.startsWith('../')) {
858
+ var parts = (parentDir + '/' + specifier).split('/');
859
+ var normalized = [];
860
+ for (var i = 0; i < parts.length; i++) {
861
+ if (parts[i] === '..') normalized.pop();
862
+ else if (parts[i] !== '.' && parts[i] !== '') normalized.push(parts[i]);
863
+ }
864
+ resolved = '/' + normalized.join('/');
865
+ } else {
866
+ resolved = specifier;
867
+ }
868
+ if (snapshotExists(resolved)) return resolved;
869
+ if (snapshotExists(resolved + '.js')) return resolved + '.js';
870
+ if (snapshotExists(resolved + '.mjs')) return resolved + '.mjs';
871
+ if (snapshotExists(resolved + '/index.js')) return resolved + '/index.js';
872
+ if (snapshotExists(resolved + '/index.mjs')) return resolved + '/index.mjs';
873
+ return null;
874
+ }
875
+
876
+ registerHooks({
877
+ resolve: function(specifier, context, nextResolve) {
878
+ if (specifier.startsWith('node:') || specifier.startsWith('data:')) {
879
+ return nextResolve(specifier, context);
880
+ }
881
+ // Stub unsupported runtime-specific protocols (bun:, deno:, etc.)
882
+ if (specifier.startsWith('bun:') || specifier.startsWith('deno:')) {
883
+ return { url: 'data:text/javascript,export default undefined;export var Database=class{constructor(){throw new Error("' + specifier + ' not available")}};', shortCircuit: true };
884
+ }
885
+ // Resolve file:// URLs to snapshot paths
886
+ if (isSnapshotUrl(specifier)) {
887
+ var canonical = urlToCanonical(specifier);
888
+ if (snapshotExists(canonical)) {
889
+ return { url: canonicalToUrl(canonical), shortCircuit: true };
890
+ }
891
+ }
892
+ // Absolute snapshot path (POSIX)
893
+ if (specifier.startsWith('/snapshot/') && snapshotExists(specifier)) {
894
+ return { url: canonicalToUrl(specifier), shortCircuit: true };
895
+ }
896
+ // Relative/bare imports from snapshot
897
+ if (context.parentURL && isSnapshotUrl(context.parentURL)) {
898
+ var parentCanonical = urlToCanonical(context.parentURL);
899
+ if (specifier.startsWith('.')) {
900
+ var resolved = resolveFromSnapshot(specifier, parentCanonical);
901
+ if (resolved) return { url: canonicalToUrl(resolved), shortCircuit: true };
902
+ }
903
+ // #imports specifier — resolve from nearest package.json imports map
904
+ if (specifier.startsWith('#')) {
905
+ var dir = parentCanonical;
906
+ while (dir.startsWith('/snapshot/')) {
907
+ dir = dir.substring(0, dir.lastIndexOf('/')) || '/';
908
+ var pkgPath = dir + '/package.json';
909
+ if (pkgJsons[pkgPath] && pkgJsons[pkgPath].imports) {
910
+ var mapping = pkgJsons[pkgPath].imports[specifier];
911
+ if (typeof mapping === 'string') {
912
+ var target = resolveFromSnapshot(mapping, dir + '/dummy');
913
+ if (target) return { url: canonicalToUrl(target), shortCircuit: true };
914
+ }
915
+ }
916
+ }
917
+ }
918
+ // Bare specifier — resolve from node_modules with exports map support
919
+ if (!specifier.startsWith('.') && !specifier.startsWith('/') && !specifier.startsWith('#')) {
920
+ var parts = specifier.split('/');
921
+ var pkgName = parts[0].startsWith('@') ? parts[0] + '/' + parts[1] : parts[0];
922
+ var subpath = '.' + specifier.slice(pkgName.length);
923
+ if (subpath === '.') subpath = '.';
924
+ var searchDir = parentCanonical;
925
+ while (searchDir.startsWith('/snapshot/')) {
926
+ searchDir = searchDir.substring(0, searchDir.lastIndexOf('/')) || '/';
927
+ var nmPkgJson = searchDir + '/node_modules/' + pkgName + '/package.json';
928
+ if (pkgJsons[nmPkgJson]) {
929
+ var pkg = pkgJsons[nmPkgJson];
930
+ var pkgDir = nmPkgJson.substring(0, nmPkgJson.lastIndexOf('/'));
931
+ var resolved = null;
932
+ if (pkg.exports) {
933
+ var exportEntry = null;
934
+ if (typeof pkg.exports === 'string') {
935
+ if (subpath === '.') exportEntry = pkg.exports;
936
+ } else if (typeof pkg.exports === 'object') {
937
+ exportEntry = pkg.exports[subpath];
938
+ if (typeof exportEntry === 'object' && exportEntry !== null) {
939
+ exportEntry = exportEntry.import || exportEntry.node || exportEntry.default || null;
940
+ }
941
+ }
942
+ if (typeof exportEntry === 'string') {
943
+ resolved = resolveFromSnapshot(exportEntry, pkgDir + '/dummy');
944
+ }
945
+ } else if (subpath === '.' && pkg.main) {
946
+ resolved = resolveFromSnapshot('./' + pkg.main, pkgDir + '/dummy');
947
+ }
948
+ if (resolved) return { url: canonicalToUrl(resolved), shortCircuit: true };
949
+ }
950
+ }
951
+ }
952
+ }
953
+ return nextResolve(specifier, context);
954
+ },
955
+ load: function(url, context, nextLoad) {
956
+ if (isSnapshotUrl(url)) {
957
+ var canonical = urlToCanonical(url);
958
+ try {
959
+ var source = fs.readFileSync(toNative(canonical), 'utf8');
960
+ var format = getModuleFormat(canonical);
961
+ // Inline sidecar source maps so --enable-source-maps works in packaged mode.
962
+ // Node reads source maps from the source text, not from separate fs reads,
963
+ // when the map is a data: URL. This avoids depending on Node internals
964
+ // reading .map files through the prelude's patched fs.
965
+ var mapMatch = source.match(/\\/\\/# sourceMappingURL=([^\\n]+\\.map)\\s*$/);
966
+ if (mapMatch) {
967
+ var mapFile = mapMatch[1];
968
+ var mapCanonical = canonical.substring(0, canonical.lastIndexOf('/') + 1) + mapFile;
969
+ try {
970
+ var mapData = fs.readFileSync(toNative(mapCanonical), 'utf8');
971
+ var mapBase64 = Buffer.from(mapData).toString('base64');
972
+ source = source.replace(
973
+ mapMatch[0],
974
+ '//# sourceMappingURL=data:application/json;base64,' + mapBase64
975
+ );
976
+ } catch {}
977
+ }
978
+ return { format: format, source: source, shortCircuit: true };
979
+ } catch {}
980
+ }
981
+ return nextLoad(url, context);
982
+ }
983
+ });
984
+
985
+ // Load the real entry
986
+ var entryCanonical = '${(0, common_1.snapshotify)(entryAbsPath, '/').replace(/\\/g, '/')}';
987
+ ${isEsm
988
+ ? `var entryUrl = canonicalToUrl(entryCanonical);
989
+ import(entryUrl).catch(function(err) { console.error(err); process.exit(1); });`
990
+ : `require(toNative(entryCanonical));`}
991
+ `;
992
+ return {
993
+ shimPath,
994
+ shimContent: Buffer.from(shimSource),
995
+ shimDir,
996
+ };
997
+ }
998
+ // ─────────────────────────────────────────────────────────────────────
999
+ // Helpers
1000
+ // ─────────────────────────────────────────────────────────────────────
1001
+ function resolveCompressType(value) {
1002
+ if (!value)
1003
+ return compress_type_1.CompressType.None;
1004
+ switch (value) {
1005
+ case 'brotli': return compress_type_1.CompressType.Brotli;
1006
+ case 'gzip': return compress_type_1.CompressType.GZip;
1007
+ default: return compress_type_1.CompressType.None;
1008
+ }
1009
+ }
1010
+ function parseTarget(spec) {
1011
+ if (!spec || spec === 'host') {
1012
+ return {
1013
+ nodeRange: 'node24',
1014
+ platform: hakobu_fetch_1.system.hostPlatform,
1015
+ arch: hakobu_fetch_1.system.hostArch,
1016
+ };
1017
+ }
1018
+ const parts = spec.split('-');
1019
+ let nodeRange = 'node24';
1020
+ let platform = hakobu_fetch_1.system.hostPlatform;
1021
+ let arch = hakobu_fetch_1.system.hostArch;
1022
+ for (const part of parts) {
1023
+ if (part.startsWith('node'))
1024
+ nodeRange = part;
1025
+ else if (['linux', 'macos', 'win', 'alpine', 'linuxstatic'].includes(part))
1026
+ platform = part;
1027
+ else if (['x64', 'arm64'].includes(part))
1028
+ arch = part;
1029
+ }
1030
+ return { nodeRange, platform, arch };
1031
+ }
1032
+ function defaultOutputPath(appId, target) {
1033
+ const ext = target.platform === 'win' ? '.exe' : '';
1034
+ return path_1.default.resolve(`${appId}-${target.platform}-${target.arch}${ext}`);
1035
+ }
1036
+ //# sourceMappingURL=packager.js.map