import { type AppBundle, type AppId, type AppMount, type FilesAdapter, type RunContext, type WorkspaceFs } from "@vendoai/core"; import { type AppDocument, type AppSourceFile, type BuiltFile } from "../../contract/index.js"; /** * What the seam needs from the store, passed in rather than imported: `@vendoai/apps` * has no store dependency by design (the sandbox harness holds a workspace and * never a store), so composition binds these once — the same shape * `createAgentTools` takes its `requireOwned` through. */ export interface AppSourceSeam { /** The app row, ownership-checked. `AppsRuntime`'s own `requireOwned`. */ requireOwned(appId: AppId, ctx: RunContext): Promise; /** Land a mutated document. `AppsRuntime`'s own compare-and-swap update. */ update(appId: AppId, mutate: (doc: AppDocument) => AppDocument, ctx: RunContext): Promise; /** * The app row's OWNER — a person's subject, or an org id. It is what decides * the app's ADDRESS (§9.7: owner and path prefix always travel together), and * it is the one question a workspace cannot answer: an org app's editor can * usually write their own `/user` mount too, so permission cannot tell the two * addresses apart. */ ownerOf(appId: AppId, ctx: RunContext): Promise; /** The workspace's OWN blob seam, for source past {@link WORKSPACE_INLINE_MAX_BYTES}. * Absent means inline-only, and an oversized file is refused loudly rather * than dropped — a silently missing source file is a lost app. */ blobs?: FilesAdapter; } /** * The mount that HOLDS an app, from its owner (§9.7). * * An owner the caller holds a membership for is an ORG; anything else is a * person's own subject. Never a guess: a personal app shared with this caller * resolves to its OWNER's `/user` mount, which the caller then genuinely cannot * commit to — an honest refusal instead of a write in the wrong place. */ export declare const appMountFor: (owner: string, ctx: RunContext) => AppMount; /** * Freeze one build's output into that namespace and describe it. * * `entry` names which of `files` the frame boots; everything else lands in * `assets` under the path the entry imports it by. Hashing goes over the BYTES * (`node:crypto`, as `@vendoai/vendo`' materialize seam does) rather than * over text, because a bundle carries fonts and images that no string * round-trip survives. */ export declare const sealBundleBlobs: (appId: AppId, files: readonly BuiltFile[], entry: string, blobs: FilesAdapter) => Promise; /** One sealed file back, by the hash that IS its key. */ export declare const readBundleBlob: (appId: AppId, hex: string, blobs: FilesAdapter) => Promise; /** One file stored INLINE, carrying its own identity. The one place that computes a stored entry's hash * and byte count, so the paint that stores a screen and the commit that diffs a * file cannot disagree about what "the content stored" means. */ export declare const inlineSourceFile: (text: string) => AppSourceFile; /** * A source key is a POSIX-relative path inside the app directory, and nothing * else. Refused here rather than at write time because a `../` key is a checkout * writing outside the app — the one way this projection could reach another app's * files. */ export declare const invalidSourcePath: (path: string) => string | null; /** * Diff the changed paths of one app's directory back into `doc.source`. * * `changed` is `CommitResult.changed` verbatim — the paths that actually reached * the store, which is why this runs AFTER the workspace commit rather than * instead of it. Paths outside this app, and the seam-owned screen, are ignored: * they belong to someone else. * * A path in `changed` that no longer EXISTS is a deletion, and drops out of * `source`. A path that is still there and merely would not READ is a fault, and * keeps its stored entry — stale beats gone. Nothing else about the document is * touched. */ export declare function commitApp(appId: AppId, changed: readonly string[], workspace: WorkspaceFs, ctx: RunContext, seam: AppSourceSeam): Promise; //# sourceMappingURL=app-source.d.ts.map