/** * Core Utilities * DO NOT MODIFY THIS FILE - You may break the project functionality * * This module provides: * - Env type: Environment bindings for Cloudflare Workers * - API helpers: Response utilities for Hono routes * * Entity System: See core-entities.ts * Workspace Context: See core-workspace.ts * Scheduler: See core-scheduler.ts */ import type { Context } from 'hono'; import type { EntityDO } from './core-entity-do'; import type { SchedulerDO } from './core-scheduler'; import type { BaseAgent } from './core-base-agent'; /** * Environment bindings for Cloudflare Workers */ export interface Env { EntityDO: DurableObjectNamespace; SchedulerDO: DurableObjectNamespace; BaseAgent?: DurableObjectNamespace; WorkspaceObject?: DurableObjectNamespace; WorkflowInstance: DurableObjectNamespace; WorkflowCoordinator: DurableObjectNamespace; BUCKET?: R2Bucket; WORKSPACE_ID?: string; APP_ID?: string; APP_NAME?: string; WORKSPACE_API_URL?: string; WORKSPACE_API_BASE_URL?: string; WORKSPACE_API_KEY?: string; DEPLOYMENT_MODE?: 'preview' | 'production'; VITE_DEPLOYMENT_MODE?: 'preview' | 'production'; RUNWORK_AI_PROXY_URL?: string; RUNWORK_PROXY_TOKEN?: string; INTEGRATIONS_PROXY_URL?: string; ALLOWED_ORIGINS?: string; } /** * Return a successful JSON response. * Returns the data directly as the response body with 200 status. */ export declare const ok: (c: Context, data: T) => Response & import("hono").TypedResponse<{ [x: string]: import("hono/utils/types").JSONValue; }, import("hono/utils/http-status").ContentfulStatusCode, "json">; /** * Return a 400 Bad Request response * Automatically logs the error for debugging in production logs */ export declare const bad: (c: Context, error: string) => Response & import("hono").TypedResponse<{ error: string; }, 400, "json">; /** * Return a 404 Not Found response * Automatically logs the error for debugging in production logs */ export declare const notFound: (c: Context, error?: string) => Response & import("hono").TypedResponse<{ error: string; }, 404, "json">; /** * Type guard for non-empty strings */ export declare const isStr: (s: unknown) => s is string; /** * Safely clone a value for Durable Object storage. * Strips non-serializable references (R2Bucket, D1Database, DO stubs, etc.) * that would cause structured clone to fail in ctx.storage.put(). */ export declare function safeClone(value: T, fallback?: T): T; /** * Platform fetch - routes requests through WorkspaceObject DO for production workers. * * Workers for Platforms (WfP) workers cannot reliably make HTTP requests back to their * parent platform worker (they get 522 timeouts). This utility routes platform API calls * through the WorkspaceObject Durable Object binding, which works across worker boundaries. * * Supported paths: * - /api/proxy/integrations/* - Integration proxy (Nango) * - /api/proxy/openai/* - AI Gateway proxy * - /api/storage/presign - Storage presigned URLs * * For preview containers (DEPLOYMENT_MODE !== 'production'), uses standard fetch. * * @example * ```typescript * // Instead of: * const response = await fetch('https://runwork.ai/api/proxy/integrations/proxy/contacts', options); * * // Use: * const response = await platformFetch(env, 'https://runwork.ai/api/proxy/integrations/proxy/contacts', options); * ``` */ /** * What the app was doing when it made a call. * * Internal plumbing, deliberately not exported from the package: app authors * never set this, the framework establishes it at each entry point (schedule * tick, workflow run, route handler, agent turn) and `platformFetch` below * reads it. It lives beside `platformFetch` because that is its only consumer. * * WHY IT EXISTS: usage rows record `appId` and `userId` and nothing about what * was executing, so a HubSpot call made by a nightly schedule cannot be told * apart from one a person made from their own agent. `runId` is the field that * cannot be reconstructed later: it links one run's AI calls and integration * calls together, which is what per-run cost is built from. * * Design: docs/plans/2026-08-28-baselines-capture-redesign.md section 4.1. */ export interface RunContext { /** * WHAT was executing. Only constructs the framework itself runs, never * "where the caller was" (a browser, MCP, the CLI): that is a different * question and `audit_logs.actor_type` owns it. */ kind: 'schedule' | 'workflow' | 'endpoint' | 'route' | 'agent'; /** * Human-readable name, following the convention the audit rows already use: * a schedule/workflow/agent slug, or `METHOD /path` for endpoints and routes. * * OMITTED rather than defaulted when genuinely unknown. A placeholder string * like 'unknown' becomes a value every query has to filter out, and it is * indistinguishable from an app that named something 'unknown'. */ name?: string; /** * App-local registry key, so a usage row joins back to a registration. The * app id is a column of its own, so this is the part after it: a slug for * schedules, workflows and agents, `METHOD /path` for endpoints. */ resourceKey?: string; /** One id shared by everything emitted inside this execution. */ runId: string; /** The enclosing run, for workflow steps, nested calls and sub-agents. */ parentRunId?: string; trigger?: 'cron' | 'manual' | 'webhook' | 'chat' | 'api'; /** * The person who started this run. Named to match the governance program's * `DelegationChain.triggererUserId` (`worker/types/permissions.ts`), which is * the same fact: one name for it across both programs. * * ATTRIBUTION, NEVER AUTHORITY. This travels on a header from the app, behind * the shared WORKSPACE_API_KEY, so an app can put any user id here. The * platform may RECORD it; nothing may ever AUTHORIZE on it. Whose authority a * run borrows is resolved platform-side by PermissionService, not stated by * the caller. */ triggererUserId?: string; attempt?: number; } /** Header carrying the context to the platform side, which writes the audit row. */ export declare const RUN_CONTEXT_HEADER = "x-runwork-run-context"; /** * Run `fn` with `ctx` as the ambient execution context. * * Nesting is automatic: entering a context inside another records the outer * `runId` as `parentRunId` unless the caller set one. That is what makes a * sub-agent's calls point at the run that started it. Re-entering the SAME * run id is not nesting (a workflow resumes into its own run across wake-ups) * and must not make a run its own parent. */ export declare function withRunContext(ctx: RunContext, fn: () => T): T; /** The current execution context, or undefined outside any entry point. */ export declare function getRunContext(): RunContext | undefined; /** * Merge the context header into request headers. * * One serialised header rather than several, so adding a field never needs a * matching change in the platform's parsing. Never overwrites a header the * caller set: a caller that knows its own context beats the ambient one. */ export declare function withRunContextHeader(init?: HeadersInit): HeadersInit | undefined; export declare function platformFetch(env: Env, url: string | URL, rawInit?: RequestInit): Promise; /** * Workspace API fetch - routes workspace service requests through WorkspaceObject DO * for production WfP workers, avoiding 522 recursive invocation errors. * * Workers for Platforms workers cannot HTTP-fetch back to their dispatcher domain. * This routes through the WorkspaceObject DO binding in production, and falls back * to standard HTTP with x-workspace-key auth header in preview/sandbox. * * @param env - Environment with workspace bindings * @param path - Workspace API sub-path (e.g., '/ingest-event') * @param init - Standard fetch options */ export declare function workspaceApiFetch(env: Pick, path: string, rawInit?: RequestInit): Promise;