@alchemy.run/fly 2.0.0-beta.84 → 2.0.0-beta.85

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 (148) hide show
  1. package/lib/App.d.ts +4 -4
  2. package/lib/App.d.ts.map +1 -1
  3. package/lib/App.js +4 -6
  4. package/lib/App.js.map +1 -1
  5. package/lib/AuthProvider.d.ts +1 -1
  6. package/lib/AuthProvider.d.ts.map +1 -1
  7. package/lib/BindService.d.ts.map +1 -1
  8. package/lib/BindService.js +1 -1
  9. package/lib/BindService.js.map +1 -1
  10. package/lib/Bucket.d.ts +2 -2
  11. package/lib/Bucket.d.ts.map +1 -1
  12. package/lib/Bucket.js +10 -10
  13. package/lib/Bucket.js.map +1 -1
  14. package/lib/BucketBinding.js +1 -1
  15. package/lib/BucketBinding.js.map +1 -1
  16. package/lib/Certificate.js +4 -4
  17. package/lib/Certificate.js.map +1 -1
  18. package/lib/ConnectPostgres.d.ts +1 -1
  19. package/lib/ConnectPostgres.d.ts.map +1 -1
  20. package/lib/ConnectPostgresHttp.js +1 -1
  21. package/lib/ConnectPostgresHttp.js.map +1 -1
  22. package/lib/Contributions.d.ts +1 -1
  23. package/lib/Credentials.d.ts +1 -1
  24. package/lib/Credentials.d.ts.map +1 -1
  25. package/lib/Credentials.js +10 -14
  26. package/lib/Credentials.js.map +1 -1
  27. package/lib/DeploymentImages.js +1 -1
  28. package/lib/DeploymentImages.js.map +1 -1
  29. package/lib/Errors.d.ts +1 -1
  30. package/lib/Errors.d.ts.map +1 -1
  31. package/lib/IpAssignment.js +4 -4
  32. package/lib/IpAssignment.js.map +1 -1
  33. package/lib/Machine.d.ts +1 -1
  34. package/lib/Machine.d.ts.map +1 -1
  35. package/lib/Machine.js +2 -2
  36. package/lib/Machine.js.map +1 -1
  37. package/lib/Postgres.d.ts +1 -1
  38. package/lib/Postgres.d.ts.map +1 -1
  39. package/lib/Postgres.js +6 -6
  40. package/lib/Postgres.js.map +1 -1
  41. package/lib/PostgresMigrations.d.ts +7 -22
  42. package/lib/PostgresMigrations.d.ts.map +1 -1
  43. package/lib/PostgresMigrations.js +37 -89
  44. package/lib/PostgresMigrations.js.map +1 -1
  45. package/lib/Providers.d.ts +1 -1
  46. package/lib/Providers.d.ts.map +1 -1
  47. package/lib/Redis.d.ts +2 -2
  48. package/lib/Redis.d.ts.map +1 -1
  49. package/lib/Redis.js +9 -6
  50. package/lib/Redis.js.map +1 -1
  51. package/lib/RedisBinding.js +1 -1
  52. package/lib/RedisBinding.js.map +1 -1
  53. package/lib/RedisHttp.d.ts +1 -1
  54. package/lib/RedisHttp.d.ts.map +1 -1
  55. package/lib/RedisHttp.js +4 -1
  56. package/lib/RedisHttp.js.map +1 -1
  57. package/lib/Secret.d.ts +1 -1
  58. package/lib/Secret.d.ts.map +1 -1
  59. package/lib/Secret.js +2 -2
  60. package/lib/Secret.js.map +1 -1
  61. package/lib/SecretKey.d.ts +1 -1
  62. package/lib/SecretKey.d.ts.map +1 -1
  63. package/lib/SecretKey.js +2 -2
  64. package/lib/SecretKey.js.map +1 -1
  65. package/lib/Service.d.ts +8 -13
  66. package/lib/Service.d.ts.map +1 -1
  67. package/lib/Service.js +51 -18
  68. package/lib/Service.js.map +1 -1
  69. package/lib/Sprite.d.ts +2 -2
  70. package/lib/Sprite.d.ts.map +1 -1
  71. package/lib/Sprite.js +7 -5
  72. package/lib/Sprite.js.map +1 -1
  73. package/lib/Volume.d.ts +2 -2
  74. package/lib/Volume.d.ts.map +1 -1
  75. package/lib/Volume.js +5 -5
  76. package/lib/Volume.js.map +1 -1
  77. package/lib/VolumeSnapshot.js +1 -1
  78. package/lib/VolumeSnapshot.js.map +1 -1
  79. package/lib/Website/AssetDeployment.d.ts.map +1 -1
  80. package/lib/Website/AssetDeployment.js +9 -9
  81. package/lib/Website/AssetDeployment.js.map +1 -1
  82. package/lib/Website/Astro.d.ts +8 -6
  83. package/lib/Website/Astro.d.ts.map +1 -1
  84. package/lib/Website/Astro.js +12 -13
  85. package/lib/Website/Astro.js.map +1 -1
  86. package/lib/Website/FrameworkSite.d.ts +39 -2
  87. package/lib/Website/FrameworkSite.d.ts.map +1 -1
  88. package/lib/Website/FrameworkSite.js +46 -3
  89. package/lib/Website/FrameworkSite.js.map +1 -1
  90. package/lib/Website/StaticSite.d.ts +10 -3
  91. package/lib/Website/StaticSite.d.ts.map +1 -1
  92. package/lib/Website/StaticSite.js +16 -4
  93. package/lib/Website/StaticSite.js.map +1 -1
  94. package/lib/Website/Vite.d.ts +9 -0
  95. package/lib/Website/Vite.d.ts.map +1 -1
  96. package/lib/Website/Vite.js +9 -0
  97. package/lib/Website/Vite.js.map +1 -1
  98. package/lib/WriteCertificatesHttp.js +2 -2
  99. package/lib/WriteCertificatesHttp.js.map +1 -1
  100. package/lib/bluegreen.d.ts +4 -4
  101. package/lib/bluegreen.d.ts.map +1 -1
  102. package/lib/bluegreen.js +6 -4
  103. package/lib/bluegreen.js.map +1 -1
  104. package/lib/hosted.d.ts +3 -4
  105. package/lib/hosted.d.ts.map +1 -1
  106. package/lib/hosted.js.map +1 -1
  107. package/lib/internal/RemoteBuilder.d.ts.map +1 -1
  108. package/lib/internal/RemoteBuilder.js +21 -8
  109. package/lib/internal/RemoteBuilder.js.map +1 -1
  110. package/lib/leases.d.ts +2 -2
  111. package/lib/replicas.d.ts +10 -10
  112. package/lib/replicas.d.ts.map +1 -1
  113. package/lib/replicas.js +7 -7
  114. package/lib/replicas.js.map +1 -1
  115. package/package.json +13 -13
  116. package/src/App.ts +5 -7
  117. package/src/BindService.ts +1 -2
  118. package/src/Bucket.ts +15 -13
  119. package/src/BucketBinding.ts +1 -1
  120. package/src/Certificate.ts +4 -4
  121. package/src/ConnectPostgres.ts +1 -1
  122. package/src/ConnectPostgresHttp.ts +1 -1
  123. package/src/Credentials.ts +9 -36
  124. package/src/DeploymentImages.ts +1 -1
  125. package/src/Errors.ts +1 -1
  126. package/src/IpAssignment.ts +4 -4
  127. package/src/Machine.ts +5 -3
  128. package/src/Postgres.ts +7 -7
  129. package/src/PostgresMigrations.ts +39 -99
  130. package/src/Redis.ts +11 -8
  131. package/src/RedisBinding.ts +1 -1
  132. package/src/RedisHttp.ts +4 -1
  133. package/src/Secret.ts +3 -3
  134. package/src/SecretKey.ts +3 -3
  135. package/src/Service.ts +53 -19
  136. package/src/Sprite.ts +11 -9
  137. package/src/Volume.ts +6 -6
  138. package/src/VolumeSnapshot.ts +1 -1
  139. package/src/Website/AssetDeployment.ts +13 -15
  140. package/src/Website/Astro.ts +20 -15
  141. package/src/Website/FrameworkSite.ts +92 -6
  142. package/src/Website/StaticSite.ts +27 -7
  143. package/src/Website/Vite.ts +9 -0
  144. package/src/WriteCertificatesHttp.ts +2 -2
  145. package/src/bluegreen.ts +7 -4
  146. package/src/hosted.ts +3 -4
  147. package/src/internal/RemoteBuilder.ts +37 -19
  148. package/src/replicas.ts +8 -8
@@ -43,7 +43,7 @@ export const certificatesWriteClient = (
43
43
  return yield* authorize(
44
44
  machines
45
45
  .createAppAcmeCertificate({ app_name: yield* appName, hostname })
46
- .pipe(Effect.catchTag("Conflict", () => Effect.succeed(undefined))),
46
+ .pipe(Effect.catchTag("Conflict", () => Effect.undefined)),
47
47
  );
48
48
  }),
49
49
  upload: Effect.fn("Fly.Certificates.upload")(function* (request) {
@@ -78,7 +78,7 @@ export const certificatesWriteClient = (
78
78
  return yield* authorize(
79
79
  machines
80
80
  .getAppCertificate({ app_name: yield* appName, hostname })
81
- .pipe(Effect.catchTag("NotFound", () => Effect.succeed(undefined))),
81
+ .pipe(Effect.catchTag("NotFound", () => Effect.undefined)),
82
82
  );
83
83
  }),
84
84
  remove: Effect.fn("Fly.Certificates.remove")(function* (hostname) {
package/src/bluegreen.ts CHANGED
@@ -102,7 +102,7 @@ export const setRouting = (
102
102
  yield* getMachineById(appName, machineId).pipe(
103
103
  Effect.filterOrFail(
104
104
  (machine) => machine !== undefined && machine.cordoned === cordoned,
105
- () => new ReplicaNotCreated({ appName, name: machineId }),
105
+ () => new ReplicaNotCreated({ appName, resourceName: machineId }),
106
106
  ),
107
107
  Effect.retry({
108
108
  times: 8,
@@ -293,7 +293,9 @@ export const reconcileBlueGreen = Effect.fn(function* (
293
293
  reusable?.[0] ??
294
294
  (yield* sha256Object({
295
295
  workload,
296
- predecessors: owned.map((machine) => machine.id).sort(),
296
+ predecessors: owned
297
+ .map((machine) => machine.id)
298
+ .sort((a, b) => ((a ?? "") < (b ?? "") ? -1 : (a ?? "") > (b ?? "") ? 1 : 0)),
297
299
  })).slice(0, 20);
298
300
  const desired = reusable?.[1] ?? [];
299
301
  if (
@@ -417,7 +419,7 @@ export const reconcileBlueGreen = Effect.fn(function* (
417
419
  ),
418
420
  Effect.filterOrFail(
419
421
  (machine) => machine !== undefined,
420
- () => new ReplicaNotCreated({ appName: input.appName, name }),
422
+ () => new ReplicaNotCreated({ appName: input.appName, resourceName: name }),
421
423
  ),
422
424
  Effect.retry({
423
425
  times: 8,
@@ -446,7 +448,8 @@ export const reconcileBlueGreen = Effect.fn(function* (
446
448
  Effect.catchReason("HttpClientError", "TransportError", () => readback),
447
449
  );
448
450
  }
449
- if (!current?.id) return yield* new ReplicaNotCreated({ appName: input.appName, name });
451
+ if (!current?.id)
452
+ return yield* new ReplicaNotCreated({ appName: input.appName, resourceName: name });
450
453
  const leased = (yield* leaseSnapshot(input.appName, [current], leases))[0];
451
454
  if (!leased?.id)
452
455
  return yield* ambiguous(
package/src/hosted.ts CHANGED
@@ -70,13 +70,12 @@ export const MACHINE_PLATFORM = "linux/amd64";
70
70
  export interface FlyBuildOptions extends Bundle.BundleConfig {
71
71
  /**
72
72
  * Native or Node-only packages to install into the Machine image with
73
- * `npm install` instead of bundling them. `pg` is CommonJS: Rolldown's
74
- * interop turns `Client` into a namespace (`The superclass is not a
75
- * constructor`). Same `build.install` shape as Lambda.
73
+ * `npm install` instead of bundling them. Same `build.install` shape as
74
+ * Lambda.
76
75
  *
77
76
  * @example
78
77
  * ```typescript
79
- * build: { install: ["pg"] }
78
+ * build: { install: ["sharp"] }
80
79
  * ```
81
80
  */
82
81
  readonly install?: PackageInstall;
@@ -37,7 +37,9 @@ const HEALTH_INTERVAL = Duration.seconds(5);
37
37
  const MAX_PENDING_POLLS = 240;
38
38
  /** How often, and how long, to wait for the builder's push to reach `registry.fly.io`. */
39
39
  const UPSTREAM_POLL = Duration.seconds(2);
40
- const MAX_UPSTREAM_POLLS = 90;
40
+ const MAX_UPSTREAM_POLLS = 30;
41
+ /** Pushes of one image before giving up on it reaching the registry. */
42
+ const MAX_PUSHES = 3;
41
43
 
42
44
  export class RemoteBuilderError extends Data.TaggedError("Fly.RemoteBuilderError")<{
43
45
  operation: string;
@@ -170,7 +172,13 @@ export const buildOnRemoteBuilder = Effect.fn(function* (input: {
170
172
  () => input.docker.run(["buildx", "rm", builder]).pipe(Effect.ignore),
171
173
  );
172
174
 
173
- yield* input.docker.image
175
+ // The builder pushes through its host's registry mirror, which forwards
176
+ // to registry.fly.io. Machines pull from there, so confirm the tag landed
177
+ // (usually within seconds) while the builder is still held. The mirror
178
+ // occasionally drops a push without an error, so a tag that hasn't
179
+ // landed is pushed again: the builder has every layer cached, so a
180
+ // repeat build only re-sends the image.
181
+ const build = input.docker.image
174
182
  .build(
175
183
  {
176
184
  context: input.contextDir,
@@ -193,25 +201,35 @@ export const buildOnRemoteBuilder = Effect.fn(function* (input: {
193
201
  }),
194
202
  }),
195
203
  );
196
-
197
- // The builder pushes through its host's registry mirror, which forwards
198
- // to registry.fly.io. Machines pull from there, so confirm the tag landed
199
- // (usually within seconds) while the builder is still held.
200
- const started = yield* Clock.currentTimeMillis;
201
- yield* input.docker.run(["buildx", "imagetools", "inspect", "--raw", input.imageRef]).pipe(
202
- Effect.provideService(DockerEnvironment, {
203
- DOCKER_AUTH_CONFIG: JSON.stringify({
204
- auths: { [input.registry.server]: { auth: basicAuth(input.registry) } },
205
- }),
206
- }),
207
- Effect.retry({ schedule: Schedule.spaced(UPSTREAM_POLL), times: MAX_UPSTREAM_POLLS }),
208
- Effect.mapError(
209
- () =>
210
- new RemoteBuilderError({
211
- operation: "upload",
212
- message: `${input.imageRef} did not reach ${input.registry.server}`,
204
+ const landed = input.docker
205
+ .run(["buildx", "imagetools", "inspect", "--raw", input.imageRef])
206
+ .pipe(
207
+ Effect.provideService(DockerEnvironment, {
208
+ DOCKER_AUTH_CONFIG: JSON.stringify({
209
+ auths: { [input.registry.server]: { auth: basicAuth(input.registry) } },
213
210
  }),
211
+ }),
212
+ Effect.retry({ schedule: Schedule.spaced(UPSTREAM_POLL), times: MAX_UPSTREAM_POLLS }),
213
+ Effect.mapError(
214
+ () =>
215
+ new RemoteBuilderError({
216
+ operation: "upload",
217
+ message: `${input.imageRef} did not reach ${input.registry.server} after ${MAX_PUSHES} pushes`,
218
+ }),
219
+ ),
220
+ );
221
+ const started = yield* Clock.currentTimeMillis;
222
+ yield* build.pipe(
223
+ Effect.andThen(landed),
224
+ Effect.tapError((error) =>
225
+ error._tag === "Fly.RemoteBuilderError" && error.operation === "upload"
226
+ ? note(`${input.imageRef} hasn't reached ${input.registry.server} yet`)
227
+ : Effect.void,
214
228
  ),
229
+ Effect.retry({
230
+ while: (error) => error._tag === "Fly.RemoteBuilderError" && error.operation === "upload",
231
+ times: MAX_PUSHES - 1,
232
+ }),
215
233
  );
216
234
  const waited = (yield* Clock.currentTimeMillis) - started;
217
235
  yield* note(`${input.imageRef} available on ${input.registry.server} after ${waited}ms`);
package/src/replicas.ts CHANGED
@@ -42,7 +42,7 @@ const waitBackoff = Schedule.exponential("500 millis");
42
42
  const SERVICE_CHECK_NAME_PREFIX = "servicecheck-";
43
43
 
44
44
  export class ReplicaNotCreated extends Data.TaggedError("Fly.ReplicaNotCreated")<{
45
- name: string;
45
+ resourceName: string;
46
46
  appName: string;
47
47
  }> {}
48
48
 
@@ -115,7 +115,7 @@ export const gone = (machine: FlyMachine | undefined) =>
115
115
  export const getMachineById = (appName: string, machineId: string) =>
116
116
  machines.getMachine({ app_name: appName, machine_id: machineId }).pipe(
117
117
  Effect.map((machine) => (gone(machine) ? undefined : machine)),
118
- Effect.catchTag("NotFound", () => Effect.succeed(undefined)),
118
+ Effect.catchTag("NotFound", () => Effect.undefined),
119
119
  );
120
120
 
121
121
  /**
@@ -137,7 +137,7 @@ const getLeasedMachine = (appName: string, machineId: string) =>
137
137
  const getLeasedMachineById = (appName: string, machineId: string) =>
138
138
  getLeasedMachine(appName, machineId).pipe(
139
139
  Effect.map((machine) => (gone(machine) ? undefined : machine)),
140
- Effect.catchTag("NotFound", () => Effect.succeed(undefined)),
140
+ Effect.catchTag("NotFound", () => Effect.undefined),
141
141
  );
142
142
 
143
143
  export const listMachinesByApp = (appName: string) =>
@@ -1163,7 +1163,7 @@ const reconcileLeasedReplicas = Effect.fn(function* (
1163
1163
  );
1164
1164
  const volumeId = volume?.id;
1165
1165
  if (volumeId === undefined) {
1166
- return yield* new ReplicaNotCreated({ name, appName: input.appName });
1166
+ return yield* new ReplicaNotCreated({ resourceName: name, appName: input.appName });
1167
1167
  }
1168
1168
  usedVolumeIds.add(volumeId);
1169
1169
  mounts.push({ volume: volumeId, path: group.disk.path });
@@ -1187,7 +1187,7 @@ const reconcileLeasedReplicas = Effect.fn(function* (
1187
1187
  skip_launch: input.skipLaunch === true ? true : undefined,
1188
1188
  min_secrets_version: input.minSecretsVersion,
1189
1189
  })
1190
- .pipe(Effect.catchTag("Conflict", () => Effect.succeed(undefined)));
1190
+ .pipe(Effect.catchTag("Conflict", () => Effect.undefined));
1191
1191
  current =
1192
1192
  created ??
1193
1193
  (yield* listMachinesByApp(input.appName).pipe(
@@ -1200,11 +1200,11 @@ const reconcileLeasedReplicas = Effect.fn(function* (
1200
1200
  ),
1201
1201
  ));
1202
1202
  if (current === undefined || current.id === undefined) {
1203
- return yield* new ReplicaNotCreated({ name, appName: input.appName });
1203
+ return yield* new ReplicaNotCreated({ resourceName: name, appName: input.appName });
1204
1204
  }
1205
1205
  const observed = (yield* leaseSnapshot(input.appName, [current], leases))[0];
1206
1206
  if (!observed || input.configDrifted(observed, { mounts, metadata })) {
1207
- return yield* new ReplicaNotCreated({ name, appName: input.appName });
1207
+ return yield* new ReplicaNotCreated({ resourceName: name, appName: input.appName });
1208
1208
  }
1209
1209
  current = observed;
1210
1210
  } else if (
@@ -1243,7 +1243,7 @@ const reconcileLeasedReplicas = Effect.fn(function* (
1243
1243
  !sameChecks(observed.config?.checks, config.checks) ||
1244
1244
  !sameStopConfig(observed.config?.stop_config, config.stop_config)
1245
1245
  )
1246
- return yield* new ReplicaNotCreated({ appName: input.appName, name });
1246
+ return yield* new ReplicaNotCreated({ appName: input.appName, resourceName: name });
1247
1247
  return observed;
1248
1248
  }).pipe(
1249
1249
  Effect.retry({