---
title: file
description: "Make a Worktree file the body of an `http` Effect: `body: file(\"dist/report.pdf\")`."
---

# `file`

Function, in `@jr2/orchestrator/src/http-effect.ts`. It is an export of `@jr2/orchestrator`, on the [Authoring surface](../authoring-surface.md) page, in Effects.

```ts
function file<S extends z.ZodType | undefined = undefined>(path: FromInput<S, string>, options: {
  slot?: string;
  segments?: FromInput<S, readonly string[]>;
  contentType?: string;
} = {}): FileBody<S>
```

Make a Worktree file the body of an `http` Effect: `body: file("dist/report.pdf")`. The Effect
then runs in the Sandbox Effector of the Workspace whose body invokes it. That Effector opens the
file in the Worktree and sends it. In a Workspace with no Repo Slot, the path is relative to
`/work`, the folder that its steps share. Use it with `PUT`, `POST` or `PATCH`. `path` and
`segments` can be functions of the input of the Effect.

Some paths and files give the output `refused`, and then nothing is sent. The path has a symlink
in it, has `..`, or is absolute. Or the file is a FIFO, a directory, or a file with more than one
link.

It refuses, when you call it:
- a path that is not a string or a function: `file(path): the path is a string, or a function of
  the Effect's input that returns one`

And when `http` takes the definition:
- a method other than `PUT`, `POST` and `PATCH`: `http({ method: "<method>", body: file(...) }):
  a file body is sent with PUT, POST, PATCH (ADR-0068)`
- a `request` beside it: ``http({ body: file(...), request }): with a file body the run's part
  is file()'s — its path, from the input if it must be, and its `segments` — so write no
  `request` (ADR-0068)``
- a `content-type` header and `contentType`: `http({ headers, body: file(path, { contentType })
  }): "content-type" is set by file()'s contentType — write one of them (ADR-0067)`

And at `jr2 up`, an Effect that no `workspace()` invokes: `workflow "<workflow>": the http Effect
"<slot>" sends a Worktree file as its body, and no workspace() invokes it — outside a Workspace
there is no Worktree to read; invoke it from a workspace()'s body, or send a json or text body
(ADR-0068)`.

**Parameters**

- `path` ([`FromInput`](type-frominput.md)): The file, relative to the Worktree of the Repo Slot, or to `/work` in a Workspace
  with no Repo Slot: a string, or a function of the input of the Effect that gives one.
- `options`: Optional. Each field says what it does.

  - `slot` (optional): `string`

    The Repo Slot whose Worktree holds the file. Write it only when the Workspace has more than
    one.
  - `segments` (optional): `FromInput<S, readonly string[]>`

    Path segments that jr2 adds to the end of the url, as `path` does in `request` for a json or
    text body. A list of strings, or a function of the input of the Effect that gives one.
  - `contentType` (optional): `string`

    The content type of the body. Default `application/octet-stream`. Do not write it beside a
    `content-type` header.

**Returns**: The `body` of an `http` Effect.

**Example**

```ts
import {
  bearer,
  command,
  fail,
  file,
  http,
  jr2Setup,
  secret,
  workspace,
  type Workspaced,
} from "@jr2/orchestrator";

type Input = Workspaced<{}, "app">;

const body = jr2Setup({
  types: {} as { context: Input; input: Input },
  actors: {
    build: command(["npm", "run", "report"]),
    upload: http({
      method: "PUT",
      url: "https://files.example.com/reports",
      auth: bearer(secret("files")),
      body: file("dist/report.pdf", {
        segments: ["report.pdf"],
        contentType: "application/pdf",
      }),
    }),
    fail: fail(),
  },
}).createMachine({
  id: "report",
  context: ({ input }) => input,
  on: { "workspace.lost": ".lost" },
  initial: "building",
  states: {
    building: { invoke: { src: "build", onDone: "uploading" } },
    uploading: { invoke: { src: "upload", onDone: "done" } },
    done: { type: "final" },
    lost: { invoke: { src: "fail", input: { reason: "the Sandbox is gone" } } },
  },
});

export const machine = workspace(body, {
  repos: { app: { url: "https://github.com/you/app.git" } },
  spec: () => ({ branch: "report" }),
});
```

**See also**

- [Run a command or call a URL with an Effect](../../guides/run-a-command-or-call-a-url.md)
- [Effects](../../concepts/effects.md)
- [ADR-0067: An Effect is an actor slot, and runs at most once unless marked idempotent](../decisions/0067-an-effect-is-an-actor-slot-and-runs-at-most-once-unless-marked-idempotent.md)
