@launchfile/macos-dev 0.1.4 → 0.2.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.
- package/dist/__tests__/bootstrap.test.d.ts +2 -0
- package/dist/__tests__/bootstrap.test.js +90 -0
- package/dist/__tests__/dry-run.test.js +21 -9
- package/dist/__tests__/env-writer.test.js +82 -8
- package/dist/bootstrap.d.ts +58 -0
- package/dist/bootstrap.js +221 -0
- package/dist/env-writer.d.ts +14 -11
- package/dist/env-writer.js +30 -3
- package/dist/index.d.ts +2 -0
- package/dist/index.js +1 -0
- package/dist/provider.js +30 -48
- package/package.json +8 -3
- package/CLAUDE.md +0 -37
- package/dist/__tests__/dry-run.test.d.ts.map +0 -1
- package/dist/__tests__/dry-run.test.js.map +0 -1
- package/dist/__tests__/env-writer.test.d.ts.map +0 -1
- package/dist/__tests__/env-writer.test.js.map +0 -1
- package/dist/__tests__/lockfile-detect.test.d.ts.map +0 -1
- package/dist/__tests__/lockfile-detect.test.js.map +0 -1
- package/dist/__tests__/port-allocator.test.d.ts.map +0 -1
- package/dist/__tests__/port-allocator.test.js.map +0 -1
- package/dist/__tests__/secret-generator.test.d.ts.map +0 -1
- package/dist/__tests__/secret-generator.test.js.map +0 -1
- package/dist/__tests__/state.test.d.ts.map +0 -1
- package/dist/__tests__/state.test.js.map +0 -1
- package/dist/cli.d.ts.map +0 -1
- package/dist/cli.js.map +0 -1
- package/dist/env-writer.d.ts.map +0 -1
- package/dist/env-writer.js.map +0 -1
- package/dist/health.d.ts.map +0 -1
- package/dist/health.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/lockfile-detect.d.ts.map +0 -1
- package/dist/lockfile-detect.js.map +0 -1
- package/dist/port-allocator.d.ts.map +0 -1
- package/dist/port-allocator.js.map +0 -1
- package/dist/prereqs.d.ts.map +0 -1
- package/dist/prereqs.js.map +0 -1
- package/dist/process-manager.d.ts.map +0 -1
- package/dist/process-manager.js.map +0 -1
- package/dist/provider.d.ts.map +0 -1
- package/dist/provider.js.map +0 -1
- package/dist/resources/index.d.ts.map +0 -1
- package/dist/resources/index.js.map +0 -1
- package/dist/resources/mysql.d.ts.map +0 -1
- package/dist/resources/mysql.js.map +0 -1
- package/dist/resources/postgres.d.ts.map +0 -1
- package/dist/resources/postgres.js.map +0 -1
- package/dist/resources/redis.d.ts.map +0 -1
- package/dist/resources/redis.js.map +0 -1
- package/dist/resources/sqlite.d.ts.map +0 -1
- package/dist/resources/sqlite.js.map +0 -1
- package/dist/resources/types.d.ts.map +0 -1
- package/dist/resources/types.js.map +0 -1
- package/dist/runtimes/bun.d.ts.map +0 -1
- package/dist/runtimes/bun.js.map +0 -1
- package/dist/runtimes/index.d.ts.map +0 -1
- package/dist/runtimes/index.js.map +0 -1
- package/dist/runtimes/node.d.ts.map +0 -1
- package/dist/runtimes/node.js.map +0 -1
- package/dist/runtimes/python.d.ts.map +0 -1
- package/dist/runtimes/python.js.map +0 -1
- package/dist/runtimes/ruby.d.ts.map +0 -1
- package/dist/runtimes/ruby.js.map +0 -1
- package/dist/runtimes/types.d.ts.map +0 -1
- package/dist/runtimes/types.js.map +0 -1
- package/dist/secret-generator.d.ts.map +0 -1
- package/dist/secret-generator.js.map +0 -1
- package/dist/shell.d.ts.map +0 -1
- package/dist/shell.js.map +0 -1
- package/dist/state.d.ts.map +0 -1
- package/dist/state.js.map +0 -1
- package/dist/storage.d.ts.map +0 -1
- package/dist/storage.js.map +0 -1
- package/src/__tests__/dry-run.test.ts +0 -157
- package/src/__tests__/env-writer.test.ts +0 -156
- package/src/__tests__/lockfile-detect.test.ts +0 -74
- package/src/__tests__/port-allocator.test.ts +0 -59
- package/src/__tests__/secret-generator.test.ts +0 -31
- package/src/__tests__/state.test.ts +0 -33
- package/src/cli.ts +0 -78
- package/src/env-writer.ts +0 -231
- package/src/health.ts +0 -80
- package/src/index.ts +0 -9
- package/src/lockfile-detect.ts +0 -48
- package/src/port-allocator.ts +0 -97
- package/src/prereqs.ts +0 -32
- package/src/process-manager.ts +0 -242
- package/src/provider.ts +0 -415
- package/src/resources/index.ts +0 -29
- package/src/resources/mysql.ts +0 -98
- package/src/resources/postgres.ts +0 -133
- package/src/resources/redis.ts +0 -58
- package/src/resources/sqlite.ts +0 -52
- package/src/resources/types.ts +0 -47
- package/src/runtimes/bun.ts +0 -25
- package/src/runtimes/index.ts +0 -24
- package/src/runtimes/node.ts +0 -71
- package/src/runtimes/python.ts +0 -42
- package/src/runtimes/ruby.ts +0 -55
- package/src/runtimes/types.ts +0 -16
- package/src/secret-generator.ts +0 -32
- package/src/shell.ts +0 -70
- package/src/state.ts +0 -92
- package/src/storage.ts +0 -67
- package/tsconfig.json +0 -18
package/src/shell.ts
DELETED
|
@@ -1,70 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Shell execution helper with timeout, logging, and structured results.
|
|
3
|
-
*/
|
|
4
|
-
|
|
5
|
-
import { exec as cpExec, type ExecOptions } from "node:child_process";
|
|
6
|
-
|
|
7
|
-
export interface ShellResult {
|
|
8
|
-
exitCode: number;
|
|
9
|
-
stdout: string;
|
|
10
|
-
stderr: string;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
export interface ShellOpts {
|
|
14
|
-
cwd?: string;
|
|
15
|
-
env?: Record<string, string>;
|
|
16
|
-
timeout?: number;
|
|
17
|
-
/** If true, don't log the command being run */
|
|
18
|
-
silent?: boolean;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
/**
|
|
22
|
-
* Run a shell command and return structured output.
|
|
23
|
-
* Throws on non-zero exit code unless `allowFailure` is set.
|
|
24
|
-
*/
|
|
25
|
-
export async function shell(
|
|
26
|
-
command: string,
|
|
27
|
-
opts: ShellOpts & { allowFailure?: boolean } = {},
|
|
28
|
-
): Promise<ShellResult> {
|
|
29
|
-
if (!opts.silent) {
|
|
30
|
-
console.log(` $ ${command}`);
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
const execOpts: ExecOptions = {
|
|
34
|
-
cwd: opts.cwd,
|
|
35
|
-
env: opts.env ? { ...process.env, ...opts.env } : undefined,
|
|
36
|
-
timeout: opts.timeout ?? 120_000,
|
|
37
|
-
maxBuffer: 10 * 1024 * 1024,
|
|
38
|
-
};
|
|
39
|
-
|
|
40
|
-
return new Promise((resolve, reject) => {
|
|
41
|
-
cpExec(command, execOpts, (error, stdout, stderr) => {
|
|
42
|
-
const result: ShellResult = {
|
|
43
|
-
exitCode: error?.code ?? (typeof error?.code === "number" ? error.code : 0),
|
|
44
|
-
stdout: typeof stdout === "string" ? stdout : "",
|
|
45
|
-
stderr: typeof stderr === "string" ? stderr : "",
|
|
46
|
-
};
|
|
47
|
-
|
|
48
|
-
// Node's exec sets error.code to the exit code on non-zero
|
|
49
|
-
if (error && result.exitCode === 0) {
|
|
50
|
-
result.exitCode = 1;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
if (error && !opts.allowFailure) {
|
|
54
|
-
reject(
|
|
55
|
-
Object.assign(new Error(`Command failed: ${command}\n${result.stderr}`), {
|
|
56
|
-
result,
|
|
57
|
-
}),
|
|
58
|
-
);
|
|
59
|
-
} else {
|
|
60
|
-
resolve(result);
|
|
61
|
-
}
|
|
62
|
-
});
|
|
63
|
-
});
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
/** Run a command, return true if exit code is 0 */
|
|
67
|
-
export async function shellOk(command: string, opts?: ShellOpts): Promise<boolean> {
|
|
68
|
-
const result = await shell(command, { ...opts, allowFailure: true, silent: true });
|
|
69
|
-
return result.exitCode === 0;
|
|
70
|
-
}
|
package/src/state.ts
DELETED
|
@@ -1,92 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* State management for the macOS dev provider.
|
|
3
|
-
*
|
|
4
|
-
* Persists secrets, ports, and resource state in .launchfile/state.json
|
|
5
|
-
* so credentials and ports are stable across restarts.
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
import { readFile, writeFile, mkdir } from "node:fs/promises";
|
|
9
|
-
import { join } from "node:path";
|
|
10
|
-
import { createHash } from "node:crypto";
|
|
11
|
-
|
|
12
|
-
export interface ResourceState {
|
|
13
|
-
type: string;
|
|
14
|
-
name: string;
|
|
15
|
-
brewService?: string;
|
|
16
|
-
port: number;
|
|
17
|
-
dbName?: string;
|
|
18
|
-
user?: string;
|
|
19
|
-
password?: string;
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
export interface LaunchState {
|
|
23
|
-
version: 1;
|
|
24
|
-
appName: string;
|
|
25
|
-
launchfileHash: string;
|
|
26
|
-
createdAt: string;
|
|
27
|
-
updatedAt: string;
|
|
28
|
-
resources: Record<string, ResourceState>;
|
|
29
|
-
secrets: Record<string, string>;
|
|
30
|
-
ports: Record<string, number>;
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
const STATE_DIR = ".launchfile";
|
|
34
|
-
const STATE_FILE = "state.json";
|
|
35
|
-
|
|
36
|
-
function stateDir(projectDir: string): string {
|
|
37
|
-
return join(projectDir, STATE_DIR);
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
function statePath(projectDir: string): string {
|
|
41
|
-
return join(stateDir(projectDir), STATE_FILE);
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
export function hashLaunchfile(content: string): string {
|
|
45
|
-
return createHash("sha256").update(content).digest("hex").slice(0, 16);
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
/** Load state from disk, or return null if none exists */
|
|
49
|
-
export async function loadState(projectDir: string): Promise<LaunchState | null> {
|
|
50
|
-
try {
|
|
51
|
-
const raw = await readFile(statePath(projectDir), "utf8");
|
|
52
|
-
return JSON.parse(raw) as LaunchState;
|
|
53
|
-
} catch {
|
|
54
|
-
return null;
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
/** Create a fresh state object */
|
|
59
|
-
export function initState(appName: string, launchfileContent: string): LaunchState {
|
|
60
|
-
const now = new Date().toISOString();
|
|
61
|
-
return {
|
|
62
|
-
version: 1,
|
|
63
|
-
appName,
|
|
64
|
-
launchfileHash: hashLaunchfile(launchfileContent),
|
|
65
|
-
createdAt: now,
|
|
66
|
-
updatedAt: now,
|
|
67
|
-
resources: {},
|
|
68
|
-
secrets: {},
|
|
69
|
-
ports: {},
|
|
70
|
-
};
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
/** Save state to disk */
|
|
74
|
-
export async function saveState(projectDir: string, state: LaunchState): Promise<void> {
|
|
75
|
-
state.updatedAt = new Date().toISOString();
|
|
76
|
-
// Security: restrict directory/file permissions — state.json contains
|
|
77
|
-
// database passwords and generated secrets in plaintext.
|
|
78
|
-
await mkdir(stateDir(projectDir), { recursive: true, mode: 0o700 });
|
|
79
|
-
await writeFile(statePath(projectDir), JSON.stringify(state, null, 2) + "\n", { mode: 0o600 });
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
/** Ensure .launchfile directories exist */
|
|
83
|
-
export async function ensureDirs(projectDir: string): Promise<void> {
|
|
84
|
-
const dirs = ["storage", "tmp", "logs", "data", "env"];
|
|
85
|
-
// Security: restrict permissions — these dirs contain secrets, logs, env files
|
|
86
|
-
await Promise.all(
|
|
87
|
-
dirs.map((d) => mkdir(join(projectDir, STATE_DIR, d), { recursive: true, mode: 0o700 })),
|
|
88
|
-
);
|
|
89
|
-
// Safety net: write a .gitignore inside .launchfile/ so secrets aren't
|
|
90
|
-
// accidentally committed even if the project's .gitignore doesn't exclude it.
|
|
91
|
-
await writeFile(join(projectDir, STATE_DIR, ".gitignore"), "*\n", { mode: 0o644 });
|
|
92
|
-
}
|
package/src/storage.ts
DELETED
|
@@ -1,67 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Local storage provisioning for Launchfile volumes.
|
|
3
|
-
*
|
|
4
|
-
* Maps container paths to local directories under .launchfile/.
|
|
5
|
-
*/
|
|
6
|
-
|
|
7
|
-
import { mkdir, rm } from "node:fs/promises";
|
|
8
|
-
import { join } from "node:path";
|
|
9
|
-
import type { StorageVolume } from "@launchfile/sdk";
|
|
10
|
-
|
|
11
|
-
const STATE_DIR = ".launchfile";
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* Create local directories for a component's storage volumes.
|
|
15
|
-
* Returns a map of container path → local path.
|
|
16
|
-
*/
|
|
17
|
-
export async function provisionStorage(
|
|
18
|
-
storage: Record<string, StorageVolume> | undefined,
|
|
19
|
-
componentName: string,
|
|
20
|
-
projectDir: string,
|
|
21
|
-
): Promise<Record<string, string>> {
|
|
22
|
-
if (!storage) return {};
|
|
23
|
-
|
|
24
|
-
const volumeMap: Record<string, string> = {};
|
|
25
|
-
|
|
26
|
-
for (const [name, volume] of Object.entries(storage)) {
|
|
27
|
-
const persistent = volume.persistent !== false; // default true
|
|
28
|
-
const subdir = persistent ? "storage" : "tmp";
|
|
29
|
-
const localPath = join(projectDir, STATE_DIR, subdir, componentName, name);
|
|
30
|
-
|
|
31
|
-
await mkdir(localPath, { recursive: true });
|
|
32
|
-
volumeMap[volume.path] = localPath;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
return volumeMap;
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
/** Clean up ephemeral (non-persistent) storage for a component */
|
|
39
|
-
export async function cleanEphemeralStorage(
|
|
40
|
-
storage: Record<string, StorageVolume> | undefined,
|
|
41
|
-
componentName: string,
|
|
42
|
-
projectDir: string,
|
|
43
|
-
): Promise<void> {
|
|
44
|
-
if (!storage) return;
|
|
45
|
-
|
|
46
|
-
for (const [name, volume] of Object.entries(storage)) {
|
|
47
|
-
if (volume.persistent === false) {
|
|
48
|
-
const localPath = join(projectDir, STATE_DIR, "tmp", componentName, name);
|
|
49
|
-
await rm(localPath, { recursive: true, force: true });
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
/** Clean up all storage (persistent + ephemeral) for a component */
|
|
55
|
-
export async function destroyStorage(
|
|
56
|
-
componentName: string,
|
|
57
|
-
projectDir: string,
|
|
58
|
-
): Promise<void> {
|
|
59
|
-
await rm(join(projectDir, STATE_DIR, "storage", componentName), {
|
|
60
|
-
recursive: true,
|
|
61
|
-
force: true,
|
|
62
|
-
});
|
|
63
|
-
await rm(join(projectDir, STATE_DIR, "tmp", componentName), {
|
|
64
|
-
recursive: true,
|
|
65
|
-
force: true,
|
|
66
|
-
});
|
|
67
|
-
}
|
package/tsconfig.json
DELETED
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"compilerOptions": {
|
|
3
|
-
"target": "ESNext",
|
|
4
|
-
"module": "ESNext",
|
|
5
|
-
"moduleResolution": "bundler",
|
|
6
|
-
"strict": true,
|
|
7
|
-
"noUncheckedIndexedAccess": true,
|
|
8
|
-
"isolatedModules": true,
|
|
9
|
-
"declaration": true,
|
|
10
|
-
"declarationMap": true,
|
|
11
|
-
"sourceMap": true,
|
|
12
|
-
"rootDir": "src",
|
|
13
|
-
"outDir": "dist",
|
|
14
|
-
"types": ["bun-types", "vitest/globals"],
|
|
15
|
-
"skipLibCheck": true
|
|
16
|
-
},
|
|
17
|
-
"include": ["src/**/*.ts"]
|
|
18
|
-
}
|