@launchfile/macos-dev 0.1.4 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (124) hide show
  1. package/dist/bootstrap.d.ts +58 -0
  2. package/dist/bootstrap.js +224 -0
  3. package/dist/env-writer.d.ts +19 -13
  4. package/dist/env-writer.js +44 -8
  5. package/dist/index.d.ts +2 -0
  6. package/dist/index.js +1 -0
  7. package/dist/process-manager.d.ts +13 -0
  8. package/dist/process-manager.js +57 -2
  9. package/dist/process-stopper.d.ts +99 -0
  10. package/dist/process-stopper.js +165 -0
  11. package/dist/provider.d.ts +18 -0
  12. package/dist/provider.js +176 -70
  13. package/dist/shell.js +1 -1
  14. package/dist/state.d.ts +28 -0
  15. package/dist/storage.d.ts +16 -3
  16. package/dist/storage.js +23 -6
  17. package/package.json +9 -4
  18. package/CLAUDE.md +0 -37
  19. package/dist/__tests__/dry-run.test.d.ts +0 -2
  20. package/dist/__tests__/dry-run.test.d.ts.map +0 -1
  21. package/dist/__tests__/dry-run.test.js +0 -129
  22. package/dist/__tests__/dry-run.test.js.map +0 -1
  23. package/dist/__tests__/env-writer.test.d.ts +0 -2
  24. package/dist/__tests__/env-writer.test.d.ts.map +0 -1
  25. package/dist/__tests__/env-writer.test.js +0 -127
  26. package/dist/__tests__/env-writer.test.js.map +0 -1
  27. package/dist/__tests__/lockfile-detect.test.d.ts +0 -2
  28. package/dist/__tests__/lockfile-detect.test.d.ts.map +0 -1
  29. package/dist/__tests__/lockfile-detect.test.js +0 -75
  30. package/dist/__tests__/lockfile-detect.test.js.map +0 -1
  31. package/dist/__tests__/port-allocator.test.d.ts +0 -2
  32. package/dist/__tests__/port-allocator.test.d.ts.map +0 -1
  33. package/dist/__tests__/port-allocator.test.js +0 -53
  34. package/dist/__tests__/port-allocator.test.js.map +0 -1
  35. package/dist/__tests__/secret-generator.test.d.ts +0 -2
  36. package/dist/__tests__/secret-generator.test.d.ts.map +0 -1
  37. package/dist/__tests__/secret-generator.test.js +0 -26
  38. package/dist/__tests__/secret-generator.test.js.map +0 -1
  39. package/dist/__tests__/state.test.d.ts +0 -2
  40. package/dist/__tests__/state.test.d.ts.map +0 -1
  41. package/dist/__tests__/state.test.js +0 -30
  42. package/dist/__tests__/state.test.js.map +0 -1
  43. package/dist/cli.d.ts.map +0 -1
  44. package/dist/cli.js.map +0 -1
  45. package/dist/env-writer.d.ts.map +0 -1
  46. package/dist/env-writer.js.map +0 -1
  47. package/dist/health.d.ts.map +0 -1
  48. package/dist/health.js.map +0 -1
  49. package/dist/index.d.ts.map +0 -1
  50. package/dist/index.js.map +0 -1
  51. package/dist/lockfile-detect.d.ts.map +0 -1
  52. package/dist/lockfile-detect.js.map +0 -1
  53. package/dist/port-allocator.d.ts.map +0 -1
  54. package/dist/port-allocator.js.map +0 -1
  55. package/dist/prereqs.d.ts.map +0 -1
  56. package/dist/prereqs.js.map +0 -1
  57. package/dist/process-manager.d.ts.map +0 -1
  58. package/dist/process-manager.js.map +0 -1
  59. package/dist/provider.d.ts.map +0 -1
  60. package/dist/provider.js.map +0 -1
  61. package/dist/resources/index.d.ts.map +0 -1
  62. package/dist/resources/index.js.map +0 -1
  63. package/dist/resources/mysql.d.ts.map +0 -1
  64. package/dist/resources/mysql.js.map +0 -1
  65. package/dist/resources/postgres.d.ts.map +0 -1
  66. package/dist/resources/postgres.js.map +0 -1
  67. package/dist/resources/redis.d.ts.map +0 -1
  68. package/dist/resources/redis.js.map +0 -1
  69. package/dist/resources/sqlite.d.ts.map +0 -1
  70. package/dist/resources/sqlite.js.map +0 -1
  71. package/dist/resources/types.d.ts.map +0 -1
  72. package/dist/resources/types.js.map +0 -1
  73. package/dist/runtimes/bun.d.ts.map +0 -1
  74. package/dist/runtimes/bun.js.map +0 -1
  75. package/dist/runtimes/index.d.ts.map +0 -1
  76. package/dist/runtimes/index.js.map +0 -1
  77. package/dist/runtimes/node.d.ts.map +0 -1
  78. package/dist/runtimes/node.js.map +0 -1
  79. package/dist/runtimes/python.d.ts.map +0 -1
  80. package/dist/runtimes/python.js.map +0 -1
  81. package/dist/runtimes/ruby.d.ts.map +0 -1
  82. package/dist/runtimes/ruby.js.map +0 -1
  83. package/dist/runtimes/types.d.ts.map +0 -1
  84. package/dist/runtimes/types.js.map +0 -1
  85. package/dist/secret-generator.d.ts.map +0 -1
  86. package/dist/secret-generator.js.map +0 -1
  87. package/dist/shell.d.ts.map +0 -1
  88. package/dist/shell.js.map +0 -1
  89. package/dist/state.d.ts.map +0 -1
  90. package/dist/state.js.map +0 -1
  91. package/dist/storage.d.ts.map +0 -1
  92. package/dist/storage.js.map +0 -1
  93. package/src/__tests__/dry-run.test.ts +0 -157
  94. package/src/__tests__/env-writer.test.ts +0 -156
  95. package/src/__tests__/lockfile-detect.test.ts +0 -74
  96. package/src/__tests__/port-allocator.test.ts +0 -59
  97. package/src/__tests__/secret-generator.test.ts +0 -31
  98. package/src/__tests__/state.test.ts +0 -33
  99. package/src/cli.ts +0 -78
  100. package/src/env-writer.ts +0 -231
  101. package/src/health.ts +0 -80
  102. package/src/index.ts +0 -9
  103. package/src/lockfile-detect.ts +0 -48
  104. package/src/port-allocator.ts +0 -97
  105. package/src/prereqs.ts +0 -32
  106. package/src/process-manager.ts +0 -242
  107. package/src/provider.ts +0 -415
  108. package/src/resources/index.ts +0 -29
  109. package/src/resources/mysql.ts +0 -98
  110. package/src/resources/postgres.ts +0 -133
  111. package/src/resources/redis.ts +0 -58
  112. package/src/resources/sqlite.ts +0 -52
  113. package/src/resources/types.ts +0 -47
  114. package/src/runtimes/bun.ts +0 -25
  115. package/src/runtimes/index.ts +0 -24
  116. package/src/runtimes/node.ts +0 -71
  117. package/src/runtimes/python.ts +0 -42
  118. package/src/runtimes/ruby.ts +0 -55
  119. package/src/runtimes/types.ts +0 -16
  120. package/src/secret-generator.ts +0 -32
  121. package/src/shell.ts +0 -70
  122. package/src/state.ts +0 -92
  123. package/src/storage.ts +0 -67
  124. package/tsconfig.json +0 -18
package/dist/state.d.ts CHANGED
@@ -13,6 +13,28 @@ export interface ResourceState {
13
13
  user?: string;
14
14
  password?: string;
15
15
  }
16
+ /**
17
+ * Records a spawned app component process so `launch down` can stop it
18
+ * from a different shell or after the foreground `launch up` session ends.
19
+ *
20
+ * Identity is captured at spawn time so `down` can re-verify the recorded
21
+ * pid still belongs to the process we started before signaling it — guarding
22
+ * against pid-reuse (a recycled pid belonging to an unrelated process).
23
+ */
24
+ export interface ProcessState {
25
+ /** Leader pid of the spawned shell (`sh -c <command>`). */
26
+ pid: number;
27
+ /**
28
+ * Process group id. Because we spawn detached, the child is its own group
29
+ * leader, so pgid === pid. We persist it explicitly so `down` can signal the
30
+ * whole group (negative pid) and take down child processes too.
31
+ */
32
+ pgid: number;
33
+ /** ISO timestamp captured immediately after spawn — part of the identity check. */
34
+ startedAt: string;
35
+ /** The shell command string we launched — used as a best-effort identity cross-check. */
36
+ command: string;
37
+ }
16
38
  export interface LaunchState {
17
39
  version: 1;
18
40
  appName: string;
@@ -22,6 +44,12 @@ export interface LaunchState {
22
44
  resources: Record<string, ResourceState>;
23
45
  secrets: Record<string, string>;
24
46
  ports: Record<string, number>;
47
+ /**
48
+ * App component processes recorded at spawn time, keyed by component name.
49
+ * Optional for backward compatibility: state files written before pid
50
+ * persistence existed simply omit this, and `down` tolerates its absence.
51
+ */
52
+ processes?: Record<string, ProcessState>;
25
53
  }
26
54
  export declare function hashLaunchfile(content: string): string;
27
55
  /** Load state from disk, or return null if none exists */
package/dist/storage.d.ts CHANGED
@@ -1,12 +1,25 @@
1
1
  /**
2
2
  * Local storage provisioning for Launchfile volumes.
3
3
  *
4
- * Maps container paths to local directories under .launchfile/.
4
+ * Maps named volumes to local directories under .launchfile/, and exposes the
5
+ * resolved local path per volume so the provider can inject it as
6
+ * `$storage.<name>.path` (D-39).
5
7
  */
6
8
  import type { StorageVolume } from "@launchfile/sdk";
7
9
  /**
8
- * Create local directories for a component's storage volumes.
9
- * Returns a map of container path → local path.
10
+ * Compute the local path this provider uses for each of a component's storage
11
+ * volumes — keyed by **volume name** (the `storage:` key), which is what
12
+ * `$storage.<name>.path` resolves against (D-39). Pure: no filesystem side
13
+ * effects, so callers that only need the resolved paths (e.g. `launchfile env`)
14
+ * can use it without provisioning. Persistent volumes live under
15
+ * `.launchfile/storage/<component>/<name>`; ephemeral ones under `.../tmp/...`.
16
+ */
17
+ export declare function storagePaths(storage: Record<string, StorageVolume> | undefined, componentName: string, projectDir: string): Record<string, string>;
18
+ /**
19
+ * Create the local directories for a component's storage volumes and return the
20
+ * volume-name → local-path map (the home-#3 value the resolver injects as
21
+ * `$storage.<name>.path`, D-39). Previously the return was keyed by container
22
+ * path and discarded at the call site — the path is now captured and delivered.
10
23
  */
11
24
  export declare function provisionStorage(storage: Record<string, StorageVolume> | undefined, componentName: string, projectDir: string): Promise<Record<string, string>>;
12
25
  /** Clean up ephemeral (non-persistent) storage for a component */
package/dist/storage.js CHANGED
@@ -1,25 +1,42 @@
1
1
  /**
2
2
  * Local storage provisioning for Launchfile volumes.
3
3
  *
4
- * Maps container paths to local directories under .launchfile/.
4
+ * Maps named volumes to local directories under .launchfile/, and exposes the
5
+ * resolved local path per volume so the provider can inject it as
6
+ * `$storage.<name>.path` (D-39).
5
7
  */
6
8
  import { mkdir, rm } from "node:fs/promises";
7
9
  import { join } from "node:path";
8
10
  const STATE_DIR = ".launchfile";
9
11
  /**
10
- * Create local directories for a component's storage volumes.
11
- * Returns a map of container path → local path.
12
+ * Compute the local path this provider uses for each of a component's storage
13
+ * volumes — keyed by **volume name** (the `storage:` key), which is what
14
+ * `$storage.<name>.path` resolves against (D-39). Pure: no filesystem side
15
+ * effects, so callers that only need the resolved paths (e.g. `launchfile env`)
16
+ * can use it without provisioning. Persistent volumes live under
17
+ * `.launchfile/storage/<component>/<name>`; ephemeral ones under `.../tmp/...`.
12
18
  */
13
- export async function provisionStorage(storage, componentName, projectDir) {
19
+ export function storagePaths(storage, componentName, projectDir) {
14
20
  if (!storage)
15
21
  return {};
16
22
  const volumeMap = {};
17
23
  for (const [name, volume] of Object.entries(storage)) {
18
24
  const persistent = volume.persistent !== false; // default true
19
25
  const subdir = persistent ? "storage" : "tmp";
20
- const localPath = join(projectDir, STATE_DIR, subdir, componentName, name);
26
+ volumeMap[name] = join(projectDir, STATE_DIR, subdir, componentName, name);
27
+ }
28
+ return volumeMap;
29
+ }
30
+ /**
31
+ * Create the local directories for a component's storage volumes and return the
32
+ * volume-name → local-path map (the home-#3 value the resolver injects as
33
+ * `$storage.<name>.path`, D-39). Previously the return was keyed by container
34
+ * path and discarded at the call site — the path is now captured and delivered.
35
+ */
36
+ export async function provisionStorage(storage, componentName, projectDir) {
37
+ const volumeMap = storagePaths(storage, componentName, projectDir);
38
+ for (const localPath of Object.values(volumeMap)) {
21
39
  await mkdir(localPath, { recursive: true });
22
- volumeMap[volume.path] = localPath;
23
40
  }
24
41
  return volumeMap;
25
42
  }
package/package.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@launchfile/macos-dev",
3
- "version": "0.1.4",
3
+ "version": "0.3.0",
4
4
  "description": "macOS dev provider for Launchfile — run apps locally via brew services and native runtimes",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
7
7
  "types": "dist/index.d.ts",
8
8
  "scripts": {
9
- "build": "tsc",
9
+ "build": "tsc -p tsconfig.build.json",
10
10
  "test": "vitest run",
11
11
  "test:watch": "vitest",
12
12
  "typecheck": "tsc --noEmit",
@@ -21,14 +21,19 @@
21
21
  "provider",
22
22
  "brew"
23
23
  ],
24
+ "files": [
25
+ "dist/**/*.js",
26
+ "dist/**/*.d.ts",
27
+ "README.md"
28
+ ],
24
29
  "license": "MIT",
25
30
  "repository": {
26
31
  "type": "git",
27
- "url": "https://github.com/launchfile/launchfile",
32
+ "url": "git+https://github.com/launchfile/launchfile.git",
28
33
  "directory": "providers/macos-dev"
29
34
  },
30
35
  "dependencies": {
31
- "@launchfile/sdk": "0.1.2",
36
+ "@launchfile/sdk": "^0.3.0",
32
37
  "semver": "^7.7.4"
33
38
  },
34
39
  "devDependencies": {
package/CLAUDE.md DELETED
@@ -1,37 +0,0 @@
1
- # macOS Dev Provider — Working Context
2
-
3
- > For project-wide context, see [../../CLAUDE.md](../../CLAUDE.md)
4
-
5
- ## What's Here
6
-
7
- A Launchfile provider that runs apps natively on macOS for local development. Uses Homebrew services for databases (postgres, redis, mysql, etc.) and native runtimes (node via fnm, python via pyenv, ruby via rbenv, bun via brew).
8
-
9
- ## Philosophy
10
-
11
- - **Source-first** — ignores `image:`, uses `runtime:` + native package managers
12
- - **Brew-first** — shared database services, app-specific databases namespaced by app name
13
- - **Supports skip by default** — use `--with-optional` for optional resources
14
-
15
- ## Commands
16
-
17
- ```bash
18
- bun install # Install dependencies
19
- bun test # Run all tests (vitest)
20
- bun run typecheck # Type-check without emitting
21
- ```
22
-
23
- This package is a library consumed by the unified `launchfile` CLI (`packages/launchfile`). End users run `npx launchfile up`, not this package directly.
24
-
25
- ## Architecture
26
-
27
- - `provider.ts` — Main orchestration (`launch up` sequence)
28
- - `env-writer.ts` — Resolves `$` expressions via SDK and writes `.env.local`
29
- - `resources/` — Brew-based provisioners (postgres, redis, mysql, sqlite)
30
- - `runtimes/` — Version manager integrations (fnm, pyenv, rbenv)
31
- - `process-manager.ts` — Multi-component startup with topological sort and health waits
32
- - `state.ts` — Persists secrets, ports, and credentials in `.launchfile/state.json`
33
-
34
- ## Dependencies
35
-
36
- - `@launchfile/sdk` — Parsing, validation, expression resolution
37
- - `semver` — Version constraint matching for brew formulae
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=dry-run.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"dry-run.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/dry-run.test.ts"],"names":[],"mappings":""}
@@ -1,129 +0,0 @@
1
- import { describe, it, expect } from "vitest";
2
- import { readFile } from "node:fs/promises";
3
- import { join } from "node:path";
4
- import { readLaunch } from "@launchfile/sdk";
5
- import { buildResolverContext, resolveComponentEnv, resolveGenerators, } from "../env-writer.js";
6
- import { getProvisioner } from "../resources/index.js";
7
- import { allocatePorts } from "../port-allocator.js";
8
- const CATALOG_DIR = join(import.meta.dirname, "../../../../catalog/drafts");
9
- /**
10
- * Dry-run test: parse a catalog Launchfile, simulate provisioning,
11
- * resolve env vars, and verify the output makes sense.
12
- */
13
- describe("dry-run against catalog", () => {
14
- it("resolves miniflux Launchfile", async () => {
15
- const yaml = await readFile(join(CATALOG_DIR, "miniflux/Launchfile"), "utf8");
16
- const launch = readLaunch(yaml);
17
- expect(launch.name).toBe("miniflux");
18
- expect(Object.keys(launch.components)).toEqual(["default"]);
19
- const component = launch.components.default;
20
- // Verify requires
21
- expect(component.requires).toHaveLength(1);
22
- expect(component.requires[0].type).toBe("postgres");
23
- expect(component.requires[0].set_env?.DATABASE_URL).toBe("$url");
24
- // Simulate provisioned postgres
25
- const resourceMap = {
26
- postgres: {
27
- url: "postgresql://launchfile_miniflux:secret@localhost:5432/launchfile_miniflux",
28
- host: "localhost",
29
- port: 5432,
30
- user: "launchfile_miniflux",
31
- password: "secret",
32
- name: "launchfile_miniflux",
33
- },
34
- };
35
- const ports = await allocatePorts(launch.components, "miniflux");
36
- const context = buildResolverContext(resourceMap, ports, {});
37
- const env = resolveComponentEnv(component, context, resourceMap);
38
- await resolveGenerators(component, env);
39
- // DATABASE_URL should be resolved from postgres $url
40
- expect(env.DATABASE_URL).toBe("postgresql://launchfile_miniflux:secret@localhost:5432/launchfile_miniflux");
41
- // Default env vars should be resolved
42
- expect(env.RUN_MIGRATIONS).toBe("1");
43
- expect(env.CREATE_ADMIN).toBe("1");
44
- expect(env.ADMIN_USERNAME).toBe("admin");
45
- // ADMIN_PASSWORD has generator: secret, so it should be generated
46
- expect(env.ADMIN_PASSWORD).toBeTruthy();
47
- expect(env.ADMIN_PASSWORD.length).toBeGreaterThan(10);
48
- });
49
- it("resolves langfuse Launchfile", async () => {
50
- const yaml = await readFile(join(CATALOG_DIR, "langfuse/Launchfile"), "utf8");
51
- const launch = readLaunch(yaml);
52
- expect(launch.name).toBe("langfuse");
53
- for (const [name, component] of Object.entries(launch.components)) {
54
- // Every required resource should have a known provisioner
55
- for (const req of component.requires ?? []) {
56
- const provisioner = getProvisioner(req.type);
57
- expect(provisioner, `No provisioner for ${req.type} in ${name}`).toBeDefined();
58
- }
59
- }
60
- });
61
- it("resolves chatwoot multi-component Launchfile", async () => {
62
- const yaml = await readFile(join(CATALOG_DIR, "chatwoot/Launchfile"), "utf8");
63
- const launch = readLaunch(yaml);
64
- expect(launch.name).toBe("chatwoot");
65
- const componentNames = Object.keys(launch.components);
66
- expect(componentNames.length).toBeGreaterThan(1);
67
- // Simulate resources
68
- const resourceMap = {
69
- postgres: {
70
- url: "postgresql://user:pass@localhost:5432/chatwoot",
71
- host: "localhost",
72
- port: 5432,
73
- user: "user",
74
- password: "pass",
75
- name: "chatwoot",
76
- },
77
- redis: {
78
- url: "redis://localhost:6379/0",
79
- host: "localhost",
80
- port: 6379,
81
- },
82
- };
83
- const ports = await allocatePorts(launch.components, "chatwoot");
84
- const secrets = {};
85
- // Generate secrets from launch.secrets
86
- if (launch.secrets) {
87
- for (const [name] of Object.entries(launch.secrets)) {
88
- secrets[name] = `test-secret-${name}`;
89
- }
90
- }
91
- const context = buildResolverContext(resourceMap, ports, secrets);
92
- // Resolve env for each component — should not throw
93
- for (const [name, component] of Object.entries(launch.components)) {
94
- const env = resolveComponentEnv(component, context, resourceMap);
95
- await resolveGenerators(component, env);
96
- // Every component should have at least some env vars
97
- expect(Object.keys(env).length, `${name} should have env vars`).toBeGreaterThan(0);
98
- }
99
- });
100
- it("identifies unsupported resource types", async () => {
101
- // Check all catalog Launchfiles for resource types we support
102
- const { readdir } = await import("node:fs/promises");
103
- const apps = await readdir(CATALOG_DIR);
104
- const unsupported = new Set();
105
- for (const app of apps) {
106
- try {
107
- const yaml = await readFile(join(CATALOG_DIR, app, "Launchfile"), "utf8");
108
- const launch = readLaunch(yaml);
109
- for (const component of Object.values(launch.components)) {
110
- for (const req of [...(component.requires ?? []), ...(component.supports ?? [])]) {
111
- if (!getProvisioner(req.type)) {
112
- unsupported.add(req.type);
113
- }
114
- }
115
- }
116
- }
117
- catch {
118
- // Skip apps that can't be parsed
119
- }
120
- }
121
- // Log unsupported types for visibility
122
- if (unsupported.size > 0) {
123
- console.log(` Unsupported resource types in catalog: ${[...unsupported].join(", ")}`);
124
- }
125
- // This test is informational — it doesn't fail
126
- expect(true).toBe(true);
127
- });
128
- });
129
- //# sourceMappingURL=dry-run.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"dry-run.test.js","sourceRoot":"","sources":["../../src/__tests__/dry-run.test.ts"],"names":[],"mappings":"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"}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=env-writer.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"env-writer.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/env-writer.test.ts"],"names":[],"mappings":""}
@@ -1,127 +0,0 @@
1
- import { describe, it, expect } from "vitest";
2
- import { buildResolverContext, resolveComponentEnv, generateSecrets, } from "../env-writer.js";
3
- describe("buildResolverContext", () => {
4
- it("builds context from resources, ports, and secrets", () => {
5
- const resources = {
6
- postgres: {
7
- url: "postgresql://user:pass@localhost:5432/mydb",
8
- host: "localhost",
9
- port: 5432,
10
- user: "user",
11
- password: "pass",
12
- name: "mydb",
13
- },
14
- };
15
- const ports = { backend: 3000, frontend: 3001 };
16
- const secrets = { "jwt-secret": "abc123" };
17
- const ctx = buildResolverContext(resources, ports, secrets);
18
- expect(ctx.components?.backend).toEqual({
19
- url: "http://localhost:3000",
20
- host: "localhost",
21
- port: 3000,
22
- });
23
- expect(ctx.resources?.postgres?.url).toBe("postgresql://user:pass@localhost:5432/mydb");
24
- expect(ctx.secrets?.["jwt-secret"]).toBe("abc123");
25
- });
26
- });
27
- describe("resolveComponentEnv", () => {
28
- it("resolves set_env from requires", () => {
29
- const component = {
30
- requires: [
31
- {
32
- type: "postgres",
33
- set_env: {
34
- DATABASE_URL: "$url",
35
- DB_HOST: "$host",
36
- },
37
- },
38
- ],
39
- };
40
- const resourceMap = {
41
- postgres: {
42
- url: "postgresql://user:pass@localhost:5432/mydb",
43
- host: "localhost",
44
- port: 5432,
45
- },
46
- };
47
- const context = buildResolverContext(resourceMap, {}, {});
48
- const env = resolveComponentEnv(component, context, resourceMap);
49
- expect(env.DATABASE_URL).toBe("postgresql://user:pass@localhost:5432/mydb");
50
- expect(env.DB_HOST).toBe("localhost");
51
- });
52
- it("resolves component-level env defaults", () => {
53
- const component = {
54
- env: {
55
- PORT: { default: "8080" },
56
- LOG_LEVEL: { default: "info" },
57
- },
58
- };
59
- const context = buildResolverContext({}, {}, {});
60
- const env = resolveComponentEnv(component, context, {});
61
- expect(env.PORT).toBe("8080");
62
- expect(env.LOG_LEVEL).toBe("info");
63
- });
64
- it("resolves cross-component references", () => {
65
- const component = {
66
- env: {
67
- BACKEND_URL: { default: "$components.backend.url" },
68
- },
69
- };
70
- const context = buildResolverContext({}, { backend: 3000 }, {});
71
- const env = resolveComponentEnv(component, context, {});
72
- expect(env.BACKEND_URL).toBe("http://localhost:3000");
73
- });
74
- it("resolves secrets references", () => {
75
- const component = {
76
- env: {
77
- SECRET_KEY: { default: "$secrets.my-key" },
78
- },
79
- };
80
- const context = buildResolverContext({}, {}, { "my-key": "super-secret" });
81
- const env = resolveComponentEnv(component, context, {});
82
- expect(env.SECRET_KEY).toBe("super-secret");
83
- });
84
- it("set_env takes precedence over component env", () => {
85
- const component = {
86
- requires: [
87
- {
88
- type: "postgres",
89
- set_env: { DATABASE_URL: "$url" },
90
- },
91
- ],
92
- env: {
93
- DATABASE_URL: { default: "fallback" },
94
- },
95
- };
96
- const resourceMap = {
97
- postgres: {
98
- url: "postgresql://real-url",
99
- host: "localhost",
100
- port: 5432,
101
- },
102
- };
103
- const context = buildResolverContext(resourceMap, {}, {});
104
- const env = resolveComponentEnv(component, context, resourceMap);
105
- expect(env.DATABASE_URL).toBe("postgresql://real-url");
106
- });
107
- });
108
- describe("generateSecrets", () => {
109
- it("generates new secrets", async () => {
110
- const defs = {
111
- "jwt-secret": { generator: "secret" },
112
- "app-uuid": { generator: "uuid" },
113
- };
114
- const secrets = await generateSecrets(defs, {});
115
- expect(secrets["jwt-secret"]).toBeTruthy();
116
- expect(secrets["app-uuid"]).toMatch(/^[0-9a-f-]+$/);
117
- });
118
- it("reuses existing secrets", async () => {
119
- const defs = {
120
- "jwt-secret": { generator: "secret" },
121
- };
122
- const existing = { "jwt-secret": "keep-this" };
123
- const secrets = await generateSecrets(defs, existing);
124
- expect(secrets["jwt-secret"]).toBe("keep-this");
125
- });
126
- });
127
- //# sourceMappingURL=env-writer.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"env-writer.test.js","sourceRoot":"","sources":["../../src/__tests__/env-writer.test.ts"],"names":[],"mappings":"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"}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=lockfile-detect.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"lockfile-detect.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/lockfile-detect.test.ts"],"names":[],"mappings":""}
@@ -1,75 +0,0 @@
1
- import { describe, it, expect } from "vitest";
2
- import { detectPackageManager } from "../lockfile-detect.js";
3
- import { mkdtemp, writeFile, rm } from "node:fs/promises";
4
- import { join } from "node:path";
5
- import { tmpdir } from "node:os";
6
- describe("detectPackageManager", () => {
7
- it("returns null for empty directory", async () => {
8
- const dir = await mkdtemp(join(tmpdir(), "lf-test-"));
9
- try {
10
- const pm = await detectPackageManager(dir);
11
- expect(pm).toBeNull();
12
- }
13
- finally {
14
- await rm(dir, { recursive: true });
15
- }
16
- });
17
- it("detects bun from bun.lockb", async () => {
18
- const dir = await mkdtemp(join(tmpdir(), "lf-test-"));
19
- try {
20
- await writeFile(join(dir, "bun.lockb"), "");
21
- const pm = await detectPackageManager(dir);
22
- expect(pm?.name).toBe("bun");
23
- expect(pm?.installCommand).toBe("bun install");
24
- }
25
- finally {
26
- await rm(dir, { recursive: true });
27
- }
28
- });
29
- it("detects yarn from yarn.lock", async () => {
30
- const dir = await mkdtemp(join(tmpdir(), "lf-test-"));
31
- try {
32
- await writeFile(join(dir, "yarn.lock"), "");
33
- const pm = await detectPackageManager(dir);
34
- expect(pm?.name).toBe("yarn");
35
- }
36
- finally {
37
- await rm(dir, { recursive: true });
38
- }
39
- });
40
- it("detects pnpm from pnpm-lock.yaml", async () => {
41
- const dir = await mkdtemp(join(tmpdir(), "lf-test-"));
42
- try {
43
- await writeFile(join(dir, "pnpm-lock.yaml"), "");
44
- const pm = await detectPackageManager(dir);
45
- expect(pm?.name).toBe("pnpm");
46
- }
47
- finally {
48
- await rm(dir, { recursive: true });
49
- }
50
- });
51
- it("detects bundler from Gemfile.lock", async () => {
52
- const dir = await mkdtemp(join(tmpdir(), "lf-test-"));
53
- try {
54
- await writeFile(join(dir, "Gemfile.lock"), "");
55
- const pm = await detectPackageManager(dir);
56
- expect(pm?.name).toBe("bundler");
57
- }
58
- finally {
59
- await rm(dir, { recursive: true });
60
- }
61
- });
62
- it("prefers bun over yarn when both present", async () => {
63
- const dir = await mkdtemp(join(tmpdir(), "lf-test-"));
64
- try {
65
- await writeFile(join(dir, "bun.lockb"), "");
66
- await writeFile(join(dir, "yarn.lock"), "");
67
- const pm = await detectPackageManager(dir);
68
- expect(pm?.name).toBe("bun");
69
- }
70
- finally {
71
- await rm(dir, { recursive: true });
72
- }
73
- });
74
- });
75
- //# sourceMappingURL=lockfile-detect.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"lockfile-detect.test.js","sourceRoot":"","sources":["../../src/__tests__/lockfile-detect.test.ts"],"names":[],"mappings":"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"}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=port-allocator.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"port-allocator.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/port-allocator.test.ts"],"names":[],"mappings":""}
@@ -1,53 +0,0 @@
1
- import { describe, it, expect } from "vitest";
2
- import { allocatePort, allocatePorts } from "../port-allocator.js";
3
- describe("allocatePort", () => {
4
- it("returns a port in the expected range", async () => {
5
- const port = await allocatePort("test-app", new Set());
6
- expect(port).toBeGreaterThanOrEqual(10_000);
7
- expect(port).toBeLessThan(20_000);
8
- });
9
- it("is deterministic for the same key", async () => {
10
- const port1 = await allocatePort("my-app", new Set());
11
- const port2 = await allocatePort("my-app", new Set());
12
- expect(port1).toBe(port2);
13
- });
14
- it("avoids ports already in use", async () => {
15
- const port1 = await allocatePort("collision-test", new Set());
16
- const port2 = await allocatePort("collision-test", new Set([port1]));
17
- expect(port2).not.toBe(port1);
18
- });
19
- it("produces different ports for different keys", async () => {
20
- const port1 = await allocatePort("app-a", new Set());
21
- const port2 = await allocatePort("app-b", new Set());
22
- // Not guaranteed but overwhelmingly likely for different inputs
23
- expect(port1).not.toBe(port2);
24
- });
25
- });
26
- describe("allocatePorts", () => {
27
- it("allocates ports for all components", async () => {
28
- const components = {
29
- backend: { provides: [{ port: 3000 }] },
30
- frontend: { provides: [{ port: 3001 }] },
31
- };
32
- const ports = await allocatePorts(components, "test-app");
33
- expect(ports.backend).toBeDefined();
34
- expect(ports.frontend).toBeDefined();
35
- expect(ports.backend).not.toBe(ports.frontend);
36
- });
37
- it("prefers the declared port if free", async () => {
38
- const components = {
39
- api: { provides: [{ port: 4567 }] },
40
- };
41
- const ports = await allocatePorts(components, "test-app");
42
- expect(ports.api).toBe(4567);
43
- });
44
- it("reuses saved ports when available", async () => {
45
- const components = {
46
- api: { provides: [{ port: 3000 }] },
47
- };
48
- const saved = { api: 9876 };
49
- const ports = await allocatePorts(components, "test-app", saved);
50
- expect(ports.api).toBe(9876);
51
- });
52
- });
53
- //# sourceMappingURL=port-allocator.test.js.map