import { z } from 'zod'; import { type ModuleManifest } from './manifest.js'; import { type RoleDefinition } from './permission.js'; /** * The runtime baseline a `runtimeNeeds` vertical builds against — the platform picks the * compatibility date, the builder never does. Advancing it is a platform release concern * (re-push under the new baseline), exactly like a kernel upgrade. * * MAINTAINED, not set-and-forget (#636): a stale baseline is the hand-copied-duplicate * disease D-38 exists to kill, one level up — while it sits still, hand-authored * wrangler-path dates advance past it, and the D-38 migration itself becomes a silent * compatibility DOWNGRADE for those verticals. Two guards hold the line mechanically: * a staleness test (packages/cli/test/push.test.ts) goes red when this date falls more * than ~6 months behind, and `resolveWranglerConfig` refuses a `runtimeNeeds` push whose * ignored wrangler.jsonc carries a NEWER date than this baseline. Keep advances a few * weeks behind today so builders' installed wrangler/workerd always know the date. */ export declare const RUNTIME_BASELINE = "2026-06-01"; /** * One of the vertical's OWN stores: a durable state class the code exports, reached in the * worker through `binding`. This is the substrate-vocabulary side of what the wire manifest * calls `doClasses` + a `durable_object_namespace` binding — the §4 sandbox contract already * guarantees a vertical binds nothing BUT its own stores, so own-stores is the entire * vocabulary; there is nothing else a builder could legitimately say. */ export declare const storeNeed: z.ZodObject<{ binding: z.ZodString; class: z.ZodString; }, z.core.$strip>; export type StoreNeed = z.infer; /** * A **per-tenant relational store** the platform provisions and hands to the vertical — * one independent SQL database *per tenant* (D1 on Cloudflare, a separate `.sqlite` file * on the pure adapter), reached in the worker through `binding` (#301). This is the third * distinct store shape, and the vocabulary keeps them apart on purpose: * * - `storeNeed` (own DO) — the vertical's own durable class, one DO **per scope**. * - a static shared `d1` binding — ONE database shared across every tenant (a build-time id). * - `tenantStoreNeed` (this) — one relational DB **per tenant**, PLATFORM-minted. * * The load-bearing difference from a static `d1` binding: the builder supplies **no * database id**. The platform mints it per tenant in the tenant lifecycle and injects it, * which is what closes the ownership gap a bundle-chosen id left open (self-serve-deploy.md * §4, `control-plane-api/src/deploy.ts`). Because there is no id to declare, a per-tenant * store is a `runtimeNeeds` NEED, never a `declaredBinding` — nothing about it is bound * statically on the shared serving script. */ export declare const tenantStoreNeed: z.ZodObject<{ binding: z.ZodString; kind: z.ZodDefault>; }, z.core.$strip>; export type TenantStoreNeed = z.infer; /** * A platform-minted per-tenant store, as handed to the vertical at provision (K-31) and * resolvable again at request time. `ref` is **opaque to the vertical**: a D1 `database_id` * on Cloudflare, a per-tenant `.sqlite` path token on the pure adapter. The vertical opens * it through the host (`openTenantStore`) and never parses it — that indirection is what * lets one vertical run unchanged against D1 in production and separate SQLite files locally. */ export declare const tenantStoreHandle: z.ZodObject<{ binding: z.ZodString; kind: z.ZodLiteral<"relational">; ref: z.ZodString; }, z.core.$strip>; export type TenantStoreHandle = z.infer; /** * The env name a tenant's store is bound under on the Cloudflare serving script (#301, * PR-2): `__`. One convention, shared by its two ends — the control * plane derives it when attaching the D1 binding to the serving script, and the vertical * worker derives it to look the binding up (`env[tenantStoreBindingName(handle.binding, * tenantId)]` narrows to a `D1Database`). It lives in contracts precisely so neither side * hardcodes the other's half. A tenant id is a ULID (uppercase alphanumeric) and the * declared binding is SCREAMING_SNAKE, so the result is always a valid binding name; the * double underscore keeps it out of the single-underscore namespace a builder would use. * On the pure adapter there is no binding to name — the handle's `ref` is the whole reach. */ export declare function tenantStoreBindingName(binding: string, tenantId: string): string; /** * A **per-tenant blob store** the platform provisions and hands to the vertical (#473) — * an object store for attachment bytes (an R2 bucket on Cloudflare, a directory on the * pure adapter), reached in the worker through `binding`. The fourth store shape, same * ownership story as `tenantStoreNeed`: the builder supplies **no bucket id** — the * platform mints one per tenant in the tenant lifecycle and injects it, so a blob store * is a `runtimeNeeds` NEED, never a `declaredBinding`. (A hand-authored static * `r2_bucket` binding remains admissible under §4 as an own store — this exists so * attachment bytes don't have to ride one: per-tenant minting closes the shared-bucket * ownership gap, and per-SCOPE isolation inside the store is platform-derived key * prefixes constructed only in kernel/adapter code, never in module or route code.) */ export declare const blobStoreNeed: z.ZodObject<{ binding: z.ZodString; kind: z.ZodDefault>; }, z.core.$strip>; export type BlobStoreNeed = z.infer; /** * A platform-minted per-tenant blob store, as handed over at provision (K-31). `ref` is * **opaque to the vertical**: an R2 bucket name on Cloudflare, a per-tenant directory * token on the pure adapter. The vertical never parses it — request-time reach is the * injected binding (Cloudflare) or the host's own resolution (pure adapter). */ export declare const blobStoreHandle: z.ZodObject<{ binding: z.ZodString; kind: z.ZodLiteral<"blob">; ref: z.ZodString; }, z.core.$strip>; export type BlobStoreHandle = z.infer; /** * The env name a tenant's blob store is bound under on the Cloudflare serving script * (#473): `__` — the same convention, and for the same reason, as * {@link tenantStoreBindingName}; the value narrows to an `R2Bucket` instead of a * `D1Database`. On the pure adapter there is no binding to name. */ export declare function blobStoreBindingName(binding: string, tenantId: string): string; /** * How the runtime routes a request between the vertical's STATIC files and its worker * (#340) — the substrate-vocabulary form of Cloudflare's `assets.config`. Every field is * optional with a runtime default, so a vertical that only wants "serve my SPA" declares * a directory and nothing else. * * The two that matter for a Substrat vertical, and why: * - `notFoundHandling: 'single-page-application'` — a deep client route (`/jobs/123`) is * not a file, and must resolve to `index.html` rather than 404. This is the inline * `serveAsset` fallback, expressed as configuration. * - `runWorkerFirst` — SPA fallback would otherwise swallow the vertical's OWN routes, * which are not files either. Listing `/api/*` + `/internal/*` keeps the worker in * front of exactly the paths it owns while everything else is served from the edge * without invoking it. `true` runs the worker in front of every request (asset serving * still happens behind it) — correct only for a vertical that inspects every path. */ export declare const assetRouting: z.ZodObject<{ htmlHandling: z.ZodOptional>; notFoundHandling: z.ZodOptional>; runWorkerFirst: z.ZodOptional]>>; }, z.core.$strip>; /** * Prefixes the PLATFORM routes worker-first, whatever a vertical declared. * * A `.well-known` URI is a protocol surface — RFC 8615 reserves it for exactly that — * so a SPA must never answer one. Left to the vertical this is a rule that rots: the * MCP surface (#112) mounts `/.well-known/oauth-protected-resource/*` because RFC 9728 * requires it at the origin root, ticket0's manifest did not list it, and the asset * layer served `index.html` from the edge without ever invoking the worker. The route * was registered correctly and unreachable, which no lint or test can see: it fails one * layer below the code, in production only. * * So the platform adds it rather than asking. A vertical that mounts nothing there is * unaffected — its own catch-all answers 404, which is what the asset layer would have * said anyway. */ export declare const PLATFORM_WORKER_FIRST_PREFIXES: readonly ['/.well-known/*']; export type AssetRouting = z.infer; /** * The vertical's STATIC files, as a NEED (#340): a directory of built bytes the platform * uploads to the runtime's own asset store, served from the edge without invoking the * worker. Native assets are not a binding — they are a top-level upload path — so this is * a `runtimeNeeds` need and never rides the §4 binding allowlist (see * {@link ADMISSIBLE_BINDING_TYPES}); the platform's own hash verification is what makes * accepting builder-supplied bytes safe (self-serve-deploy.md §4.1). * * Replaces the inline-into-the-worker workaround every demo carried while WfP dispatch had * no asset path: base64 in the bundle costs ~+33 % against the script-size limit, is * re-parsed on every cold start, and invokes the worker for every image. */ export declare const assetsNeed: z.ZodObject<{ htmlHandling: z.ZodOptional>; notFoundHandling: z.ZodOptional>; runWorkerFirst: z.ZodOptional]>>; directory: z.ZodString; }, z.core.$strip>; export type AssetsNeed = z.infer; /** * What a vertical needs from the runtime, in substrate vocabulary (package.json * `substrat.runtimeNeeds`). A vertical authored with this section never writes deploy * config for a specific substrate — the CLI derives that at push time (D-38: builders * keep the substrate vocabulary; the Cloudflare mapping lives behind the platform). * A single shared relational database is still not bundle-declarable here; a PER-TENANT * relational store is, via `tenantStores` — the platform provisions it (self-serve-deploy.md * §4), so the vertical declares the NEED and never a database id. */ export declare const runtimeNeeds: z.ZodObject<{ entry: z.ZodString; needsNodeCompat: z.ZodDefault; build: z.ZodOptional; stores: z.ZodDefault>>; tenantStores: z.ZodDefault>; }, z.core.$strip>>>; blobStores: z.ZodDefault>; }, z.core.$strip>>>; assets: z.ZodOptional>; notFoundHandling: z.ZodOptional>; runWorkerFirst: z.ZodOptional]>>; directory: z.ZodString; }, z.core.$strip>>; }, z.core.$strip>; export type RuntimeNeeds = z.infer; /** * One declared outbound destination (#303, D-46): a lowercase hostname the vertical's * worker may `fetch()` directly, or a `*.`-prefixed wildcard matching any subdomain depth * (`*.googleapis.com` matches `oauth2.googleapis.com` and `a.b.googleapis.com`, never the * apex `googleapis.com` — declare the apex separately if it is called). Hostname only: * no scheme, no port, no path, no embedded wildcards. IDNs are declared in punycode, * because that is the hostname the runtime sees. */ export declare const outboundHost: z.ZodString; export type OutboundHost = z.infer; /** * Does a destination hostname match the vertical's declared outbound surface? One * implementation for every seam that answers the question — the egress worker enforcing * (apps/vertical-egress), the CLI predicting, a console rendering — so "allowed" cannot * mean different things at different layers. Exact entries match exactly; `*.` entries * match any subdomain depth but never the apex. Case-insensitive on the hostname side * (DNS is), strict on the declared side (the schema only admits lowercase). */ export declare function matchesOutboundHost(hostname: string, declared: readonly string[]): boolean; /** * Lift the declared `outbound` surface out of a STORED manifest's JSON (#303) without * re-parsing the whole manifest through the schema — a version list should not pay a full * manifest validation per row, and a legacy manifest predating the field must read as * null (unenforced) rather than fail. Null in ⇒ null out; malformed JSON reads as null, * because a manifest that never parsed also never served. */ export declare function outboundOfManifestJson(manifestJson: string | null | undefined): string[] | null; /** * The §4 sandbox allowlist: the binding types a hosted vertical may declare, because each * is one of its OWN resources and carries no reach into platform infrastructure. This is a * POSITIVE allowlist — anything not named here is refused (self-serve-deploy.md §4), the * inverse of the original allow-by-omission denylist. It lives in `contracts` so both ends * speak one list: the CLI can predict admission, the control plane enforces it, and "what * passes" is a written set rather than an emergent property of what the check forgot to ban. * * Notable exclusions and why they are refused, not merely absent: * - `service` — a hosted vertical is ONE serving script (the DO is the app); it reaches the * platform through the router (K-27), never a service binding. No own sibling to bind. * - `dispatch_namespace` — the platform's Workers-for-Platforms fabric, never a vertical's. * - anything managed/egress-shaped (`ai`, `browser`, `vectorize`, `hyperdrive`, `send_email`, * `mtls_certificate`) — the outside world is a connector concern, and a vertical's own * direct egress is the DECLARED `outbound` host list (#303, D-46), enforced by the egress * worker — never a binding-shaped capability. * * NOT on this list because it is not a binding at all: **native static assets** (#340). They * are a top-level upload path (`assets: { jwt, config }` in the script metadata), so they can * neither be allowed nor refused here. They are admitted by a separate, narrower rule written * down in self-serve-deploy.md §4.1: the bytes are inert and public — no code, no authority, * no cross-tenant reach — but their content-address is a namespace-wide dedup key, so the * platform RE-DERIVES every hash from the uploaded bytes ({@link assetHash}) and refuses a * mismatch. What is trusted is the bytes; what is verified is the key. * * Caveat on `d1`: admissible as an own relational store (e.g. a Better-Auth `AUTH_DB`), but * the check does not yet PROVE the declared `database_id` is the vertical's own rather than * another tenant's — trusted under model-B human admission; platform provisioning closes that * gap (#301). A `durable_object_namespace` is admissible only for the vertical's OWN classes * (no `script_name`, `class_name` ∈ declared `doClasses`) — the control plane checks that. */ export declare const ADMISSIBLE_BINDING_TYPES: readonly ['durable_object_namespace', 'd1', 'kv_namespace', 'queue', 'r2_bucket', 'analytics_engine', 'secret_text', 'plain_text']; export type AdmissibleBindingType = (typeof ADMISSIBLE_BINDING_TYPES)[number]; /** A binding the uploaded worker declares, as far as the sandbox contract check needs it. * `type` stays a free string here — the §4 allowlist (`ADMISSIBLE_BINDING_TYPES`) is enforced * by the control plane, not the schema, so a refused type produces a *named* rejection that * points at the doc rather than a generic Zod parse error the builder can't act on. */ export declare const declaredBinding: z.ZodObject<{ type: z.ZodString; name: z.ZodString; class_name: z.ZodOptional; script_name: z.ZodOptional; id: z.ZodOptional; }, z.core.$strip>; export type DeclaredBinding = z.infer; /** * One row of the permission registry: a declared key, its description, and the module(s) * that declare it (§1 of PERMISSIONS.md, made machine-readable). `declaredBy` lets a * console group keys by owning engine without re-deriving from module code. */ export declare const permissionRegistryEntry: z.ZodObject<{ key: z.core.$ZodBranded; description: z.ZodString; declaredBy: z.ZodArray>; }, z.core.$strip>; export type PermissionRegistryEntry = z.infer; /** An entity-narrowed grant SHAPE — which keys a per-entity grant carries (§4 of * PERMISSIONS.md). The grants themselves are per-principal, runtime, scope-local; only * their declared shapes are a code fact and belong in the manifest. */ export declare const entityGrantShape: z.ZodObject<{ entityType: z.ZodString; permissions: z.ZodArray>; }, z.core.$strip>; export type EntityGrantShape = z.infer; /** * The vertical's declared permission surface, shipped in the deploy manifest (D-39) — the * machine-readable twin of PERMISSIONS.md. Assembled at push from the SAME `MODULES` + * `ROLES` + `ENTITY_GRANTS` the host registers (via the checked-in `permissions.json` that * `tools/permission-diff.mts` emits and CI keeps fresh), so it cannot drift from what is * enforced. `digests.permission` is its content hash: the platform now holds the registry * it already committed to, not only the hash. Immutable per version; consumed by admission * (a real permission diff between versions) and any tenant-facing permissions view. * * Deliberately NOT the runtime grant table: minted capability grants are scope-local tuples * (control-plane.md §4.5), reachable only through the admin-query RPC, never mirrored here. */ export declare const permissionRegistry: z.ZodObject<{ permissions: z.ZodArray; description: z.ZodString; declaredBy: z.ZodArray>; }, z.core.$strip>>; roles: z.ZodArray>; source: z.ZodUnion, z.ZodLiteral<"vertical">]>; }, z.core.$strip>>; entityGrants: z.ZodDefault>; }, z.core.$strip>>>; }, z.core.$strip>; export type PermissionRegistry = z.infer; /** * A vertical's declared permission surface, as the **single typed source** — the input the * permission checkpoint (`tools/permission-diff.mts`) and `substrat push` both read to derive * the {@link permissionRegistry}. It is not the registry itself: keys carry no `declaredBy` yet * (that is derived from `modules`), because this is what an author *writes*, once. * * `modules` is structural on purpose — a `ModuleRegistration[]` (kernel) is assignable, but * `contracts` may not depend on the kernel, so it asks only for the `manifest` it reads. */ export interface PermissionsInput { /** The modules the host registers — the source of every permission key + description. */ modules: readonly { manifest: ModuleManifest; }[]; /** The role templates provisioning stamps into each tenant. */ roles: readonly RoleDefinition[]; /** Entity-narrowed grant shapes — keys reachable outside the role table (default none). */ entityGrants?: readonly EntityGrantShape[]; /** * The declared keys, as literals — the array `defineOperations` needs (#1208). * * `modules` already carries every key, but not as a type anything can read back: * a manifest is a `moduleManifest.parse(…)` output, so each `key` is the branded * `PermissionKey` and the literal is gone one step before this function sees it. * `defineOperations(entities, KEYS)` needs the literal union to turn a mistyped * `permission:` into a compile error naming the real keys, so a vertical writes * the keys once as a `const` array and hands the SAME array to both. * * That is still a second description — but it is the only one, and it is no longer * unchecked: given here, {@link definePermissions} throws at module load if it and * the modules disagree in either direction. A vertical that used to carry its own * "the keys still match the modules" test can delete it. * * Optional, so every existing vertical keeps compiling; a vertical that omits it * gets `never` from {@link PermissionKeysOf}, never a silently-widened `string`. */ keys?: readonly string[]; } /** * The literal key union a {@link definePermissions} result carries — what `defineOperations` * wants as its `Perms` argument, read off the declared surface instead of restated a third time. * * `never` when `keys` was omitted, and deliberately not `string`: widening to `string` would make * `defineOperations` accept any `permission:` value at all, quietly deleting the check this exists * to serve. An unusable type is the loud answer; a permissive one is the silent wrong answer. * * Same answer when the array was written without `as const`, which is the likelier mistake — its * element type is already `string`, so passing it straight through would be that silent widening * arriving by a different road. `string extends …` is the test for "this is the widened type * rather than a union that happens to include it". */ export type PermissionKeysOf = T['keys'] extends readonly string[] ? string extends T['keys'][number] ? never : T['keys'][number] : never; /** * Declare a vertical's permission surface, once, in TypeScript. A near-identity helper: it pins the * shape so a missing or mistyped field is a **compile error**, not a silently-skipped vertical, * and returns a plain, side-effect-free object safe to import in any Node context to read the * surface without running the vertical. A vertical exports the result and points at it from * `package.json` `substrat.permissions`; the checkpoint discovers it there rather than from a * by-name `seed.ts` re-export. * * `const T` rather than `PermissionsInput` so the input's literal types survive the call and * {@link PermissionKeysOf} has something to read. The runtime value is unchanged — it returns * exactly what it was given — and every existing call site keeps its old type by construction. * * The one thing it does beyond returning: if `keys` is given, it must be exactly the set the * modules declare, or this throws at module load. Load time is the right place, for the same * reason `defineOperations`' own assertions are there — it fires in every build, every test and * every dev server, so no vertical has to remember to write the check. */ export declare function definePermissions(input: T): T; /** * Derive the machine-readable {@link permissionRegistry} from a vertical's declared surface — * the keys+descriptions each module declares (with `declaredBy`), the role templates, and the * entity-grant shapes. `substrat push` calls this on the imported `permissions` entry to build * what it ships in the manifest; the permission checkpoint uses the same function, so the * derived surface is one code path with no room to disagree. * * Deterministic: every array is sorted (keys, roles, grants, and the members within each), so * the output — and therefore `digests.permission` — is a pure function of content, independent * of declaration order. */ export declare function buildPermissionRegistry(input: PermissionsInput): PermissionRegistry; /** * One static file in the shipped manifest (#340). The trio Cloudflare's asset store keys * on — content-addressed `hash`, `size` — plus the `contentType` the platform attaches at * upload and the runtime serves back. * * `hash` is the platform's DEDUP KEY, and the reason it is re-derived at the trust boundary * rather than trusted: the asset store dedups by hash across the whole dispatch namespace, * so bytes accepted under a hash they do not have would let one push decide what a DIFFERENT * vertical's identical-hash asset serves. The bytes themselves are inert and public; the * *key* is not. The control plane recomputes every hash from the uploaded bytes and refuses * a mismatch (self-serve-deploy.md §4.1). * * The recipe is Cloudflare's, and must stay byte-identical on both ends or nothing dedups: * `sha256(base64(content) + extension)`, first 32 hex chars ({@link assetHash}). */ export declare const assetEntry: z.ZodObject<{ path: z.ZodString; hash: z.ZodString; size: z.ZodNumber; contentType: z.ZodString; }, z.core.$strip>; export type AssetEntry = z.infer; /** * The multipart part-name prefix static files ride under in a push (#340) — * `asset:/index.html`. Here, with the manifest schema, for the reason this file exists: * both ends must speak the same shape. The prefix is what separates the two kinds of part * in one body — anything unprefixed is a worker module — so an asset called `worker.js` * can never be uploaded as code, and a served path is never constrained to be a legal * module name. */ export declare const ASSET_PART_PREFIX = "asset:"; /** * The content-address of one static file — **Cloudflare's recipe, not ours**: * `sha256(base64(content) + extension)` (extension without the dot), first 32 hex chars. * It is reproduced here rather than imported because both ends must compute it identically: * the CLI to build the manifest it ships, the control plane to VERIFY that manifest against * the bytes before either reaches the asset store (see {@link assetEntry}). A divergence * would not merely fail — it would silently defeat dedup, or store bytes under a key that * is not theirs. * * Web Crypto (`globalThis.crypto.subtle`), so the one implementation runs unchanged in node, * workerd, and the browser. */ export declare function assetHash(content: Uint8Array, path: string): Promise; /** * The static-file half of a push (#340): the routing config, plus the full file manifest. * * The manifest is retained (it rides `manifest_json` like the rest of the deploy manifest) * for a load-bearing reason: a promote re-uploads a version onto the STABLE serving script * from its archive (#286), and an asset upload session is driven by the manifest, not by * bytes — content already in the namespace's asset store is skipped, so the retained * manifest is what lets a promote re-attach the same assets without the builder re-pushing. * It is also what the dashboard renders as the per-version asset list. */ export declare const deployAssets: z.ZodObject<{ htmlHandling: z.ZodOptional>; notFoundHandling: z.ZodOptional>; runWorkerFirst: z.ZodOptional]>>; files: z.ZodArray>; }, z.core.$strip>; export type DeployAssets = z.infer; /** The JSON part a `substrat push` sends alongside the module files. */ /** * One operation's DECLARED output fields (#1321) — the operation id as OpenAPI * knows it, and the property names of the response body. An operation whose * response declares no properties (a 204, a bare scalar) contributes nothing and * is omitted rather than carried as an empty list, so absence means "declares no * fields" everywhere in the surface. */ export declare const declaredOperationOutput: z.ZodObject<{ operationId: z.ZodString; fields: z.ZodArray; }, z.core.$strip>; export type DeclaredOperationOutput = z.infer; /** * One event type a module declares, and which side of the seam it sits on * (#1234). `emits` and `consumes` are kept apart because the findings differ: an * unemitted type may be a dead code path, while an unconsumed one is a consumer * that never runs — and the star topology means the two are declared by * different modules that never import each other. */ export declare const declaredEventSurface: z.ZodObject<{ moduleId: z.core.$ZodBranded; type: z.ZodString; direction: z.ZodEnum<{ consumes: "consumes"; emits: "emits"; }>; }, z.core.$strip>; export type DeclaredEventSurface = z.infer; export declare const deployManifest: z.ZodObject<{ version: z.ZodString; name: z.ZodOptional; entry: z.ZodString; compatibilityDate: z.ZodString; compatibilityFlags: z.ZodDefault>; doClasses: z.ZodDefault>; bindings: z.ZodDefault; script_name: z.ZodOptional; id: z.ZodOptional; }, z.core.$strip>>>; tenantStores: z.ZodDefault>; }, z.core.$strip>>>; blobStores: z.ZodDefault>; }, z.core.$strip>>>; assets: z.ZodOptional>; notFoundHandling: z.ZodOptional>; runWorkerFirst: z.ZodOptional]>>; files: z.ZodArray>; }, z.core.$strip>>; envSpec: z.ZodOptional; description: z.ZodString; placeholder: z.ZodOptional; required: z.ZodDefault; secret: z.ZodDefault; default: z.ZodOptional; group: z.ZodOptional; }, z.core.$strip>>>; ownerGrants: z.ZodOptional>>; entitlements: z.ZodOptional>; provides: z.ZodOptional>; requires: z.ZodOptional>; provisions: z.ZodOptional>; outbound: z.ZodOptional>; sendsEmail: z.ZodOptional; usesModels: z.ZodOptional; surfaces: z.ZodOptional>>; model: z.ZodOptional; entities: z.ZodRecord; parents: z.ZodOptional>; primaryKey: z.ZodOptional>; key: z.ZodOptional>; erasable: z.ZodOptional>; }, z.core.$strip>>; lifecycles: z.ZodOptional>; allow: z.ZodOptional>; extensible: z.ZodOptional>; terminal: z.ZodOptional>; }, z.core.$strip>>; }, z.core.$strip>>>; }, z.core.$strip>>; outputSurface: z.ZodOptional; }, z.core.$strip>>>; declaredEvents: z.ZodOptional; type: z.ZodString; direction: z.ZodEnum<{ consumes: "consumes"; emits: "emits"; }>; }, z.core.$strip>>>; declaredEventsTruncated: z.ZodOptional; schedules: z.ZodOptional; input: z.ZodOptional>; permissions: z.ZodDefault>>; moduleId: z.core.$ZodBranded; }, z.core.$strip>>>; freshness: z.ZodOptional; moduleId: z.core.$ZodBranded; }, z.core.$strip>>>; registry: z.ZodObject<{ permissions: z.ZodArray; description: z.ZodString; declaredBy: z.ZodArray>; }, z.core.$strip>>; roles: z.ZodArray>; source: z.ZodUnion, z.ZodLiteral<"vertical">]>; }, z.core.$strip>>; entityGrants: z.ZodDefault>; }, z.core.$strip>>>; }, z.core.$strip>; digests: z.ZodObject<{ manifest: z.ZodString; permission: z.ZodString; migration: z.ZodString; }, z.core.$strip>; }, z.core.$strip>; export type DeployManifest = z.infer; /** * The same manifest for **reading persisted history**, where `registry` may be absent — a * version pushed before it was carried (D-39) or before it was required (D-41). The push trust * boundary always parses with the strict {@link deployManifest} (registry required), so a NEW * push cannot omit it; only re-reads of already-stored manifests use this lenient form, so an * old version stays readable and re-deployable in place (#286) instead of failing to parse. */ export declare const storedDeployManifest: z.ZodObject<{ version: z.ZodString; name: z.ZodOptional; entry: z.ZodString; compatibilityDate: z.ZodString; compatibilityFlags: z.ZodDefault>; doClasses: z.ZodDefault>; bindings: z.ZodDefault; script_name: z.ZodOptional; id: z.ZodOptional; }, z.core.$strip>>>; tenantStores: z.ZodDefault>; }, z.core.$strip>>>; blobStores: z.ZodDefault>; }, z.core.$strip>>>; assets: z.ZodOptional>; notFoundHandling: z.ZodOptional>; runWorkerFirst: z.ZodOptional]>>; files: z.ZodArray>; }, z.core.$strip>>; envSpec: z.ZodOptional; description: z.ZodString; placeholder: z.ZodOptional; required: z.ZodDefault; secret: z.ZodDefault; default: z.ZodOptional; group: z.ZodOptional; }, z.core.$strip>>>; ownerGrants: z.ZodOptional>>; entitlements: z.ZodOptional>; provides: z.ZodOptional>; requires: z.ZodOptional>; provisions: z.ZodOptional>; outbound: z.ZodOptional>; sendsEmail: z.ZodOptional; usesModels: z.ZodOptional; surfaces: z.ZodOptional>>; model: z.ZodOptional; entities: z.ZodRecord; parents: z.ZodOptional>; primaryKey: z.ZodOptional>; key: z.ZodOptional>; erasable: z.ZodOptional>; }, z.core.$strip>>; lifecycles: z.ZodOptional>; allow: z.ZodOptional>; extensible: z.ZodOptional>; terminal: z.ZodOptional>; }, z.core.$strip>>; }, z.core.$strip>>>; }, z.core.$strip>>; outputSurface: z.ZodOptional; }, z.core.$strip>>>; declaredEvents: z.ZodOptional; type: z.ZodString; direction: z.ZodEnum<{ consumes: "consumes"; emits: "emits"; }>; }, z.core.$strip>>>; declaredEventsTruncated: z.ZodOptional; schedules: z.ZodOptional; input: z.ZodOptional>; permissions: z.ZodDefault>>; moduleId: z.core.$ZodBranded; }, z.core.$strip>>>; freshness: z.ZodOptional; moduleId: z.core.$ZodBranded; }, z.core.$strip>>>; digests: z.ZodObject<{ manifest: z.ZodString; permission: z.ZodString; migration: z.ZodString; }, z.core.$strip>; registry: z.ZodOptional; description: z.ZodString; declaredBy: z.ZodArray>; }, z.core.$strip>>; roles: z.ZodArray>; source: z.ZodUnion, z.ZodLiteral<"vertical">]>; }, z.core.$strip>>; entityGrants: z.ZodDefault>; }, z.core.$strip>>>; }, z.core.$strip>>; }, z.core.$strip>; export type StoredDeployManifest = z.infer; //# sourceMappingURL=deploy.d.ts.map