Sprite
Source:
src/Fly/Sprite.ts
A Sprite is an Effect program running in a Fly.io Sprite. Sprites
are org-scoped Linux sandboxes. They hibernate when idle and wake
on demand. There is no parent App. Unlike a Service,
Alchemy does not build a Docker image.
Declare a Sprite
Section titled “Declare a Sprite”A Sprite is a class. Props describe the sandbox. The Effect is the program that runs on it. There is no parent App.
main: import.meta.url is the bundle entrypoint. Alchemy bundles
this file with Rolldown, writes it onto the Sprite, and runs it as
a Sprite service on port. Auth is FLY_API_TOKEN.
export default class Box extends Fly.Sprite<Box>()( "Box", { main: import.meta.url }, Effect.gen(function* () { return {}; }),) {}Serve HTTP with fetch
Section titled “Serve HTTP with fetch”Return fetch from the init Effect to boot an HTTP server. The
Sprite URL proxies to port.
export default class Box extends Fly.Sprite<Box>()( "Box", { main: import.meta.url }, Effect.gen(function* () { return { fetch: Effect.succeed(HttpServerResponse.text("hello")), }; }),) {}The public URL
Section titled “The public URL”Yield the Sprite in the Stack. box.url is
https://{name}-….sprites.app.
export default Alchemy.Stack( "MyApp", { providers: Fly.providers(), state: Alchemy.localState() }, Effect.gen(function* () { const box = yield* Box; return { url: box.url }; }),);URL auth
Section titled “URL auth”urlAuth is public or sprite. Default is public so url
answers without a Sprites token.
export default class Box extends Fly.Sprite<Box>()( "Box", { main: import.meta.url, urlAuth: "sprite" }, Effect.gen(function* () { return { fetch: Effect.succeed(HttpServerResponse.text("hello")), }; }),) {}Config
Section titled “Config”Yield Config in init. Alchemy reads the value from the env of
whoever deploys and writes it onto the Sprite. Do not pass
env: { ... } on a Sprite.
Yield FileSystem.FileSystem in init, never inside fetch.
import * as Config from "effect/Config";import * as FileSystem from "effect/FileSystem";import * as Redacted from "effect/Redacted";
export default class Box extends Fly.Sprite<Box>()( "Box", { main: import.meta.url }, Effect.gen(function* () { const apiKey = yield* Config.redacted("API_KEY"); const fs = yield* FileSystem.FileSystem; yield* fs.makeDirectory("/tmp", { recursive: true });
return { fetch: Effect.gen(function* () { const token = Redacted.value(apiKey); return HttpServerResponse.text("ok"); }), }; }),) {}Exec runs a command on the Sprite. Provide ExecHttp.
const exec = yield* Fly.Exec(Box);const result = yield* exec({ cmd: ["ls", "-la"] });Checkpoint
Section titled “Checkpoint”Checkpoint snapshots and restores the Sprite disk. Provide
CheckpointHttp.
const checkpoint = yield* Fly.Checkpoint(Box);yield* checkpoint.create({ comment: "before" });yield* checkpoint.restore("v1");A stable name
Section titled “A stable name”Omit name and Alchemy generates one from the stack, stage, and
logical ID.
export default class Box extends Fly.Sprite<Box>()( "Box", { main: import.meta.url, name: "box" }, Effect.gen(function* () { return { fetch: Effect.succeed(HttpServerResponse.text("hello")), }; }),) {}Named export
Section titled “Named export”handler is the named export to load from main. Default is
"default".
export default class Box extends Fly.Sprite<Box>()( "Box", { main: import.meta.url, handler: "box" }, Effect.gen(function* () { return { fetch: Effect.succeed(HttpServerResponse.text("hello")), }; }),) {}