> ## Documentation Index
> Fetch the complete documentation index at: https://sonamu.cartanova.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Context

> Sonamu API 요청 컨텍스트 레퍼런스

Context는 Sonamu API 메서드 실행 중에 HTTP 요청과 관련된 정보에 접근할 수 있게 해주는 객체입니다. API 메서드의 파라미터로 주입받아 사용할 수 있으며, AsyncLocalStorage를 통해 관리됩니다.

## 타입 정의

```typescript theme={null}
type Context = {
  request: FastifyRequest;
  reply: FastifyReply;
  headers: IncomingHttpHeaders;
  createSSE: <T extends ZodObject>(events: T) => ReturnType<typeof createSSEFactory<T>>;
  naiteStore: NaiteStore;
  locale: string;
  /** buffer 모드에서 업로드된 파일 */
  bufferedFiles?: BufferedFile[];
  /** stream 모드에서 업로드된 파일 */
  uploadedFiles?: UploadedFile[];
} & AuthContext &
  ContextExtend;
```

Context 타입은 \*\*교차 타입(Intersection Type, `&`)\*\*으로 구성됩니다:

* 기본 Context 객체 (request, reply 등)
* `AuthContext`: 인증 관련 속성 (user, session)
* `ContextExtend`: 프로젝트별 확장 속성

이러한 구조 덕분에 Context는 타입 안전성을 유지하면서 확장 가능합니다.

## Context 속성

### request

```typescript theme={null}
request: FastifyRequest;
```

현재 HTTP 요청을 나타내는 Fastify Request 객체입니다. 요청 URL, 메서드, 쿼리 파라미터 등에 접근할 수 있습니다.

### reply

```typescript theme={null}
reply: FastifyReply;
```

현재 HTTP 응답을 나타내는 Fastify Reply 객체입니다. 응답 헤더 설정, 상태 코드 변경 등에 사용할 수 있습니다.

### headers

```typescript theme={null}
headers: IncomingHttpHeaders;
```

HTTP 요청 헤더입니다. `request.headers`와 동일한 값으로, 편의를 위해 제공됩니다.

### createSSE

```typescript theme={null}
createSSE: <T extends ZodObject>(events: T) => ReturnType<typeof createSSEFactory<T>>;
```

Server-Sent Events(SSE) 스트림을 생성하는 함수입니다. Zod 스키마를 사용하여 타입 안전한 이벤트 스트림을 만들 수 있습니다.

**사용 예시:**

```typescript theme={null}
import { z } from "zod";

const ProcessEventsSchema = z.object({
  progress: z.object({ percent: z.number() }),
  complete: z.object({ result: z.string() }),
});

class MyModelClass extends BaseModelClass {
  @stream({
    type: "sse",
    events: ProcessEventsSchema,
  })
  async processData(ctx: Context) {
    const sse = ctx.createSSE(ProcessEventsSchema);

    // 진행률 전송
    await sse.publish("progress", { percent: 50 });

    // 완료 이벤트 전송
    await sse.publish("complete", { result: "done" });

    return sse;
  }
}
```

### naiteStore

```typescript theme={null}
naiteStore: NaiteStore;
```

Naite 테스팅 프레임워크에서 사용하는 저장소입니다. 테스트 중 모킹된 데이터나 스냅샷 정보를 저장하는 용도로 사용됩니다.

### locale

```typescript theme={null}
locale: string;
```

현재 요청의 locale(언어 설정)입니다. 항상 값이 존재합니다.

`Accept-Language` 헤더를 파싱하여 지원하는 locale 중 하나를 자동으로 선택하며, 일치하는 locale이 없으면 `defaultLocale`이 사용됩니다.

**설정 예시:**

```typescript theme={null}
// sonamu.config.ts
export default {
  i18n: {
    defaultLocale: "ko",
    supportedLocales: ["ko", "en", "ja"],
  },
} satisfies SonamuConfig;
```

**사용 예시:**

```typescript theme={null}
class PostModelClass extends BaseModelClass {
  @api({ httpMethod: "GET" })
  async findMany(ctx: Context) {
    const locale = ctx.locale; // "ko", "en", "ja" 중 하나

    // locale에 따라 다른 응답
    const posts = await this.getPuri("r").table("posts").where("locale", locale).select("*");

    return posts;
  }
}
```

### bufferedFiles

```typescript theme={null}
bufferedFiles?: BufferedFile[]
```

Buffer 모드로 업로드된 파일 목록입니다. `@upload` 데코레이터가 적용된 메서드에서, 기본값(`consume: "buffer"`) 또는 `@upload({ consume: "buffer" })`로 설정된 경우에 존재합니다.

각 파일은 메모리에 로드된 상태로, MD5 계산이나 이미지 처리 등 유연한 작업이 가능합니다.

**BufferedFile 주요 속성 및 메서드:**

```typescript theme={null}
interface BufferedFile {
  // 파일 정보
  filename: string; // 파일명
  mimetype: string; // MIME 타입 (예: "image/png", "application/pdf")
  size: number; // 파일 크기 (bytes)
  extname: string; // 확장자 (예: "png", "pdf")

  // 파일 처리 메서드
  buffer: Buffer; // 파일 Buffer (getter)
  md5(): Promise<string>; // MD5 해시 생성
  saveToDisk(diskName: string, key: string): Promise<string>; // 파일 저장 후 URL 반환
}
```

**기본 사용 예시:**

```typescript theme={null}
class FileModelClass extends BaseModelClass {
  @upload({ limits: { files: 10 } })
  async upload(): Promise<{ files: SonamuFile[] }> {
    const { bufferedFiles } = Sonamu.getContext();

    if (!bufferedFiles || bufferedFiles.length === 0) {
      throw new BadRequestException("파일이 업로드되지 않았습니다");
    }

    const processedFiles = await Promise.all(
      bufferedFiles.map(async (file) => {
        const md5 = await file.md5();
        const key = `${md5}.${file.extname}`;
        return {
          name: file.filename,
          url: await file.saveToDisk("fs", key),
          mime_type: file.mimetype,
          size: file.size,
        };
      }),
    );

    return { files: processedFiles };
  }
}
```

**이미지 처리 예시:**

```typescript theme={null}
import sharp from "sharp";

class ImageModelClass extends BaseModelClass {
  @upload({ limits: { files: 1 } })
  async uploadThumbnail(): Promise<{ url: string }> {
    const { bufferedFiles } = Sonamu.getContext();

    if (!bufferedFiles || bufferedFiles.length === 0) {
      throw new BadRequestException("이미지가 업로드되지 않았습니다");
    }

    const file = bufferedFiles[0];

    // Buffer로 이미지 처리 (getter 사용)
    const thumbnail = await sharp(file.buffer).resize(200, 200).jpeg({ quality: 80 }).toBuffer();

    // 처리된 이미지 저장
    const disk = Sonamu.storage.use("fs");
    const key = `thumbnails/${await file.md5()}.jpg`;
    await disk.put(key, thumbnail);

    return { url: await disk.getUrl(key) };
  }
}
```

### uploadedFiles

```typescript theme={null}
uploadedFiles?: UploadedFile[]
```

Stream 모드로 업로드된 파일 목록입니다. `@upload({ consume: "stream", destination: "..." })` 설정 시 존재합니다.

파일이 이미 저장소에 스트리밍 완료된 상태로, URL/key 등 메타데이터만 접근 가능합니다. 대용량 파일 업로드에 적합합니다.

**UploadedFile 주요 속성 및 메서드:**

```typescript theme={null}
interface UploadedFile {
  // 파일 정보
  filename: string; // 파일명
  mimetype: string; // MIME 타입 (예: "image/png", "application/pdf")
  size: number; // 파일 크기 (bytes)
  extname: string; // 확장자 (예: "png", "pdf")
  url: string; // 저장된 파일의 URL
  signedUrl: string; // Signed URL (만료 시간 있음)
  key: string; // 저장소 내 키
  diskName: string; // 저장된 디스크 이름

  // 파일 처리 메서드
  download(): Promise<Buffer>; // 저장소에서 파일 다운로드
}
```

**Stream 모드 사용 예시:**

```typescript theme={null}
class FileModelClass extends BaseModelClass {
  @upload({ consume: "stream", destination: "s3", limits: { files: 5 } })
  async uploadLargeFiles(): Promise<{ files: SonamuFile[] }> {
    const { uploadedFiles } = Sonamu.getContext();

    if (!uploadedFiles || uploadedFiles.length === 0) {
      throw new BadRequestException("파일이 업로드되지 않았습니다");
    }

    // 이미 저장소에 업로드 완료된 상태
    return {
      files: uploadedFiles.map((file) => ({
        name: file.filename,
        url: file.url,
        mime_type: file.mimetype,
        size: file.size,
      })),
    };
  }
}
```

<Info>
  **파일 업로드 처리**: - `@upload` 데코레이터와 함께 사용해야 합니다 - Buffer 모드(기본):
  `bufferedFiles` 사용 - 메모리에 로드, MD5 계산/이미지 처리에 적합 - Stream 모드: `uploadedFiles`
  사용 - 저장소로 직접 스트리밍, 대용량 파일에 적합 - 자세한 내용은 [@upload
  데코레이터](/ko/api-reference/decorators/upload) 문서를 참고하세요
</Info>

### AuthContext 속성

Context는 [AuthContext](/ko/api-reference/context/auth-context)의 속성들도 포함합니다:

* `user`: 현재 인증된 사용자 정보 (`User | null`)
* `session`: 현재 세션 정보 (`Session | null`)

## Context 확장

프로젝트에서 Context에 커스텀 속성을 추가하려면 `ContextExtend` 인터페이스를 확장할 수 있습니다:

```typescript theme={null}
// src/types.ts
declare module "sonamu" {
  interface ContextExtend {
    customProperty: string;
    helperMethod: () => void;
  }
}
```

이렇게 확장된 속성은 `contextProvider`를 통해 주입할 수 있습니다:

```typescript theme={null}
// sonamu.config.ts
export default {
  server: {
    apiConfig: {
      contextProvider: async (baseContext) => {
        return {
          ...baseContext,
          customProperty: "custom value",
          helperMethod: () => console.log("helper"),
        };
      },
    },
  },
} satisfies SonamuConfig;
```

## 관련 문서

* [AuthContext](/ko/api-reference/context/auth-context)
* [Context 메서드](/ko/api-reference/context/methods)
* [Context 가져오기](/ko/api-development/context/getting-context)
* [커스텀 Context](/ko/api-development/context/custom-context)
