clawfire 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (87) hide show
  1. package/README.md +182 -0
  2. package/dist/admin.cjs +309 -0
  3. package/dist/admin.cjs.map +1 -0
  4. package/dist/admin.d.cts +93 -0
  5. package/dist/admin.d.ts +93 -0
  6. package/dist/admin.js +274 -0
  7. package/dist/admin.js.map +1 -0
  8. package/dist/auth-DQ3cifhb.d.cts +55 -0
  9. package/dist/auth-DtnUPbXT.d.ts +55 -0
  10. package/dist/chunk-37Y2XI7X.js +75 -0
  11. package/dist/chunk-YGIPORYL.js +339 -0
  12. package/dist/cli.js +241 -0
  13. package/dist/client.cjs +97 -0
  14. package/dist/client.cjs.map +1 -0
  15. package/dist/client.d.cts +4 -0
  16. package/dist/client.d.ts +4 -0
  17. package/dist/client.js +68 -0
  18. package/dist/client.js.map +1 -0
  19. package/dist/codegen.cjs +648 -0
  20. package/dist/codegen.cjs.map +1 -0
  21. package/dist/codegen.d.cts +25 -0
  22. package/dist/codegen.d.ts +25 -0
  23. package/dist/codegen.js +617 -0
  24. package/dist/codegen.js.map +1 -0
  25. package/dist/config-QMBJRn9G.d.cts +46 -0
  26. package/dist/config-QMBJRn9G.d.ts +46 -0
  27. package/dist/dev-server-QAVWINAT.js +973 -0
  28. package/dist/dev.cjs +1388 -0
  29. package/dist/dev.cjs.map +1 -0
  30. package/dist/dev.d.cts +111 -0
  31. package/dist/dev.d.ts +111 -0
  32. package/dist/dev.js +1349 -0
  33. package/dist/dev.js.map +1 -0
  34. package/dist/discover-BPMAZFBD.js +9 -0
  35. package/dist/discover-DYNqz_ym.d.cts +28 -0
  36. package/dist/discover-DYNqz_ym.d.ts +28 -0
  37. package/dist/errors-s_mP7rs9.d.cts +33 -0
  38. package/dist/errors-s_mP7rs9.d.ts +33 -0
  39. package/dist/functions.cjs +1156 -0
  40. package/dist/functions.cjs.map +1 -0
  41. package/dist/functions.d.cts +115 -0
  42. package/dist/functions.d.ts +115 -0
  43. package/dist/functions.js +1108 -0
  44. package/dist/functions.js.map +1 -0
  45. package/dist/hosting-7WVFHAYJ.js +85 -0
  46. package/dist/html-PCUCJGBH.js +7 -0
  47. package/dist/index.cjs +349 -0
  48. package/dist/index.cjs.map +1 -0
  49. package/dist/index.d.cts +22 -0
  50. package/dist/index.d.ts +22 -0
  51. package/dist/index.js +312 -0
  52. package/dist/index.js.map +1 -0
  53. package/dist/playground.cjs +364 -0
  54. package/dist/playground.cjs.map +1 -0
  55. package/dist/playground.d.cts +12 -0
  56. package/dist/playground.d.ts +12 -0
  57. package/dist/playground.js +337 -0
  58. package/dist/playground.js.map +1 -0
  59. package/dist/router-BVB_I-tu.d.ts +65 -0
  60. package/dist/router-Cikk8Heq.d.cts +65 -0
  61. package/dist/schema-BJsictSV.d.cts +172 -0
  62. package/dist/schema-BJsictSV.d.ts +172 -0
  63. package/package.json +150 -0
  64. package/templates/CLAUDE.md +71 -0
  65. package/templates/app/routes/auth/login.ts +35 -0
  66. package/templates/app/routes/health.ts +20 -0
  67. package/templates/app/schemas/user.ts +26 -0
  68. package/templates/clawfire.config.ts +25 -0
  69. package/templates/functions/index.ts +43 -0
  70. package/templates/starter/.claude/skills/clawfire-api/SKILL.md +131 -0
  71. package/templates/starter/.claude/skills/clawfire-auth/SKILL.md +111 -0
  72. package/templates/starter/.claude/skills/clawfire-deploy/SKILL.md +95 -0
  73. package/templates/starter/.claude/skills/clawfire-diagnose/SKILL.md +99 -0
  74. package/templates/starter/.claude/skills/clawfire-model/SKILL.md +128 -0
  75. package/templates/starter/CLAUDE.md +227 -0
  76. package/templates/starter/app/routes/health.ts +20 -0
  77. package/templates/starter/app/routes/todos/create.ts +25 -0
  78. package/templates/starter/app/routes/todos/delete.ts +20 -0
  79. package/templates/starter/app/routes/todos/list.ts +26 -0
  80. package/templates/starter/app/routes/todos/update.ts +32 -0
  81. package/templates/starter/app/schemas/todo.ts +16 -0
  82. package/templates/starter/app/store.ts +56 -0
  83. package/templates/starter/clawfire.config.ts +25 -0
  84. package/templates/starter/dev.ts +12 -0
  85. package/templates/starter/package.json +19 -0
  86. package/templates/starter/public/index.html +365 -0
  87. package/templates/starter/tsconfig.json +17 -0
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/core/errors.ts","../src/functions.ts","../src/core/schema.ts","../src/routing/router.ts","../src/core/logger.ts","../src/firebase/auth.ts","../src/routing/discover.ts","../src/firebase/firestore.ts","../src/firebase/rules.ts","../src/firebase/hosting.ts","../src/security/middleware.ts","../src/core/index.ts"],"sourcesContent":["/**\n * Clawfire Error System\n *\n * 표준화된 에러 코드와 구조로 일관된 에러 응답을 제공합니다.\n */\n\nexport type ClawfireErrorCode =\n | \"VALIDATION_ERROR\"\n | \"UNAUTHORIZED\"\n | \"FORBIDDEN\"\n | \"NOT_FOUND\"\n | \"CONFLICT\"\n | \"RATE_LIMITED\"\n | \"REAUTH_REQUIRED\"\n | \"INTERNAL_ERROR\"\n | \"SERVICE_UNAVAILABLE\";\n\nconst HTTP_STATUS_MAP: Record<ClawfireErrorCode, number> = {\n VALIDATION_ERROR: 400,\n UNAUTHORIZED: 401,\n FORBIDDEN: 403,\n NOT_FOUND: 404,\n CONFLICT: 409,\n RATE_LIMITED: 429,\n REAUTH_REQUIRED: 401,\n INTERNAL_ERROR: 500,\n SERVICE_UNAVAILABLE: 503,\n};\n\nexport class ClawfireError extends Error {\n readonly code: ClawfireErrorCode;\n readonly statusCode: number;\n readonly details?: unknown;\n\n constructor(code: ClawfireErrorCode, message: string, details?: unknown) {\n super(message);\n this.name = \"ClawfireError\";\n this.code = code;\n this.statusCode = HTTP_STATUS_MAP[code];\n this.details = details;\n }\n\n toJSON() {\n return {\n error: {\n code: this.code,\n message: this.message,\n ...(this.details ? { details: this.details } : {}),\n },\n };\n }\n}\n\n/** 편의 팩토리 함수 */\nexport const Errors = {\n validation: (message: string, details?: unknown) =>\n new ClawfireError(\"VALIDATION_ERROR\", message, details),\n\n unauthorized: (message = \"Authentication required\") =>\n new ClawfireError(\"UNAUTHORIZED\", message),\n\n forbidden: (message = \"Insufficient permissions\") =>\n new ClawfireError(\"FORBIDDEN\", message),\n\n notFound: (message = \"Resource not found\") =>\n new ClawfireError(\"NOT_FOUND\", message),\n\n conflict: (message: string) =>\n new ClawfireError(\"CONFLICT\", message),\n\n rateLimited: (message = \"Too many requests\") =>\n new ClawfireError(\"RATE_LIMITED\", message),\n\n reauthRequired: (message = \"Re-authentication required for this action\") =>\n new ClawfireError(\"REAUTH_REQUIRED\", message),\n\n internal: (message = \"Internal server error\") =>\n new ClawfireError(\"INTERNAL_ERROR\", message),\n\n unavailable: (message = \"Service temporarily unavailable\") =>\n new ClawfireError(\"SERVICE_UNAVAILABLE\", message),\n};\n","/**\n * Clawfire Functions Entry Point\n *\n * Firebase Functions에서 사용하는 서버사이드 API\n *\n * @example\n * ```ts\n * import { createRouter, createAdminDB, createSecurityMiddleware } from \"clawfire/functions\";\n * import * as admin from \"firebase-admin\";\n *\n * admin.initializeApp();\n * const db = createAdminDB(admin.firestore());\n * const router = createRouter({\n * auth: admin.auth(),\n * cors: [\"https://myapp.web.app\"],\n * middleware: createSecurityMiddleware(),\n * });\n * ```\n */\n\n// Router\nexport {\n ClawfireRouter,\n createRouter,\n type Route,\n type RouterOptions,\n type Middleware,\n} from \"./routing/index.js\";\n\n// Route Discovery\nexport {\n discoverRoutes,\n generateRouteImports,\n type DiscoveredRoute,\n} from \"./routing/index.js\";\n\n// Firebase (server-side)\nexport {\n createAdminDB,\n type AdminDB,\n type FirestoreDoc,\n type QueryFilter,\n type QueryOrder,\n type QueryOptions,\n type PaginatedResult,\n} from \"./firebase/firestore.js\";\n\nexport {\n verifyToken,\n verifyReauth,\n extractBearerToken,\n checkAuthLevel,\n setUserRole,\n getUserRole,\n setCustomClaims,\n} from \"./firebase/auth.js\";\n\nexport {\n generateFirestoreRules,\n generateFirestoreIndexes,\n} from \"./firebase/rules.js\";\n\nexport {\n generateFirebaseJson,\n generateDefaultRules,\n type FirebaseJsonConfig,\n} from \"./firebase/hosting.js\";\n\n// Security Middleware\nexport {\n requestLogger,\n inputSizeLimit,\n sanitizeInput,\n corsMiddleware,\n createSecurityMiddleware,\n} from \"./security/index.js\";\n\n// Core (re-export for convenience)\nexport {\n defineAPI,\n defineModel,\n zodToJsonSchema,\n modelToZodSchema,\n type APIContract,\n type APIMeta,\n type AuthLevel,\n type AuthContext,\n type HandlerContext,\n type ModelDefinition,\n} from \"./core/index.js\";\n\nexport { ClawfireError, Errors } from \"./core/errors.js\";\nexport { logger } from \"./core/logger.js\";\nexport { z } from \"zod\";\n","/**\n * Clawfire Schema & Contract System\n *\n * 모든 API는 input/output schema + meta + handler로 구성된 \"계약(Contract)\"으로 정의됩니다.\n * Zod를 사용하여 타입 안전성과 런타임 검증을 동시에 보장합니다.\n */\nimport { z, type ZodType, type ZodObject, type ZodRawShape } from \"zod\";\n\n// ─── Types ───────────────────────────────────────────────────────────\n\n/** 인증 컨텍스트 */\nexport interface AuthContext {\n uid: string;\n email?: string;\n emailVerified?: boolean;\n role?: string;\n customClaims?: Record<string, unknown>;\n token?: string;\n}\n\n/** API 핸들러에 전달되는 컨텍스트 */\nexport interface HandlerContext {\n auth: AuthContext | null;\n /** 재인증 여부 (민감 작업용) */\n reauthenticated?: boolean;\n /** 원본 요청 헤더 */\n headers?: Record<string, string>;\n /** 요청 IP */\n ip?: string;\n}\n\n/** 권한 수준 */\nexport type AuthLevel = \"public\" | \"authenticated\" | \"role\" | \"reauth\";\n\n/** API 메타데이터 */\nexport interface APIMeta {\n /** API 설명 (AI/Playground용) */\n description: string;\n /** 태그 (그룹화용) */\n tags?: string[];\n /** 인증 요구 수준 */\n auth?: AuthLevel;\n /** 필요 역할 (auth가 'role'일 때) */\n roles?: string[];\n /** 재인증 필요 여부 */\n reauth?: boolean;\n /** Rate limit (초당 요청 수) */\n rateLimit?: number;\n /** 비활성화 여부 */\n deprecated?: boolean;\n /** 예시 입력값 */\n exampleInput?: unknown;\n /** 예시 출력값 */\n exampleOutput?: unknown;\n}\n\n/** API 계약 정의 */\nexport interface APIContract<\n TInput extends ZodType = ZodType,\n TOutput extends ZodType = ZodType,\n> {\n /** 입력 스키마 */\n input: TInput;\n /** 출력 스키마 */\n output: TOutput;\n /** 메타데이터 */\n meta: APIMeta;\n /** 핸들러 함수 */\n handler: (\n input: z.infer<TInput>,\n ctx: HandlerContext,\n ) => Promise<z.infer<TOutput>>;\n}\n\n/** 모델 필드 정의 */\nexport interface ModelField {\n type: \"string\" | \"number\" | \"boolean\" | \"timestamp\" | \"array\" | \"map\" | \"reference\" | \"geopoint\";\n required?: boolean;\n description?: string;\n default?: unknown;\n /** 배열 아이템 타입 */\n items?: ModelField;\n /** 맵 값 타입 */\n values?: ModelField;\n /** 참조 대상 컬렉션 */\n ref?: string;\n /** enum 값 리스트 */\n enum?: string[];\n}\n\n/** 모델 정의 */\nexport interface ModelDefinition {\n /** 컬렉션 이름 */\n collection: string;\n /** 필드 정의 */\n fields: Record<string, ModelField>;\n /** 서브컬렉션 */\n subcollections?: Record<string, ModelDefinition>;\n /** 인덱스 */\n indexes?: ModelIndex[];\n /** 보안 규칙 */\n rules?: ModelRules;\n /** 타임스탬프 자동 생성 */\n timestamps?: boolean;\n /** 소프트 삭제 */\n softDelete?: boolean;\n}\n\n/** Firestore 인덱스 */\nexport interface ModelIndex {\n fields: Array<{ field: string; order?: \"asc\" | \"desc\" }>;\n}\n\n/** 모델 보안 규칙 */\nexport interface ModelRules {\n read?: AuthLevel;\n create?: AuthLevel;\n update?: AuthLevel;\n delete?: AuthLevel;\n readRoles?: string[];\n createRoles?: string[];\n updateRoles?: string[];\n deleteRoles?: string[];\n /** 소유자만 읽기/쓰기 가능 필드 */\n ownerField?: string;\n}\n\n// ─── Builders ────────────────────────────────────────────────────────\n\n/**\n * API 계약 정의\n *\n * @example\n * ```ts\n * export default defineAPI({\n * input: z.object({ name: z.string() }),\n * output: z.object({ id: z.string(), name: z.string() }),\n * meta: { description: \"상품 생성\", auth: \"authenticated\" },\n * handler: async (input, ctx) => {\n * const id = await db.create(\"products\", input);\n * return { id, ...input };\n * }\n * });\n * ```\n */\nexport function defineAPI<\n TInput extends ZodType,\n TOutput extends ZodType,\n>(contract: APIContract<TInput, TOutput>): APIContract<TInput, TOutput> {\n return contract;\n}\n\n/**\n * 모델(Firestore 컬렉션) 정의\n *\n * @example\n * ```ts\n * export const Product = defineModel({\n * collection: \"products\",\n * fields: {\n * name: { type: \"string\", required: true },\n * price: { type: \"number\", required: true },\n * tags: { type: \"array\", items: { type: \"string\" } },\n * },\n * timestamps: true,\n * rules: { read: \"public\", create: \"authenticated\" }\n * });\n * ```\n */\nexport function defineModel(definition: ModelDefinition): ModelDefinition {\n return {\n timestamps: true,\n ...definition,\n };\n}\n\n// ─── Schema Utilities ────────────────────────────────────────────────\n\n/** Zod 스키마에서 JSON Schema 생성 (Playground/문서용) */\nexport function zodToJsonSchema(schema: ZodType): Record<string, unknown> {\n return extractZodShape(schema);\n}\n\nfunction extractZodShape(schema: ZodType): Record<string, unknown> {\n const def = (schema as any)._def;\n\n if (!def) return { type: \"unknown\" };\n\n switch (def.typeName) {\n case \"ZodObject\": {\n const shape = (schema as ZodObject<ZodRawShape>).shape;\n const properties: Record<string, unknown> = {};\n const required: string[] = [];\n\n for (const [key, value] of Object.entries(shape)) {\n properties[key] = extractZodShape(value as ZodType);\n if (!(value as any).isOptional?.()) {\n const innerDef = (value as any)._def;\n if (innerDef?.typeName !== \"ZodOptional\" && innerDef?.typeName !== \"ZodDefault\") {\n required.push(key);\n }\n }\n }\n\n return { type: \"object\", properties, ...(required.length > 0 ? { required } : {}) };\n }\n case \"ZodString\":\n return { type: \"string\", ...(def.checks?.length ? extractStringChecks(def.checks) : {}) };\n case \"ZodNumber\":\n return { type: \"number\" };\n case \"ZodBoolean\":\n return { type: \"boolean\" };\n case \"ZodArray\":\n return { type: \"array\", items: extractZodShape(def.type) };\n case \"ZodEnum\":\n return { type: \"string\", enum: def.values };\n case \"ZodOptional\":\n return { ...extractZodShape(def.innerType), optional: true };\n case \"ZodDefault\":\n return { ...extractZodShape(def.innerType), default: def.defaultValue() };\n case \"ZodNullable\":\n return { ...extractZodShape(def.innerType), nullable: true };\n case \"ZodLiteral\":\n return { type: typeof def.value, const: def.value };\n case \"ZodUnion\":\n return { oneOf: def.options.map((o: ZodType) => extractZodShape(o)) };\n case \"ZodRecord\":\n return { type: \"object\", additionalProperties: extractZodShape(def.valueType) };\n case \"ZodDate\":\n return { type: \"string\", format: \"date-time\" };\n default:\n return { type: \"unknown\" };\n }\n}\n\nfunction extractStringChecks(checks: Array<{ kind: string; value?: unknown }>): Record<string, unknown> {\n const result: Record<string, unknown> = {};\n for (const check of checks) {\n switch (check.kind) {\n case \"min\": result.minLength = check.value; break;\n case \"max\": result.maxLength = check.value; break;\n case \"email\": result.format = \"email\"; break;\n case \"url\": result.format = \"uri\"; break;\n case \"uuid\": result.format = \"uuid\"; break;\n }\n }\n return result;\n}\n\n/** 모델 정의에서 Zod 스키마 자동 생성 */\nexport function modelToZodSchema(model: ModelDefinition): ZodObject<ZodRawShape> {\n const shape: ZodRawShape = {};\n\n for (const [key, field] of Object.entries(model.fields)) {\n let fieldSchema: ZodType = fieldToZod(field);\n if (!field.required) {\n fieldSchema = fieldSchema.optional();\n }\n shape[key] = fieldSchema;\n }\n\n if (model.timestamps) {\n shape.createdAt = z.string().datetime().optional();\n shape.updatedAt = z.string().datetime().optional();\n }\n\n if (model.softDelete) {\n shape.deletedAt = z.string().datetime().nullable().optional();\n }\n\n return z.object(shape);\n}\n\nfunction fieldToZod(field: ModelField): ZodType {\n switch (field.type) {\n case \"string\":\n if (field.enum) return z.enum(field.enum as [string, ...string[]]);\n return z.string();\n case \"number\":\n return z.number();\n case \"boolean\":\n return z.boolean();\n case \"timestamp\":\n return z.string().datetime();\n case \"array\":\n if (field.items) return z.array(fieldToZod(field.items));\n return z.array(z.unknown());\n case \"map\":\n if (field.values) return z.record(z.string(), fieldToZod(field.values));\n return z.record(z.string(), z.unknown());\n case \"reference\":\n return z.string(); // 참조는 문서 경로 문자열\n case \"geopoint\":\n return z.object({ latitude: z.number(), longitude: z.number() });\n default:\n return z.unknown();\n }\n}\n\n// ─── Manifest ────────────────────────────────────────────────────────\n\n/** API 매니페스트 항목 */\nexport interface ManifestEntry {\n path: string;\n method: \"POST\"; // Clawfire는 모두 POST\n meta: APIMeta;\n inputSchema: Record<string, unknown>;\n outputSchema: Record<string, unknown>;\n}\n\n/** 전체 매니페스트 */\nexport interface Manifest {\n version: string;\n generatedAt: string;\n apis: ManifestEntry[];\n models: Record<string, ModelDefinition>;\n}\n\n/** 계약에서 매니페스트 항목 생성 */\nexport function contractToManifest(\n path: string,\n contract: APIContract,\n): ManifestEntry {\n return {\n path,\n method: \"POST\",\n meta: contract.meta,\n inputSchema: zodToJsonSchema(contract.input),\n outputSchema: zodToJsonSchema(contract.output),\n };\n}\n","/**\n * Clawfire File-based Router\n *\n * app/routes/ 디렉터리 구조를 자동으로 API 경로로 매핑합니다.\n *\n * 파일 구조 → API 경로:\n * app/routes/products/list.ts → /api/products/list\n * app/routes/products/create.ts → /api/products/create\n * app/routes/auth/login.ts → /api/auth/login\n * app/routes/users/[id]/get.ts → /api/users/:id/get\n */\nimport { z } from \"zod\";\nimport type { APIContract, HandlerContext, AuthContext, Manifest, ManifestEntry } from \"../core/schema.js\";\nimport { contractToManifest, zodToJsonSchema } from \"../core/schema.js\";\nimport { ClawfireError, Errors } from \"../core/errors.js\";\nimport { logger } from \"../core/logger.js\";\nimport { checkAuthLevel, extractBearerToken, verifyToken, verifyReauth } from \"../firebase/auth.js\";\n\n// ─── Types ───────────────────────────────────────────────────────────\n\nexport interface Route {\n path: string;\n contract: APIContract;\n}\n\nexport interface RouterOptions {\n /** Firebase Admin Auth 인스턴스 */\n auth?: any;\n /** Firebase Admin Firestore 인스턴스 */\n firestore?: any;\n /** CORS 허용 도메인 */\n cors?: string[];\n /** 전역 rate limit */\n rateLimit?: number;\n /** 전역 미들웨어 */\n middleware?: Middleware[];\n /** 플레이그라운드 활성화 */\n playground?: boolean;\n}\n\nexport type Middleware = (\n input: unknown,\n ctx: HandlerContext,\n next: () => Promise<unknown>,\n) => Promise<unknown>;\n\n// ─── Rate Limiter (in-memory) ────────────────────────────────────────\n\nclass RateLimiter {\n private store = new Map<string, { count: number; resetAt: number }>();\n private defaultLimit: number;\n\n constructor(defaultLimit: number) {\n this.defaultLimit = defaultLimit;\n }\n\n check(key: string, limit?: number): boolean {\n const max = limit || this.defaultLimit;\n const now = Date.now();\n const entry = this.store.get(key);\n\n if (!entry || now > entry.resetAt) {\n this.store.set(key, { count: 1, resetAt: now + 60000 }); // 1분 윈도우\n return true;\n }\n\n if (entry.count >= max) {\n return false;\n }\n\n entry.count++;\n return true;\n }\n\n // 오래된 엔트리 정리\n cleanup() {\n const now = Date.now();\n for (const [key, entry] of this.store) {\n if (now > entry.resetAt) this.store.delete(key);\n }\n }\n}\n\n// ─── Router ──────────────────────────────────────────────────────────\n\nexport class ClawfireRouter {\n private routes = new Map<string, Route>();\n private options: RouterOptions;\n private rateLimiter: RateLimiter;\n private cleanupInterval?: ReturnType<typeof setInterval>;\n\n constructor(options: RouterOptions = {}) {\n this.options = options;\n this.rateLimiter = new RateLimiter(options.rateLimit || 100);\n this.cleanupInterval = setInterval(() => this.rateLimiter.cleanup(), 60000);\n }\n\n /** 라우트 등록 */\n register(path: string, contract: APIContract): this {\n const normalizedPath = path.startsWith(\"/\") ? path : `/${path}`;\n this.routes.set(normalizedPath, { path: normalizedPath, contract });\n logger.debug(`Route registered: ${normalizedPath}`);\n return this;\n }\n\n /** 여러 라우트 한 번에 등록 */\n registerAll(routes: Record<string, APIContract>): this {\n for (const [path, contract] of Object.entries(routes)) {\n this.register(path, contract);\n }\n return this;\n }\n\n /** 매니페스트 생성 */\n getManifest(): Manifest {\n const apis: ManifestEntry[] = [];\n for (const [path, route] of this.routes) {\n apis.push(contractToManifest(path, route.contract));\n }\n\n return {\n version: \"1.0.0\",\n generatedAt: new Date().toISOString(),\n apis,\n models: {},\n };\n }\n\n /** HTTP 요청 핸들러 (Firebase Functions에서 사용) */\n async handleRequest(\n req: { path?: string; url?: string; body?: unknown; headers?: Record<string, string>; ip?: string; method?: string },\n res: { status: (code: number) => { json: (data: unknown) => void; send: (data: string) => void; end: () => void }; set: (headers: Record<string, string>) => void },\n ): Promise<void> {\n // CORS 처리\n const corsOrigins = this.options.cors || [];\n const origin = req.headers?.origin || req.headers?.Origin || \"\";\n\n if (corsOrigins.length > 0 && corsOrigins.includes(origin)) {\n res.set({\n \"Access-Control-Allow-Origin\": origin,\n \"Access-Control-Allow-Methods\": \"POST, OPTIONS\",\n \"Access-Control-Allow-Headers\": \"Content-Type, Authorization\",\n \"Access-Control-Max-Age\": \"86400\",\n });\n } else if (corsOrigins.length === 0) {\n // CORS 기본 deny — 설정 없으면 허용하지 않음\n res.set({\n \"Access-Control-Allow-Origin\": \"\",\n \"Access-Control-Allow-Methods\": \"POST, OPTIONS\",\n \"Access-Control-Allow-Headers\": \"Content-Type, Authorization\",\n });\n }\n\n // OPTIONS (preflight)\n if (req.method === \"OPTIONS\") {\n res.status(204).end();\n return;\n }\n\n // 안전 헤더\n res.set({\n \"X-Content-Type-Options\": \"nosniff\",\n \"X-Frame-Options\": \"DENY\",\n \"X-XSS-Protection\": \"1; mode=block\",\n \"Content-Type\": \"application/json\",\n });\n\n // 경로 추출 — /api/xxx/yyy → /xxx/yyy\n let routePath = req.path || req.url || \"\";\n if (routePath.startsWith(\"/api\")) {\n routePath = routePath.slice(4);\n }\n\n // 시스템 엔드포인트 (GET 허용)\n if (routePath === \"/__manifest\") {\n res.status(200).json(this.getManifest());\n return;\n }\n\n // POST만 허용 (시스템 엔드포인트 제외)\n if (req.method && req.method !== \"POST\") {\n res.status(405).json({ error: { code: \"METHOD_NOT_ALLOWED\", message: \"Only POST is allowed\" } });\n return;\n }\n\n // 라우트 매칭\n const route = this.matchRoute(routePath);\n if (!route) {\n res.status(404).json({ error: { code: \"NOT_FOUND\", message: `API not found: ${routePath}` } });\n return;\n }\n\n try {\n // Rate limit\n const clientKey = req.ip || \"unknown\";\n const rateLimit = route.contract.meta.rateLimit || this.options.rateLimit;\n if (rateLimit && !this.rateLimiter.check(clientKey, rateLimit)) {\n throw Errors.rateLimited();\n }\n\n // Auth 처리\n let authCtx: AuthContext | null = null;\n let reauthenticated = false;\n const authHeader = req.headers?.authorization || req.headers?.Authorization;\n\n if (authHeader && this.options.auth) {\n const token = extractBearerToken(authHeader as string);\n if (token) {\n if (route.contract.meta.reauth || route.contract.meta.auth === \"reauth\") {\n authCtx = await verifyReauth(this.options.auth, token);\n reauthenticated = true;\n } else {\n authCtx = await verifyToken(this.options.auth, token);\n }\n }\n }\n\n // 권한 체크\n if (route.contract.meta.auth) {\n checkAuthLevel(authCtx, route.contract.meta.auth, route.contract.meta.roles, reauthenticated);\n }\n\n // 입력 검증\n const rawInput = req.body || {};\n const parsed = route.contract.input.safeParse(rawInput);\n if (!parsed.success) {\n throw Errors.validation(\"Invalid input\", parsed.error.flatten());\n }\n\n // 핸들러 컨텍스트\n const ctx: HandlerContext = {\n auth: authCtx,\n reauthenticated,\n headers: req.headers as Record<string, string>,\n ip: req.ip,\n };\n\n // 미들웨어 + 핸들러 실행\n let result: unknown;\n if (this.options.middleware && this.options.middleware.length > 0) {\n result = await this.runMiddleware(\n this.options.middleware,\n parsed.data,\n ctx,\n () => route.contract.handler(parsed.data, ctx),\n );\n } else {\n result = await route.contract.handler(parsed.data, ctx);\n }\n\n // 성공 응답\n res.status(200).json({ data: result });\n } catch (err) {\n if (err instanceof ClawfireError) {\n logger.warn(`API error [${err.code}]: ${err.message}`);\n res.status(err.statusCode).json(err.toJSON());\n } else {\n logger.error(\"Unhandled error\", err);\n res.status(500).json({\n error: {\n code: \"INTERNAL_ERROR\",\n message: \"An unexpected error occurred\",\n },\n });\n }\n }\n }\n\n /** 라우트 매칭 (동적 파라미터 지원) */\n private matchRoute(path: string): Route | undefined {\n // 정확한 매칭\n const exact = this.routes.get(path);\n if (exact) return exact;\n\n // 동적 파라미터 매칭 (/users/:id/get → /users/abc123/get)\n for (const [routePath, route] of this.routes) {\n if (this.matchDynamicRoute(routePath, path)) {\n return route;\n }\n }\n\n return undefined;\n }\n\n private matchDynamicRoute(pattern: string, actual: string): boolean {\n const patternParts = pattern.split(\"/\").filter(Boolean);\n const actualParts = actual.split(\"/\").filter(Boolean);\n if (patternParts.length !== actualParts.length) return false;\n\n return patternParts.every(\n (part, i) => part.startsWith(\":\") || part.startsWith(\"[\") || part === actualParts[i],\n );\n }\n\n /** 미들웨어 체인 실행 */\n private async runMiddleware(\n middlewares: Middleware[],\n input: unknown,\n ctx: HandlerContext,\n handler: () => Promise<unknown>,\n ): Promise<unknown> {\n let index = 0;\n const next = async (): Promise<unknown> => {\n if (index >= middlewares.length) {\n return handler();\n }\n const mw = middlewares[index++];\n return mw(input, ctx, next);\n };\n return next();\n }\n\n /** 등록된 라우트 목록 */\n getRoutes(): Route[] {\n return Array.from(this.routes.values());\n }\n\n /** 리소스 정리 */\n destroy() {\n if (this.cleanupInterval) {\n clearInterval(this.cleanupInterval);\n }\n }\n}\n\n/**\n * 라우터 생성 헬퍼\n */\nexport function createRouter(options?: RouterOptions): ClawfireRouter {\n return new ClawfireRouter(options);\n}\n","/**\n * Clawfire Logger\n *\n * 보안 로깅 (민감 정보 마스킹 포함)\n */\n\n/** 마스킹할 필드명 패턴 */\nconst SENSITIVE_FIELDS = [\n \"password\",\n \"token\",\n \"secret\",\n \"apiKey\",\n \"api_key\",\n \"authorization\",\n \"credit_card\",\n \"creditCard\",\n \"ssn\",\n \"cardNumber\",\n \"card_number\",\n \"cvv\",\n \"pin\",\n];\n\ntype LogLevel = \"debug\" | \"info\" | \"warn\" | \"error\";\n\nconst LOG_LEVELS: Record<LogLevel, number> = {\n debug: 0,\n info: 1,\n warn: 2,\n error: 3,\n};\n\nlet currentLevel: LogLevel = \"info\";\n\nexport function setLogLevel(level: LogLevel) {\n currentLevel = level;\n}\n\nfunction shouldLog(level: LogLevel): boolean {\n return LOG_LEVELS[level] >= LOG_LEVELS[currentLevel];\n}\n\n/** 민감 필드 마스킹 */\nexport function maskSensitive(obj: unknown): unknown {\n if (obj === null || obj === undefined) return obj;\n if (typeof obj === \"string\") return obj;\n if (typeof obj !== \"object\") return obj;\n\n if (Array.isArray(obj)) {\n return obj.map(maskSensitive);\n }\n\n const masked: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(obj as Record<string, unknown>)) {\n if (SENSITIVE_FIELDS.some((f) => key.toLowerCase().includes(f.toLowerCase()))) {\n masked[key] = \"***MASKED***\";\n } else if (typeof value === \"object\" && value !== null) {\n masked[key] = maskSensitive(value);\n } else {\n masked[key] = value;\n }\n }\n return masked;\n}\n\nfunction formatLog(level: LogLevel, message: string, data?: unknown): string {\n const timestamp = new Date().toISOString();\n const prefix = `[${timestamp}] [CLAWFIRE] [${level.toUpperCase()}]`;\n if (data !== undefined) {\n return `${prefix} ${message} ${JSON.stringify(maskSensitive(data))}`;\n }\n return `${prefix} ${message}`;\n}\n\nexport const logger = {\n debug(message: string, data?: unknown) {\n if (shouldLog(\"debug\")) console.debug(formatLog(\"debug\", message, data));\n },\n info(message: string, data?: unknown) {\n if (shouldLog(\"info\")) console.info(formatLog(\"info\", message, data));\n },\n warn(message: string, data?: unknown) {\n if (shouldLog(\"warn\")) console.warn(formatLog(\"warn\", message, data));\n },\n error(message: string, data?: unknown) {\n if (shouldLog(\"error\")) console.error(formatLog(\"error\", message, data));\n },\n};\n","/**\n * Clawfire Auth Helpers\n *\n * Firebase Auth 통합: 토큰 검증, 역할 관리, 재인증\n */\nimport type { AuthContext, AuthLevel } from \"../core/schema.js\";\nimport { Errors } from \"../core/errors.js\";\n\n// ─── Server-side Auth (Admin SDK) ────────────────────────────────────\n\n/**\n * Firebase ID 토큰에서 AuthContext 추출 (서버사이드)\n */\nexport async function verifyToken(\n auth: any, // firebase-admin Auth instance\n idToken: string,\n): Promise<AuthContext> {\n const decoded = await auth.verifyIdToken(idToken);\n return {\n uid: decoded.uid,\n email: decoded.email,\n emailVerified: decoded.email_verified,\n role: decoded.role || decoded.customClaims?.role,\n customClaims: decoded,\n token: idToken,\n };\n}\n\n/**\n * 재인증 토큰 검증 (최근 5분 이내 인증)\n */\nexport async function verifyReauth(\n auth: any,\n idToken: string,\n maxAgeSeconds = 300,\n): Promise<AuthContext> {\n const decoded = await auth.verifyIdToken(idToken, true);\n const authTime = decoded.auth_time * 1000;\n const now = Date.now();\n\n if (now - authTime > maxAgeSeconds * 1000) {\n throw Errors.reauthRequired(\n `Re-authentication required. Last auth was ${Math.floor((now - authTime) / 1000)}s ago.`,\n );\n }\n\n return {\n uid: decoded.uid,\n email: decoded.email,\n emailVerified: decoded.email_verified,\n role: decoded.role || decoded.customClaims?.role,\n customClaims: decoded,\n token: idToken,\n };\n}\n\n/**\n * 요청에서 Authorization 헤더의 Bearer 토큰 추출\n */\nexport function extractBearerToken(authHeader?: string): string | null {\n if (!authHeader) return null;\n const parts = authHeader.split(\" \");\n if (parts.length !== 2 || parts[0] !== \"Bearer\") return null;\n return parts[1];\n}\n\n/**\n * 인증 수준 체크\n */\nexport function checkAuthLevel(\n authCtx: AuthContext | null,\n level: AuthLevel,\n roles?: string[],\n reauthenticated?: boolean,\n): void {\n switch (level) {\n case \"public\":\n return; // 누구나 접근 가능\n\n case \"authenticated\":\n if (!authCtx) throw Errors.unauthorized();\n return;\n\n case \"role\":\n if (!authCtx) throw Errors.unauthorized();\n if (!roles || roles.length === 0) return;\n if (!authCtx.role || !roles.includes(authCtx.role)) {\n throw Errors.forbidden(`Required role: ${roles.join(\" or \")}`);\n }\n return;\n\n case \"reauth\":\n if (!authCtx) throw Errors.unauthorized();\n if (!reauthenticated) {\n throw Errors.reauthRequired();\n }\n return;\n }\n}\n\n// ─── Custom Claims / Role Management ─────────────────────────────────\n\n/**\n * 사용자에게 역할(Role) 설정\n */\nexport async function setUserRole(\n auth: any,\n uid: string,\n role: string,\n): Promise<void> {\n const user = await auth.getUser(uid);\n const currentClaims = user.customClaims || {};\n await auth.setCustomUserClaims(uid, { ...currentClaims, role });\n}\n\n/**\n * 사용자의 역할 조회\n */\nexport async function getUserRole(auth: any, uid: string): Promise<string | undefined> {\n const user = await auth.getUser(uid);\n return user.customClaims?.role;\n}\n\n/**\n * 사용자에게 커스텀 클레임 설정\n */\nexport async function setCustomClaims(\n auth: any,\n uid: string,\n claims: Record<string, unknown>,\n): Promise<void> {\n const user = await auth.getUser(uid);\n const currentClaims = user.customClaims || {};\n await auth.setCustomUserClaims(uid, { ...currentClaims, ...claims });\n}\n\n// ─── Client-side Auth Helpers ────────────────────────────────────────\n\n/**\n * 클라이언트 사이드 Auth 헬퍼 (firebase/auth 래핑)\n */\nexport function createClientAuth(firebaseAuth: any) {\n return {\n /** 현재 사용자 조회 */\n getCurrentUser(): any | null {\n return firebaseAuth.currentUser;\n },\n\n /** ID 토큰 취득 */\n async getIdToken(forceRefresh = false): Promise<string | null> {\n const user = firebaseAuth.currentUser;\n if (!user) return null;\n return user.getIdToken(forceRefresh);\n },\n\n /** 인증 상태 변경 리스너 */\n onAuthStateChanged(callback: (user: any | null) => void): () => void {\n return firebaseAuth.onAuthStateChanged(callback);\n },\n\n /** 로그아웃 */\n async signOut(): Promise<void> {\n await firebaseAuth.signOut();\n },\n\n /** 원시 auth 접근 */\n raw: firebaseAuth,\n };\n}\n\nexport type ClientAuth = ReturnType<typeof createClientAuth>;\n","/**\n * Clawfire Route Discovery\n *\n * 파일 시스템에서 라우트 자동 발견 (빌드 타임 & 런타임)\n */\nimport { resolve, relative, join } from \"path\";\nimport { existsSync, readdirSync, statSync } from \"fs\";\n\nexport interface DiscoveredRoute {\n /** 파일 경로 (상대) */\n filePath: string;\n /** API 경로 (/products/list) */\n apiPath: string;\n /** 동적 파라미터 이름 */\n params: string[];\n}\n\n/**\n * routes 디렉터리에서 라우트 파일 자동 발견\n *\n * @param routesDir - routes 디렉터리 절대 경로\n * @returns 발견된 라우트 목록\n *\n * @example\n * ```\n * app/routes/products/list.ts → { apiPath: \"/products/list\", params: [] }\n * app/routes/products/[id]/get.ts → { apiPath: \"/products/:id/get\", params: [\"id\"] }\n * app/routes/health.ts → { apiPath: \"/health\", params: [] }\n * ```\n */\nexport function discoverRoutes(routesDir: string): DiscoveredRoute[] {\n if (!existsSync(routesDir)) {\n return [];\n }\n\n const routes: DiscoveredRoute[] = [];\n scanDirectory(routesDir, routesDir, routes);\n return routes.sort((a, b) => a.apiPath.localeCompare(b.apiPath));\n}\n\nfunction scanDirectory(baseDir: string, currentDir: string, routes: DiscoveredRoute[]): void {\n const entries = readdirSync(currentDir);\n\n for (const entry of entries) {\n const fullPath = join(currentDir, entry);\n const stat = statSync(fullPath);\n\n if (stat.isDirectory()) {\n // 숨김 디렉터리, node_modules 무시\n if (entry.startsWith(\".\") || entry === \"node_modules\") continue;\n scanDirectory(baseDir, fullPath, routes);\n } else if (stat.isFile()) {\n // .ts, .js 파일만\n if (!entry.endsWith(\".ts\") && !entry.endsWith(\".js\")) continue;\n // index, _로 시작하는 파일 무시\n if (entry.startsWith(\"_\")) continue;\n // .d.ts 무시\n if (entry.endsWith(\".d.ts\")) continue;\n\n const relativePath = relative(baseDir, fullPath);\n const route = filePathToRoute(relativePath);\n routes.push(route);\n }\n }\n}\n\nfunction filePathToRoute(filePath: string): DiscoveredRoute {\n const params: string[] = [];\n\n // 확장자 제거\n let routePath = filePath.replace(/\\.(ts|js)$/, \"\");\n\n // Windows 경로 → POSIX\n routePath = routePath.replace(/\\\\/g, \"/\");\n\n // index 파일은 디렉터리 자체\n if (routePath.endsWith(\"/index\") || routePath === \"index\") {\n routePath = routePath.replace(/\\/?index$/, \"\");\n }\n\n // [param] → :param 변환\n routePath = routePath.replace(/\\[([^\\]]+)\\]/g, (_, param) => {\n params.push(param);\n return `:${param}`;\n });\n\n // 앞에 / 추가\n const apiPath = `/${routePath}`;\n\n return {\n filePath,\n apiPath,\n params,\n };\n}\n\n/**\n * 라우트 파일에서 import하여 라우터에 등록하는 코드 생성 (빌드 타임)\n */\nexport function generateRouteImports(routes: DiscoveredRoute[], routesDir: string): string {\n const lines: string[] = [\n '// AUTO-GENERATED by Clawfire — DO NOT EDIT',\n '// This file is regenerated whenever routes change.',\n '',\n 'import { createRouter } from \"clawfire/functions\";',\n '',\n ];\n\n routes.forEach((route, i) => {\n const importPath = `./${route.filePath.replace(/\\.(ts|js)$/, \".js\")}`;\n lines.push(`import route_${i} from \"${importPath}\";`);\n });\n\n lines.push('');\n lines.push('export function registerAllRoutes(router: ReturnType<typeof createRouter>) {');\n\n routes.forEach((route, i) => {\n lines.push(` router.register(\"${route.apiPath}\", route_${i});`);\n });\n\n lines.push(' return router;');\n lines.push('}');\n\n return lines.join('\\n');\n}\n","/**\n * Clawfire Firestore Wrapper\n *\n * 타입 안전한 Firestore CRUD 오퍼레이션\n * Admin SDK (서버) / Client SDK (클라이언트) 모두 지원\n */\nimport type { ModelDefinition } from \"../core/schema.js\";\n\n// ─── Types ───────────────────────────────────────────────────────────\n\nexport interface FirestoreDoc {\n id: string;\n [key: string]: unknown;\n}\n\nexport interface QueryFilter {\n field: string;\n op: \"==\" | \"!=\" | \"<\" | \"<=\" | \">\" | \">=\" | \"in\" | \"not-in\" | \"array-contains\" | \"array-contains-any\";\n value: unknown;\n}\n\nexport interface QueryOrder {\n field: string;\n direction?: \"asc\" | \"desc\";\n}\n\nexport interface QueryOptions {\n filters?: QueryFilter[];\n orderBy?: QueryOrder[];\n limit?: number;\n offset?: number;\n startAfter?: unknown;\n}\n\nexport interface PaginatedResult<T> {\n data: T[];\n hasMore: boolean;\n lastDoc?: unknown;\n total?: number;\n}\n\n// ─── Admin Firestore (Server-side) ──────────────────────────────────\n\n/**\n * 서버사이드(Firebase Functions)에서 사용하는 Firestore DB 래퍼\n *\n * @example\n * ```ts\n * const db = createAdminDB(admin.firestore());\n * const product = await db.get(\"products\", \"abc123\");\n * const products = await db.query(\"products\", { filters: [{ field: \"price\", op: \">\", value: 100 }] });\n * ```\n */\nexport function createAdminDB(firestore: any) {\n return {\n /** 문서 조회 */\n async get<T extends FirestoreDoc = FirestoreDoc>(\n collection: string,\n id: string,\n ): Promise<T | null> {\n const doc = await firestore.collection(collection).doc(id).get();\n if (!doc.exists) return null;\n return { id: doc.id, ...doc.data() } as T;\n },\n\n /** 문서 생성 (ID 자동 생성) */\n async create<T extends Record<string, unknown>>(\n collection: string,\n data: T,\n ): Promise<string> {\n const now = new Date().toISOString();\n const ref = await firestore.collection(collection).add({\n ...data,\n createdAt: now,\n updatedAt: now,\n });\n return ref.id;\n },\n\n /** 문서 생성 (ID 지정) */\n async set<T extends Record<string, unknown>>(\n collection: string,\n id: string,\n data: T,\n merge = false,\n ): Promise<void> {\n const now = new Date().toISOString();\n await firestore\n .collection(collection)\n .doc(id)\n .set(\n {\n ...data,\n ...(merge ? { updatedAt: now } : { createdAt: now, updatedAt: now }),\n },\n { merge },\n );\n },\n\n /** 문서 부분 업데이트 */\n async update<T extends Record<string, unknown>>(\n collection: string,\n id: string,\n data: Partial<T>,\n ): Promise<void> {\n await firestore.collection(collection).doc(id).update({\n ...data,\n updatedAt: new Date().toISOString(),\n });\n },\n\n /** 문서 삭제 */\n async delete(collection: string, id: string): Promise<void> {\n await firestore.collection(collection).doc(id).delete();\n },\n\n /** 소프트 삭제 */\n async softDelete(collection: string, id: string): Promise<void> {\n await firestore.collection(collection).doc(id).update({\n deletedAt: new Date().toISOString(),\n updatedAt: new Date().toISOString(),\n });\n },\n\n /** 쿼리 */\n async query<T extends FirestoreDoc = FirestoreDoc>(\n collection: string,\n options: QueryOptions = {},\n ): Promise<PaginatedResult<T>> {\n let ref: any = firestore.collection(collection);\n\n if (options.filters) {\n for (const filter of options.filters) {\n ref = ref.where(filter.field, filter.op, filter.value);\n }\n }\n\n if (options.orderBy) {\n for (const order of options.orderBy) {\n ref = ref.orderBy(order.field, order.direction || \"asc\");\n }\n }\n\n if (options.startAfter) {\n ref = ref.startAfter(options.startAfter);\n }\n\n const limit = options.limit || 20;\n ref = ref.limit(limit + 1); // +1 for hasMore check\n\n const snapshot = await ref.get();\n const docs = snapshot.docs.map((doc: any) => ({\n id: doc.id,\n ...doc.data(),\n })) as T[];\n\n const hasMore = docs.length > limit;\n if (hasMore) docs.pop();\n\n return {\n data: docs,\n hasMore,\n lastDoc: docs.length > 0 ? snapshot.docs[docs.length - 1] : undefined,\n };\n },\n\n /** 문서 수 */\n async count(collection: string, filters?: QueryFilter[]): Promise<number> {\n let ref: any = firestore.collection(collection);\n if (filters) {\n for (const filter of filters) {\n ref = ref.where(filter.field, filter.op, filter.value);\n }\n }\n const snapshot = await ref.count().get();\n return snapshot.data().count;\n },\n\n /** 배치 작업 */\n async batch(operations: Array<{\n type: \"create\" | \"set\" | \"update\" | \"delete\";\n collection: string;\n id?: string;\n data?: Record<string, unknown>;\n }>): Promise<string[]> {\n const batch = firestore.batch();\n const ids: string[] = [];\n\n for (const op of operations) {\n const now = new Date().toISOString();\n switch (op.type) {\n case \"create\": {\n const ref = firestore.collection(op.collection).doc();\n batch.set(ref, { ...op.data, createdAt: now, updatedAt: now });\n ids.push(ref.id);\n break;\n }\n case \"set\": {\n const ref = firestore.collection(op.collection).doc(op.id);\n batch.set(ref, { ...op.data, createdAt: now, updatedAt: now });\n ids.push(op.id!);\n break;\n }\n case \"update\": {\n const ref = firestore.collection(op.collection).doc(op.id);\n batch.update(ref, { ...op.data, updatedAt: now });\n ids.push(op.id!);\n break;\n }\n case \"delete\": {\n const ref = firestore.collection(op.collection).doc(op.id);\n batch.delete(ref);\n ids.push(op.id!);\n break;\n }\n }\n }\n\n await batch.commit();\n return ids;\n },\n\n /** 트랜잭션 */\n async transaction<T>(\n fn: (tx: {\n get: (collection: string, id: string) => Promise<FirestoreDoc | null>;\n set: (collection: string, id: string, data: Record<string, unknown>) => void;\n update: (collection: string, id: string, data: Record<string, unknown>) => void;\n delete: (collection: string, id: string) => void;\n }) => Promise<T>,\n ): Promise<T> {\n return firestore.runTransaction(async (transaction: any) => {\n return fn({\n async get(collection: string, id: string) {\n const doc = await transaction.get(firestore.collection(collection).doc(id));\n if (!doc.exists) return null;\n return { id: doc.id, ...doc.data() } as FirestoreDoc;\n },\n set(collection: string, id: string, data: Record<string, unknown>) {\n const now = new Date().toISOString();\n transaction.set(firestore.collection(collection).doc(id), {\n ...data,\n createdAt: now,\n updatedAt: now,\n });\n },\n update(collection: string, id: string, data: Record<string, unknown>) {\n transaction.update(firestore.collection(collection).doc(id), {\n ...data,\n updatedAt: new Date().toISOString(),\n });\n },\n delete(collection: string, id: string) {\n transaction.delete(firestore.collection(collection).doc(id));\n },\n });\n });\n },\n\n /** 원시 Firestore 접근 */\n raw: firestore,\n };\n}\n\nexport type AdminDB = ReturnType<typeof createAdminDB>;\n","/**\n * Clawfire Security Rules Generator\n *\n * 모델 정의에서 Firestore Security Rules 자동 생성\n */\nimport type { ModelDefinition, ModelRules, AuthLevel } from \"../core/schema.js\";\n\n/**\n * 모델 정의 배열에서 Firestore Security Rules 생성\n */\nexport function generateFirestoreRules(\n models: Record<string, ModelDefinition>,\n): string {\n const rules: string[] = [];\n rules.push(\"rules_version = '2';\");\n rules.push(\"service cloud.firestore {\");\n rules.push(\" match /databases/{database}/documents {\");\n rules.push(\"\");\n rules.push(\" // ── Helper Functions ──\");\n rules.push(\" function isAuthenticated() {\");\n rules.push(\" return request.auth != null;\");\n rules.push(\" }\");\n rules.push(\"\");\n rules.push(\" function isOwner(userId) {\");\n rules.push(\" return isAuthenticated() && request.auth.uid == userId;\");\n rules.push(\" }\");\n rules.push(\"\");\n rules.push(\" function hasRole(role) {\");\n rules.push(\" return isAuthenticated() && request.auth.token.role == role;\");\n rules.push(\" }\");\n rules.push(\"\");\n rules.push(\" function hasAnyRole(roles) {\");\n rules.push(\" return isAuthenticated() && request.auth.token.role in roles;\");\n rules.push(\" }\");\n rules.push(\"\");\n rules.push(\" function isRecentAuth() {\");\n rules.push(\" return request.auth.token.auth_time > (request.time - duration.value(5, 'm'));\");\n rules.push(\" }\");\n rules.push(\"\");\n\n for (const [name, model] of Object.entries(models)) {\n rules.push(` // ── ${name} ──`);\n rules.push(` match /${model.collection}/{docId} {`);\n\n const modelRules = model.rules || { read: \"authenticated\" as AuthLevel, create: \"authenticated\" as AuthLevel, update: \"authenticated\" as AuthLevel, delete: \"authenticated\" as AuthLevel };\n\n rules.push(` allow read: if ${buildRuleCondition(modelRules, \"read\", model)};`);\n rules.push(` allow create: if ${buildRuleCondition(modelRules, \"create\", model)};`);\n rules.push(` allow update: if ${buildRuleCondition(modelRules, \"update\", model)};`);\n rules.push(` allow delete: if ${buildRuleCondition(modelRules, \"delete\", model)};`);\n\n // 서브컬렉션\n if (model.subcollections) {\n for (const [subName, subModel] of Object.entries(model.subcollections)) {\n rules.push(\"\");\n rules.push(` // ${subName}`);\n rules.push(` match /${subModel.collection}/{subDocId} {`);\n const subRules = subModel.rules || { read: \"authenticated\" as AuthLevel, create: \"authenticated\" as AuthLevel, update: \"authenticated\" as AuthLevel, delete: \"authenticated\" as AuthLevel };\n rules.push(` allow read: if ${buildRuleCondition(subRules, \"read\", subModel)};`);\n rules.push(` allow create: if ${buildRuleCondition(subRules, \"create\", subModel)};`);\n rules.push(` allow update: if ${buildRuleCondition(subRules, \"update\", subModel)};`);\n rules.push(` allow delete: if ${buildRuleCondition(subRules, \"delete\", subModel)};`);\n rules.push(\" }\");\n }\n }\n\n rules.push(\" }\");\n rules.push(\"\");\n }\n\n rules.push(\" }\");\n rules.push(\"}\");\n\n return rules.join(\"\\n\");\n}\n\nfunction buildRuleCondition(\n rules: ModelRules,\n operation: \"read\" | \"create\" | \"update\" | \"delete\",\n model: ModelDefinition,\n): string {\n const level = rules[operation] || \"authenticated\";\n const roles = rules[`${operation}Roles` as keyof ModelRules] as string[] | undefined;\n const ownerField = rules.ownerField;\n\n const conditions: string[] = [];\n\n switch (level) {\n case \"public\":\n return \"true\";\n\n case \"authenticated\":\n conditions.push(\"isAuthenticated()\");\n break;\n\n case \"role\":\n if (roles && roles.length > 0) {\n if (roles.length === 1) {\n conditions.push(`hasRole('${roles[0]}')`);\n } else {\n conditions.push(`hasAnyRole(${JSON.stringify(roles)})`);\n }\n } else {\n conditions.push(\"isAuthenticated()\");\n }\n break;\n\n case \"reauth\":\n conditions.push(\"isAuthenticated()\");\n conditions.push(\"isRecentAuth()\");\n break;\n }\n\n // 소유자 기반 접근 제어\n if (ownerField && (operation === \"read\" || operation === \"update\" || operation === \"delete\")) {\n const ownerCondition = operation === \"read\"\n ? `resource.data.${ownerField} == request.auth.uid`\n : `resource.data.${ownerField} == request.auth.uid`;\n\n if (conditions.length > 0) {\n // 소유자이거나 권한이 있는 경우\n return `(${conditions.join(\" && \")}) || (isAuthenticated() && ${ownerCondition})`;\n }\n return `isAuthenticated() && ${ownerCondition}`;\n }\n\n if (ownerField && operation === \"create\") {\n conditions.push(`request.resource.data.${ownerField} == request.auth.uid`);\n }\n\n return conditions.join(\" && \") || \"false\";\n}\n\n/**\n * 모델 정의에서 Firestore 인덱스 설정 생성 (firestore.indexes.json 형식)\n */\nexport function generateFirestoreIndexes(\n models: Record<string, ModelDefinition>,\n): { indexes: Array<{ collectionGroup: string; queryScope: string; fields: Array<{ fieldPath: string; order?: string }> }> } {\n const indexes: Array<{\n collectionGroup: string;\n queryScope: string;\n fields: Array<{ fieldPath: string; order?: string }>;\n }> = [];\n\n for (const model of Object.values(models)) {\n if (model.indexes) {\n for (const index of model.indexes) {\n indexes.push({\n collectionGroup: model.collection,\n queryScope: \"COLLECTION\",\n fields: index.fields.map((f) => ({\n fieldPath: f.field,\n order: (f.order || \"asc\").toUpperCase(),\n })),\n });\n }\n }\n }\n\n return { indexes };\n}\n","/**\n * Clawfire Firebase Hosting & firebase.json Config Generator\n */\nimport type { ClawfireConfig } from \"../core/config.js\";\n\nexport interface FirebaseJsonConfig {\n hosting?: {\n public: string;\n ignore: string[];\n rewrites?: Array<{ source: string; function?: string; destination?: string }>;\n headers?: Array<{ source: string; headers: Array<{ key: string; value: string }> }>;\n };\n functions?: {\n source: string;\n runtime?: string;\n codebase?: string;\n } | Array<{\n source: string;\n codebase: string;\n runtime?: string;\n }>;\n firestore?: {\n rules: string;\n indexes: string;\n };\n emulators?: {\n functions?: { port: number };\n firestore?: { port: number };\n auth?: { port: number };\n hosting?: { port: number };\n ui?: { enabled: boolean; port?: number };\n };\n}\n\n/**\n * firebase.json 설정 생성\n */\nexport function generateFirebaseJson(config?: Partial<ClawfireConfig>): FirebaseJsonConfig {\n return {\n hosting: {\n public: \"public\",\n ignore: [\"firebase.json\", \"**/.*\", \"**/node_modules/**\"],\n rewrites: [\n {\n source: \"/api/**\",\n function: \"api\",\n },\n {\n source: \"**\",\n destination: \"/index.html\",\n },\n ],\n headers: [\n {\n source: \"/api/**\",\n headers: [\n { key: \"Cache-Control\", value: \"no-store\" },\n { key: \"X-Content-Type-Options\", value: \"nosniff\" },\n { key: \"X-Frame-Options\", value: \"DENY\" },\n { key: \"X-XSS-Protection\", value: \"1; mode=block\" },\n { key: \"Referrer-Policy\", value: \"strict-origin-when-cross-origin\" },\n ],\n },\n {\n source: \"**/*.@(js|css|svg|png|jpg|jpeg|gif|ico|webp|woff|woff2)\",\n headers: [\n { key: \"Cache-Control\", value: \"public, max-age=31536000, immutable\" },\n ],\n },\n ],\n },\n functions: {\n source: \"functions\",\n runtime: \"nodejs20\",\n codebase: \"clawfire\",\n },\n firestore: {\n rules: \"firestore.rules\",\n indexes: \"firestore.indexes.json\",\n },\n emulators: {\n functions: { port: 5001 },\n firestore: { port: 8080 },\n auth: { port: 9099 },\n hosting: { port: 5000 },\n ui: { enabled: true, port: 4000 },\n },\n };\n}\n\n/**\n * 기본 Firestore rules 파일 내용 생성\n */\nexport function generateDefaultRules(): string {\n return `rules_version = '2';\nservice cloud.firestore {\n match /databases/{database}/documents {\n\n // Helper functions\n function isAuthenticated() {\n return request.auth != null;\n }\n\n function isOwner(userId) {\n return isAuthenticated() && request.auth.uid == userId;\n }\n\n function hasRole(role) {\n return isAuthenticated() && request.auth.token.role == role;\n }\n\n // Default: deny all\n match /{document=**} {\n allow read, write: if false;\n }\n }\n}\n`;\n}\n","/**\n * Clawfire Security Middleware\n *\n * PRD 7.7: 보안 기본값 — 입력 검증 ON, 안전 헤더, CORS deny, 로그 마스킹, rate limit\n */\nimport type { Middleware } from \"../routing/router.js\";\nimport type { HandlerContext } from \"../core/schema.js\";\nimport { logger, maskSensitive } from \"../core/logger.js\";\n\n/**\n * 요청 로깅 미들웨어 (민감 데이터 마스킹)\n */\nexport function requestLogger(): Middleware {\n return async (input, ctx, next) => {\n const start = Date.now();\n const uid = ctx.auth?.uid || \"anonymous\";\n\n logger.info(`→ Request from ${uid}`, {\n hasAuth: !!ctx.auth,\n ip: ctx.ip,\n });\n\n try {\n const result = await next();\n const duration = Date.now() - start;\n logger.info(`← Response [${duration}ms]`);\n return result;\n } catch (err) {\n const duration = Date.now() - start;\n logger.error(`← Error [${duration}ms]`, {\n error: err instanceof Error ? err.message : \"Unknown error\",\n });\n throw err;\n }\n };\n}\n\n/**\n * 입력 크기 제한 미들웨어\n */\nexport function inputSizeLimit(maxBytes: number = 1024 * 1024): Middleware {\n return async (input, ctx, next) => {\n const size = JSON.stringify(input).length;\n if (size > maxBytes) {\n const { Errors } = await import(\"../core/errors.js\");\n throw Errors.validation(`Input too large: ${size} bytes (max: ${maxBytes})`);\n }\n return next();\n };\n}\n\n/**\n * 입력 새니타이즈 미들웨어 (XSS 방지)\n */\nexport function sanitizeInput(): Middleware {\n return async (input, ctx, next) => {\n if (typeof input === \"object\" && input !== null) {\n sanitizeObject(input as Record<string, unknown>);\n }\n return next();\n };\n}\n\nfunction sanitizeObject(obj: Record<string, unknown>): void {\n for (const [key, value] of Object.entries(obj)) {\n if (typeof value === \"string\") {\n // 기본 XSS 방지: script 태그 이스케이프\n obj[key] = value\n .replace(/</g, \"&lt;\")\n .replace(/>/g, \"&gt;\");\n } else if (typeof value === \"object\" && value !== null && !Array.isArray(value)) {\n sanitizeObject(value as Record<string, unknown>);\n } else if (Array.isArray(value)) {\n for (let i = 0; i < value.length; i++) {\n if (typeof value[i] === \"string\") {\n value[i] = (value[i] as string).replace(/</g, \"&lt;\").replace(/>/g, \"&gt;\");\n } else if (typeof value[i] === \"object\" && value[i] !== null) {\n sanitizeObject(value[i] as Record<string, unknown>);\n }\n }\n }\n }\n}\n\n/**\n * CORS 미들웨어\n */\nexport function corsMiddleware(allowedOrigins: string[] = []): Middleware {\n return async (input, ctx, next) => {\n // CORS는 router.handleRequest에서 헤더로 처리됨\n // 이 미들웨어는 추가 로직이 필요할 때 사용\n return next();\n };\n}\n\n/**\n * 보안 기본값 미들웨어 세트 생성\n */\nexport function createSecurityMiddleware(options?: {\n maxInputSize?: number;\n sanitize?: boolean;\n logRequests?: boolean;\n}): Middleware[] {\n const middlewares: Middleware[] = [];\n\n if (options?.logRequests !== false) {\n middlewares.push(requestLogger());\n }\n\n if (options?.maxInputSize) {\n middlewares.push(inputSizeLimit(options.maxInputSize));\n } else {\n middlewares.push(inputSizeLimit()); // 기본 1MB\n }\n\n if (options?.sanitize !== false) {\n middlewares.push(sanitizeInput());\n }\n\n return middlewares;\n}\n","export {\n defineAPI,\n defineModel,\n zodToJsonSchema,\n modelToZodSchema,\n contractToManifest,\n type APIContract,\n type APIMeta,\n type AuthLevel,\n type AuthContext,\n type HandlerContext,\n type ModelDefinition,\n type ModelField,\n type ModelIndex,\n type ModelRules,\n type ManifestEntry,\n type Manifest,\n} from \"./schema.js\";\n\nexport {\n ClawfireError,\n Errors,\n type ClawfireErrorCode,\n} from \"./errors.js\";\n\nexport {\n logger,\n setLogLevel,\n maskSensitive,\n} from \"./logger.js\";\n\nexport {\n configureClawfire,\n getConfig,\n type ClawfireConfig,\n} from \"./config.js\";\n"],"mappings":"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","names":["Errors","import_zod"]}
@@ -0,0 +1,115 @@
1
+ import { M as Middleware } from './router-Cikk8Heq.cjs';
2
+ export { C as ClawfireRouter, R as Route, a as RouterOptions, c as createRouter } from './router-Cikk8Heq.cjs';
3
+ export { D as DiscoveredRoute, d as discoverRoutes, g as generateRouteImports } from './discover-DYNqz_ym.cjs';
4
+ export { a as checkAuthLevel, e as extractBearerToken, g as getUserRole, s as setCustomClaims, b as setUserRole, v as verifyReauth, d as verifyToken } from './auth-DQ3cifhb.cjs';
5
+ export { FirebaseJsonConfig, generateDefaultRules, generateFirebaseJson, generateFirestoreIndexes, generateFirestoreRules } from './admin.cjs';
6
+ export { A as APIContract, a as APIMeta, b as AuthContext, c as AuthLevel, H as HandlerContext, e as ModelDefinition, g as defineAPI, h as defineModel, m as modelToZodSchema, z as zodToJsonSchema } from './schema-BJsictSV.cjs';
7
+ export { C as ClawfireError, E as Errors } from './errors-s_mP7rs9.cjs';
8
+ export { logger } from './index.cjs';
9
+ export { z } from 'zod';
10
+ import './config-QMBJRn9G.cjs';
11
+
12
+ interface FirestoreDoc {
13
+ id: string;
14
+ [key: string]: unknown;
15
+ }
16
+ interface QueryFilter {
17
+ field: string;
18
+ op: "==" | "!=" | "<" | "<=" | ">" | ">=" | "in" | "not-in" | "array-contains" | "array-contains-any";
19
+ value: unknown;
20
+ }
21
+ interface QueryOrder {
22
+ field: string;
23
+ direction?: "asc" | "desc";
24
+ }
25
+ interface QueryOptions {
26
+ filters?: QueryFilter[];
27
+ orderBy?: QueryOrder[];
28
+ limit?: number;
29
+ offset?: number;
30
+ startAfter?: unknown;
31
+ }
32
+ interface PaginatedResult<T> {
33
+ data: T[];
34
+ hasMore: boolean;
35
+ lastDoc?: unknown;
36
+ total?: number;
37
+ }
38
+ /**
39
+ * 서버사이드(Firebase Functions)에서 사용하는 Firestore DB 래퍼
40
+ *
41
+ * @example
42
+ * ```ts
43
+ * const db = createAdminDB(admin.firestore());
44
+ * const product = await db.get("products", "abc123");
45
+ * const products = await db.query("products", { filters: [{ field: "price", op: ">", value: 100 }] });
46
+ * ```
47
+ */
48
+ declare function createAdminDB(firestore: any): {
49
+ /** 문서 조회 */
50
+ get<T extends FirestoreDoc = FirestoreDoc>(collection: string, id: string): Promise<T | null>;
51
+ /** 문서 생성 (ID 자동 생성) */
52
+ create<T extends Record<string, unknown>>(collection: string, data: T): Promise<string>;
53
+ /** 문서 생성 (ID 지정) */
54
+ set<T extends Record<string, unknown>>(collection: string, id: string, data: T, merge?: boolean): Promise<void>;
55
+ /** 문서 부분 업데이트 */
56
+ update<T extends Record<string, unknown>>(collection: string, id: string, data: Partial<T>): Promise<void>;
57
+ /** 문서 삭제 */
58
+ delete(collection: string, id: string): Promise<void>;
59
+ /** 소프트 삭제 */
60
+ softDelete(collection: string, id: string): Promise<void>;
61
+ /** 쿼리 */
62
+ query<T extends FirestoreDoc = FirestoreDoc>(collection: string, options?: QueryOptions): Promise<PaginatedResult<T>>;
63
+ /** 문서 수 */
64
+ count(collection: string, filters?: QueryFilter[]): Promise<number>;
65
+ /** 배치 작업 */
66
+ batch(operations: Array<{
67
+ type: "create" | "set" | "update" | "delete";
68
+ collection: string;
69
+ id?: string;
70
+ data?: Record<string, unknown>;
71
+ }>): Promise<string[]>;
72
+ /** 트랜잭션 */
73
+ transaction<T>(fn: (tx: {
74
+ get: (collection: string, id: string) => Promise<FirestoreDoc | null>;
75
+ set: (collection: string, id: string, data: Record<string, unknown>) => void;
76
+ update: (collection: string, id: string, data: Record<string, unknown>) => void;
77
+ delete: (collection: string, id: string) => void;
78
+ }) => Promise<T>): Promise<T>;
79
+ /** 원시 Firestore 접근 */
80
+ raw: any;
81
+ };
82
+ type AdminDB = ReturnType<typeof createAdminDB>;
83
+
84
+ /**
85
+ * Clawfire Security Middleware
86
+ *
87
+ * PRD 7.7: 보안 기본값 — 입력 검증 ON, 안전 헤더, CORS deny, 로그 마스킹, rate limit
88
+ */
89
+
90
+ /**
91
+ * 요청 로깅 미들웨어 (민감 데이터 마스킹)
92
+ */
93
+ declare function requestLogger(): Middleware;
94
+ /**
95
+ * 입력 크기 제한 미들웨어
96
+ */
97
+ declare function inputSizeLimit(maxBytes?: number): Middleware;
98
+ /**
99
+ * 입력 새니타이즈 미들웨어 (XSS 방지)
100
+ */
101
+ declare function sanitizeInput(): Middleware;
102
+ /**
103
+ * CORS 미들웨어
104
+ */
105
+ declare function corsMiddleware(allowedOrigins?: string[]): Middleware;
106
+ /**
107
+ * 보안 기본값 미들웨어 세트 생성
108
+ */
109
+ declare function createSecurityMiddleware(options?: {
110
+ maxInputSize?: number;
111
+ sanitize?: boolean;
112
+ logRequests?: boolean;
113
+ }): Middleware[];
114
+
115
+ export { type AdminDB, type FirestoreDoc, Middleware, type PaginatedResult, type QueryFilter, type QueryOptions, type QueryOrder, corsMiddleware, createAdminDB, createSecurityMiddleware, inputSizeLimit, requestLogger, sanitizeInput };
@@ -0,0 +1,115 @@
1
+ import { M as Middleware } from './router-BVB_I-tu.js';
2
+ export { C as ClawfireRouter, R as Route, a as RouterOptions, c as createRouter } from './router-BVB_I-tu.js';
3
+ export { D as DiscoveredRoute, d as discoverRoutes, g as generateRouteImports } from './discover-DYNqz_ym.js';
4
+ export { a as checkAuthLevel, e as extractBearerToken, g as getUserRole, s as setCustomClaims, b as setUserRole, v as verifyReauth, d as verifyToken } from './auth-DtnUPbXT.js';
5
+ export { FirebaseJsonConfig, generateDefaultRules, generateFirebaseJson, generateFirestoreIndexes, generateFirestoreRules } from './admin.js';
6
+ export { A as APIContract, a as APIMeta, b as AuthContext, c as AuthLevel, H as HandlerContext, e as ModelDefinition, g as defineAPI, h as defineModel, m as modelToZodSchema, z as zodToJsonSchema } from './schema-BJsictSV.js';
7
+ export { C as ClawfireError, E as Errors } from './errors-s_mP7rs9.js';
8
+ export { logger } from './index.js';
9
+ export { z } from 'zod';
10
+ import './config-QMBJRn9G.js';
11
+
12
+ interface FirestoreDoc {
13
+ id: string;
14
+ [key: string]: unknown;
15
+ }
16
+ interface QueryFilter {
17
+ field: string;
18
+ op: "==" | "!=" | "<" | "<=" | ">" | ">=" | "in" | "not-in" | "array-contains" | "array-contains-any";
19
+ value: unknown;
20
+ }
21
+ interface QueryOrder {
22
+ field: string;
23
+ direction?: "asc" | "desc";
24
+ }
25
+ interface QueryOptions {
26
+ filters?: QueryFilter[];
27
+ orderBy?: QueryOrder[];
28
+ limit?: number;
29
+ offset?: number;
30
+ startAfter?: unknown;
31
+ }
32
+ interface PaginatedResult<T> {
33
+ data: T[];
34
+ hasMore: boolean;
35
+ lastDoc?: unknown;
36
+ total?: number;
37
+ }
38
+ /**
39
+ * 서버사이드(Firebase Functions)에서 사용하는 Firestore DB 래퍼
40
+ *
41
+ * @example
42
+ * ```ts
43
+ * const db = createAdminDB(admin.firestore());
44
+ * const product = await db.get("products", "abc123");
45
+ * const products = await db.query("products", { filters: [{ field: "price", op: ">", value: 100 }] });
46
+ * ```
47
+ */
48
+ declare function createAdminDB(firestore: any): {
49
+ /** 문서 조회 */
50
+ get<T extends FirestoreDoc = FirestoreDoc>(collection: string, id: string): Promise<T | null>;
51
+ /** 문서 생성 (ID 자동 생성) */
52
+ create<T extends Record<string, unknown>>(collection: string, data: T): Promise<string>;
53
+ /** 문서 생성 (ID 지정) */
54
+ set<T extends Record<string, unknown>>(collection: string, id: string, data: T, merge?: boolean): Promise<void>;
55
+ /** 문서 부분 업데이트 */
56
+ update<T extends Record<string, unknown>>(collection: string, id: string, data: Partial<T>): Promise<void>;
57
+ /** 문서 삭제 */
58
+ delete(collection: string, id: string): Promise<void>;
59
+ /** 소프트 삭제 */
60
+ softDelete(collection: string, id: string): Promise<void>;
61
+ /** 쿼리 */
62
+ query<T extends FirestoreDoc = FirestoreDoc>(collection: string, options?: QueryOptions): Promise<PaginatedResult<T>>;
63
+ /** 문서 수 */
64
+ count(collection: string, filters?: QueryFilter[]): Promise<number>;
65
+ /** 배치 작업 */
66
+ batch(operations: Array<{
67
+ type: "create" | "set" | "update" | "delete";
68
+ collection: string;
69
+ id?: string;
70
+ data?: Record<string, unknown>;
71
+ }>): Promise<string[]>;
72
+ /** 트랜잭션 */
73
+ transaction<T>(fn: (tx: {
74
+ get: (collection: string, id: string) => Promise<FirestoreDoc | null>;
75
+ set: (collection: string, id: string, data: Record<string, unknown>) => void;
76
+ update: (collection: string, id: string, data: Record<string, unknown>) => void;
77
+ delete: (collection: string, id: string) => void;
78
+ }) => Promise<T>): Promise<T>;
79
+ /** 원시 Firestore 접근 */
80
+ raw: any;
81
+ };
82
+ type AdminDB = ReturnType<typeof createAdminDB>;
83
+
84
+ /**
85
+ * Clawfire Security Middleware
86
+ *
87
+ * PRD 7.7: 보안 기본값 — 입력 검증 ON, 안전 헤더, CORS deny, 로그 마스킹, rate limit
88
+ */
89
+
90
+ /**
91
+ * 요청 로깅 미들웨어 (민감 데이터 마스킹)
92
+ */
93
+ declare function requestLogger(): Middleware;
94
+ /**
95
+ * 입력 크기 제한 미들웨어
96
+ */
97
+ declare function inputSizeLimit(maxBytes?: number): Middleware;
98
+ /**
99
+ * 입력 새니타이즈 미들웨어 (XSS 방지)
100
+ */
101
+ declare function sanitizeInput(): Middleware;
102
+ /**
103
+ * CORS 미들웨어
104
+ */
105
+ declare function corsMiddleware(allowedOrigins?: string[]): Middleware;
106
+ /**
107
+ * 보안 기본값 미들웨어 세트 생성
108
+ */
109
+ declare function createSecurityMiddleware(options?: {
110
+ maxInputSize?: number;
111
+ sanitize?: boolean;
112
+ logRequests?: boolean;
113
+ }): Middleware[];
114
+
115
+ export { type AdminDB, type FirestoreDoc, Middleware, type PaginatedResult, type QueryFilter, type QueryOptions, type QueryOrder, corsMiddleware, createAdminDB, createSecurityMiddleware, inputSizeLimit, requestLogger, sanitizeInput };