Skip to content

@usine/gateway

The usine gateway: a credential-injecting proxy for GitHub and LLM providers, and an egress allowlist, in front of Worker VMs.

No credential: requests go upstream as they are, so only what GitHub serves anonymously works, which is reading a public repository.

  • Schema.Class

new AnonymousCredential(…args): AnonymousCredential

Parameter Type
…args [props?: object, options?: MakeOptions]

AnonymousCredential


An Anthropic API key, sent upstream as x-api-key.

  • Schema.Class

new AnthropicApiKey(…args): AnthropicApiKey

Parameter Type
…args [props: object, options?: MakeOptions]

AnthropicApiKey

readonly key: Redacted<string>


Claude Code’s upstream: ANTHROPIC_BASE_URL on the Worker points at http://llm.<domain>/anthropic.

  • Schema.Class

new AnthropicProvider(…args): AnthropicProvider

Parameter Type
…args [props: object, options?: MakeOptions]

AnthropicProvider

readonly credential: AnthropicApiKey | AnthropicSubscriptionToken

readonly upstream: string & Brand<"UpstreamBase">


A Claude subscription token from claude setup-token, sent upstream as a bearer token with the OAuth beta flag. Anthropic does not document a proxy that swaps a placeholder for one; test/placeholder-swap checks whether it works before anyone relies on it.

  • Schema.Class

new AnthropicSubscriptionToken(…args): AnthropicSubscriptionToken

Parameter Type
…args [props: object, options?: MakeOptions]

AnthropicSubscriptionToken

readonly token: Redacted<string>


The executor’s grant to one Worker VM for one repository: until expiresAt, the gateway adds credential to that VM’s requests for that repository and honors the caller token issued for this attachment. The executor sets expiresAt to the token’s own expiry, so an attachment never outlives its token. Several attachments may be in force for the same Worker and repository, one per Attempt.

  • Schema.Class

new Attachment(…args): Attachment

Parameter Type
…args [props: object, options?: MakeOptions]

Attachment

readonly credential: InstallationCredential | AnonymousCredential

readonly expiresAt: Utc

readonly id: string & Brand<"AttachmentId">

readonly repository: string & Brand<"RepositoryName">

readonly worker: string & Brand<"WorkerName">

isLiveAt(now): boolean

Whether the attachment still grants access at now.

Parameter Type
now Utc

boolean


The executor tried to attach a token that had already expired.

  • Schema.Class

new AttachmentAlreadyExpired(…args): AttachmentAlreadyExpired

Parameter Type
…args [props: object, options?: MakeOptions]

AttachmentAlreadyExpired

readonly expiresAt: Utc

readonly repository: string & Brand<"RepositoryName">

readonly worker: string & Brand<"WorkerName">


A renewal named an attachment id that belongs to another Worker or repository.

  • Schema.Class

new AttachmentConflict(…args): AttachmentConflict

Parameter Type
…args [props: object, options?: MakeOptions]

AttachmentConflict

readonly id: string & Brand<"AttachmentId">

readonly repository: string & Brand<"RepositoryName">

readonly worker: string & Brand<"WorkerName">


The attachments the executor has made, keyed by attachment id and kept in memory only. A gateway restart forgets them, and the executor attaches again, with the same ids, when it renews or restarts.

  • Context.ServiceClass

readonly Service: object

The service’s operations: what yield* Attachments returns.

readonly attach: (attachment) => Effect.Effect<void, AttachmentAlreadyExpired | AttachmentConflict>

Stores an attachment, or renews the one with the same id: the new credential and expiry replace the old ones. An id already used for another Worker or repository is refused.

Parameter Type
attachment Attachment

Effect.Effect<void, AttachmentAlreadyExpired | AttachmentConflict>

readonly detach: (id) => Effect.Effect<boolean>

Removes the attachment; false when there was none.

Parameter Type
id AttachmentId

Effect.Effect<boolean>

readonly find: (id) => Effect.Effect<AttachmentLookup>

Whether the attachment is in force, and if not, why.

Parameter Type
id AttachmentId

Effect.Effect<AttachmentLookup>

readonly list: () => Effect.Effect<ReadonlyArray<Attachment>>

Every attachment still in force, oldest expiry first.

Effect.Effect<ReadonlyArray<Attachment>>

readonly sweep: () => Effect.Effect<number>

Forgets expired attachments and returns how many it removed.

Effect.Effect<number>

readonly static layer: Layer<Attachments, never, never>

An empty store that sweeps expired attachments every minute while the layer is in scope.


What a caller token proves: the attachment it was issued with, and that attachment’s Worker and repository. Binding the attachment id means a token from an earlier attachment is refused once a new one is made for the same Worker and repository.

  • Schema.Class

new CallerClaims(…args): CallerClaims

Parameter Type
…args [props: object, options?: MakeOptions]

CallerClaims

readonly attachment: string & Brand<"AttachmentId">

readonly repository: string & Brand<"RepositoryName">

readonly worker: string & Brand<"WorkerName">


A presented caller token that the gateway did not issue: malformed is not in its format, bad-signature was not signed with its key.

  • Schema.Class

new CallerTokenRejected(…args): CallerTokenRejected

Parameter Type
…args [props: object, options?: MakeOptions]

CallerTokenRejected

readonly reason: "malformed" | "bad-signature"


Issues and checks caller tokens. A token is ugw1.<claims>.<HMAC-SHA256> under the gateway’s caller key, so the same attachment yields the same token after a gateway restart or a renewal, and the gateway keeps no token table.

  • Context.ServiceClass

readonly Service: object

The service’s operations: what yield* CallerTokens returns.

readonly issue: (claims) => Effect.Effect<CallerToken>

Parameter Type
claims CallerClaims

Effect.Effect<CallerToken>

readonly verify: (token) => Effect.Effect<CallerClaims, CallerTokenRejected>

Parameter Type
token CallerToken

Effect.Effect<CallerClaims, CallerTokenRejected>

readonly withoutCallerTokens: (headers) => Effect.Effect<Headers.Headers>

Removes caller tokens from headers bound for a host outside the gateway: the gateway header always, and an Authorization or x-api-key value only when it verifies as a caller token, so a Worker’s own credential for a registry still goes through.

Parameter Type
headers Headers.Headers

Effect.Effect<Headers.Headers>

readonly static layer: Layer<CallerTokens, never, GatewaySettings>


The hosts Workers may reach through the gateway’s forward proxy. Everything not listed is refused; IP addresses are always refused, since a rule names hosts and an address would bypass it.

  • Schema.Class

new EgressAllowlist(…args): EgressAllowlist

Parameter Type
…args [props: object, options?: MakeOptions]

EgressAllowlist

readonly rules: readonly EgressRule[]

decide(host, port): EgressDecision

Decides whether a client may open a connection to host on port.

Parameter Type
host string
port number

EgressDecision


Why the allowlist file could not be read: the line and what is wrong with it.

  • Schema.Class

new EgressAllowlistError(…args): EgressAllowlistError

Parameter Type
…args [props: object, options?: MakeOptions]

EgressAllowlistError

readonly line: number

readonly message: string


A destination the allowlist permits, with the rule that permits it.

  • Schema.Class

new EgressPermitted(…args): EgressPermitted

Parameter Type
…args [props: object, options?: MakeOptions]

EgressPermitted

readonly host: string & Brand<"HostName">

readonly port: number & Brand<"Port">

readonly rule: EgressRule


A destination the allowlist refuses. host is the raw host the client asked for.

  • Schema.Class

new EgressRefused(…args): EgressRefused

Parameter Type
…args [props: object, options?: MakeOptions]

EgressRefused

readonly host: string

readonly port: number

readonly reason: "host-not-allowed" | "port-not-allowed" | "address-literal" | "private-address" | "not-tls" | "server-name-missing" | "server-name-mismatch"


One allowlist line. exact permits that host only; subdomains permits every name below the domain (*.pythonhosted.org), not the domain itself.

  • Schema.Class

new EgressRule(…args): EgressRule

Parameter Type
…args [props: object, options?: MakeOptions]

EgressRule

readonly host: string & Brand<"HostName">

readonly match: "exact" | "subdomains"

readonly ports: readonly [number & Brand<"Port">, number & Brand<"Port">]

covers(host): boolean

Whether this rule covers host, whatever the port.

Parameter Type
host string & Brand<"HostName">

boolean


The attachment existed but its token has expired; the executor did not renew it.

  • Schema.Class

new ExpiredAttachment(…args): ExpiredAttachment

Parameter Type
…args [props: object, options?: MakeOptions]

ExpiredAttachment

readonly expiredAt: Utc


The reverse proxy Worker VMs reach on the private network. git.<domain> serves GitHub with the attached installation token and llm.<domain> serves the LLM providers with the gateway’s API keys; every request presents a caller token whose attachment is in force. Any other host is refused: the forward proxy serves the allowlisted ones.

  • Context.ServiceClass

readonly Service: object

The service’s operations: what yield* GatewayProxy returns.

readonly handle: Effect.Effect<HttpServerResponse.HttpServerResponse, never, HttpServerRequest.HttpServerRequest>

Forwards one Worker request with the attached credential, or refuses it and logs why.

readonly static layer: Layer<GatewayProxy, never, HttpClient | Attachments | CallerTokens | GatewaySettings>


The gateway’s configuration, read once at startup by the platform entry point. Secrets stay Redacted and are only unwrapped where they are sent or used to sign.

  • Context.ServiceClass

readonly Service: object

The service’s operations: what yield* GatewaySettings returns.

readonly adminToken: AdminToken

readonly callerKey: CallerKey

readonly domain: GatewayDomain

readonly egress: EgressAllowlist

readonly github: GitHubOrigins

readonly providers: LlmProviders


A GitHub App installation token the gateway adds to the Worker’s requests for the repository.

  • Schema.Class

new InstallationCredential(…args): InstallationCredential

Parameter Type
…args [props: object, options?: MakeOptions]

InstallationCredential

readonly token: Redacted<string>


The attachment is in force.

  • Schema.Class

new LiveAttachment(…args): LiveAttachment

Parameter Type
…args [props: object, options?: MakeOptions]

LiveAttachment

readonly attachment: Attachment


No attachment with the id is in the store: it was detached, or never attached on this gateway.

  • Schema.Class

new MissingAttachment(…args): MissingAttachment

Parameter Type
…args [props?: object, options?: MakeOptions]

MissingAttachment


An OpenAI-compatible upstream for Codex: its model_provider base_url on the Worker is http://llm.<domain>/openai/v1. The key is sent as a bearer token.

  • Schema.Class

new OpenAiProvider(…args): OpenAiProvider

Parameter Type
…args [props: object, options?: MakeOptions]

OpenAiProvider

readonly key: Redacted<string>

readonly upstream: string & Brand<"UpstreamBase">

Where the gateway forwards GitHub requests: web serves git smart HTTP, api REST and GraphQL, uploads release asset uploads.

readonly api: string & Brand<"UpstreamBase">

readonly uploads: string & Brand<"UpstreamBase">

readonly web: string & Brand<"UpstreamBase">


The LLM upstreams the gateway forwards to. A provider without a credential is refused.

readonly anthropic: Option<AnthropicProvider>

readonly openai: Option<OpenAiProvider>

AdminToken = typeof AdminToken.Type

The bearer token the executor sends to the admin API, decoded from its raw value: at least 32 characters.


AnthropicCredential = typeof AnthropicCredential.Type

The credential the gateway adds to Anthropic requests.


AttachmentCredential = typeof AttachmentCredential.Type

What the gateway adds to a Worker’s GitHub requests for an attached repository.


AttachmentId = typeof AttachmentId.Type

Identifies one attachment from its first attach to its detach. Renewals keep it; a fresh attach for the same Worker and repository gets a new one, so a caller token from an earlier attachment is never honored again.


AttachmentLookup = LiveAttachment | ExpiredAttachment | MissingAttachment

The outcome of looking up an attachment by its id.


CallerKey = typeof CallerKey.Type

The HMAC key caller tokens are signed with, decoded from its raw value: at least 32 characters, held only by the gateway.


CallerToken = typeof CallerToken.Type

The credential a Worker VM sends in place of a real one. The gateway issues it with each attachment and honors it only while that attachment is in force, so it grants nothing the executor did not attach.


EgressDecision = EgressPermitted | EgressRefused


EgressRefusalReason = typeof EgressRefusalReason.Type

Why a destination is refused: its host is not listed, its port is not, it is an IP address, or its name resolves to a private, loopback, or link-local address (checked by a proxy that resolves names itself). For a tunnel, also when the client’s first bytes are not a TLS ClientHello, when the ClientHello names no server or hides it with ECH, or when it names another server than the CONNECT host.


HostName = typeof HostName.Type

A lowercase DNS host name without a trailing dot.


Port = typeof Port.Type

A TCP port.


RefusalReason = typeof RefusalReason.Type

Why the gateway refused a request. Every refusal is logged at warning level with this reason, the host, and the Worker when the caller token names one, and the response carries it in x-usine-gateway-refusal.


UpstreamBase = typeof UpstreamBase.Type

The base URL of an upstream API: scheme, host, and an optional path prefix, without a query, a fragment, or a trailing slash.

const adminRoutes: Layer.Layer<never, never, FileSystem | GatewaySettings | Generator | HttpPlatform | HttpRouter | Path | Request | Request>

The admin API’s routes, for an HttpRouter the platform serves. Bind it to a loopback or otherwise private address: the executor reaches it through its SSH connection to the gateway.


const AdminToken: Schema.RedactedFromValue<Schema.String>

The bearer token the executor sends to the admin API, decoded from its raw value: at least 32 characters.


const AnthropicCredential: Schema.Union<readonly [typeof AnthropicApiKey, typeof AnthropicSubscriptionToken]>

The credential the gateway adds to Anthropic requests.


const AttachmentCredential: Schema.Union<readonly [typeof InstallationCredential, typeof AnonymousCredential]>

What the gateway adds to a Worker’s GitHub requests for an attached repository.


const AttachmentId: Schema.brand<Schema.String, "AttachmentId">

Identifies one attachment from its first attach to its detach. Renewals keep it; a fresh attach for the same Worker and repository gets a new one, so a caller token from an earlier attachment is never honored again.


const CallerKey: Schema.RedactedFromValue<Schema.String>

The HMAC key caller tokens are signed with, decoded from its raw value: at least 32 characters, held only by the gateway.


const CallerToken: Schema.Redacted<Schema.NonEmptyString>

The credential a Worker VM sends in place of a real one. The gateway issues it with each attachment and honors it only while that attachment is in force, so it grants nothing the executor did not attach.


const EgressRefusalReason: Schema.Literals<readonly ["host-not-allowed", "port-not-allowed", "address-literal", "private-address", "not-tls", "server-name-missing", "server-name-mismatch"]>

Why a destination is refused: its host is not listed, its port is not, it is an IP address, or its name resolves to a private, loopback, or link-local address (checked by a proxy that resolves names itself). For a tunnel, also when the client’s first bytes are not a TLS ClientHello, when the ClientHello names no server or hides it with ECH, or when it names another server than the CONNECT host.


const endToEndHeaders: (headers) => Headers.Headers

Removes hop-by-hop headers, including any the Connection header names.

Parameter Type
headers Headers.Headers

Headers.Headers


const GATEWAY_TOKEN_HEADER: "x-usine-gateway-token" = "x-usine-gateway-token"

The header a caller sets when its tool can add one, such as git with http.extraHeader.


const gatewayHosts: (domain) => object

The host names the gateway serves under its domain.

Parameter Type
domain GatewayDomain

object

readonly git: `git.${string & Brand}`

readonly llm: `llm.${string & Brand}`


const gatewayServices: Layer.Layer<Attachments | CallerTokens, never, GatewaySettings>

The gateway’s shared state for one process: the attachment store and the caller token signer. The reverse proxy and the admin API must use the same instance, so provide this layer once to both.


const GITHUB_ORIGINS: GitHubOrigins

github.com itself.


const HostName: Schema.brand<Schema.String, "HostName">

A lowercase DNS host name without a trailing dot.


const parseEgressAllowlist: (text) => Result.Result<EgressAllowlist, EgressAllowlistError>

Parses an allowlist file: one rule per line, # starts a comment, blank lines are skipped. A line is host, *.domain, or either with :port; without a port the rule permits 443 and 80.

Parameter Type
text string

Result.Result<EgressAllowlist, EgressAllowlistError>


const Port: Schema.brand<Schema.Int, "Port">

A TCP port.


const REFUSAL_HEADER: "x-usine-gateway-refusal" = "x-usine-gateway-refusal"

The header a refused response names its reason in.


const RefusalReason: Schema.Literals<readonly ["unknown-host", "unsupported-path", "missing-caller-token", "invalid-caller-token", "stale-caller-token", "attachment-expired", "repository-mismatch", "provider-not-configured"]>

Why the gateway refused a request. Every refusal is logged at warning level with this reason, the host, and the Worker when the caller token names one, and the response carries it in x-usine-gateway-refusal.


const tokenFromAuthorization: (value) => Option.Option<CallerToken>

The credential in an Authorization or Proxy-Authorization value: the parameter of Bearer and token, or the password of Basic (the user name when the password is empty).

Parameter Type
value string

Option.Option<CallerToken>


const UpstreamBase: Schema.brand<Schema.String, "UpstreamBase">

The base URL of an upstream API: scheme, host, and an optional path prefix, without a query, a fragment, or a trailing slash.

Re-exports GatewayDomain