@orkify/cli 1.0.0-beta.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +191 -0
- package/README.md +1701 -0
- package/bin/orkify +3 -0
- package/boot/systemd/orkify@.service +30 -0
- package/dist/agent-name.d.ts +4 -0
- package/dist/agent-name.js +42 -0
- package/dist/alerts/AlertEvaluator.d.ts +14 -0
- package/dist/alerts/AlertEvaluator.js +135 -0
- package/dist/cli/commands/autostart.d.ts +3 -0
- package/dist/cli/commands/autostart.js +11 -0
- package/dist/cli/commands/crash-test.d.ts +3 -0
- package/dist/cli/commands/crash-test.js +17 -0
- package/dist/cli/commands/daemon-reload.d.ts +3 -0
- package/dist/cli/commands/daemon-reload.js +72 -0
- package/dist/cli/commands/delete.d.ts +3 -0
- package/dist/cli/commands/delete.js +37 -0
- package/dist/cli/commands/deploy.d.ts +6 -0
- package/dist/cli/commands/deploy.js +266 -0
- package/dist/cli/commands/down.d.ts +3 -0
- package/dist/cli/commands/down.js +36 -0
- package/dist/cli/commands/flush.d.ts +3 -0
- package/dist/cli/commands/flush.js +28 -0
- package/dist/cli/commands/kill.d.ts +3 -0
- package/dist/cli/commands/kill.js +35 -0
- package/dist/cli/commands/list.d.ts +14 -0
- package/dist/cli/commands/list.js +361 -0
- package/dist/cli/commands/logs.d.ts +3 -0
- package/dist/cli/commands/logs.js +107 -0
- package/dist/cli/commands/mcp.d.ts +3 -0
- package/dist/cli/commands/mcp.js +151 -0
- package/dist/cli/commands/reload.d.ts +3 -0
- package/dist/cli/commands/reload.js +54 -0
- package/dist/cli/commands/restart.d.ts +3 -0
- package/dist/cli/commands/restart.js +43 -0
- package/dist/cli/commands/restore.d.ts +3 -0
- package/dist/cli/commands/restore.js +88 -0
- package/dist/cli/commands/run.d.ts +8 -0
- package/dist/cli/commands/run.js +212 -0
- package/dist/cli/commands/snap.d.ts +3 -0
- package/dist/cli/commands/snap.js +30 -0
- package/dist/cli/commands/up.d.ts +3 -0
- package/dist/cli/commands/up.js +125 -0
- package/dist/cli/crash-recovery.d.ts +2 -0
- package/dist/cli/crash-recovery.js +67 -0
- package/dist/cli/index.d.ts +3 -0
- package/dist/cli/index.js +46 -0
- package/dist/cli/parse.d.ts +28 -0
- package/dist/cli/parse.js +97 -0
- package/dist/cluster/ClusterWrapper.d.ts +18 -0
- package/dist/cluster/ClusterWrapper.js +602 -0
- package/dist/config/ConfigStore.d.ts +11 -0
- package/dist/config/ConfigStore.js +21 -0
- package/dist/config/schema.d.ts +103 -0
- package/dist/config/schema.js +49 -0
- package/dist/constants.d.ts +83 -0
- package/dist/constants.js +289 -0
- package/dist/cron/CronScheduler.d.ts +25 -0
- package/dist/cron/CronScheduler.js +149 -0
- package/dist/daemon/GracefulManager.d.ts +8 -0
- package/dist/daemon/GracefulManager.js +29 -0
- package/dist/daemon/ManagedProcess.d.ts +71 -0
- package/dist/daemon/ManagedProcess.js +1020 -0
- package/dist/daemon/Orchestrator.d.ts +51 -0
- package/dist/daemon/Orchestrator.js +416 -0
- package/dist/daemon/RotatingWriter.d.ts +27 -0
- package/dist/daemon/RotatingWriter.js +264 -0
- package/dist/daemon/index.d.ts +2 -0
- package/dist/daemon/index.js +106 -0
- package/dist/daemon/startDaemon.d.ts +30 -0
- package/dist/daemon/startDaemon.js +693 -0
- package/dist/deploy/CommandPoller.d.ts +13 -0
- package/dist/deploy/CommandPoller.js +53 -0
- package/dist/deploy/DeployExecutor.d.ts +33 -0
- package/dist/deploy/DeployExecutor.js +340 -0
- package/dist/deploy/config.d.ts +20 -0
- package/dist/deploy/config.js +161 -0
- package/dist/deploy/env.d.ts +2 -0
- package/dist/deploy/env.js +17 -0
- package/dist/deploy/tarball.d.ts +32 -0
- package/dist/deploy/tarball.js +243 -0
- package/dist/detect/framework.d.ts +2 -0
- package/dist/detect/framework.js +24 -0
- package/dist/ipc/DaemonClient.d.ts +31 -0
- package/dist/ipc/DaemonClient.js +248 -0
- package/dist/ipc/DaemonServer.d.ts +28 -0
- package/dist/ipc/DaemonServer.js +166 -0
- package/dist/ipc/MultiUserClient.d.ts +27 -0
- package/dist/ipc/MultiUserClient.js +203 -0
- package/dist/ipc/protocol.d.ts +7 -0
- package/dist/ipc/protocol.js +53 -0
- package/dist/ipc/restoreDaemon.d.ts +8 -0
- package/dist/ipc/restoreDaemon.js +19 -0
- package/dist/machine-id.d.ts +11 -0
- package/dist/machine-id.js +51 -0
- package/dist/mcp/auth.d.ts +118 -0
- package/dist/mcp/auth.js +245 -0
- package/dist/mcp/http.d.ts +20 -0
- package/dist/mcp/http.js +229 -0
- package/dist/mcp/index.d.ts +3 -0
- package/dist/mcp/index.js +8 -0
- package/dist/mcp/server.d.ts +37 -0
- package/dist/mcp/server.js +413 -0
- package/dist/probe/compute-fingerprint.d.ts +27 -0
- package/dist/probe/compute-fingerprint.js +65 -0
- package/dist/probe/parse-frames.d.ts +21 -0
- package/dist/probe/parse-frames.js +57 -0
- package/dist/probe/resolve-sourcemaps.d.ts +25 -0
- package/dist/probe/resolve-sourcemaps.js +281 -0
- package/dist/state/StateStore.d.ts +11 -0
- package/dist/state/StateStore.js +78 -0
- package/dist/telemetry/TelemetryReporter.d.ts +49 -0
- package/dist/telemetry/TelemetryReporter.js +451 -0
- package/dist/types/index.d.ts +373 -0
- package/dist/types/index.js +2 -0
- package/package.json +148 -0
- package/packages/cache/README.md +114 -0
- package/packages/cache/dist/CacheClient.d.ts +26 -0
- package/packages/cache/dist/CacheClient.d.ts.map +1 -0
- package/packages/cache/dist/CacheClient.js +174 -0
- package/packages/cache/dist/CacheClient.js.map +1 -0
- package/packages/cache/dist/CacheFileStore.d.ts +45 -0
- package/packages/cache/dist/CacheFileStore.d.ts.map +1 -0
- package/packages/cache/dist/CacheFileStore.js +446 -0
- package/packages/cache/dist/CacheFileStore.js.map +1 -0
- package/packages/cache/dist/CachePersistence.d.ts +9 -0
- package/packages/cache/dist/CachePersistence.d.ts.map +1 -0
- package/packages/cache/dist/CachePersistence.js +67 -0
- package/packages/cache/dist/CachePersistence.js.map +1 -0
- package/packages/cache/dist/CachePrimary.d.ts +25 -0
- package/packages/cache/dist/CachePrimary.d.ts.map +1 -0
- package/packages/cache/dist/CachePrimary.js +155 -0
- package/packages/cache/dist/CachePrimary.js.map +1 -0
- package/packages/cache/dist/CacheStore.d.ts +50 -0
- package/packages/cache/dist/CacheStore.d.ts.map +1 -0
- package/packages/cache/dist/CacheStore.js +271 -0
- package/packages/cache/dist/CacheStore.js.map +1 -0
- package/packages/cache/dist/constants.d.ts +6 -0
- package/packages/cache/dist/constants.d.ts.map +1 -0
- package/packages/cache/dist/constants.js +9 -0
- package/packages/cache/dist/constants.js.map +1 -0
- package/packages/cache/dist/index.d.ts +16 -0
- package/packages/cache/dist/index.d.ts.map +1 -0
- package/packages/cache/dist/index.js +86 -0
- package/packages/cache/dist/index.js.map +1 -0
- package/packages/cache/dist/serialize.d.ts +9 -0
- package/packages/cache/dist/serialize.d.ts.map +1 -0
- package/packages/cache/dist/serialize.js +40 -0
- package/packages/cache/dist/serialize.js.map +1 -0
- package/packages/cache/dist/types.d.ts +123 -0
- package/packages/cache/dist/types.d.ts.map +1 -0
- package/packages/cache/dist/types.js +2 -0
- package/packages/cache/dist/types.js.map +1 -0
- package/packages/cache/package.json +27 -0
- package/packages/cache/src/CacheClient.ts +227 -0
- package/packages/cache/src/CacheFileStore.ts +528 -0
- package/packages/cache/src/CachePersistence.ts +89 -0
- package/packages/cache/src/CachePrimary.ts +172 -0
- package/packages/cache/src/CacheStore.ts +308 -0
- package/packages/cache/src/constants.ts +10 -0
- package/packages/cache/src/index.ts +100 -0
- package/packages/cache/src/serialize.ts +49 -0
- package/packages/cache/src/types.ts +156 -0
- package/packages/cache/tsconfig.json +18 -0
- package/packages/cache/tsconfig.tsbuildinfo +1 -0
- package/packages/next/README.md +166 -0
- package/packages/next/dist/error-capture.d.ts +34 -0
- package/packages/next/dist/error-capture.d.ts.map +1 -0
- package/packages/next/dist/error-capture.js +130 -0
- package/packages/next/dist/error-capture.js.map +1 -0
- package/packages/next/dist/error-handler.d.ts +10 -0
- package/packages/next/dist/error-handler.d.ts.map +1 -0
- package/packages/next/dist/error-handler.js +186 -0
- package/packages/next/dist/error-handler.js.map +1 -0
- package/packages/next/dist/isr-cache.d.ts +9 -0
- package/packages/next/dist/isr-cache.d.ts.map +1 -0
- package/packages/next/dist/isr-cache.js +86 -0
- package/packages/next/dist/isr-cache.js.map +1 -0
- package/packages/next/dist/stream.d.ts +5 -0
- package/packages/next/dist/stream.d.ts.map +1 -0
- package/packages/next/dist/stream.js +22 -0
- package/packages/next/dist/stream.js.map +1 -0
- package/packages/next/dist/types.d.ts +33 -0
- package/packages/next/dist/types.d.ts.map +1 -0
- package/packages/next/dist/types.js +6 -0
- package/packages/next/dist/types.js.map +1 -0
- package/packages/next/dist/use-cache.d.ts +4 -0
- package/packages/next/dist/use-cache.d.ts.map +1 -0
- package/packages/next/dist/use-cache.js +86 -0
- package/packages/next/dist/use-cache.js.map +1 -0
- package/packages/next/dist/utils.d.ts +32 -0
- package/packages/next/dist/utils.d.ts.map +1 -0
- package/packages/next/dist/utils.js +88 -0
- package/packages/next/dist/utils.js.map +1 -0
- package/packages/next/package.json +52 -0
- package/packages/next/src/error-capture.ts +177 -0
- package/packages/next/src/error-handler.ts +221 -0
- package/packages/next/src/isr-cache.ts +100 -0
- package/packages/next/src/stream.ts +23 -0
- package/packages/next/src/types.ts +33 -0
- package/packages/next/src/use-cache.ts +99 -0
- package/packages/next/src/utils.ts +102 -0
- package/packages/next/tsconfig.json +19 -0
- package/packages/next/tsconfig.tsbuildinfo +1 -0
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { Orchestrator } from '../daemon/Orchestrator.js';
|
|
2
|
+
import type { TelemetryReporter } from '../telemetry/TelemetryReporter.js';
|
|
3
|
+
import type { TelemetryConfig } from '../types/index.js';
|
|
4
|
+
export declare class CommandPoller {
|
|
5
|
+
private config;
|
|
6
|
+
private orchestrator;
|
|
7
|
+
private telemetry;
|
|
8
|
+
private polling;
|
|
9
|
+
constructor(config: TelemetryConfig, orchestrator: Orchestrator, telemetry: TelemetryReporter);
|
|
10
|
+
start(): void;
|
|
11
|
+
fetchAndExecute(): Promise<void>;
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=CommandPoller.d.ts.map
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
import { hostname } from 'node:os';
|
|
2
|
+
import { getAgentName } from '../agent-name.js';
|
|
3
|
+
import { DeployExecutor } from './DeployExecutor.js';
|
|
4
|
+
export class CommandPoller {
|
|
5
|
+
config;
|
|
6
|
+
orchestrator;
|
|
7
|
+
telemetry;
|
|
8
|
+
polling = false;
|
|
9
|
+
constructor(config, orchestrator, telemetry) {
|
|
10
|
+
this.config = config;
|
|
11
|
+
this.orchestrator = orchestrator;
|
|
12
|
+
this.telemetry = telemetry;
|
|
13
|
+
}
|
|
14
|
+
start() {
|
|
15
|
+
this.telemetry.on('commands:pending', () => {
|
|
16
|
+
void this.fetchAndExecute();
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
async fetchAndExecute() {
|
|
20
|
+
if (this.polling)
|
|
21
|
+
return;
|
|
22
|
+
this.polling = true;
|
|
23
|
+
try {
|
|
24
|
+
const hn = hostname();
|
|
25
|
+
const agentName = getAgentName();
|
|
26
|
+
const response = await fetch(`${this.config.apiHost}/api/v1/deploy/commands?hostname=${encodeURIComponent(hn)}&agentName=${encodeURIComponent(agentName)}`, {
|
|
27
|
+
headers: { Authorization: `Bearer ${this.config.apiKey}` },
|
|
28
|
+
signal: AbortSignal.timeout(10000),
|
|
29
|
+
});
|
|
30
|
+
if (!response.ok) {
|
|
31
|
+
console.error(`Command poll failed: ${response.status}`);
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
const body = (await response.json());
|
|
35
|
+
for (const cmd of body.commands) {
|
|
36
|
+
if (cmd.type === 'deploy') {
|
|
37
|
+
const executor = new DeployExecutor(this.config, this.orchestrator, this.telemetry, cmd);
|
|
38
|
+
// Execute asynchronously — status reported via telemetry
|
|
39
|
+
executor.execute().catch((err) => {
|
|
40
|
+
console.error(`Deploy execution error: ${err.message}`);
|
|
41
|
+
});
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
catch (err) {
|
|
46
|
+
console.error(`Command poll error: ${err.message}`);
|
|
47
|
+
}
|
|
48
|
+
finally {
|
|
49
|
+
this.polling = false;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
//# sourceMappingURL=CommandPoller.js.map
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { Orchestrator } from '../daemon/Orchestrator.js';
|
|
2
|
+
import type { TelemetryReporter } from '../telemetry/TelemetryReporter.js';
|
|
3
|
+
import type { DeployCommand, DeployOptions, TelemetryConfig } from '../types/index.js';
|
|
4
|
+
export declare class DeployExecutor {
|
|
5
|
+
private config;
|
|
6
|
+
private orchestrator;
|
|
7
|
+
private telemetry;
|
|
8
|
+
private cmd;
|
|
9
|
+
private options;
|
|
10
|
+
private buildLog;
|
|
11
|
+
private buildLogLines;
|
|
12
|
+
private nextDeploymentId;
|
|
13
|
+
private onProgress?;
|
|
14
|
+
private onOutput?;
|
|
15
|
+
constructor(config: TelemetryConfig, orchestrator: Orchestrator, telemetry: TelemetryReporter, cmd: DeployCommand, options?: DeployOptions);
|
|
16
|
+
setProgressCallback(cb: (phase: string, error?: string) => void): void;
|
|
17
|
+
setOutputCallback(cb: (line: string) => void): void;
|
|
18
|
+
execute(): Promise<{
|
|
19
|
+
success: boolean;
|
|
20
|
+
error?: string;
|
|
21
|
+
}>;
|
|
22
|
+
private reportPhase;
|
|
23
|
+
private download;
|
|
24
|
+
private verifySha256;
|
|
25
|
+
private extract;
|
|
26
|
+
private fetchSecrets;
|
|
27
|
+
private runCommand;
|
|
28
|
+
private swapSymlink;
|
|
29
|
+
private monitorCrashWindow;
|
|
30
|
+
private reconcileProcesses;
|
|
31
|
+
private cleanupOldReleases;
|
|
32
|
+
}
|
|
33
|
+
//# sourceMappingURL=DeployExecutor.d.ts.map
|
|
@@ -0,0 +1,340 @@
|
|
|
1
|
+
import { execSync, spawn } from 'node:child_process';
|
|
2
|
+
import { createHash } from 'node:crypto';
|
|
3
|
+
import { copyFileSync, createReadStream, createWriteStream, existsSync, mkdirSync, readdirSync, readlinkSync, renameSync, rmSync, statSync, symlinkSync, unlinkSync, writeFileSync, } from 'node:fs';
|
|
4
|
+
import { join } from 'node:path';
|
|
5
|
+
import { Readable } from 'node:stream';
|
|
6
|
+
import { pipeline } from 'node:stream/promises';
|
|
7
|
+
import { DEPLOY_CRASH_WINDOW_DEFAULT, DEPLOY_META_FILE, ORKIFY_DEPLOYS_DIR } from '../constants.js';
|
|
8
|
+
import { detectFramework } from '../detect/framework.js';
|
|
9
|
+
import { getOrkifyConfig } from './config.js';
|
|
10
|
+
export class DeployExecutor {
|
|
11
|
+
config;
|
|
12
|
+
orchestrator;
|
|
13
|
+
telemetry;
|
|
14
|
+
cmd;
|
|
15
|
+
options;
|
|
16
|
+
buildLog = '';
|
|
17
|
+
buildLogLines = [];
|
|
18
|
+
nextDeploymentId;
|
|
19
|
+
onProgress;
|
|
20
|
+
onOutput;
|
|
21
|
+
constructor(config, orchestrator, telemetry, cmd, options) {
|
|
22
|
+
this.config = config;
|
|
23
|
+
this.orchestrator = orchestrator;
|
|
24
|
+
this.telemetry = telemetry;
|
|
25
|
+
this.cmd = cmd;
|
|
26
|
+
this.options = options ?? {};
|
|
27
|
+
}
|
|
28
|
+
setProgressCallback(cb) {
|
|
29
|
+
this.onProgress = cb;
|
|
30
|
+
}
|
|
31
|
+
setOutputCallback(cb) {
|
|
32
|
+
this.onOutput = cb;
|
|
33
|
+
}
|
|
34
|
+
async execute() {
|
|
35
|
+
const deployConfig = this.cmd.deployConfig;
|
|
36
|
+
const deploysDir = this.options.deploysDir ?? ORKIFY_DEPLOYS_DIR;
|
|
37
|
+
const releaseName = this.options.localTarball
|
|
38
|
+
? `local-${this.cmd.version}`
|
|
39
|
+
: `${this.cmd.version}-${this.cmd.artifactId.slice(0, 8)}`;
|
|
40
|
+
const releasesDir = join(deploysDir, 'releases');
|
|
41
|
+
const releaseDir = join(releasesDir, releaseName);
|
|
42
|
+
const currentLink = join(deploysDir, 'current');
|
|
43
|
+
try {
|
|
44
|
+
mkdirSync(releasesDir, { recursive: true });
|
|
45
|
+
// 1. Download or copy local tarball
|
|
46
|
+
this.reportPhase('downloading');
|
|
47
|
+
const tarPath = join(releasesDir, `v${this.cmd.version}.tar.gz`);
|
|
48
|
+
if (this.options.localTarball) {
|
|
49
|
+
copyFileSync(this.options.localTarball, tarPath);
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
await this.download(this.cmd.downloadUrl, tarPath);
|
|
53
|
+
await this.verifySha256(tarPath, this.cmd.sha256);
|
|
54
|
+
}
|
|
55
|
+
// 2. Extract
|
|
56
|
+
this.reportPhase('extracting');
|
|
57
|
+
mkdirSync(releaseDir, { recursive: true });
|
|
58
|
+
await this.extract(tarPath, releaseDir);
|
|
59
|
+
unlinkSync(tarPath);
|
|
60
|
+
// 2b. Write deploy metadata (used by restore to identify the current release)
|
|
61
|
+
writeFileSync(join(releaseDir, DEPLOY_META_FILE), JSON.stringify({
|
|
62
|
+
version: this.cmd.version,
|
|
63
|
+
artifactId: this.cmd.artifactId,
|
|
64
|
+
}), 'utf-8');
|
|
65
|
+
// 2c. Detect Next.js for version skew protection
|
|
66
|
+
if (detectFramework(releaseDir) === 'nextjs') {
|
|
67
|
+
this.nextDeploymentId = `v${this.cmd.version}-${this.cmd.artifactId.slice(0, 8)}`;
|
|
68
|
+
}
|
|
69
|
+
// 3. Fetch secrets
|
|
70
|
+
const secrets = this.options.secrets !== undefined
|
|
71
|
+
? this.options.secrets
|
|
72
|
+
: await this.fetchSecrets(this.cmd.downloadToken);
|
|
73
|
+
// 4. Install + 5. Build
|
|
74
|
+
const buildEnv = { ...secrets, ...deployConfig.buildEnv };
|
|
75
|
+
// Pass NEXT_DEPLOYMENT_ID to build (unless user already set it)
|
|
76
|
+
if (this.nextDeploymentId && !buildEnv.NEXT_DEPLOYMENT_ID) {
|
|
77
|
+
buildEnv.NEXT_DEPLOYMENT_ID = this.nextDeploymentId;
|
|
78
|
+
}
|
|
79
|
+
if (!this.options.skipInstall) {
|
|
80
|
+
this.reportPhase('installing');
|
|
81
|
+
await this.runCommand(deployConfig.install, releaseDir, buildEnv);
|
|
82
|
+
}
|
|
83
|
+
if (!this.options.skipBuild && deployConfig.build) {
|
|
84
|
+
this.reportPhase('building');
|
|
85
|
+
await this.runCommand(deployConfig.build, releaseDir, buildEnv);
|
|
86
|
+
}
|
|
87
|
+
// 6. Swap symlink
|
|
88
|
+
let previousDir = null;
|
|
89
|
+
if (existsSync(currentLink)) {
|
|
90
|
+
try {
|
|
91
|
+
previousDir = readlinkSync(currentLink);
|
|
92
|
+
}
|
|
93
|
+
catch {
|
|
94
|
+
// Not a symlink
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
this.reportPhase('reloading');
|
|
98
|
+
this.swapSymlink(currentLink, releaseDir);
|
|
99
|
+
// 7. Reconcile processes
|
|
100
|
+
await this.reconcileProcesses(currentLink, secrets);
|
|
101
|
+
// 8. Monitor crash window
|
|
102
|
+
if (!this.options.skipMonitor) {
|
|
103
|
+
this.reportPhase('monitoring');
|
|
104
|
+
const crashWindow = deployConfig.crashWindow ?? DEPLOY_CRASH_WINDOW_DEFAULT;
|
|
105
|
+
const healthy = await this.monitorCrashWindow(crashWindow);
|
|
106
|
+
if (!healthy) {
|
|
107
|
+
if (previousDir && existsSync(previousDir)) {
|
|
108
|
+
this.swapSymlink(currentLink, previousDir);
|
|
109
|
+
await this.reconcileProcesses(currentLink, secrets);
|
|
110
|
+
this.reportPhase('rolled_back', 'Workers crashed within monitoring window');
|
|
111
|
+
return {
|
|
112
|
+
success: false,
|
|
113
|
+
error: 'Workers crashed within monitoring window, rolled back',
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
else {
|
|
117
|
+
const msg = 'Workers crashed and no previous version to rollback to';
|
|
118
|
+
this.reportPhase('failed', msg);
|
|
119
|
+
return { success: false, error: msg };
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
// 9. Success — health checks are now handled per-process during reconcile/reload
|
|
124
|
+
this.reportPhase('success');
|
|
125
|
+
// 10. Cleanup old releases (preserve the previous version for rollback)
|
|
126
|
+
this.cleanupOldReleases(releasesDir, 3, previousDir);
|
|
127
|
+
return { success: true };
|
|
128
|
+
}
|
|
129
|
+
catch (err) {
|
|
130
|
+
const message = err.message;
|
|
131
|
+
this.reportPhase('failed', message);
|
|
132
|
+
return { success: false, error: message };
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
reportPhase(phase, error) {
|
|
136
|
+
console.log(`[deploy] v${this.cmd.version}: ${phase}${error ? ` — ${error}` : ''}`);
|
|
137
|
+
this.onProgress?.(phase, error);
|
|
138
|
+
if (this.options.skipTelemetry)
|
|
139
|
+
return;
|
|
140
|
+
const status = {
|
|
141
|
+
deployId: this.cmd.deployId,
|
|
142
|
+
targetId: this.cmd.targetId,
|
|
143
|
+
phase,
|
|
144
|
+
buildLog: this.buildLog.slice(-5000),
|
|
145
|
+
error,
|
|
146
|
+
};
|
|
147
|
+
this.telemetry.setDeployStatus(status);
|
|
148
|
+
// Emit deploy lifecycle events for SSE streaming.
|
|
149
|
+
// Fields must be nested inside `details` so they survive Zod parsing
|
|
150
|
+
// on the ingest endpoint and end up in the ClickHouse details column.
|
|
151
|
+
if (phase === 'downloading') {
|
|
152
|
+
this.telemetry.emitEvent('process:deploy-started', 'deploy', {
|
|
153
|
+
details: { deployId: this.cmd.deployId, targetId: this.cmd.targetId },
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
else if (phase === 'success') {
|
|
157
|
+
this.telemetry.emitEvent('process:deploy-finished', 'deploy', {
|
|
158
|
+
details: { deployId: this.cmd.deployId, targetId: this.cmd.targetId },
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
else if (phase === 'failed' || phase === 'rolled_back') {
|
|
162
|
+
this.telemetry.emitEvent('process:deploy-failed', 'deploy', {
|
|
163
|
+
details: {
|
|
164
|
+
deployId: this.cmd.deployId,
|
|
165
|
+
targetId: this.cmd.targetId,
|
|
166
|
+
error: error ?? phase,
|
|
167
|
+
},
|
|
168
|
+
});
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
async download(url, destPath) {
|
|
172
|
+
const response = await fetch(url);
|
|
173
|
+
if (!response.ok || !response.body) {
|
|
174
|
+
throw new Error(`Download failed: ${response.status}`);
|
|
175
|
+
}
|
|
176
|
+
const fileStream = createWriteStream(destPath);
|
|
177
|
+
const nodeStream = Readable.fromWeb(response.body);
|
|
178
|
+
await pipeline(nodeStream, fileStream);
|
|
179
|
+
}
|
|
180
|
+
async verifySha256(filePath, expected) {
|
|
181
|
+
const hash = createHash('sha256');
|
|
182
|
+
const stream = createReadStream(filePath);
|
|
183
|
+
for await (const chunk of stream) {
|
|
184
|
+
hash.update(chunk);
|
|
185
|
+
}
|
|
186
|
+
const actual = hash.digest('hex');
|
|
187
|
+
if (actual !== expected) {
|
|
188
|
+
throw new Error(`SHA-256 mismatch: expected ${expected.slice(0, 12)}..., got ${actual.slice(0, 12)}...`);
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
extract(tarPath, destDir) {
|
|
192
|
+
execSync(`tar xzf "${tarPath}" -C "${destDir}"`, { stdio: 'pipe' });
|
|
193
|
+
}
|
|
194
|
+
async fetchSecrets(token) {
|
|
195
|
+
try {
|
|
196
|
+
const response = await fetch(`${this.config.apiHost}/api/v1/deploy/secrets`, {
|
|
197
|
+
method: 'POST',
|
|
198
|
+
headers: { 'Content-Type': 'application/json' },
|
|
199
|
+
body: JSON.stringify({ token }),
|
|
200
|
+
signal: AbortSignal.timeout(10000),
|
|
201
|
+
});
|
|
202
|
+
if (!response.ok) {
|
|
203
|
+
console.error(`Secrets fetch failed: ${response.status}`);
|
|
204
|
+
return {};
|
|
205
|
+
}
|
|
206
|
+
const body = (await response.json());
|
|
207
|
+
return body.secrets ?? {};
|
|
208
|
+
}
|
|
209
|
+
catch (err) {
|
|
210
|
+
console.error(`Secrets fetch error: ${err.message}`);
|
|
211
|
+
return {};
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
async runCommand(cmd, cwd, env) {
|
|
215
|
+
// Strip NODE_ENV during install/build so devDependencies (TypeScript,
|
|
216
|
+
// bundlers, etc.) are installed. Runtime processes get NODE_ENV from
|
|
217
|
+
// secrets/env as configured — this only affects the build phase.
|
|
218
|
+
const { NODE_ENV: _stripped, ...parentEnv } = process.env;
|
|
219
|
+
return new Promise((resolve, reject) => {
|
|
220
|
+
const isWin = process.platform === 'win32';
|
|
221
|
+
const child = spawn(isWin ? 'cmd.exe' : 'sh', isWin ? ['/c', cmd] : ['-c', cmd], {
|
|
222
|
+
cwd,
|
|
223
|
+
env: { ...parentEnv, ...env },
|
|
224
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
225
|
+
});
|
|
226
|
+
const capture = (data) => {
|
|
227
|
+
const text = data.toString();
|
|
228
|
+
this.buildLogLines.push(...text.split('\n'));
|
|
229
|
+
if (this.buildLogLines.length > 1000) {
|
|
230
|
+
this.buildLogLines.splice(0, this.buildLogLines.length - 1000);
|
|
231
|
+
}
|
|
232
|
+
this.buildLog = this.buildLogLines.join('\n');
|
|
233
|
+
if (this.onOutput) {
|
|
234
|
+
for (const line of text.split('\n')) {
|
|
235
|
+
if (line.trim())
|
|
236
|
+
this.onOutput(line);
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
};
|
|
240
|
+
child.stdout?.on('data', capture);
|
|
241
|
+
child.stderr?.on('data', capture);
|
|
242
|
+
child.on('exit', (code) => {
|
|
243
|
+
if (code === 0)
|
|
244
|
+
resolve();
|
|
245
|
+
else
|
|
246
|
+
reject(new Error(`Command "${cmd}" exited with code ${code}\n${this.buildLog}`));
|
|
247
|
+
});
|
|
248
|
+
child.on('error', reject);
|
|
249
|
+
});
|
|
250
|
+
}
|
|
251
|
+
swapSymlink(linkPath, targetPath) {
|
|
252
|
+
if (process.platform === 'win32') {
|
|
253
|
+
if (existsSync(linkPath))
|
|
254
|
+
rmSync(linkPath, { recursive: true });
|
|
255
|
+
execSync(`mklink /J "${linkPath}" "${targetPath}"`, { shell: 'cmd.exe' });
|
|
256
|
+
}
|
|
257
|
+
else {
|
|
258
|
+
const tmpLink = linkPath + '.tmp';
|
|
259
|
+
if (existsSync(tmpLink))
|
|
260
|
+
unlinkSync(tmpLink);
|
|
261
|
+
symlinkSync(targetPath, tmpLink);
|
|
262
|
+
renameSync(tmpLink, linkPath);
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
async monitorCrashWindow(windowSeconds) {
|
|
266
|
+
return new Promise((resolve) => {
|
|
267
|
+
let settled = false;
|
|
268
|
+
const onExit = (data) => {
|
|
269
|
+
if (!settled && data.code !== 0 && data.code !== null) {
|
|
270
|
+
settled = true;
|
|
271
|
+
clearTimeout(timer);
|
|
272
|
+
this.orchestrator.removeListener('worker:exit', onExit);
|
|
273
|
+
resolve(false);
|
|
274
|
+
}
|
|
275
|
+
};
|
|
276
|
+
this.orchestrator.on('worker:exit', onExit);
|
|
277
|
+
const timer = setTimeout(() => {
|
|
278
|
+
if (!settled) {
|
|
279
|
+
settled = true;
|
|
280
|
+
this.orchestrator.removeListener('worker:exit', onExit);
|
|
281
|
+
resolve(true);
|
|
282
|
+
}
|
|
283
|
+
}, windowSeconds * 1000);
|
|
284
|
+
timer.unref();
|
|
285
|
+
});
|
|
286
|
+
}
|
|
287
|
+
async reconcileProcesses(currentLink, secrets) {
|
|
288
|
+
const fileConfig = getOrkifyConfig(currentLink);
|
|
289
|
+
if (!fileConfig?.processes?.length) {
|
|
290
|
+
throw new Error('No processes defined in orkify.yml');
|
|
291
|
+
}
|
|
292
|
+
const configs = fileConfig.processes;
|
|
293
|
+
// Resolve script paths relative to currentLink and set cwd
|
|
294
|
+
const resolvedConfigs = configs.map((config) => ({
|
|
295
|
+
...config,
|
|
296
|
+
script: join(currentLink, config.script),
|
|
297
|
+
cwd: currentLink,
|
|
298
|
+
}));
|
|
299
|
+
// Default NODE_ENV=production for runtime processes during deploy.
|
|
300
|
+
// Users can override this via secrets/env vars on the dashboard.
|
|
301
|
+
const runtimeEnv = { NODE_ENV: 'production', ...secrets };
|
|
302
|
+
// Pass NEXT_DEPLOYMENT_ID to runtime for version skew protection
|
|
303
|
+
if (this.nextDeploymentId && !runtimeEnv.NEXT_DEPLOYMENT_ID) {
|
|
304
|
+
runtimeEnv.NEXT_DEPLOYMENT_ID = this.nextDeploymentId;
|
|
305
|
+
}
|
|
306
|
+
const result = await this.orchestrator.reconcile(resolvedConfigs, runtimeEnv);
|
|
307
|
+
if (result.started.length > 0) {
|
|
308
|
+
console.log(`[deploy] Started: ${result.started.join(', ')}`);
|
|
309
|
+
}
|
|
310
|
+
if (result.reloaded.length > 0) {
|
|
311
|
+
console.log(`[deploy] Reloaded: ${result.reloaded.join(', ')}`);
|
|
312
|
+
}
|
|
313
|
+
if (result.deleted.length > 0) {
|
|
314
|
+
console.log(`[deploy] Deleted: ${result.deleted.join(', ')}`);
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
cleanupOldReleases(releasesDir, keep, preserveDir) {
|
|
318
|
+
try {
|
|
319
|
+
const entries = readdirSync(releasesDir)
|
|
320
|
+
.filter((e) => statSync(join(releasesDir, e)).isDirectory())
|
|
321
|
+
.sort((a, b) => {
|
|
322
|
+
// Sort by directory mtime descending (newest first)
|
|
323
|
+
const mtimeA = statSync(join(releasesDir, a)).mtimeMs;
|
|
324
|
+
const mtimeB = statSync(join(releasesDir, b)).mtimeMs;
|
|
325
|
+
return mtimeB - mtimeA;
|
|
326
|
+
});
|
|
327
|
+
for (const entry of entries.slice(keep)) {
|
|
328
|
+
const dir = join(releasesDir, entry);
|
|
329
|
+
// Never delete the previous release — it's the rollback target
|
|
330
|
+
if (preserveDir && dir === preserveDir)
|
|
331
|
+
continue;
|
|
332
|
+
rmSync(dir, { recursive: true, force: true });
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
catch {
|
|
336
|
+
// Ignore cleanup errors
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
}
|
|
340
|
+
//# sourceMappingURL=DeployExecutor.js.map
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { SavedState } from '../types/index.js';
|
|
2
|
+
interface PackageManager {
|
|
3
|
+
name: string;
|
|
4
|
+
install: string;
|
|
5
|
+
}
|
|
6
|
+
export declare function detectPackageManager(projectDir: string): PackageManager;
|
|
7
|
+
export declare function detectBuildCommand(packageJson: Record<string, unknown>, pm: PackageManager): null | string;
|
|
8
|
+
export declare function detectEntryPoint(packageJson: Record<string, unknown>, projectDir: string): string;
|
|
9
|
+
export declare function readPackageJson(projectDir: string): Record<string, unknown>;
|
|
10
|
+
export declare function getOrkifyConfig(projectDir: string): null | SavedState;
|
|
11
|
+
export declare function saveOrkifyConfig(projectDir: string, config: SavedState): void;
|
|
12
|
+
export declare function interactiveConfig(projectDir: string): Promise<SavedState>;
|
|
13
|
+
export declare function collectGitMetadata(projectDir: string): {
|
|
14
|
+
gitSha?: string;
|
|
15
|
+
gitBranch?: string;
|
|
16
|
+
gitAuthor?: string;
|
|
17
|
+
gitMessage?: string;
|
|
18
|
+
};
|
|
19
|
+
export {};
|
|
20
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
import { execSync } from 'node:child_process';
|
|
2
|
+
import { existsSync, readFileSync, writeFileSync } from 'node:fs';
|
|
3
|
+
import { join } from 'node:path';
|
|
4
|
+
import { createInterface } from 'node:readline';
|
|
5
|
+
import { parse, stringify } from 'yaml';
|
|
6
|
+
import { DEFAULT_LOG_MAX_AGE, DEFAULT_LOG_MAX_FILES, DEFAULT_LOG_MAX_SIZE, ORKIFY_CONFIG_FILE, } from '../constants.js';
|
|
7
|
+
export function detectPackageManager(projectDir) {
|
|
8
|
+
if (existsSync(join(projectDir, 'pnpm-lock.yaml')))
|
|
9
|
+
return { name: 'pnpm', install: 'pnpm install --frozen-lockfile' };
|
|
10
|
+
if (existsSync(join(projectDir, 'yarn.lock')))
|
|
11
|
+
return { name: 'yarn', install: 'yarn install --frozen-lockfile' };
|
|
12
|
+
if (existsSync(join(projectDir, 'bun.lock')))
|
|
13
|
+
return { name: 'bun', install: 'bun install --frozen-lockfile' };
|
|
14
|
+
return { name: 'npm', install: 'npm ci' };
|
|
15
|
+
}
|
|
16
|
+
export function detectBuildCommand(packageJson, pm) {
|
|
17
|
+
const scripts = packageJson.scripts;
|
|
18
|
+
if (scripts?.build)
|
|
19
|
+
return `${pm.name} run build`;
|
|
20
|
+
return null;
|
|
21
|
+
}
|
|
22
|
+
export function detectEntryPoint(packageJson, projectDir) {
|
|
23
|
+
if (packageJson.main && typeof packageJson.main === 'string')
|
|
24
|
+
return packageJson.main;
|
|
25
|
+
const candidates = [
|
|
26
|
+
'server.mjs',
|
|
27
|
+
'server.js',
|
|
28
|
+
'app.mjs',
|
|
29
|
+
'app.js',
|
|
30
|
+
'index.mjs',
|
|
31
|
+
'index.js',
|
|
32
|
+
'src/server.mjs',
|
|
33
|
+
'src/server.js',
|
|
34
|
+
'src/index.mjs',
|
|
35
|
+
'src/index.js',
|
|
36
|
+
'dist/server.js',
|
|
37
|
+
'dist/index.js',
|
|
38
|
+
'build/index.js',
|
|
39
|
+
];
|
|
40
|
+
for (const candidate of candidates) {
|
|
41
|
+
if (existsSync(join(projectDir, candidate)))
|
|
42
|
+
return candidate;
|
|
43
|
+
}
|
|
44
|
+
return 'server.js';
|
|
45
|
+
}
|
|
46
|
+
export function readPackageJson(projectDir) {
|
|
47
|
+
const pkgPath = join(projectDir, 'package.json');
|
|
48
|
+
if (!existsSync(pkgPath)) {
|
|
49
|
+
throw new Error(`No package.json found in ${projectDir}`);
|
|
50
|
+
}
|
|
51
|
+
return JSON.parse(readFileSync(pkgPath, 'utf-8'));
|
|
52
|
+
}
|
|
53
|
+
export function getOrkifyConfig(projectDir) {
|
|
54
|
+
const configPath = join(projectDir, ORKIFY_CONFIG_FILE);
|
|
55
|
+
if (!existsSync(configPath))
|
|
56
|
+
return null;
|
|
57
|
+
try {
|
|
58
|
+
const content = readFileSync(configPath, 'utf-8');
|
|
59
|
+
const raw = parse(content);
|
|
60
|
+
if (!raw)
|
|
61
|
+
return null;
|
|
62
|
+
return raw;
|
|
63
|
+
}
|
|
64
|
+
catch {
|
|
65
|
+
return null;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
export function saveOrkifyConfig(projectDir, config) {
|
|
69
|
+
const configPath = join(projectDir, ORKIFY_CONFIG_FILE);
|
|
70
|
+
writeFileSync(configPath, stringify(config, { defaultStringType: 'QUOTE_DOUBLE' }), 'utf-8');
|
|
71
|
+
}
|
|
72
|
+
async function prompt(question, prefill) {
|
|
73
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
74
|
+
return new Promise((resolve) => {
|
|
75
|
+
rl.question(`${question}: `, (answer) => {
|
|
76
|
+
rl.close();
|
|
77
|
+
resolve(answer.trim());
|
|
78
|
+
});
|
|
79
|
+
rl.write(prefill);
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
export async function interactiveConfig(projectDir) {
|
|
83
|
+
const hasPkg = existsSync(join(projectDir, 'package.json'));
|
|
84
|
+
const pkg = hasPkg ? readPackageJson(projectDir) : {};
|
|
85
|
+
const pm = detectPackageManager(projectDir);
|
|
86
|
+
const buildCmd = detectBuildCommand(pkg, pm);
|
|
87
|
+
const entry = detectEntryPoint(pkg, projectDir);
|
|
88
|
+
console.log('\nConfiguring deployment for this project:\n');
|
|
89
|
+
const install = await prompt('Install command (empty to skip)', hasPkg ? pm.install : '');
|
|
90
|
+
const build = await prompt('Build command (empty to skip)', hasPkg ? buildCmd || `${pm.name} run build` : '');
|
|
91
|
+
const entryPoint = await prompt('Entry point', entry);
|
|
92
|
+
const workersStr = await prompt('Workers (0 = max CPU cores, 1 = fork mode)', '0');
|
|
93
|
+
const parsed = parseInt(workersStr, 10);
|
|
94
|
+
const workers = Number.isNaN(parsed) ? 0 : parsed;
|
|
95
|
+
const deploy = { install };
|
|
96
|
+
if (build) {
|
|
97
|
+
deploy.build = build;
|
|
98
|
+
}
|
|
99
|
+
const process = {
|
|
100
|
+
name: 'app',
|
|
101
|
+
script: entryPoint,
|
|
102
|
+
cwd: projectDir,
|
|
103
|
+
workerCount: workers,
|
|
104
|
+
execMode: workers === 0 || workers > 1 ? 'cluster' : 'fork',
|
|
105
|
+
watch: false,
|
|
106
|
+
env: {},
|
|
107
|
+
nodeArgs: [],
|
|
108
|
+
args: [],
|
|
109
|
+
killTimeout: 5000,
|
|
110
|
+
maxRestarts: 10,
|
|
111
|
+
minUptime: 1000,
|
|
112
|
+
restartDelay: 100,
|
|
113
|
+
sticky: false,
|
|
114
|
+
logMaxSize: DEFAULT_LOG_MAX_SIZE,
|
|
115
|
+
logMaxFiles: DEFAULT_LOG_MAX_FILES,
|
|
116
|
+
logMaxAge: DEFAULT_LOG_MAX_AGE,
|
|
117
|
+
};
|
|
118
|
+
return {
|
|
119
|
+
version: 1,
|
|
120
|
+
deploy,
|
|
121
|
+
processes: [process],
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
export function collectGitMetadata(projectDir) {
|
|
125
|
+
const meta = {};
|
|
126
|
+
try {
|
|
127
|
+
meta.gitSha = execSync('git rev-parse HEAD', { cwd: projectDir, encoding: 'utf-8' }).trim();
|
|
128
|
+
}
|
|
129
|
+
catch {
|
|
130
|
+
// Not a git repo
|
|
131
|
+
}
|
|
132
|
+
try {
|
|
133
|
+
meta.gitBranch = execSync('git branch --show-current', {
|
|
134
|
+
cwd: projectDir,
|
|
135
|
+
encoding: 'utf-8',
|
|
136
|
+
}).trim();
|
|
137
|
+
}
|
|
138
|
+
catch {
|
|
139
|
+
// git not available
|
|
140
|
+
}
|
|
141
|
+
try {
|
|
142
|
+
meta.gitAuthor = execSync('git log -1 --format=%an', {
|
|
143
|
+
cwd: projectDir,
|
|
144
|
+
encoding: 'utf-8',
|
|
145
|
+
}).trim();
|
|
146
|
+
}
|
|
147
|
+
catch {
|
|
148
|
+
// git not available
|
|
149
|
+
}
|
|
150
|
+
try {
|
|
151
|
+
meta.gitMessage = execSync('git log -1 --format=%s', {
|
|
152
|
+
cwd: projectDir,
|
|
153
|
+
encoding: 'utf-8',
|
|
154
|
+
}).trim();
|
|
155
|
+
}
|
|
156
|
+
catch {
|
|
157
|
+
// git not available
|
|
158
|
+
}
|
|
159
|
+
return meta;
|
|
160
|
+
}
|
|
161
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
export function parseEnvFile(content) {
|
|
2
|
+
const env = {};
|
|
3
|
+
for (const line of content.split('\n')) {
|
|
4
|
+
const trimmed = line.trim();
|
|
5
|
+
if (!trimmed || trimmed.startsWith('#'))
|
|
6
|
+
continue;
|
|
7
|
+
const eqIndex = trimmed.indexOf('=');
|
|
8
|
+
if (eqIndex === -1)
|
|
9
|
+
continue;
|
|
10
|
+
const key = trimmed.slice(0, eqIndex).trim();
|
|
11
|
+
const value = trimmed.slice(eqIndex + 1).trim();
|
|
12
|
+
if (key)
|
|
13
|
+
env[key] = value;
|
|
14
|
+
}
|
|
15
|
+
return env;
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=env.js.map
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
interface FileDep {
|
|
2
|
+
dir: string;
|
|
3
|
+
files: string[];
|
|
4
|
+
}
|
|
5
|
+
/**
|
|
6
|
+
* Scan package.json for `file:` dependencies. For each one, walk the
|
|
7
|
+
* referenced directory and collect its files. Returns a rewritten
|
|
8
|
+
* package.json string with paths pointing to `.file-deps/<name>/` and
|
|
9
|
+
* a map of the collected files — or null if there are no file deps.
|
|
10
|
+
*/
|
|
11
|
+
export declare function bundleFileDeps(projectDir: string): null | {
|
|
12
|
+
rewrittenPkg: string;
|
|
13
|
+
rewrittenLock: null | string;
|
|
14
|
+
fileDeps: Map<string, FileDep>;
|
|
15
|
+
};
|
|
16
|
+
/**
|
|
17
|
+
* Create a tar.gz archive of the project directory.
|
|
18
|
+
*
|
|
19
|
+
* Walks the directory tree, respecting .gitignore files from the git root
|
|
20
|
+
* all the way down into the project, plus a built-in exclude list
|
|
21
|
+
* (node_modules, .git, .env, etc.).
|
|
22
|
+
*
|
|
23
|
+
* Any `file:` dependencies in package.json are bundled into the tarball
|
|
24
|
+
* under `.file-deps/<name>/` and the paths are rewritten so `npm ci`
|
|
25
|
+
* can resolve them on the deploy target.
|
|
26
|
+
*/
|
|
27
|
+
export interface TarballOptions {
|
|
28
|
+
excludeSourceMaps?: boolean;
|
|
29
|
+
}
|
|
30
|
+
export declare function createTarball(projectDir: string, options?: TarballOptions): Promise<string>;
|
|
31
|
+
export {};
|
|
32
|
+
//# sourceMappingURL=tarball.d.ts.map
|