apps/server/src/assets/AssetAccess.ts

import type { AssetResource } from "@t3tools/contracts";
import {
  AssetAttachmentNotFoundError,
  AssetGitHubMediaUrlValidationError,
  AssetPreviewTypeValidationError,
  AssetProjectFaviconInspectionError,
  AssetProjectFaviconNotFoundError,
  AssetProjectFaviconResolutionError,
  AssetSigningKeyLoadError,
  AssetWorkspaceAssetInspectionError,
  AssetWorkspaceAssetNotFoundError,
  AssetWorkspaceContextNotFoundError,
  AssetWorkspacePathValidationError,
  AssetWorkspaceResolutionError,
  AssetWorkspaceRootNormalizationError,
  ToolActivityNativeAppReference,
} from "@t3tools/contracts";
import {
  audioMimeTypeFromExtension,
  hostPreviewMimeTypeFromExtension,
  isWorkspaceImagePreviewPath,
  isWorkspacePreviewEntryPath,
  WORKSPACE_BROWSER_PREVIEW_EXTENSIONS,
  WORKSPACE_IMAGE_PREVIEW_EXTENSIONS,
} from "@t3tools/shared/filePreview";
import {
  IMAGE_DIMENSIONS_HEADER_BYTES,
  readImageDimensions,
  type ImageDimensions,
} from "@t3tools/shared/imageDimensions";
import { githubMediaFetchUrl, githubMediaFileName } from "@t3tools/shared/githubMedia";
import { PROJECT_FAVICON_FALLBACK_MARKER } from "@t3tools/shared/projectFavicon";
import * as Clock from "effect/Clock";
import * as Crypto from "effect/Crypto";
import * as Effect from "effect/Effect";
import * as Encoding from "effect/Encoding";
import * as FileSystem from "effect/FileSystem";
import * as Option from "effect/Option";
import * as Path from "effect/Path";
import * as PlatformError from "effect/PlatformError";
import * as Schema from "effect/Schema";

import {
  base64UrlDecodeUtf8,
  base64UrlEncode,
  signPayload,
  timingSafeEqualBase64Url,
} from "../auth/utils.ts";
import * as ServerSecretStore from "../auth/ServerSecretStore.ts";
import { parseAttachmentFileExtension, resolveAttachmentPathById } from "../attachmentStore.ts";
import * as ServerConfig from "../config.ts";
import * as ProjectFaviconResolver from "../project/ProjectFaviconResolver.ts";
import * as WorkspacePaths from "../workspace/WorkspacePaths.ts";
import * as NativeAppIconResolver from "./NativeAppIconResolver.ts";
import { openMediaFile, readMediaFileHeader, type OpenMediaFile } from "./MediaFile.ts";

export const ASSET_ROUTE_PREFIX = "/api/assets";

const SIGNING_SECRET_NAME = "asset-access-signing-key";
const ASSET_TOKEN_TTL_MS = 60 * 60 * 1000;
const PROJECT_FAVICON_TOKEN_BUCKET_MS = 30 * 60 * 1000;
const PROJECT_FAVICON_VERSION_PREFIX = "v";
const INLINE_VIDEO_MIME_TYPE_PATTERN = /^video\/[\w!#$&^.+-]+$/i;
// Extensions a document viewer or audio player may request inline. The extension comes from
// the attachment id the server assigned, never from the client's mime type.
const INLINE_PREVIEW_MIME_TYPES: Record<string, string> = {
  pdf: "application/pdf",
  html: "text/html",
  htm: "text/html",
};
const inlinePreviewMimeTypeForExtension = (extension: string) =>
  INLINE_PREVIEW_MIME_TYPES[extension] ?? audioMimeTypeFromExtension(`.${extension}`) ?? undefined;
const PREVIEW_ASSET_EXTENSIONS = new Set([
  ...WORKSPACE_BROWSER_PREVIEW_EXTENSIONS,
  ...WORKSPACE_IMAGE_PREVIEW_EXTENSIONS,
  ".css",
  ".js",
  ".mjs",
  ".otf",
  ".ttf",
  ".woff",
  ".woff2",
]);

const AssetClaimsSchema = Schema.Union([
  Schema.Struct({
    version: Schema.Literal(1),
    kind: Schema.Literal("workspace-file"),
    workspaceRoot: Schema.String,
    baseRelativePath: Schema.String,
    expiresAt: Schema.Number,
  }),
  Schema.Struct({
    version: Schema.Literal(1),
    kind: Schema.Literal("workspace-file-exact"),
    workspaceRoot: Schema.String,
    relativePath: Schema.String,
    expiresAt: Schema.Number,
  }),
  Schema.Struct({
    version: Schema.Literal(1),
    kind: Schema.Literal("media-file-exact"),
    filePath: Schema.String,
    device: Schema.String,
    inode: Schema.String,
    expiresAt: Schema.Number,
  }),
  Schema.Struct({
    version: Schema.Literal(1),
    kind: Schema.Literal("attachment"),
    attachmentId: Schema.String,
    /** Decided at mint time. Absent tokens (from before this field) serve
        inline, which is only ever the image case. */
    download: Schema.optionalKey(Schema.Boolean),
    /** Display name and mime the caller supplied at mint time; drive the
        download filename and Content-Type. */
    fileName: Schema.optionalKey(Schema.String),
    mimeType: Schema.optionalKey(Schema.String),
    expiresAt: Schema.Number,
  }),
  Schema.Struct({
    version: Schema.Literal(1),
    kind: Schema.Literal("project-favicon"),
    workspaceRoot: Schema.String,
    relativePath: Schema.NullOr(Schema.String),
    expiresAt: Schema.Number,
  }),
  Schema.Struct({
    version: Schema.Literal(1),
    kind: Schema.Literal("project-favicon-external"),
    filePath: Schema.String,
    expiresAt: Schema.Number,
  }),
  Schema.Struct({
    version: Schema.Literal(1),
    kind: Schema.Literal("native-app-icon"),
    app: ToolActivityNativeAppReference,
    expiresAt: Schema.Number,
  }),
  Schema.Struct({
    version: Schema.Literal(1),
    kind: Schema.Literal("github-media"),
    /** Already narrowed to a GitHub media host at mint time; the signature is what keeps it there. */
    url: Schema.String,
    cwd: Schema.String,
    expiresAt: Schema.Number,
  }),
]);
type AssetClaims = typeof AssetClaimsSchema.Type;

const AssetClaimsJson = Schema.fromJsonString(AssetClaimsSchema);
const decodeAssetClaims = Schema.decodeUnknownOption(AssetClaimsJson);
const encodeAssetClaims = Schema.encodeSync(AssetClaimsJson);

export type ResolvedAsset =
  | {
      readonly kind: "file";
      readonly path: string;
      readonly download?: boolean;
      readonly fileName?: string;
      readonly mimeType?: string;
      readonly file?: OpenMediaFile;
    }
  | {
      readonly kind: "github-media";
      readonly url: string;
      readonly cwd: string;
      /** When the signed URL that granted this stops working, which bounds how long a client
          may keep the bytes it fetched with it. */
      readonly expiresAt: number;
    };

function decodeClaims(encodedPayload: string): AssetClaims | null {
  try {
    return Option.getOrNull(decodeAssetClaims(base64UrlDecodeUtf8(encodedPayload)));
  } catch {
    return null;
  }
}

function decodeRelativePath(value: string): string | null {
  try {
    return decodeURIComponent(value);
  } catch {
    return null;
  }
}

const optionOnNotFound = <A, R>(
  effect: Effect.Effect<A, PlatformError.PlatformError, R>,
): Effect.Effect<Option.Option<A>, PlatformError.PlatformError, R> =>
  effect.pipe(
    Effect.asSome,
    Effect.catchTags({
      PlatformError: (error) =>
        error.reason._tag === "NotFound" ? Effect.succeed(Option.none<A>()) : Effect.fail(error),
    }),
  );

const resolveCanonicalFile = Effect.fn("AssetAccess.resolveCanonicalFile")(function* (
  filePath: string,
) {
  const fileSystem = yield* FileSystem.FileSystem;
  const canonicalFile = yield* optionOnNotFound(fileSystem.realPath(filePath));
  if (Option.isNone(canonicalFile)) return null;

  const info = yield* optionOnNotFound(fileSystem.stat(canonicalFile.value));
  return Option.isSome(info) && info.value.type === "File" ? canonicalFile.value : null;
});

const resolveCanonicalWorkspaceFile = Effect.fn("AssetAccess.resolveCanonicalWorkspaceFile")(
  function* (input: { readonly workspaceRoot: string; readonly relativePath: string }) {
    const fileSystem = yield* FileSystem.FileSystem;
    const workspacePaths = yield* WorkspacePaths.WorkspacePaths;
    const resolved = yield* workspacePaths.resolveRelativePathWithinRoot(input).pipe(
      Effect.asSome,
      Effect.catchTags({
        WorkspacePathOutsideRootError: () => Effect.succeedNone,
      }),
    );
    if (Option.isNone(resolved)) return null;

    const [canonicalRoot, canonicalFile] = yield* Effect.all([
      optionOnNotFound(fileSystem.realPath(input.workspaceRoot)),
      optionOnNotFound(fileSystem.realPath(resolved.value.absolutePath)),
    ]);
    if (Option.isNone(canonicalRoot) || Option.isNone(canonicalFile)) return null;

    const path = yield* Path.Path;
    const relative = path.relative(canonicalRoot.value, canonicalFile.value);
    if (relative === "" || relative.startsWith("..") || path.isAbsolute(relative)) return null;

    const info = yield* optionOnNotFound(fileSystem.stat(canonicalFile.value));
    return Option.isSome(info) && info.value.type === "File" ? canonicalFile.value : null;
  },
);

const resolveCanonicalWorkspaceFileForRequest = (input: {
  readonly workspaceRoot: string;
  readonly relativePath: string;
}) =>
  resolveCanonicalWorkspaceFile(input).pipe(
    Effect.tapError((cause) =>
      Effect.logError("Failed to resolve canonical asset path.", {
        workspaceRoot: input.workspaceRoot,
        relativePath: input.relativePath,
        cause,
      }),
    ),
    Effect.orElseSucceed(() => null),
  );

/**
 * Reads pixel dimensions from an image's header so clients can reserve the
 * exact box before the bytes arrive. Best effort: an unreadable or unsupported
 * file just leaves the field out, and the client measures after decode. Only
 * formats the parser understands are opened; SVG and the rest are skipped.
 */
const HEADER_IMAGE_EXTENSIONS = new Set([".png", ".jpg", ".jpeg", ".gif", ".webp"]);

/** From the identity-checked, non-blocking handle the caller already holds. */
const readImageDimensionsFromOpenFile = (filePath: string, file: OpenMediaFile) =>
  readMediaFileHeader(filePath, file, IMAGE_DIMENSIONS_HEADER_BYTES).pipe(
    Effect.map(readImageDimensions),
    Effect.orElseSucceed((): ImageDimensions | null => null),
  );

/**
 * Opens through `openMediaFile` so a path swapped for a FIFO cannot block the
 * request; a regular open would wait for a writer that never comes.
 */
const readImageDimensionsFromHeader = (filePath: string) =>
  openMediaFile(filePath).pipe(
    Effect.flatMap((file) =>
      file === null ? Effect.succeed(null) : readImageDimensionsFromOpenFile(filePath, file),
    ),
    Effect.scoped,
    Effect.orElseSucceed((): ImageDimensions | null => null),
  );

const finalizeAbsoluteMediaFileAsset = Effect.fn("AssetAccess.finalizeAbsoluteMediaFileAsset")(
  function* (input: {
    readonly requestedPath: string;
    readonly resource: AssetResource;
    readonly expiresAt: number;
  }) {
    const path = yield* Path.Path;
    const canonicalFile = yield* resolveCanonicalFile(input.requestedPath).pipe(
      Effect.mapError(
        (cause) => new AssetWorkspaceAssetInspectionError({ resource: input.resource, cause }),
      ),
    );
    if (!canonicalFile) {
      return yield* new AssetWorkspaceAssetNotFoundError({ resource: input.resource });
    }
    if (hostPreviewMimeTypeFromExtension(path.extname(canonicalFile)) === null) {
      return yield* new AssetPreviewTypeValidationError({ resource: input.resource });
    }
    const wantsDimensions = HEADER_IMAGE_EXTENSIONS.has(path.extname(canonicalFile).toLowerCase());
    const opened = yield* openMediaFile(canonicalFile).pipe(
      Effect.flatMap((file) =>
        file === null
          ? Effect.succeed(null)
          : Effect.map(
              wantsDimensions
                ? readImageDimensionsFromOpenFile(canonicalFile, file)
                : Effect.succeed(null),
              (dimensions) => ({
                identity: { device: file.info.dev.toString(), inode: file.info.ino.toString() },
                dimensions,
              }),
            ),
      ),
      Effect.scoped,
      Effect.mapError(
        (cause) => new AssetWorkspaceAssetInspectionError({ resource: input.resource, cause }),
      ),
    );
    if (!opened) {
      return yield* new AssetWorkspaceAssetNotFoundError({ resource: input.resource });
    }
    return {
      claims: {
        version: 1 as const,
        kind: "media-file-exact" as const,
        filePath: canonicalFile,
        ...opened.identity,
        expiresAt: input.expiresAt,
      },
      fileName: path.basename(canonicalFile),
      imageDimensions: opened.dimensions,
    };
  },
);

const finalizeWorkspaceFileAsset = Effect.fn("AssetAccess.finalizeWorkspaceFileAsset")(
  function* (input: {
    readonly workspaceRoot: string;
    readonly requestedPath: string;
    readonly resource: AssetResource;
    readonly expiresAt: number;
  }) {
    const path = yield* Path.Path;
    const fileSystem = yield* FileSystem.FileSystem;
    const workspacePaths = yield* WorkspacePaths.WorkspacePaths;
    const relativePath = path.isAbsolute(input.requestedPath)
      ? path.relative(input.workspaceRoot, input.requestedPath)
      : input.requestedPath;
    const resolved = yield* workspacePaths
      .resolveRelativePathWithinRoot({ workspaceRoot: input.workspaceRoot, relativePath })
      .pipe(
        Effect.mapError(
          (cause) =>
            new AssetWorkspacePathValidationError({
              resource: input.resource,
              cause,
            }),
        ),
      );
    if (!isWorkspacePreviewEntryPath(resolved.relativePath)) {
      return yield* new AssetPreviewTypeValidationError({
        resource: input.resource,
      });
    }
    const canonicalFile = yield* resolveCanonicalWorkspaceFile({
      workspaceRoot: input.workspaceRoot,
      relativePath: resolved.relativePath,
    }).pipe(
      Effect.mapError(
        (cause) =>
          new AssetWorkspaceAssetInspectionError({
            resource: input.resource,
            cause,
          }),
      ),
    );
    if (!canonicalFile) {
      return yield* new AssetWorkspaceAssetNotFoundError({
        resource: input.resource,
      });
    }
    const canonicalWorkspaceRoot = yield* fileSystem.realPath(input.workspaceRoot).pipe(
      Effect.mapError(
        (cause) =>
          new AssetWorkspaceResolutionError({
            resource: input.resource,
            cause,
          }),
      ),
    );
    const imageDimensions = HEADER_IMAGE_EXTENSIONS.has(
      path.extname(resolved.relativePath).toLowerCase(),
    )
      ? yield* readImageDimensionsFromHeader(canonicalFile)
      : null;
    return {
      claims: isWorkspaceImagePreviewPath(resolved.relativePath)
        ? {
            version: 1 as const,
            kind: "workspace-file-exact" as const,
            workspaceRoot: canonicalWorkspaceRoot,
            relativePath: resolved.relativePath,
            expiresAt: input.expiresAt,
          }
        : {
            version: 1 as const,
            kind: "workspace-file" as const,
            workspaceRoot: canonicalWorkspaceRoot,
            baseRelativePath: path.dirname(resolved.relativePath),
            expiresAt: input.expiresAt,
          },
      fileName: path.basename(resolved.relativePath),
      imageDimensions,
    };
  },
);

export const issueAssetUrl = Effect.fn("AssetAccess.issueAssetUrl")(function* (input: {
  readonly resource: AssetResource;
  readonly workspaceRoot?: string;
  readonly projectFaviconPath?: string;
}) {
  const fileSystem = yield* FileSystem.FileSystem;
  const path = yield* Path.Path;
  const workspacePaths = yield* WorkspacePaths.WorkspacePaths;
  let expiresAt = (yield* Clock.currentTimeMillis) + ASSET_TOKEN_TTL_MS;
  let claims: AssetClaims;
  let fileName: string;
  let sourcePath: string | undefined;
  let imageDimensions: ImageDimensions | null = null;

  switch (input.resource._tag) {
    case "media-file": {
      let requestedPath = input.resource.path;
      if (!path.isAbsolute(requestedPath)) {
        if (!input.workspaceRoot) {
          return yield* new AssetWorkspaceContextNotFoundError({ resource: input.resource });
        }
        const workspaceRoot = yield* workspacePaths
          .normalizeWorkspaceRoot(input.workspaceRoot)
          .pipe(
            Effect.mapError(
              (cause) =>
                new AssetWorkspaceRootNormalizationError({ resource: input.resource, cause }),
            ),
          );
        requestedPath = path.resolve(workspaceRoot, requestedPath);
      }
      const finalized = yield* finalizeAbsoluteMediaFileAsset({
        requestedPath,
        resource: input.resource,
        expiresAt,
      });
      claims = finalized.claims;
      fileName = finalized.fileName;
      imageDimensions = finalized.imageDimensions;
      break;
    }
    case "workspace-file": {
      if (!input.workspaceRoot) {
        return yield* new AssetWorkspaceContextNotFoundError({
          resource: input.resource,
        });
      }
      const workspaceRoot = yield* workspacePaths.normalizeWorkspaceRoot(input.workspaceRoot).pipe(
        Effect.mapError(
          (cause) =>
            new AssetWorkspaceRootNormalizationError({
              resource: input.resource,
              cause,
            }),
        ),
      );
      const finalized = yield* finalizeWorkspaceFileAsset({
        workspaceRoot,
        requestedPath: input.resource.path,
        resource: input.resource,
        expiresAt,
      });
      claims = finalized.claims;
      fileName = finalized.fileName;
      imageDimensions = finalized.imageDimensions;
      break;
    }
    case "draft-workspace-file": {
      // The draft names its workspace root in the resource itself; an explicit
      // root only overrides it.
      const draftWorkspaceRoot = input.workspaceRoot ?? input.resource.cwd;
      if (path.isAbsolute(input.resource.path)) {
        // An absolute draft path serves exactly like an absolute media path.
        const finalized = yield* finalizeAbsoluteMediaFileAsset({
          requestedPath: input.resource.path,
          resource: input.resource,
          expiresAt,
        });
        claims = finalized.claims;
        fileName = finalized.fileName;
        imageDimensions = finalized.imageDimensions;
        break;
      }
      const workspaceRoot = yield* workspacePaths.normalizeWorkspaceRoot(draftWorkspaceRoot).pipe(
        Effect.mapError(
          (cause) =>
            new AssetWorkspaceRootNormalizationError({
              resource: input.resource,
              cause,
            }),
        ),
      );
      const finalized = yield* finalizeWorkspaceFileAsset({
        workspaceRoot,
        requestedPath: input.resource.path,
        resource: input.resource,
        expiresAt,
      });
      claims = finalized.claims;
      fileName = finalized.fileName;
      imageDimensions = finalized.imageDimensions;
      break;
    }
    case "attachment": {
      const config = yield* ServerConfig.ServerConfig;
      const attachmentPath = resolveAttachmentPathById({
        attachmentsDir: config.attachmentsDir,
        attachmentId: input.resource.attachmentId,
      });
      if (!attachmentPath) {
        return yield* new AssetAttachmentNotFoundError({
          resource: input.resource,
        });
      }
      // Generic files carry their extension inside the attachment id (that
      // shape resolves the on-disk path); images do not. Videos and images
      // render inline. Other generic files download unless a viewer requests
      // a supported document or audio format inline.
      const extension = parseAttachmentFileExtension(input.resource.attachmentId);
      const isGenericFile = extension !== null;
      const videoMimeType = input.resource.mimeType?.split(";", 1)[0]?.trim() ?? "";
      const isVideo = INLINE_VIDEO_MIME_TYPE_PATTERN.test(videoMimeType);
      const inlinePreviewMimeType =
        input.resource.disposition === "inline" && extension !== null
          ? inlinePreviewMimeTypeForExtension(extension)
          : undefined;
      if (!isGenericFile) {
        imageDimensions = yield* readImageDimensionsFromHeader(attachmentPath);
      }
      claims = {
        version: 1,
        kind: "attachment",
        attachmentId: input.resource.attachmentId,
        ...(isGenericFile && !isVideo && inlinePreviewMimeType === undefined
          ? { download: true }
          : {}),
        ...(input.resource.fileName !== undefined ? { fileName: input.resource.fileName } : {}),
        ...(inlinePreviewMimeType !== undefined
          ? { mimeType: inlinePreviewMimeType }
          : input.resource.mimeType !== undefined
            ? { mimeType: isVideo ? videoMimeType : input.resource.mimeType }
            : {}),
        expiresAt,
      };
      fileName = input.resource.fileName ?? path.basename(attachmentPath);
      break;
    }
    case "project-favicon": {
      const workspaceRoot = yield* workspacePaths.normalizeWorkspaceRoot(input.resource.cwd).pipe(
        Effect.mapError(
          (cause) =>
            new AssetWorkspaceRootNormalizationError({
              resource: input.resource,
              cause,
            }),
        ),
      );
      const faviconResolver = yield* ProjectFaviconResolver.ProjectFaviconResolver;
      const faviconPath = yield* faviconResolver
        .resolvePath(workspaceRoot, input.projectFaviconPath ?? undefined)
        .pipe(
          Effect.mapError(
            (cause) =>
              new AssetProjectFaviconResolutionError({
                resource: input.resource,
                cause,
              }),
          ),
        );
      const isExternalOverride =
        faviconPath !== null &&
        input.projectFaviconPath !== undefined &&
        path.isAbsolute(input.projectFaviconPath) &&
        path.normalize(faviconPath) === path.normalize(input.projectFaviconPath);
      const relativePath =
        faviconPath && !isExternalOverride ? path.relative(workspaceRoot, faviconPath) : null;
      const sourceFaviconPath = isExternalOverride ? faviconPath : relativePath;
      if (sourceFaviconPath && !isWorkspaceImagePreviewPath(sourceFaviconPath)) {
        return yield* new AssetPreviewTypeValidationError({ resource: input.resource });
      }
      sourcePath = sourceFaviconPath ?? undefined;
      const canonicalFaviconPath = sourceFaviconPath
        ? yield* (
            isExternalOverride
              ? resolveCanonicalFile(sourceFaviconPath)
              : resolveCanonicalWorkspaceFile({ workspaceRoot, relativePath: sourceFaviconPath })
          ).pipe(
            Effect.mapError(
              (cause) =>
                new AssetProjectFaviconInspectionError({
                  resource: input.resource,
                  cause,
                }),
            ),
          )
        : null;
      if (sourceFaviconPath && !canonicalFaviconPath) {
        return yield* new AssetProjectFaviconNotFoundError({
          resource: input.resource,
        });
      }
      claims =
        isExternalOverride && canonicalFaviconPath
          ? {
              version: 1,
              kind: "project-favicon-external",
              filePath: canonicalFaviconPath,
              expiresAt,
            }
          : {
              version: 1,
              kind: "project-favicon",
              workspaceRoot: yield* fileSystem.realPath(workspaceRoot).pipe(
                Effect.mapError(
                  (cause) =>
                    new AssetWorkspaceResolutionError({
                      resource: input.resource,
                      cause,
                    }),
                ),
              ),
              relativePath,
              expiresAt,
            };
      if (sourceFaviconPath && canonicalFaviconPath) {
        const crypto = yield* Crypto.Crypto;
        const faviconBytes = yield* fileSystem.readFile(canonicalFaviconPath).pipe(
          Effect.mapError(
            (cause) =>
              new AssetProjectFaviconInspectionError({
                resource: input.resource,
                cause,
              }),
          ),
        );
        const revision = yield* crypto.digest("SHA-256", faviconBytes).pipe(
          Effect.map(Encoding.encodeHex),
          Effect.mapError(
            (cause) =>
              new AssetProjectFaviconInspectionError({
                resource: input.resource,
                cause,
              }),
          ),
        );
        fileName = `${PROJECT_FAVICON_VERSION_PREFIX}${revision}-${path.basename(sourceFaviconPath)}`;
      } else {
        fileName = PROJECT_FAVICON_FALLBACK_MARKER;
      }
      break;
    }
    case "native-app-icon": {
      claims = {
        version: 1,
        kind: "native-app-icon",
        app: input.resource.app,
        expiresAt,
      };
      fileName = "native-app-icon.png";
      break;
    }
    case "github-media": {
      const fetchUrl = githubMediaFetchUrl(input.resource.url);
      if (fetchUrl === null) {
        return yield* new AssetGitHubMediaUrlValidationError({});
      }
      claims = {
        version: 1,
        kind: "github-media",
        url: fetchUrl,
        cwd: input.resource.cwd,
        expiresAt,
      };
      fileName = githubMediaFileName(fetchUrl);
      break;
    }
  }

  const secretStore = yield* ServerSecretStore.ServerSecretStore;
  const signingSecret = yield* secretStore.getOrCreateRandom(SIGNING_SECRET_NAME, 32).pipe(
    Effect.mapError(
      (cause) =>
        new AssetSigningKeyLoadError({
          resource: input.resource,
          cause,
        }),
    ),
  );
  if (claims.kind === "project-favicon" || claims.kind === "project-favicon-external") {
    const issuedAt = yield* Clock.currentTimeMillis;
    expiresAt =
      (Math.floor(issuedAt / PROJECT_FAVICON_TOKEN_BUCKET_MS) + 2) *
      PROJECT_FAVICON_TOKEN_BUCKET_MS;
    claims = { ...claims, expiresAt };
  }
  const encodedPayload = base64UrlEncode(encodeAssetClaims(claims));
  const token = `${encodedPayload}.${signPayload(encodedPayload, signingSecret)}`;
  return {
    relativeUrl: `${ASSET_ROUTE_PREFIX}/${token}/${encodeURIComponent(fileName)}`,
    expiresAt,
    ...(sourcePath !== undefined ? { sourcePath } : {}),
    ...(imageDimensions !== null ? { imageDimensions } : {}),
  };
});

export const resolveAsset = Effect.fn("AssetAccess.resolveAsset")(function* (
  token: string,
  relativePath: string,
) {
  const [encodedPayload, signature] = token.split(".");
  if (!encodedPayload || !signature) return null;

  const secretStore = yield* ServerSecretStore.ServerSecretStore;
  const signingSecret = yield* secretStore.getOrCreateRandom(SIGNING_SECRET_NAME, 32).pipe(
    Effect.tapError((cause) => Effect.logError("Failed to load the asset signing key.", { cause })),
    Effect.orElseSucceed(() => null),
  );
  if (!signingSecret) return null;
  if (!timingSafeEqualBase64Url(signature, signPayload(encodedPayload, signingSecret))) return null;

  const claims = decodeClaims(encodedPayload);
  if (!claims || claims.expiresAt <= (yield* Clock.currentTimeMillis)) return null;

  if (claims.kind === "attachment") {
    const config = yield* ServerConfig.ServerConfig;
    const attachmentPath = resolveAttachmentPathById({
      attachmentsDir: config.attachmentsDir,
      attachmentId: claims.attachmentId,
    });
    if (!attachmentPath) return null;
    const fileSystem = yield* FileSystem.FileSystem;
    const info = yield* optionOnNotFound(fileSystem.stat(attachmentPath)).pipe(
      Effect.tapError((cause) =>
        Effect.logError("Failed to inspect attachment asset.", {
          attachmentId: claims.attachmentId,
          path: attachmentPath,
          cause,
        }),
      ),
      Effect.orElseSucceed(() => Option.none()),
    );
    return Option.isSome(info) && info.value.type === "File"
      ? ({
          kind: "file",
          path: attachmentPath,
          ...(claims.download ? { download: true } : {}),
          ...(claims.fileName !== undefined ? { fileName: claims.fileName } : {}),
          ...(claims.mimeType !== undefined ? { mimeType: claims.mimeType } : {}),
        } satisfies ResolvedAsset)
      : null;
  }

  if (claims.kind === "project-favicon") {
    if (claims.relativePath === null) return null;
    const faviconPath = yield* resolveCanonicalWorkspaceFileForRequest({
      workspaceRoot: claims.workspaceRoot,
      relativePath: claims.relativePath,
    });
    return faviconPath ? ({ kind: "file", path: faviconPath } satisfies ResolvedAsset) : null;
  }

  if (claims.kind === "project-favicon-external") {
    const faviconPath = yield* resolveCanonicalFile(claims.filePath).pipe(
      Effect.tapError((cause) =>
        Effect.logError("Failed to resolve canonical asset path.", {
          filePath: claims.filePath,
          cause,
        }),
      ),
      Effect.orElseSucceed(() => null),
    );
    return faviconPath === claims.filePath
      ? ({ kind: "file", path: faviconPath } satisfies ResolvedAsset)
      : null;
  }

  if (claims.kind === "github-media") {
    return {
      kind: "github-media",
      url: claims.url,
      cwd: claims.cwd,
      expiresAt: claims.expiresAt,
    } satisfies ResolvedAsset;
  }

  if (claims.kind === "native-app-icon") {
    const nativeAppIconResolver = yield* NativeAppIconResolver.NativeAppIconResolver;
    const iconPath = yield* nativeAppIconResolver.resolve(claims.app);
    return iconPath ? ({ kind: "file", path: iconPath } satisfies ResolvedAsset) : null;
  }

  const decodedPath = decodeRelativePath(relativePath);
  if (decodedPath === null) return null;
  const path = yield* Path.Path;
  if (claims.kind === "media-file-exact") {
    if (decodedPath !== path.basename(claims.filePath)) return null;
    const canonicalFile = yield* resolveCanonicalFile(claims.filePath).pipe(
      Effect.tapError((cause) =>
        Effect.logError("Failed to resolve canonical media path.", {
          filePath: claims.filePath,
          cause,
        }),
      ),
      Effect.orElseSucceed(() => null),
    );
    if (canonicalFile !== claims.filePath) return null;
    const mimeType = hostPreviewMimeTypeFromExtension(path.extname(canonicalFile));
    if (!mimeType) return null;
    const file = yield* openMediaFile(canonicalFile, claims).pipe(
      Effect.tapError((cause) =>
        Effect.logError("Failed to open canonical media file.", { filePath: canonicalFile, cause }),
      ),
      Effect.orElseSucceed(() => null),
    );
    return file
      ? ({ kind: "file", path: canonicalFile, mimeType, file } satisfies ResolvedAsset)
      : null;
  }
  if (claims.kind === "workspace-file-exact") {
    if (decodedPath !== path.basename(claims.relativePath)) return null;
    const exactWorkspaceFile = yield* resolveCanonicalWorkspaceFileForRequest({
      workspaceRoot: claims.workspaceRoot,
      relativePath: claims.relativePath,
    });
    return exactWorkspaceFile
      ? ({ kind: "file", path: exactWorkspaceFile } satisfies ResolvedAsset)
      : null;
  }
  const segments = decodedPath.split(/[\\/]/);
  if (
    decodedPath.length === 0 ||
    decodedPath.includes("\0") ||
    segments.some((segment) => segment === "." || segment === ".." || segment.startsWith(".")) ||
    !PREVIEW_ASSET_EXTENSIONS.has(path.extname(decodedPath).toLowerCase())
  ) {
    return null;
  }
  const joinedRelativePath =
    claims.baseRelativePath === "." ? decodedPath : path.join(claims.baseRelativePath, decodedPath);
  const workspaceFile = yield* resolveCanonicalWorkspaceFileForRequest({
    workspaceRoot: claims.workspaceRoot,
    relativePath: joinedRelativePath,
  });
  return workspaceFile ? ({ kind: "file", path: workspaceFile } satisfies ResolvedAsset) : null;
});