@replayio/app-building 1.8.1 → 1.8.3

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/container.js CHANGED
@@ -119,8 +119,9 @@ export async function startContainer(config, repo) {
119
119
  const containerEnv = buildContainerEnv(repo, config.envVars, extra);
120
120
  // Build docker run args
121
121
  const args = ["run", "-d", "--rm", "--name", containerName];
122
- // --network host: container shares host network stack (no -p needed)
123
- args.push("--network", "host");
122
+ // Use explicit port mapping for macOS Docker Desktop compatibility
123
+ // (--network host only works on Linux)
124
+ args.push("-p", `${hostPort}:${hostPort}`);
124
125
  for (const [k, v] of Object.entries(containerEnv)) {
125
126
  args.push("--env", `${k}=${v}`);
126
127
  }
package/dist/fly.js CHANGED
@@ -85,36 +85,61 @@ export async function createMachine(app, token, image, env, name) {
85
85
  // Create a volume for /repo storage
86
86
  const volumeName = `repo_${name.replace(/-/g, "_")}`.slice(0, 30);
87
87
  const volumeId = await createVolume(app, token, volumeName, 50);
88
- try {
89
- const res = await flyFetch(`/apps/${app}/machines`, token, {
90
- method: "POST",
91
- body: JSON.stringify({
92
- name,
93
- config: {
94
- image,
95
- env,
96
- auto_destroy: true,
97
- restart: { policy: "no" },
98
- guest: {
99
- cpu_kind: "performance",
100
- cpus: 16,
101
- memory_mb: 32768,
102
- },
103
- mounts: [{ volume: volumeId, path: "/repo" }],
104
- services: [
105
- {
106
- ports: [{ port: 443, handlers: ["tls", "http"] }],
107
- protocol: "tcp",
108
- internal_port: 3000,
109
- autostart: false,
110
- autostop: "off",
111
- },
112
- ],
88
+ // Delete unattached volumes in parallel with creating the new machine.
89
+ const cleanupDone = listVolumes(app, token).then(vols => Promise.all(vols.map(async ({ id, attached_machine_id }) => {
90
+ if (attached_machine_id || id == volumeId)
91
+ return;
92
+ await deleteVolume(app, token, id).catch(() => { });
93
+ })));
94
+ const machineBody = JSON.stringify({
95
+ name,
96
+ config: {
97
+ image,
98
+ env,
99
+ auto_destroy: true,
100
+ restart: { policy: "no" },
101
+ guest: {
102
+ cpu_kind: "performance",
103
+ cpus: 16,
104
+ memory_mb: 32768,
105
+ },
106
+ mounts: [{ volume: volumeId, path: "/repo" }],
107
+ services: [
108
+ {
109
+ ports: [{ port: 443, handlers: ["tls", "http"] }],
110
+ protocol: "tcp",
111
+ internal_port: 3000,
112
+ autostart: false,
113
+ autostop: "off",
113
114
  },
114
- }),
115
- });
116
- const data = (await res.json());
117
- return { machineId: data.id, volumeId };
115
+ ],
116
+ },
117
+ });
118
+ try {
119
+ // Retry machine creation — volume may take a moment to become available
120
+ let lastErr;
121
+ for (let attempt = 0; attempt < 5; attempt++) {
122
+ try {
123
+ const res = await flyFetch(`/apps/${app}/machines`, token, {
124
+ method: "POST",
125
+ body: machineBody,
126
+ });
127
+ const data = (await res.json());
128
+ await cleanupDone;
129
+ return { machineId: data.id, volumeId };
130
+ }
131
+ catch (err) {
132
+ const msg = err instanceof Error ? err.message : String(err);
133
+ if (msg.includes("volume not found") && attempt < 4) {
134
+ console.log(`Volume not yet available, retrying in 3s... (attempt ${attempt + 1})`);
135
+ await new Promise((r) => setTimeout(r, 3000));
136
+ lastErr = err;
137
+ continue;
138
+ }
139
+ throw err;
140
+ }
141
+ }
142
+ throw lastErr;
118
143
  }
119
144
  catch (err) {
120
145
  // Clean up volume if machine creation fails
@@ -127,14 +152,22 @@ export async function createMachine(app, token, image, env, name) {
127
152
  */
128
153
  export async function waitForMachine(app, token, machineId, timeoutMs = 180000) {
129
154
  const start = Date.now();
155
+ let lastLogTime = 0;
130
156
  while (Date.now() - start < timeoutMs) {
131
157
  try {
132
158
  await flyFetch(`/apps/${app}/machines/${machineId}/wait?state=started&timeout=60`, token);
133
159
  return;
134
160
  }
135
161
  catch (e) {
136
- const elapsed = Math.round((Date.now() - start) / 1000);
137
- console.log(`Still waiting for machine to start (${elapsed}s elapsed): ${e instanceof Error ? e.message : e}`);
162
+ const now = Date.now();
163
+ const elapsed = Math.round((now - start) / 1000);
164
+ // Only log at most once every 10 seconds
165
+ if (now - lastLogTime >= 10000) {
166
+ console.log(`Still waiting for machine to start (${elapsed}s elapsed): ${e instanceof Error ? e.message : e}`);
167
+ lastLogTime = now;
168
+ }
169
+ // Wait before retrying
170
+ await new Promise((r) => setTimeout(r, 5000));
138
171
  }
139
172
  }
140
173
  throw new Error(`Machine ${machineId} did not reach started state within ${timeoutMs / 1000}s`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@replayio/app-building",
3
- "version": "1.8.1",
3
+ "version": "1.8.3",
4
4
  "description": "Library for managing agentic app-building containers",
5
5
  "type": "module",
6
6
  "exports": {