/** * The alchemy Worker source-provider entry for Next.js * (`@distilled.cloud/nextjs/source`). * * The default export implements alchemy's `WorkerSourceModule` contract * (`packages/alchemy/src/Cloudflare/Workers/Source.ts`) **structurally** — * this package deliberately does not import alchemy types. The shapes * mirrored here are: * * - `WorkerSourceModule` — `{ make(options) => Effect }` * - `SourceProvider` — `{ ownsAssets, build(ctx), hash(ctx, previous), dev(ctx) }` * - `SourceBuildOutput` — `{ bundle: { files, hash }, assets: AssetReadResult, hash }` * - `AssetReadResult` — the manifest shape alchemy's asset uploader consumes * (per-file hash = sha256 hex truncated to 32 chars, the Workers Assets * API's content-address format) * * `build()` wraps this package's `Framework` service (the OpenNext-based, * wrangler-free pipeline in `Nextjs.ts`): server modules become the worker * bundle (entry first), `.open-next/assets` becomes the static-assets * manifest, and the project tree is content-hashed for rebuild-free diffs. * `hash()` never builds — it recomputes the input-tree hash (including this * package's version, so an adapter upgrade busts the memo). `dev()` is v1 * preview parity: the built worker served under cloudflare-runtime (workerd); * ISR revalidation writes are a documented no-op (read-only static-assets * incremental cache). */ import type { BindingHooks, RuntimeWorker } from "@distilled.cloud/cloudflare-runtime"; import * as Effect from "effect/Effect"; import * as FileSystem from "effect/FileSystem"; import * as Path from "effect/Path"; import type { PlatformError } from "effect/PlatformError"; import type * as Scope from "effect/Scope"; declare const SourceProviderError_base: new = {}>(args: import("effect/Types").VoidIfEmpty<{ readonly [P in keyof A as P extends "_tag" ? never : P]: A[P]; }>) => import("effect/Cause").YieldableError & { readonly _tag: "Cloudflare.Workers.SourceProviderError"; } & Readonly; /** * Structural mirror of alchemy's `Cloudflare.Workers.SourceProviderError` * (same `_tag`, so alchemy-side `Effect.catchTag` handles it as its own). */ export declare class SourceProviderError extends SourceProviderError_base<{ readonly provider: string; readonly message: string; readonly cause?: unknown; }> { } /** Mirror of alchemy's `SourceHash` (the Worker `hash` attribute slots). */ export interface SourceHash { readonly bundle: string | undefined; readonly assets: string | undefined; readonly input: string | undefined; readonly additionalWorkspaces: Array | undefined; } /** Mirror of alchemy's `Bundle.BundleFile`. */ export interface SourceBundleFile { readonly path: string; readonly content: string | Uint8Array; readonly hash: string; } /** Mirror of alchemy's `AssetReadResult` (Workers Assets manifest shape). */ export interface SourceAssets { directory: string; config: Record | undefined; manifest: Record; _headers: string | undefined; _redirects: string | undefined; hash: string; } /** Mirror of alchemy's `SourceBuildOutput`. */ export interface SourceBuildOutput { readonly bundle: { readonly files: Array; readonly hash: string; } | undefined; readonly assets: SourceAssets | undefined; readonly hash: SourceHash; } /** The subset of alchemy's `SourceContext` this provider consumes. */ export interface SourceContext { readonly id: string; readonly workerName: string; readonly compatibility: { readonly date: string; readonly flags: Array; }; readonly assets?: string | Record | undefined; } type WorkerWiring = Omit, "compatibilityDate" | "compatibilityFlags" | "modules">; /** The subset of alchemy's `DevContext` this provider consumes. */ export interface DevContext extends SourceContext { readonly worker: { readonly name: string; readonly bindings: NonNullable; readonly durableObjectNamespaces: NonNullable; readonly hyperdrives: NonNullable; readonly queueConsumers: Effect.Effect>; readonly assets: WorkerWiring["assets"] | undefined; }; /** * The host's runtime stack (a `Context.Context`) — the * dev binding proxy is hosted in it instead of the credential-free * internal layer, so `Alchemy.remote()` bindings resolve in dev. */ readonly runtimeContext: unknown; } export type SourceDevHandle = { readonly mode: "server"; readonly url: URL; }; export type SourceError = SourceProviderError | PlatformError; export type SourceServices = FileSystem.FileSystem | Path.Path; /** Mirror of alchemy's `SourceProvider` (the arms this module implements). */ export interface SourceProvider { readonly ownsAssets: boolean; readonly build: (ctx: SourceContext) => Effect.Effect; readonly hash: (ctx: SourceContext, previous: SourceHash | undefined) => Effect.Effect, SourceError, SourceServices>; readonly dev: (ctx: DevContext) => Effect.Effect; } /** * Controls which project files are content-hashed to decide whether the * OpenNext build needs to re-run. Mirrors the semantics of alchemy's * `MemoOptions` (`Command/Memo.ts`) with a built-in glob matcher: * `**` crosses directory boundaries, `*`/`?` stay within a segment. */ export interface NextjsMemoOptions { /** Glob patterns of files to hash, relative to the project root. @default all files */ readonly include?: Array | undefined; /** Glob patterns to exclude from hashing. Build outputs (`.next`, `.open-next`, `dist`) and `node_modules` are always excluded. */ readonly exclude?: Array | undefined; /** * Include the nearest package-manager lockfile in the hash, even when it * lives above the project root (e.g. a monorepo root). * @default true when both `include` and `exclude` are unset; false otherwise */ readonly lockfile?: boolean | undefined; } /** * The JSON-serializable options of the `@distilled.cloud/nextjs/source` * descriptor (`WorkerProps.source.options`). Must stay JSON-stable — the * descriptor persists in state and participates in the Worker metadata hash. */ export interface NextjsSourceOptions { /** The Next.js project root. Defaults to the process working directory. */ readonly root?: string | undefined; /** Rebuild-scope configuration (which files bust the build memo). */ readonly memo?: NextjsMemoOptions | undefined; /** Path of the OpenNext config, relative to the project root. @default "open-next.config.ts" */ readonly configPath?: string | undefined; /** The command the OpenNext pipeline runs to build the Next.js app. @default "npx next build" */ readonly buildCommand?: string | undefined; /** Skip the internal `next build` (reuse an existing `.next`). */ readonly skipNextBuild?: boolean | undefined; /** Minify the OpenNext bundling steps and the final bundle pass. */ readonly minify?: boolean | undefined; /** Enable OpenNext debug logging (and verbose workerd output in dev). */ readonly debug?: boolean | undefined; /** Dev-server behavior (JSON-stable; does not affect the build). */ readonly dev?: { /** * - `"preview"` (default): build the OpenNext worker and serve it * under `cloudflare-runtime` (workerd) — production parity, no HMR. * - `"hmr"`: run the real `next dev` (Turbopack HMR) in Node with the * worker's bindings proxied from `cloudflare-runtime` onto * OpenNext's `getCloudflareContext()` contract. App code runs in * Node, not workerd — CF-specific runtime behavior and ISR/caching * semantics still need `"preview"`. * @default "preview" */ readonly mode?: "preview" | "hmr" | undefined; } | undefined; } /** * The `WorkerSourceModule` implementation: validate the descriptor options * and hand back the provider. */ declare const make: (options: unknown) => Effect.Effect; declare const _default: { make: typeof make; }; export default _default; //# sourceMappingURL=source.d.ts.map