Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.deep.space/llms.txt

Use this file to discover all available pages before exploring further.

The scaffolded worker.ts already uses these for every cross-worker call. They prefer service bindings (set up automatically on deploy) and fall back to HTTPS URLs in local dev.
import {
  apiWorkerFetch, platformWorkerFetch, authWorkerFetch,
  resolveApiTransport,
  createScopedR2Handler,
} from 'deepspace/worker'

import type {
  ApiWorkerEnv, PlatformWorkerEnv, AuthWorkerEnv,
  ScopedR2Config, ScopedR2Handler, ScopedR2Auth, ScopeContext, PrefixResult,
} from 'deepspace/worker'
Do not replace these with raw c.env.X.fetch(...). wrangler dev doesn’t surface service bindings cross-process for SDK apps - the binding is undefined locally and the raw fetch silently fails. The helpers paper over the dev/prod mismatch.

apiWorkerFetch(env, path, init?)

Fetch the api-worker (Stripe, integrations, profiles, OAuth, usage tracking).
function apiWorkerFetch(
  env: ApiWorkerEnv,
  path: string,
  init?: RequestInit,
): Promise<Response>

interface ApiWorkerEnv {
  API_WORKER?: Fetcher       // service binding (preferred in prod)
  API_WORKER_URL?: string    // HTTPS fallback (used in dev)
}
Prefers the API_WORKER service binding; falls back to API_WORKER_URL. Throws an actionable Error if neither is configured.

platformWorkerFetch(env, pathOrRequest, init?)

Fetch the platform-worker (cross-app DOs, R2 file gateway, WebSocket multiplexing).
function platformWorkerFetch(
  env: PlatformWorkerEnv,
  pathOrRequest: string | Request,
  init?: RequestInit,
): Promise<Response>

interface PlatformWorkerEnv {
  PLATFORM_WORKER?: Fetcher
  PLATFORM_WORKER_URL?: string
}
Accepts either a path string or a full Request, so you can hand off c.req.raw derivatives with method/headers/body intact:
app.get('/ws/:roomId', async (c) => {
  const roomId = c.req.param('roomId')
  if (/^(workspace|dir|conv):/.test(roomId)) {
    return platformWorkerFetch(c.env, c.req.raw)
  }
  return wsRoute((env) => env.RECORD_ROOMS)(c)
})
wsRoute in the example above is not an SDK export - it’s a small helper defined locally in the scaffolded worker.ts (around line 345 of templates/starter/worker.ts). It owns the JWT verification + URL rewriting boilerplate for WebSocket routes. Apps are free to edit or replace it. For PNG capture against an *.app.space / *.deep.space URL, prefer the higher-level captureScreenshot wrapper instead of calling platformWorkerFetch against /internal/screenshot yourself - it owns the HMAC headers and the null-on-failure contract.

authWorkerFetch(env, path, init?)

Fetch the auth-worker (Better Auth, JWT issuance, OAuth flows).
function authWorkerFetch(
  env: AuthWorkerEnv,
  path: string,
  init?: RequestInit,
): Promise<Response>

interface AuthWorkerEnv {
  /**
   * HTTPS URL for the auth-worker. Optional on the type so apps can declare
   * a partial env shape during local bring-up, but the function throws if it's
   * unset at call time.
   */
  AUTH_WORKER_URL?: string
}
URL-only by design - the auth-worker has no service binding, which keeps Set-Cookie headers verbatim over plain HTTPS. (Service bindings strip some headers in transit.) Throws if AUTH_WORKER_URL is missing.

resolveApiTransport(env)

Exported for the AI helper, which needs the URL form to rewrite an internal https://api-worker.internal placeholder before calling provider SDKs. Most apps don’t need this.
function resolveApiTransport(env: ApiWorkerEnv):
  | { kind: 'binding'; fetcher: Fetcher }
  | { kind: 'url'; baseUrl: string }

Production note

Cross-worker calls over plain *.workers.dev URLs return Cloudflare error 1042 in production. The service binding is the only working transport for deployed apps; the URL fallback is a dev-only convenience the CLI writes into .dev.vars. If a deployed app needs apiWorkerFetch or platformWorkerFetch, the corresponding [[services]] binding must be in wrangler.toml:
[[services]]
binding = "API_WORKER"
service = "deepspace-api"

[[services]]
binding = "PLATFORM_WORKER"
service = "deepspace-platform"

R2 helpers

createScopedR2Handler(config)

Factory that builds a route handler for prefix-scoped R2 reads/writes. The scaffold uses this implicitly via the useR2Files client hook - most apps don’t call it directly.
function createScopedR2Handler(config: ScopedR2Config): ScopedR2Handler

interface ScopedR2Config {
  /**
   * Resolve the R2 key prefix for the given scope.
   * Called with the `?scope=` query param value (default: 'self').
   */
  resolvePrefix(scope: string, ctx: ScopeContext): PrefixResult
  /** Require a non-null userId for upload and delete. Default: true. */
  requireAuthForMutations?: boolean
}

interface ScopeContext {
  userId: string | null
  url: URL
}

type PrefixResult =
  | { prefix: string; error?: undefined }
  | { prefix?: undefined; error: string }

type ScopedR2Handler = (
  request: Request,
  url: URL,
  bucket: R2Bucket,
  auth: { userId: string | null },
) => Promise<Response>
Security guarantees: download/delete keys are validated against the resolved prefix, path traversal (..) is rejected at the entry point, and mutations require a non-null userId by default.

See also