@edge-base/cli 0.2.6 → 0.2.8

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 (53) hide show
  1. package/dist/commands/build-app.d.ts +3 -0
  2. package/dist/commands/build-app.d.ts.map +1 -0
  3. package/dist/commands/build-app.js +45 -0
  4. package/dist/commands/build-app.js.map +1 -0
  5. package/dist/commands/deploy.d.ts.map +1 -1
  6. package/dist/commands/deploy.js +14 -14
  7. package/dist/commands/deploy.js.map +1 -1
  8. package/dist/commands/dev.d.ts.map +1 -1
  9. package/dist/commands/dev.js +43 -36
  10. package/dist/commands/dev.js.map +1 -1
  11. package/dist/commands/docker.d.ts +5 -0
  12. package/dist/commands/docker.d.ts.map +1 -1
  13. package/dist/commands/docker.js +83 -5
  14. package/dist/commands/docker.js.map +1 -1
  15. package/dist/commands/pack.d.ts +3 -0
  16. package/dist/commands/pack.d.ts.map +1 -0
  17. package/dist/commands/pack.js +117 -0
  18. package/dist/commands/pack.js.map +1 -0
  19. package/dist/index.js +7 -5
  20. package/dist/index.js.map +1 -1
  21. package/dist/lib/app-bundle.d.ts +48 -0
  22. package/dist/lib/app-bundle.d.ts.map +1 -0
  23. package/dist/lib/app-bundle.js +240 -0
  24. package/dist/lib/app-bundle.js.map +1 -0
  25. package/dist/lib/deploy-shared.d.ts +4 -0
  26. package/dist/lib/deploy-shared.d.ts.map +1 -1
  27. package/dist/lib/deploy-shared.js +40 -8
  28. package/dist/lib/deploy-shared.js.map +1 -1
  29. package/dist/lib/frontend-config.d.ts +7 -0
  30. package/dist/lib/frontend-config.d.ts.map +1 -0
  31. package/dist/lib/frontend-config.js +8 -0
  32. package/dist/lib/frontend-config.js.map +1 -0
  33. package/dist/lib/function-registry.d.ts +1 -0
  34. package/dist/lib/function-registry.d.ts.map +1 -1
  35. package/dist/lib/function-registry.js +3 -1
  36. package/dist/lib/function-registry.js.map +1 -1
  37. package/dist/lib/managed-resource-names.d.ts +2 -0
  38. package/dist/lib/managed-resource-names.d.ts.map +1 -1
  39. package/dist/lib/managed-resource-names.js +19 -1
  40. package/dist/lib/managed-resource-names.js.map +1 -1
  41. package/dist/lib/node-tools.d.ts +3 -1
  42. package/dist/lib/node-tools.d.ts.map +1 -1
  43. package/dist/lib/node-tools.js +2 -2
  44. package/dist/lib/node-tools.js.map +1 -1
  45. package/dist/lib/pack.d.ts +102 -0
  46. package/dist/lib/pack.d.ts.map +1 -0
  47. package/dist/lib/pack.js +1047 -0
  48. package/dist/lib/pack.js.map +1 -0
  49. package/dist/lib/runtime-scaffold.d.ts +43 -3
  50. package/dist/lib/runtime-scaffold.d.ts.map +1 -1
  51. package/dist/lib/runtime-scaffold.js +455 -38
  52. package/dist/lib/runtime-scaffold.js.map +1 -1
  53. package/package.json +7 -4
@@ -0,0 +1,1047 @@
1
+ import { execFileSync } from 'node:child_process';
2
+ import { chmodSync, copyFileSync, cpSync, existsSync, mkdirSync, readFileSync, readdirSync, realpathSync, rmSync, writeFileSync } from 'node:fs';
3
+ import { basename, dirname, join, resolve } from 'node:path';
4
+ import { createAppBundle, findAppProjectRoot, } from './app-bundle.js';
5
+ import { loadConfigSafe } from './load-config.js';
6
+ import { generateTempWranglerToml } from './deploy-shared.js';
7
+ import { resolveLocalDevBindings } from './project-runtime.js';
8
+ const EDGEBASE_CONFIG_FILES = ['edgebase.config.ts', 'edgebase.config.js'];
9
+ export function findPackProjectRoot(startDir) {
10
+ return findAppProjectRoot(startDir);
11
+ }
12
+ function buildPackManifest(outputDir, appManifest) {
13
+ const defaultOpenPath = appManifest.frontend.enabled
14
+ ? appManifest.frontend.mountPath ?? '/'
15
+ : '/admin';
16
+ return {
17
+ schemaVersion: 1,
18
+ format: 'dir',
19
+ createdAt: new Date().toISOString(),
20
+ projectName: appManifest.projectName,
21
+ outputDir,
22
+ appManifest: 'edgebase-app.json',
23
+ frontend: appManifest.frontend,
24
+ runtime: appManifest.runtime,
25
+ config: appManifest.config,
26
+ functions: appManifest.functions,
27
+ launcher: {
28
+ entry: 'launcher.mjs',
29
+ unix: 'run.sh',
30
+ windows: 'run.cmd',
31
+ defaultOpenPath,
32
+ defaultPort: deriveLauncherPort(appManifest.projectName),
33
+ defaultHost: '127.0.0.1',
34
+ defaultDataDir: 'os-app-data',
35
+ appDataDirName: buildAppDataDirectoryName(appManifest.projectName),
36
+ stateDir: 'state',
37
+ runtimeDir: 'runtime',
38
+ singleInstance: true,
39
+ portSearchLimit: 20,
40
+ },
41
+ };
42
+ }
43
+ function deriveLauncherPort(projectName) {
44
+ const normalized = sanitizeExecutableName(projectName).toLowerCase();
45
+ let hash = 0;
46
+ for (const char of normalized) {
47
+ hash = (hash * 31 + char.charCodeAt(0)) % 2000;
48
+ }
49
+ return 47600 + hash;
50
+ }
51
+ function buildAppDataDirectoryName(projectName) {
52
+ return `edgebase-${sanitizeExecutableName(projectName).toLowerCase()}`;
53
+ }
54
+ function buildPortableManifest(options) {
55
+ return {
56
+ schemaVersion: 1,
57
+ format: 'portable',
58
+ createdAt: new Date().toISOString(),
59
+ projectName: options.projectName,
60
+ platform: process.platform,
61
+ arch: process.arch,
62
+ artifactKind: options.artifactKind,
63
+ outputPath: options.outputPath,
64
+ bundledAppDir: options.bundledAppDir,
65
+ launcherPath: options.launcherPath,
66
+ embeddedNodePath: options.embeddedNodePath,
67
+ appManifest: options.appManifestPath,
68
+ packManifest: options.packManifestPath,
69
+ };
70
+ }
71
+ function buildArchiveManifest(options) {
72
+ return {
73
+ schemaVersion: 1,
74
+ format: 'archive',
75
+ createdAt: new Date().toISOString(),
76
+ projectName: options.projectName,
77
+ platform: process.platform,
78
+ arch: process.arch,
79
+ archiveType: options.archiveType,
80
+ outputPath: options.outputPath,
81
+ sourcePortablePath: options.sourcePortablePath,
82
+ launcherPath: options.launcherPath,
83
+ embeddedNodePath: options.embeddedNodePath,
84
+ appManifest: options.appManifestPath,
85
+ packManifest: options.packManifestPath,
86
+ };
87
+ }
88
+ function resolvePortableOutputPath(projectDir, projectName, explicitOutput) {
89
+ if (explicitOutput) {
90
+ return resolve(projectDir, explicitOutput);
91
+ }
92
+ if (process.platform === 'darwin') {
93
+ return join(projectDir, 'dist', `${projectName}.app`);
94
+ }
95
+ return join(projectDir, 'dist', `${projectName}-${process.platform}-${process.arch}-portable`);
96
+ }
97
+ function resolveArchiveOutputPath(projectDir, projectName, explicitOutput) {
98
+ if (explicitOutput) {
99
+ return resolve(projectDir, explicitOutput);
100
+ }
101
+ const archiveExtension = process.platform === 'linux' ? '.tar.gz' : '.zip';
102
+ return join(projectDir, 'dist', `${projectName}-${process.platform}-${process.arch}${archiveExtension}`);
103
+ }
104
+ function sanitizeExecutableName(appName) {
105
+ const normalized = appName
106
+ .replace(/\.app$/i, '')
107
+ .replace(/[^A-Za-z0-9._-]+/g, '-')
108
+ .replace(/^-+|-+$/g, '');
109
+ return normalized || 'edgebase-app';
110
+ }
111
+ function commandExists(command) {
112
+ try {
113
+ execFileSync('which', [command], { stdio: 'pipe' });
114
+ return true;
115
+ }
116
+ catch {
117
+ return false;
118
+ }
119
+ }
120
+ function isMacSystemLibraryPath(libraryPath) {
121
+ return libraryPath.startsWith('/System/')
122
+ || libraryPath.startsWith('/usr/lib/');
123
+ }
124
+ function listMachODependencies(binaryPath) {
125
+ const output = execFileSync('otool', ['-L', binaryPath], {
126
+ encoding: 'utf-8',
127
+ stdio: 'pipe',
128
+ });
129
+ return output
130
+ .split(/\r?\n/)
131
+ .slice(1)
132
+ .map((line) => line.trim())
133
+ .filter(Boolean)
134
+ .map((line) => line.replace(/\s+\(compatibility version.*$/, ''));
135
+ }
136
+ function listMachORpaths(binaryPath) {
137
+ const output = execFileSync('otool', ['-l', binaryPath], {
138
+ encoding: 'utf-8',
139
+ stdio: 'pipe',
140
+ });
141
+ const lines = output.split(/\r?\n/);
142
+ const rpaths = [];
143
+ for (let index = 0; index < lines.length; index += 1) {
144
+ if (lines[index]?.trim() !== 'cmd LC_RPATH')
145
+ continue;
146
+ for (let lookahead = index + 1; lookahead < lines.length; lookahead += 1) {
147
+ const trimmed = lines[lookahead]?.trim() ?? '';
148
+ if (trimmed.startsWith('path ')) {
149
+ const match = trimmed.match(/^path\s+(.+?)\s+\(offset \d+\)$/);
150
+ if (match?.[1]) {
151
+ rpaths.push(match[1]);
152
+ }
153
+ break;
154
+ }
155
+ if (trimmed.startsWith('cmd ')) {
156
+ break;
157
+ }
158
+ }
159
+ }
160
+ return rpaths;
161
+ }
162
+ function resolveMachOReferencePath(reference, binaryPath, executableDir, visited = new Set()) {
163
+ if (reference.startsWith('/')) {
164
+ return existsSync(reference) ? realpathSync(reference) : null;
165
+ }
166
+ if (reference.startsWith('@loader_path/')) {
167
+ const candidate = resolve(dirname(binaryPath), reference.slice('@loader_path/'.length));
168
+ return existsSync(candidate) ? realpathSync(candidate) : null;
169
+ }
170
+ if (reference.startsWith('@executable_path/')) {
171
+ const candidate = resolve(executableDir, reference.slice('@executable_path/'.length));
172
+ return existsSync(candidate) ? realpathSync(candidate) : null;
173
+ }
174
+ if (reference.startsWith('@rpath/')) {
175
+ const key = `${binaryPath}::${reference}`;
176
+ if (visited.has(key))
177
+ return null;
178
+ visited.add(key);
179
+ const suffix = reference.slice('@rpath/'.length);
180
+ for (const rpath of listMachORpaths(binaryPath)) {
181
+ const resolvedRpath = resolveMachOReferencePath(rpath, binaryPath, executableDir, visited);
182
+ if (!resolvedRpath)
183
+ continue;
184
+ const candidate = join(resolvedRpath, suffix);
185
+ if (existsSync(candidate)) {
186
+ return realpathSync(candidate);
187
+ }
188
+ }
189
+ }
190
+ return null;
191
+ }
192
+ function collectMacPortableLibraries(entryBinaryPath) {
193
+ const executablePath = realpathSync(entryBinaryPath);
194
+ const executableDir = dirname(executablePath);
195
+ const libraries = new Map();
196
+ const queue = [executablePath];
197
+ while (queue.length > 0) {
198
+ const current = queue.shift();
199
+ if (!current)
200
+ continue;
201
+ for (const dependency of listMachODependencies(current)) {
202
+ const resolvedDependency = resolveMachOReferencePath(dependency, current, executableDir);
203
+ if (!resolvedDependency || isMacSystemLibraryPath(resolvedDependency)) {
204
+ continue;
205
+ }
206
+ if (resolvedDependency === executablePath) {
207
+ continue;
208
+ }
209
+ const destinationName = basename(resolvedDependency);
210
+ const existingSource = [...libraries.entries()]
211
+ .find(([, existingDestination]) => existingDestination === destinationName)?.[0];
212
+ if (existingSource && existingSource !== resolvedDependency) {
213
+ throw new Error(`Portable macOS packaging found two libraries with the same filename: ${existingSource} and ${resolvedDependency}.`);
214
+ }
215
+ if (libraries.has(resolvedDependency))
216
+ continue;
217
+ libraries.set(resolvedDependency, destinationName);
218
+ queue.push(resolvedDependency);
219
+ }
220
+ }
221
+ return libraries;
222
+ }
223
+ function rewriteMacPortableBinary(targetPath, sourcePath, libraries, mode) {
224
+ const executableDir = dirname(realpathSync(process.execPath));
225
+ const args = [];
226
+ if (mode === 'library') {
227
+ args.push('-id', `@loader_path/${basename(targetPath)}`);
228
+ }
229
+ for (const dependency of listMachODependencies(sourcePath)) {
230
+ const resolvedDependency = resolveMachOReferencePath(dependency, sourcePath, executableDir);
231
+ if (!resolvedDependency || isMacSystemLibraryPath(resolvedDependency)) {
232
+ continue;
233
+ }
234
+ const destinationName = libraries.get(resolvedDependency);
235
+ if (!destinationName)
236
+ continue;
237
+ const rewrittenDependency = mode === 'executable'
238
+ ? `@loader_path/../Frameworks/${destinationName}`
239
+ : `@loader_path/${destinationName}`;
240
+ if (dependency !== rewrittenDependency) {
241
+ args.push('-change', dependency, rewrittenDependency);
242
+ }
243
+ }
244
+ if (args.length === 0)
245
+ return;
246
+ execFileSync('install_name_tool', [...args, targetPath], {
247
+ stdio: 'pipe',
248
+ });
249
+ }
250
+ function signMacPortableBundle(bundlePath) {
251
+ if (!commandExists('codesign'))
252
+ return;
253
+ execFileSync('codesign', ['--force', '--deep', '--sign', '-', bundlePath], {
254
+ stdio: 'pipe',
255
+ });
256
+ }
257
+ function copyPortableNodeRuntime(embeddedNodePath, options = {}) {
258
+ const sourceNodePath = realpathSync(process.execPath);
259
+ copyFileSync(sourceNodePath, embeddedNodePath);
260
+ chmodSync(embeddedNodePath, 0o755);
261
+ if (process.platform === 'darwin') {
262
+ const frameworksDir = options.macFrameworksDir;
263
+ if (!frameworksDir) {
264
+ throw new Error('macFrameworksDir is required when creating a macOS portable artifact.');
265
+ }
266
+ mkdirSync(frameworksDir, { recursive: true });
267
+ const libraries = collectMacPortableLibraries(sourceNodePath);
268
+ for (const [sourcePath, destinationName] of libraries) {
269
+ const targetPath = join(frameworksDir, destinationName);
270
+ copyFileSync(sourcePath, targetPath);
271
+ chmodSync(targetPath, 0o755);
272
+ }
273
+ rewriteMacPortableBinary(embeddedNodePath, sourceNodePath, libraries, 'executable');
274
+ for (const [sourcePath, destinationName] of libraries) {
275
+ rewriteMacPortableBinary(join(frameworksDir, destinationName), sourcePath, libraries, 'library');
276
+ }
277
+ return;
278
+ }
279
+ if (process.platform === 'win32') {
280
+ const sourceDir = dirname(sourceNodePath);
281
+ for (const entry of readdirSync(sourceDir)) {
282
+ if (!/\.dll$/i.test(entry))
283
+ continue;
284
+ copyFileSync(join(sourceDir, entry), join(dirname(embeddedNodePath), entry));
285
+ }
286
+ return;
287
+ }
288
+ if (process.platform === 'linux') {
289
+ const portableLibDir = options.portableLibDir;
290
+ if (!portableLibDir || !commandExists('ldd')) {
291
+ return;
292
+ }
293
+ mkdirSync(portableLibDir, { recursive: true });
294
+ const output = execFileSync('ldd', [sourceNodePath], {
295
+ encoding: 'utf-8',
296
+ stdio: 'pipe',
297
+ });
298
+ const copiedLibraries = new Set();
299
+ for (const line of output.split(/\r?\n/)) {
300
+ const match = line.match(/=>\s+(\/[^ ]+)/) ?? line.match(/^\s*(\/[^ ]+)/);
301
+ const libraryPath = match?.[1];
302
+ if (!libraryPath || !existsSync(libraryPath))
303
+ continue;
304
+ if (libraryPath.startsWith('/lib/') || libraryPath.startsWith('/usr/lib/')) {
305
+ continue;
306
+ }
307
+ const resolvedPath = realpathSync(libraryPath);
308
+ const destinationName = basename(resolvedPath);
309
+ if (copiedLibraries.has(destinationName))
310
+ continue;
311
+ copiedLibraries.add(destinationName);
312
+ copyFileSync(resolvedPath, join(portableLibDir, destinationName));
313
+ }
314
+ }
315
+ }
316
+ export function createArchiveFromPortableArtifact(sourcePath, archivePath) {
317
+ rmSync(archivePath, { force: true, recursive: true });
318
+ mkdirSync(dirname(archivePath), { recursive: true });
319
+ if (process.platform === 'darwin') {
320
+ execFileSync('ditto', ['-c', '-k', '--keepParent', basename(sourcePath), archivePath], {
321
+ cwd: dirname(sourcePath),
322
+ stdio: 'pipe',
323
+ });
324
+ return 'zip';
325
+ }
326
+ if (process.platform === 'win32') {
327
+ execFileSync('powershell', [
328
+ '-NoProfile',
329
+ '-Command',
330
+ `Compress-Archive -Path '${sourcePath.replace(/'/g, "''")}' -DestinationPath '${archivePath.replace(/'/g, "''")}' -Force`,
331
+ ], {
332
+ stdio: 'pipe',
333
+ });
334
+ return 'zip';
335
+ }
336
+ execFileSync('tar', ['-czf', archivePath, '-C', dirname(sourcePath), basename(sourcePath)], {
337
+ stdio: 'pipe',
338
+ });
339
+ return 'tar.gz';
340
+ }
341
+ function finalizePackWrangler(projectDir, outputDir) {
342
+ const configFile = EDGEBASE_CONFIG_FILES
343
+ .map((name) => join(projectDir, name))
344
+ .find((path) => existsSync(path));
345
+ if (!configFile) {
346
+ throw new Error(`No EdgeBase config file found in ${projectDir}.`);
347
+ }
348
+ const config = loadConfigSafe(configFile, projectDir, {
349
+ allowRegexFallback: false,
350
+ });
351
+ const wranglerPath = join(outputDir, 'wrangler.toml');
352
+ const generatedPath = generateTempWranglerToml(wranglerPath, {
353
+ bindings: resolveLocalDevBindings(config),
354
+ triggerMode: 'preserve',
355
+ });
356
+ if (!generatedPath)
357
+ return;
358
+ writeFileSync(wranglerPath, readFileSync(generatedPath, 'utf-8'), 'utf-8');
359
+ rmSync(generatedPath, { force: true });
360
+ }
361
+ function buildLauncherSource(manifest) {
362
+ return `#!/usr/bin/env node
363
+ import { createWriteStream, existsSync, mkdirSync, readFileSync, readdirSync, rmSync, writeFileSync } from 'node:fs';
364
+ import { spawn, spawnSync } from 'node:child_process';
365
+ import { createServer } from 'node:net';
366
+ import { homedir } from 'node:os';
367
+ import { dirname, join, resolve } from 'node:path';
368
+ import { fileURLToPath } from 'node:url';
369
+
370
+ const DEFAULT_HOST = ${JSON.stringify(manifest.launcher.defaultHost)};
371
+ const DEFAULT_PORT = ${manifest.launcher.defaultPort};
372
+ const DEFAULT_OPEN_PATH = ${JSON.stringify(manifest.launcher.defaultOpenPath)};
373
+ const APP_DATA_DIR_NAME = ${JSON.stringify(manifest.launcher.appDataDirName)};
374
+ const DEFAULT_STATE_DIR = ${JSON.stringify(manifest.launcher.stateDir)};
375
+ const DEFAULT_RUNTIME_DIR = ${JSON.stringify(manifest.launcher.runtimeDir)};
376
+ const SINGLE_INSTANCE = ${manifest.launcher.singleInstance ? 'true' : 'false'};
377
+ const PORT_SEARCH_LIMIT = ${manifest.launcher.portSearchLimit};
378
+
379
+ function parseArgs(argv) {
380
+ const options = {
381
+ host: process.env.HOST || process.env.EDGEBASE_HOST || DEFAULT_HOST,
382
+ port: process.env.PORT || process.env.EDGEBASE_PORT || '',
383
+ dataDir: process.env.EDGEBASE_DATA_DIR || '',
384
+ persistTo: process.env.PERSIST_DIR || '',
385
+ open: process.env.EDGEBASE_OPEN === '1' || process.env.EDGEBASE_OPEN === 'true',
386
+ dryRun: false,
387
+ json: false,
388
+ envFile: process.env.EDGEBASE_ENV_FILE || '',
389
+ };
390
+
391
+ for (let index = 0; index < argv.length; index += 1) {
392
+ const arg = argv[index];
393
+ const next = argv[index + 1];
394
+
395
+ if (arg === '--host' && next) {
396
+ options.host = next;
397
+ index += 1;
398
+ continue;
399
+ }
400
+ if (arg.startsWith('--host=')) {
401
+ options.host = arg.slice('--host='.length);
402
+ continue;
403
+ }
404
+ if (arg === '--port' && next) {
405
+ options.port = next;
406
+ index += 1;
407
+ continue;
408
+ }
409
+ if (arg.startsWith('--port=')) {
410
+ options.port = arg.slice('--port='.length);
411
+ continue;
412
+ }
413
+ if (arg === '--persist-to' && next) {
414
+ options.persistTo = next;
415
+ index += 1;
416
+ continue;
417
+ }
418
+ if (arg.startsWith('--persist-to=')) {
419
+ options.persistTo = arg.slice('--persist-to='.length);
420
+ continue;
421
+ }
422
+ if (arg === '--data-dir' && next) {
423
+ options.dataDir = next;
424
+ index += 1;
425
+ continue;
426
+ }
427
+ if (arg.startsWith('--data-dir=')) {
428
+ options.dataDir = arg.slice('--data-dir='.length);
429
+ continue;
430
+ }
431
+ if (arg === '--env-file' && next) {
432
+ options.envFile = next;
433
+ index += 1;
434
+ continue;
435
+ }
436
+ if (arg.startsWith('--env-file=')) {
437
+ options.envFile = arg.slice('--env-file='.length);
438
+ continue;
439
+ }
440
+ if (arg === '--open') {
441
+ options.open = true;
442
+ continue;
443
+ }
444
+ if (arg === '--dry-run') {
445
+ options.dryRun = true;
446
+ continue;
447
+ }
448
+ if (arg === '--json') {
449
+ options.json = true;
450
+ continue;
451
+ }
452
+ }
453
+
454
+ return options;
455
+ }
456
+
457
+ function readJson(filePath) {
458
+ if (!existsSync(filePath)) return null;
459
+ try {
460
+ return JSON.parse(readFileSync(filePath, 'utf-8'));
461
+ } catch {
462
+ return null;
463
+ }
464
+ }
465
+
466
+ function parseEnvFile(filePath) {
467
+ if (!filePath || !existsSync(filePath)) return {};
468
+ const content = readFileSync(filePath, 'utf-8');
469
+ const values = {};
470
+
471
+ for (const rawLine of content.split(/\\r?\\n/)) {
472
+ const line = rawLine.trim();
473
+ if (!line || line.startsWith('#')) continue;
474
+ const separator = line.indexOf('=');
475
+ if (separator <= 0) continue;
476
+ const key = line.slice(0, separator).trim();
477
+ let value = line.slice(separator + 1).trim();
478
+ if ((value.startsWith('"') && value.endsWith('"')) || (value.startsWith("'") && value.endsWith("'"))) {
479
+ value = value.slice(1, -1);
480
+ }
481
+ values[key] = value;
482
+ }
483
+
484
+ return values;
485
+ }
486
+
487
+ function serializeEnvValue(value) {
488
+ return /^[A-Za-z0-9_./:@+-]+$/.test(value) ? value : JSON.stringify(value);
489
+ }
490
+
491
+ function saveJson(filePath, payload) {
492
+ mkdirSync(dirname(filePath), { recursive: true });
493
+ writeFileSync(filePath, JSON.stringify(payload, null, 2) + '\\n', 'utf-8');
494
+ }
495
+
496
+ function removeFileIfExists(filePath) {
497
+ try {
498
+ rmSync(filePath, { force: true });
499
+ } catch {
500
+ // best-effort cleanup only
501
+ }
502
+ }
503
+
504
+ function isProcessAlive(pid) {
505
+ if (!Number.isInteger(pid) || pid <= 0) return false;
506
+ try {
507
+ process.kill(pid, 0);
508
+ return true;
509
+ } catch {
510
+ return false;
511
+ }
512
+ }
513
+
514
+ function terminateProcessTree(pid) {
515
+ if (!Number.isInteger(pid) || pid <= 0) return;
516
+
517
+ if (process.platform === 'win32') {
518
+ spawnSync('taskkill', ['/pid', String(pid), '/t', '/f'], { stdio: 'ignore' });
519
+ return;
520
+ }
521
+
522
+ try {
523
+ process.kill(pid, 'SIGTERM');
524
+ } catch {
525
+ // best-effort cleanup only
526
+ }
527
+ }
528
+
529
+ function resolveDataRoot(dataDir) {
530
+ if (dataDir) {
531
+ return resolve(process.cwd(), dataDir);
532
+ }
533
+
534
+ if (process.platform === 'darwin') {
535
+ return resolve(homedir(), 'Library', 'Application Support', APP_DATA_DIR_NAME);
536
+ }
537
+
538
+ if (process.platform === 'win32') {
539
+ const base = process.env.LOCALAPPDATA || join(homedir(), 'AppData', 'Local');
540
+ return resolve(base, APP_DATA_DIR_NAME);
541
+ }
542
+
543
+ const base = process.env.XDG_DATA_HOME || join(homedir(), '.local', 'share');
544
+ return resolve(base, APP_DATA_DIR_NAME);
545
+ }
546
+
547
+ async function probePort(port, host) {
548
+ return new Promise((resolvePromise) => {
549
+ const server = createServer();
550
+ server.once('error', () => resolvePromise(false));
551
+ server.once('listening', () => {
552
+ server.close(() => resolvePromise(true));
553
+ });
554
+ server.listen({ port, host, exclusive: true });
555
+ });
556
+ }
557
+
558
+ async function resolveSelectedPort(host, explicitPort, statePath) {
559
+ if (explicitPort) {
560
+ return {
561
+ port: Number.parseInt(String(explicitPort), 10),
562
+ source: 'explicit',
563
+ };
564
+ }
565
+
566
+ const savedState = readJson(statePath);
567
+ const preferredPort = typeof savedState?.port === 'number'
568
+ ? savedState.port
569
+ : DEFAULT_PORT;
570
+
571
+ for (let offset = 0; offset < PORT_SEARCH_LIMIT; offset += 1) {
572
+ const candidate = preferredPort + offset;
573
+ if (await probePort(candidate, host)) {
574
+ return {
575
+ port: candidate,
576
+ source: candidate === preferredPort
577
+ ? (typeof savedState?.port === 'number' ? 'saved' : 'default')
578
+ : 'fallback',
579
+ };
580
+ }
581
+ }
582
+
583
+ throw new Error(
584
+ \`Could not find an available port in the range \${preferredPort}-\${preferredPort + PORT_SEARCH_LIMIT - 1}.\`,
585
+ );
586
+ }
587
+
588
+ function readActiveInstance(lockPath, host) {
589
+ if (!SINGLE_INSTANCE) return null;
590
+
591
+ const lock = readJson(lockPath);
592
+ if (!lock || typeof lock.port !== 'number' || typeof lock.pid !== 'number') {
593
+ removeFileIfExists(lockPath);
594
+ return null;
595
+ }
596
+
597
+ if (typeof lock.host !== 'string' || lock.host !== host) {
598
+ return null;
599
+ }
600
+
601
+ if (!isProcessAlive(lock.pid)) {
602
+ removeFileIfExists(lockPath);
603
+ return null;
604
+ }
605
+
606
+ return lock;
607
+ }
608
+
609
+ function findWranglerPackageJson(runtimeNodeModules) {
610
+ const direct = join(runtimeNodeModules, 'wrangler', 'package.json');
611
+ if (existsSync(direct)) return direct;
612
+
613
+ const pnpmDir = join(runtimeNodeModules, '.pnpm');
614
+ if (existsSync(pnpmDir)) {
615
+ const candidate = readdirSync(pnpmDir)
616
+ .filter((entry) => entry.startsWith('wrangler@'))
617
+ .map((entry) => join(pnpmDir, entry, 'node_modules', 'wrangler', 'package.json'))
618
+ .find((entry) => existsSync(entry));
619
+ if (candidate) return candidate;
620
+ }
621
+
622
+ throw new Error('Could not find wrangler/package.json inside the packed runtime.');
623
+ }
624
+
625
+ function resolveWranglerBin(runtimeNodeModules) {
626
+ const packageJsonPath = findWranglerPackageJson(runtimeNodeModules);
627
+ const packageJson = JSON.parse(readFileSync(packageJsonPath, 'utf-8'));
628
+ const relBin = typeof packageJson.bin === 'string'
629
+ ? packageJson.bin
630
+ : packageJson.bin?.wrangler ?? packageJson.bin?.wrangler2;
631
+ if (!relBin) {
632
+ throw new Error('Could not resolve the packed Wrangler binary.');
633
+ }
634
+ return resolve(dirname(packageJsonPath), relBin);
635
+ }
636
+
637
+ function openBrowser(url) {
638
+ if (process.platform === 'darwin') {
639
+ spawn('open', [url], { stdio: 'ignore', detached: true }).unref();
640
+ return;
641
+ }
642
+ if (process.platform === 'win32') {
643
+ spawn('cmd', ['/c', 'start', '', url], { stdio: 'ignore', detached: true }).unref();
644
+ return;
645
+ }
646
+ spawn('xdg-open', [url], { stdio: 'ignore', detached: true }).unref();
647
+ }
648
+
649
+ const artifactRoot = dirname(fileURLToPath(import.meta.url));
650
+ const runtimeRoot = join(artifactRoot, '.edgebase', 'runtime', 'server');
651
+ const runtimeNodeModules = join(runtimeRoot, 'node_modules');
652
+ const options = parseArgs(process.argv.slice(2));
653
+ const dataRoot = resolveDataRoot(options.dataDir);
654
+ const workDir = join(dataRoot, DEFAULT_RUNTIME_DIR);
655
+ const persistDir = options.persistTo
656
+ ? resolve(process.cwd(), options.persistTo)
657
+ : join(dataRoot, DEFAULT_STATE_DIR);
658
+ const statePath = join(dataRoot, 'launcher-state.json');
659
+ const lockPath = join(dataRoot, 'launcher-lock.json');
660
+ const logPath = join(dataRoot, 'launcher.log');
661
+ mkdirSync(dataRoot, { recursive: true });
662
+ mkdirSync(workDir, { recursive: true });
663
+ mkdirSync(persistDir, { recursive: true });
664
+ const logStream = createWriteStream(logPath, { flags: 'a' });
665
+
666
+ const envFileCandidates = [
667
+ join(process.cwd(), '.env'),
668
+ join(process.cwd(), '.env.local'),
669
+ join(artifactRoot, '.env'),
670
+ join(artifactRoot, '.env.local'),
671
+ options.envFile ? resolve(process.cwd(), options.envFile) : '',
672
+ ].filter(Boolean);
673
+ const mergedEnv = Object.assign(
674
+ {},
675
+ ...envFileCandidates.map((filePath) => parseEnvFile(filePath)),
676
+ Object.fromEntries(Object.entries(process.env).filter(([, value]) => typeof value === 'string')),
677
+ );
678
+
679
+ const devVarsPath = join(workDir, '.dev.vars');
680
+ writeFileSync(
681
+ devVarsPath,
682
+ Object.keys(mergedEnv)
683
+ .sort()
684
+ .map((key) => \`\${key}=\${serializeEnvValue(String(mergedEnv[key]))}\`)
685
+ .join('\\n') + '\\n',
686
+ 'utf-8',
687
+ );
688
+
689
+ const wranglerBin = resolveWranglerBin(runtimeNodeModules);
690
+ const existingInstance = readActiveInstance(lockPath, options.host);
691
+ const selectedPort = existingInstance && !options.port
692
+ ? { port: existingInstance.port, source: 'existing' }
693
+ : await resolveSelectedPort(options.host, options.port, statePath);
694
+ saveJson(statePath, {
695
+ host: options.host,
696
+ port: selectedPort.port,
697
+ updatedAt: new Date().toISOString(),
698
+ });
699
+ const wranglerArgs = [
700
+ wranglerBin,
701
+ 'dev',
702
+ '--config',
703
+ join(artifactRoot, 'wrangler.toml'),
704
+ '--port',
705
+ String(selectedPort.port),
706
+ '--ip',
707
+ options.host,
708
+ '--persist-to',
709
+ persistDir,
710
+ ];
711
+ const openUrl = \`http://\${options.host}:\${selectedPort.port}\${DEFAULT_OPEN_PATH}\`;
712
+
713
+ if (options.dryRun) {
714
+ const payload = {
715
+ status: 'success',
716
+ artifactRoot,
717
+ runtimeRoot,
718
+ dataRoot,
719
+ workDir,
720
+ wranglerCommand: process.execPath,
721
+ wranglerBin,
722
+ wranglerArgs,
723
+ host: options.host,
724
+ port: selectedPort.port,
725
+ persistDir,
726
+ devVarsPath,
727
+ statePath,
728
+ lockPath,
729
+ existingInstance: Boolean(existingInstance && !options.port),
730
+ openUrl,
731
+ };
732
+ process.stdout.write(options.json ? JSON.stringify(payload, null, 2) + '\\n' : JSON.stringify(payload) + '\\n');
733
+ process.exit(0);
734
+ }
735
+
736
+ if (existingInstance && !options.port) {
737
+ openBrowser(openUrl);
738
+ process.exit(0);
739
+ }
740
+
741
+ saveJson(lockPath, {
742
+ pid: process.pid,
743
+ host: options.host,
744
+ port: selectedPort.port,
745
+ createdAt: new Date().toISOString(),
746
+ });
747
+
748
+ const child = spawn(process.execPath, wranglerArgs, {
749
+ cwd: workDir,
750
+ stdio: ['ignore', 'pipe', 'pipe'],
751
+ env: {
752
+ ...process.env,
753
+ ...mergedEnv,
754
+ },
755
+ detached: process.platform !== 'win32',
756
+ });
757
+
758
+ const shouldMirrorStdIo = Boolean(process.stdout?.isTTY || process.stderr?.isTTY);
759
+
760
+ const relayOutput = (stream, writer) => {
761
+ if (!stream) return;
762
+ stream.on('data', (chunk) => {
763
+ if (shouldMirrorStdIo && writer?.writable) {
764
+ writer.write(chunk);
765
+ }
766
+ logStream.write(chunk);
767
+ });
768
+ };
769
+
770
+ relayOutput(child.stdout, process.stdout);
771
+ relayOutput(child.stderr, process.stderr);
772
+
773
+ const cleanupLock = () => {
774
+ const current = readJson(lockPath);
775
+ if (current?.pid === process.pid) {
776
+ removeFileIfExists(lockPath);
777
+ }
778
+ };
779
+
780
+ process.on('exit', cleanupLock);
781
+
782
+ if (options.open) {
783
+ setTimeout(() => openBrowser(openUrl), 1500);
784
+ }
785
+
786
+ const forward = (signal) => {
787
+ if (child.exitCode !== null || child.signalCode !== null) return;
788
+ if (process.platform === 'win32') {
789
+ terminateProcessTree(child.pid);
790
+ return;
791
+ }
792
+ child.kill(signal);
793
+ };
794
+
795
+ process.on('SIGINT', () => forward('SIGINT'));
796
+ process.on('SIGTERM', () => forward('SIGTERM'));
797
+
798
+ child.on('error', (error) => {
799
+ cleanupLock();
800
+ logStream.write(String(error.stack || error) + '\\n');
801
+ logStream.end();
802
+ process.stderr.write(String(error.stack || error) + '\\n');
803
+ process.exit(1);
804
+ });
805
+
806
+ child.on('exit', (code, signal) => {
807
+ cleanupLock();
808
+ logStream.end();
809
+ if (signal) {
810
+ process.exit(1);
811
+ return;
812
+ }
813
+ process.exit(code ?? 0);
814
+ });
815
+ `;
816
+ }
817
+ function writeLauncherFiles(outputDir, manifest) {
818
+ const launcherPath = join(outputDir, manifest.launcher.entry);
819
+ const runShPath = join(outputDir, manifest.launcher.unix);
820
+ const runCmdPath = join(outputDir, manifest.launcher.windows);
821
+ writeFileSync(launcherPath, buildLauncherSource(manifest), 'utf-8');
822
+ writeFileSync(runShPath, `#!/usr/bin/env bash
823
+ set -euo pipefail
824
+ SCRIPT_DIR="$(cd -- "$(dirname -- "$0")" && pwd)"
825
+ exec node "$SCRIPT_DIR/${manifest.launcher.entry}" "$@"
826
+ `, 'utf-8');
827
+ writeFileSync(runCmdPath, `@echo off
828
+ set SCRIPT_DIR=%~dp0
829
+ node "%SCRIPT_DIR%\\${manifest.launcher.entry}" %*
830
+ `, 'utf-8');
831
+ chmodSync(launcherPath, 0o755);
832
+ chmodSync(runShPath, 0o755);
833
+ }
834
+ function createMacPortableArtifact(outputPath, appName, dirArtifact) {
835
+ const executableName = sanitizeExecutableName(appName);
836
+ const contentsDir = join(outputPath, 'Contents');
837
+ const macOsDir = join(contentsDir, 'MacOS');
838
+ const frameworksDir = join(contentsDir, 'Frameworks');
839
+ const resourcesDir = join(contentsDir, 'Resources');
840
+ const bundledAppDir = join(resourcesDir, 'app');
841
+ const embeddedNodePath = join(macOsDir, 'node');
842
+ const launcherPath = join(macOsDir, executableName);
843
+ rmSync(outputPath, { recursive: true, force: true });
844
+ mkdirSync(macOsDir, { recursive: true });
845
+ mkdirSync(frameworksDir, { recursive: true });
846
+ mkdirSync(resourcesDir, { recursive: true });
847
+ cpSync(dirArtifact.outputDir, bundledAppDir, {
848
+ recursive: true,
849
+ force: true,
850
+ dereference: false,
851
+ verbatimSymlinks: true,
852
+ });
853
+ copyPortableNodeRuntime(embeddedNodePath, {
854
+ macFrameworksDir: frameworksDir,
855
+ });
856
+ writeFileSync(launcherPath, `#!/usr/bin/env bash
857
+ set -euo pipefail
858
+ SCRIPT_DIR="$(cd -- "$(dirname -- "$0")" && pwd)"
859
+ APP_DIR="$(cd -- "$SCRIPT_DIR/../Resources/app" && pwd)"
860
+ export DYLD_LIBRARY_PATH="$SCRIPT_DIR/../Frameworks\${DYLD_LIBRARY_PATH:+:$DYLD_LIBRARY_PATH}"
861
+ exec "$SCRIPT_DIR/node" "$APP_DIR/launcher.mjs" "$@"
862
+ `, 'utf-8');
863
+ chmodSync(launcherPath, 0o755);
864
+ writeFileSync(join(contentsDir, 'Info.plist'), `<?xml version="1.0" encoding="UTF-8"?>
865
+ <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
866
+ <plist version="1.0">
867
+ <dict>
868
+ <key>CFBundleDevelopmentRegion</key>
869
+ <string>en</string>
870
+ <key>CFBundleDisplayName</key>
871
+ <string>${appName.replace(/\.app$/i, '')}</string>
872
+ <key>CFBundleExecutable</key>
873
+ <string>${executableName}</string>
874
+ <key>CFBundleIdentifier</key>
875
+ <string>fun.edgebase.${sanitizeExecutableName(dirArtifact.manifest.projectName)}</string>
876
+ <key>CFBundleName</key>
877
+ <string>${appName.replace(/\.app$/i, '')}</string>
878
+ <key>CFBundlePackageType</key>
879
+ <string>APPL</string>
880
+ <key>CFBundleShortVersionString</key>
881
+ <string>0.1.0</string>
882
+ <key>LSMinimumSystemVersion</key>
883
+ <string>13.0</string>
884
+ </dict>
885
+ </plist>
886
+ `, 'utf-8');
887
+ const manifest = buildPortableManifest({
888
+ outputPath,
889
+ bundledAppDir,
890
+ launcherPath,
891
+ embeddedNodePath,
892
+ appManifestPath: join(bundledAppDir, 'edgebase-app.json'),
893
+ packManifestPath: join(bundledAppDir, 'edgebase-pack.json'),
894
+ projectName: dirArtifact.manifest.projectName,
895
+ artifactKind: 'macos-app',
896
+ });
897
+ const manifestPath = join(resourcesDir, 'edgebase-portable.json');
898
+ writeFileSync(manifestPath, `${JSON.stringify(manifest, null, 2)}\n`, 'utf-8');
899
+ signMacPortableBundle(outputPath);
900
+ return {
901
+ format: 'portable',
902
+ projectDir: dirArtifact.projectDir,
903
+ outputPath,
904
+ manifestPath,
905
+ manifest,
906
+ launcherPath,
907
+ bundledAppDir,
908
+ appManifestPath: join(bundledAppDir, 'edgebase-app.json'),
909
+ packManifestPath: join(bundledAppDir, 'edgebase-pack.json'),
910
+ appManifest: dirArtifact.appManifest,
911
+ packManifest: dirArtifact.manifest,
912
+ };
913
+ }
914
+ function createPortableDirectoryArtifact(outputPath, dirArtifact) {
915
+ const bundledAppDir = join(outputPath, 'app');
916
+ const binDir = join(outputPath, 'bin');
917
+ const embeddedNodeName = process.platform === 'win32' ? 'node.exe' : 'node';
918
+ const embeddedNodePath = join(binDir, embeddedNodeName);
919
+ const launcherName = process.platform === 'win32' ? 'run.cmd' : 'run.sh';
920
+ const launcherPath = join(outputPath, launcherName);
921
+ rmSync(outputPath, { recursive: true, force: true });
922
+ mkdirSync(binDir, { recursive: true });
923
+ cpSync(dirArtifact.outputDir, bundledAppDir, {
924
+ recursive: true,
925
+ force: true,
926
+ dereference: false,
927
+ verbatimSymlinks: true,
928
+ });
929
+ copyPortableNodeRuntime(embeddedNodePath, {
930
+ portableLibDir: process.platform === 'linux' ? join(outputPath, 'lib') : undefined,
931
+ });
932
+ if (process.platform === 'win32') {
933
+ writeFileSync(launcherPath, `@echo off
934
+ set SCRIPT_DIR=%~dp0
935
+ "%SCRIPT_DIR%bin\\node.exe" "%SCRIPT_DIR%app\\launcher.mjs" %*
936
+ `, 'utf-8');
937
+ }
938
+ else {
939
+ const libraryEnvExport = process.platform === 'linux'
940
+ ? 'export LD_LIBRARY_PATH="$SCRIPT_DIR/lib${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}"\n'
941
+ : '';
942
+ writeFileSync(launcherPath, `#!/usr/bin/env bash
943
+ set -euo pipefail
944
+ SCRIPT_DIR="$(cd -- "$(dirname -- "$0")" && pwd)"
945
+ ${libraryEnvExport}exec "$SCRIPT_DIR/bin/${embeddedNodeName}" "$SCRIPT_DIR/app/launcher.mjs" "$@"
946
+ `, 'utf-8');
947
+ chmodSync(launcherPath, 0o755);
948
+ }
949
+ const manifest = buildPortableManifest({
950
+ outputPath,
951
+ bundledAppDir,
952
+ launcherPath,
953
+ embeddedNodePath,
954
+ appManifestPath: join(bundledAppDir, 'edgebase-app.json'),
955
+ packManifestPath: join(bundledAppDir, 'edgebase-pack.json'),
956
+ projectName: dirArtifact.manifest.projectName,
957
+ artifactKind: 'portable-dir',
958
+ });
959
+ const manifestPath = join(outputPath, 'edgebase-portable.json');
960
+ writeFileSync(manifestPath, `${JSON.stringify(manifest, null, 2)}\n`, 'utf-8');
961
+ return {
962
+ format: 'portable',
963
+ projectDir: dirArtifact.projectDir,
964
+ outputPath,
965
+ manifestPath,
966
+ manifest,
967
+ launcherPath,
968
+ bundledAppDir,
969
+ appManifestPath: join(bundledAppDir, 'edgebase-app.json'),
970
+ packManifestPath: join(bundledAppDir, 'edgebase-pack.json'),
971
+ appManifest: dirArtifact.appManifest,
972
+ packManifest: dirArtifact.manifest,
973
+ };
974
+ }
975
+ export function createDirPackArtifact(projectDir, options = {}) {
976
+ const appBundle = createAppBundle(projectDir, {
977
+ ...options,
978
+ portableDependencies: true,
979
+ dependencyProfile: 'portable',
980
+ });
981
+ finalizePackWrangler(projectDir, appBundle.outputDir);
982
+ const manifest = buildPackManifest(appBundle.outputDir, appBundle.manifest);
983
+ const manifestPath = join(appBundle.outputDir, 'edgebase-pack.json');
984
+ writePackManifest(manifestPath, manifest);
985
+ writeLauncherFiles(appBundle.outputDir, manifest);
986
+ return {
987
+ format: 'dir',
988
+ projectDir: appBundle.projectDir,
989
+ outputDir: appBundle.outputDir,
990
+ manifestPath,
991
+ manifest,
992
+ appManifestPath: appBundle.manifestPath,
993
+ appManifest: appBundle.manifest,
994
+ };
995
+ }
996
+ export function createPortablePackArtifact(projectDir, options = {}) {
997
+ const dirArtifact = createDirPackArtifact(projectDir, {
998
+ outputDir: join('.edgebase', 'targets', 'portable-pack-source'),
999
+ overwrite: true,
1000
+ portableDependencies: true,
1001
+ });
1002
+ const outputPath = resolvePortableOutputPath(projectDir, dirArtifact.manifest.projectName, options.outputDir);
1003
+ const appName = options.appName ?? basename(outputPath);
1004
+ if (process.platform === 'darwin') {
1005
+ return createMacPortableArtifact(outputPath, appName, dirArtifact);
1006
+ }
1007
+ return createPortableDirectoryArtifact(outputPath, dirArtifact);
1008
+ }
1009
+ export function createArchivePackArtifact(projectDir, options = {}) {
1010
+ const archiveSourceName = process.platform === 'darwin'
1011
+ ? `${sanitizeExecutableName(options.appName ?? basename(projectDir))}.app`
1012
+ : `${sanitizeExecutableName(options.appName ?? basename(projectDir))}-${process.platform}-${process.arch}-portable`;
1013
+ const sourcePortablePath = resolvePortableOutputPath(projectDir, sanitizeExecutableName(options.appName ?? basename(projectDir)), join('.edgebase', 'targets', archiveSourceName));
1014
+ const portableArtifact = createPortablePackArtifact(projectDir, {
1015
+ outputDir: sourcePortablePath,
1016
+ appName: options.appName,
1017
+ });
1018
+ const outputPath = resolveArchiveOutputPath(projectDir, portableArtifact.packManifest.projectName, options.outputDir);
1019
+ const archiveType = createArchiveFromPortableArtifact(portableArtifact.outputPath, outputPath);
1020
+ const manifest = buildArchiveManifest({
1021
+ outputPath,
1022
+ sourcePortablePath: portableArtifact.outputPath,
1023
+ launcherPath: portableArtifact.launcherPath,
1024
+ embeddedNodePath: portableArtifact.manifest.embeddedNodePath,
1025
+ appManifestPath: portableArtifact.appManifestPath,
1026
+ packManifestPath: portableArtifact.packManifestPath,
1027
+ projectName: portableArtifact.packManifest.projectName,
1028
+ archiveType,
1029
+ });
1030
+ return {
1031
+ format: 'archive',
1032
+ projectDir: portableArtifact.projectDir,
1033
+ outputPath,
1034
+ manifest,
1035
+ sourcePortablePath: portableArtifact.outputPath,
1036
+ launcherPath: portableArtifact.launcherPath,
1037
+ bundledAppDir: portableArtifact.bundledAppDir,
1038
+ appManifestPath: portableArtifact.appManifestPath,
1039
+ packManifestPath: portableArtifact.packManifestPath,
1040
+ appManifest: portableArtifact.appManifest,
1041
+ packManifest: portableArtifact.packManifest,
1042
+ };
1043
+ }
1044
+ function writePackManifest(path, manifest) {
1045
+ writeFileSync(path, `${JSON.stringify(manifest, null, 2)}\n`, 'utf-8');
1046
+ }
1047
+ //# sourceMappingURL=pack.js.map