@mandujs/core 0.13.0 → 0.13.2
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.
- package/README.ko.md +4 -4
- package/README.md +653 -653
- package/package.json +1 -1
- package/src/bundler/build.ts +91 -91
- package/src/bundler/css.ts +302 -302
- package/src/client/Link.tsx +227 -227
- package/src/client/globals.ts +44 -44
- package/src/client/hooks.ts +267 -267
- package/src/client/index.ts +5 -5
- package/src/client/island.ts +8 -8
- package/src/client/router.ts +435 -435
- package/src/client/runtime.ts +23 -23
- package/src/client/serialize.ts +404 -404
- package/src/client/window-state.ts +101 -101
- package/src/config/mandu.ts +9 -0
- package/src/config/validate.ts +12 -0
- package/src/config/watcher.ts +311 -311
- package/src/constants.ts +40 -40
- package/src/content/content-layer.ts +314 -314
- package/src/content/content.test.ts +433 -433
- package/src/content/data-store.ts +245 -245
- package/src/content/digest.ts +133 -133
- package/src/content/index.ts +164 -164
- package/src/content/loader-context.ts +172 -172
- package/src/content/loaders/api.ts +216 -216
- package/src/content/loaders/file.ts +169 -169
- package/src/content/loaders/glob.ts +252 -252
- package/src/content/loaders/index.ts +34 -34
- package/src/content/loaders/types.ts +137 -137
- package/src/content/meta-store.ts +209 -209
- package/src/content/types.ts +282 -282
- package/src/content/watcher.ts +135 -135
- package/src/contract/client-safe.test.ts +42 -42
- package/src/contract/client-safe.ts +114 -114
- package/src/contract/client.ts +16 -16
- package/src/contract/define.ts +459 -459
- package/src/contract/handler.ts +10 -10
- package/src/contract/normalize.test.ts +276 -276
- package/src/contract/normalize.ts +404 -404
- package/src/contract/registry.test.ts +206 -206
- package/src/contract/registry.ts +568 -568
- package/src/contract/schema.ts +48 -48
- package/src/contract/types.ts +58 -58
- package/src/contract/validator.ts +32 -32
- package/src/devtools/ai/context-builder.ts +375 -375
- package/src/devtools/ai/index.ts +25 -25
- package/src/devtools/ai/mcp-connector.ts +465 -465
- package/src/devtools/client/catchers/error-catcher.ts +327 -327
- package/src/devtools/client/catchers/index.ts +18 -18
- package/src/devtools/client/catchers/network-proxy.ts +363 -363
- package/src/devtools/client/components/index.ts +39 -39
- package/src/devtools/client/components/kitchen-root.tsx +362 -362
- package/src/devtools/client/components/mandu-character.tsx +241 -241
- package/src/devtools/client/components/overlay.tsx +368 -368
- package/src/devtools/client/components/panel/errors-panel.tsx +259 -259
- package/src/devtools/client/components/panel/guard-panel.tsx +244 -244
- package/src/devtools/client/components/panel/index.ts +32 -32
- package/src/devtools/client/components/panel/islands-panel.tsx +304 -304
- package/src/devtools/client/components/panel/network-panel.tsx +292 -292
- package/src/devtools/client/components/panel/panel-container.tsx +259 -259
- package/src/devtools/client/filters/context-filters.ts +282 -282
- package/src/devtools/client/filters/index.ts +16 -16
- package/src/devtools/client/index.ts +63 -63
- package/src/devtools/client/persistence.ts +335 -335
- package/src/devtools/client/state-manager.ts +478 -478
- package/src/devtools/design-tokens.ts +263 -263
- package/src/devtools/hook/create-hook.ts +207 -207
- package/src/devtools/hook/index.ts +13 -13
- package/src/devtools/index.ts +439 -439
- package/src/devtools/init.ts +266 -266
- package/src/devtools/protocol.ts +237 -237
- package/src/devtools/server/index.ts +17 -17
- package/src/devtools/server/source-context.ts +444 -444
- package/src/devtools/types.ts +319 -319
- package/src/devtools/worker/index.ts +25 -25
- package/src/devtools/worker/redaction-worker.ts +222 -222
- package/src/devtools/worker/worker-manager.ts +409 -409
- package/src/error/domains.ts +265 -265
- package/src/error/result.ts +46 -46
- package/src/error/types.ts +6 -6
- package/src/errors/extractor.ts +409 -409
- package/src/errors/index.ts +19 -19
- package/src/filling/auth.ts +308 -308
- package/src/filling/context.ts +24 -1
- package/src/filling/deps.ts +238 -238
- package/src/filling/index.ts +4 -0
- package/src/filling/sse-catchup.test.ts +56 -0
- package/src/filling/sse-catchup.ts +67 -0
- package/src/filling/sse.test.ts +168 -0
- package/src/filling/sse.ts +162 -0
- package/src/generator/index.ts +3 -3
- package/src/guard/analyzer.ts +360 -360
- package/src/guard/ast-analyzer.ts +806 -806
- package/src/guard/contract-guard.ts +9 -9
- package/src/guard/file-type.test.ts +24 -24
- package/src/guard/presets/atomic.ts +70 -70
- package/src/guard/presets/clean.ts +77 -77
- package/src/guard/presets/fsd.ts +79 -79
- package/src/guard/presets/hexagonal.ts +68 -68
- package/src/guard/presets/index.ts +291 -291
- package/src/guard/reporter.ts +445 -445
- package/src/guard/rules.ts +12 -12
- package/src/guard/statistics.ts +578 -578
- package/src/guard/suggestions.ts +358 -358
- package/src/guard/types.ts +348 -348
- package/src/guard/validator.ts +834 -834
- package/src/guard/watcher.ts +404 -404
- package/src/index.ts +6 -1
- package/src/intent/index.ts +310 -310
- package/src/island/index.ts +304 -304
- package/src/logging/index.ts +22 -22
- package/src/logging/transports.ts +365 -365
- package/src/plugins/index.ts +38 -38
- package/src/plugins/registry.ts +377 -377
- package/src/plugins/types.ts +363 -363
- package/src/report/index.ts +1 -1
- package/src/router/fs-patterns.ts +387 -387
- package/src/router/fs-scanner.ts +497 -497
- package/src/runtime/boundary.tsx +232 -232
- package/src/runtime/compose.ts +222 -222
- package/src/runtime/escape.ts +44 -0
- package/src/runtime/lifecycle.ts +381 -381
- package/src/runtime/logger.test.ts +345 -345
- package/src/runtime/logger.ts +677 -677
- package/src/runtime/router.test.ts +476 -476
- package/src/runtime/router.ts +105 -105
- package/src/runtime/security.ts +155 -155
- package/src/runtime/server.ts +257 -0
- package/src/runtime/session-key.ts +328 -328
- package/src/runtime/ssr.ts +16 -21
- package/src/runtime/streaming-ssr.ts +24 -33
- package/src/runtime/trace.ts +144 -144
- package/src/seo/index.ts +214 -214
- package/src/seo/integration/ssr.ts +307 -307
- package/src/seo/render/basic.ts +427 -427
- package/src/seo/render/index.ts +143 -143
- package/src/seo/render/jsonld.ts +539 -539
- package/src/seo/render/opengraph.ts +191 -191
- package/src/seo/render/robots.ts +116 -116
- package/src/seo/render/sitemap.ts +137 -137
- package/src/seo/render/twitter.ts +126 -126
- package/src/seo/resolve/index.ts +353 -353
- package/src/seo/resolve/opengraph.ts +143 -143
- package/src/seo/resolve/robots.ts +73 -73
- package/src/seo/resolve/title.ts +94 -94
- package/src/seo/resolve/twitter.ts +73 -73
- package/src/seo/resolve/url.ts +97 -97
- package/src/seo/routes/index.ts +290 -290
- package/src/seo/types.ts +575 -575
- package/src/slot/validator.ts +39 -39
- package/src/spec/index.ts +3 -3
- package/src/spec/load.ts +76 -76
- package/src/spec/lock.ts +56 -56
- package/src/utils/bun.ts +8 -8
- package/src/utils/lru-cache.ts +75 -75
- package/src/utils/safe-io.ts +188 -188
- package/src/utils/string-safe.ts +298 -298
package/src/seo/types.ts
CHANGED
|
@@ -1,575 +1,575 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Mandu SEO - Type Definitions
|
|
3
|
-
*
|
|
4
|
-
* Next.js Metadata API 패턴 기반
|
|
5
|
-
* @see https://nextjs.org/docs/app/api-reference/functions/generate-metadata
|
|
6
|
-
*/
|
|
7
|
-
|
|
8
|
-
// ============================================================================
|
|
9
|
-
// Basic Types
|
|
10
|
-
// ============================================================================
|
|
11
|
-
|
|
12
|
-
export type ReferrerEnum =
|
|
13
|
-
| 'no-referrer'
|
|
14
|
-
| 'no-referrer-when-downgrade'
|
|
15
|
-
| 'origin'
|
|
16
|
-
| 'origin-when-cross-origin'
|
|
17
|
-
| 'same-origin'
|
|
18
|
-
| 'strict-origin'
|
|
19
|
-
| 'strict-origin-when-cross-origin'
|
|
20
|
-
| 'unsafe-url'
|
|
21
|
-
|
|
22
|
-
export type ColorSchemeEnum = 'normal' | 'light' | 'dark' | 'light dark' | 'dark light' | 'only light'
|
|
23
|
-
|
|
24
|
-
// ============================================================================
|
|
25
|
-
// Title Types
|
|
26
|
-
// ============================================================================
|
|
27
|
-
|
|
28
|
-
export interface TemplateString {
|
|
29
|
-
default: string
|
|
30
|
-
template?: string // "%s | My Site" - %s is replaced with page title
|
|
31
|
-
absolute?: string // Ignores parent template
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
/**
|
|
35
|
-
* 단축형 absolute 타이틀 (템플릿 무시)
|
|
36
|
-
*/
|
|
37
|
-
export interface AbsoluteString {
|
|
38
|
-
absolute: string
|
|
39
|
-
template?: string
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
export type Title = string | TemplateString | AbsoluteString
|
|
43
|
-
|
|
44
|
-
export interface AbsoluteTemplateString {
|
|
45
|
-
absolute: string
|
|
46
|
-
template: string | null
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
// ============================================================================
|
|
50
|
-
// Author & Creator
|
|
51
|
-
// ============================================================================
|
|
52
|
-
|
|
53
|
-
export interface Author {
|
|
54
|
-
name?: string
|
|
55
|
-
url?: string | URL
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
// ============================================================================
|
|
59
|
-
// Robots
|
|
60
|
-
// ============================================================================
|
|
61
|
-
|
|
62
|
-
export interface Robots {
|
|
63
|
-
index?: boolean
|
|
64
|
-
follow?: boolean
|
|
65
|
-
noarchive?: boolean
|
|
66
|
-
nosnippet?: boolean
|
|
67
|
-
noimageindex?: boolean
|
|
68
|
-
nocache?: boolean
|
|
69
|
-
notranslate?: boolean
|
|
70
|
-
'max-snippet'?: number
|
|
71
|
-
'max-image-preview'?: 'none' | 'standard' | 'large'
|
|
72
|
-
'max-video-preview'?: number
|
|
73
|
-
/** Google 전용 설정 (다르게 적용할 경우) */
|
|
74
|
-
googleBot?: Omit<Robots, 'googleBot'>
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
export interface ResolvedRobots {
|
|
78
|
-
basic: string | null
|
|
79
|
-
googleBot: string | null
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
// ============================================================================
|
|
83
|
-
// Google SEO Specific
|
|
84
|
-
// ============================================================================
|
|
85
|
-
|
|
86
|
-
/**
|
|
87
|
-
* Google 전용 메타 설정
|
|
88
|
-
*/
|
|
89
|
-
export interface GoogleMeta {
|
|
90
|
-
/** Google 사이트링크 검색창 비활성화 */
|
|
91
|
-
nositelinkssearchbox?: boolean
|
|
92
|
-
/** Google 번역 제안 비활성화 */
|
|
93
|
-
notranslate?: boolean
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
/**
|
|
97
|
-
* 전화번호/이메일 자동 감지 설정
|
|
98
|
-
*/
|
|
99
|
-
export interface FormatDetection {
|
|
100
|
-
telephone?: boolean
|
|
101
|
-
date?: boolean
|
|
102
|
-
address?: boolean
|
|
103
|
-
email?: boolean
|
|
104
|
-
url?: boolean
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
/**
|
|
108
|
-
* 리소스 힌트 (성능 최적화)
|
|
109
|
-
*/
|
|
110
|
-
export interface ResourceHint {
|
|
111
|
-
/** preconnect URLs (외부 도메인 미리 연결) */
|
|
112
|
-
preconnect?: string[]
|
|
113
|
-
/** dns-prefetch URLs (DNS 미리 조회) */
|
|
114
|
-
dnsPrefetch?: string[]
|
|
115
|
-
/** preload resources */
|
|
116
|
-
preload?: Array<{
|
|
117
|
-
href: string
|
|
118
|
-
as: 'script' | 'style' | 'font' | 'image' | 'fetch'
|
|
119
|
-
type?: string
|
|
120
|
-
crossOrigin?: 'anonymous' | 'use-credentials'
|
|
121
|
-
}>
|
|
122
|
-
/** prefetch resources (다음 페이지용) */
|
|
123
|
-
prefetch?: string[]
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
/**
|
|
127
|
-
* App 관련 메타 (PWA, iOS)
|
|
128
|
-
*/
|
|
129
|
-
export interface AppLinks {
|
|
130
|
-
/** iOS App Store ID */
|
|
131
|
-
iosAppStoreId?: string
|
|
132
|
-
/** iOS App 이름 */
|
|
133
|
-
iosAppName?: string
|
|
134
|
-
/** iOS App URL Scheme */
|
|
135
|
-
iosUrl?: string
|
|
136
|
-
/** Android Package */
|
|
137
|
-
androidPackage?: string
|
|
138
|
-
/** Android App 이름 */
|
|
139
|
-
androidAppName?: string
|
|
140
|
-
/** Android URL */
|
|
141
|
-
androidUrl?: string
|
|
142
|
-
}
|
|
143
|
-
|
|
144
|
-
/**
|
|
145
|
-
* Theme Color 설정
|
|
146
|
-
*/
|
|
147
|
-
export interface ThemeColor {
|
|
148
|
-
color: string
|
|
149
|
-
media?: string // e.g., '(prefers-color-scheme: dark)'
|
|
150
|
-
}
|
|
151
|
-
|
|
152
|
-
// ============================================================================
|
|
153
|
-
// Icons
|
|
154
|
-
// ============================================================================
|
|
155
|
-
|
|
156
|
-
export type IconURL = string | URL
|
|
157
|
-
|
|
158
|
-
export interface IconDescriptor {
|
|
159
|
-
url: string | URL
|
|
160
|
-
type?: string
|
|
161
|
-
sizes?: string
|
|
162
|
-
color?: string
|
|
163
|
-
rel?: string
|
|
164
|
-
media?: string
|
|
165
|
-
fetchPriority?: 'auto' | 'high' | 'low'
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
export type Icon = IconURL | IconDescriptor
|
|
169
|
-
|
|
170
|
-
export interface Icons {
|
|
171
|
-
icon?: Icon | Icon[]
|
|
172
|
-
shortcut?: Icon | Icon[]
|
|
173
|
-
apple?: Icon | Icon[]
|
|
174
|
-
other?: IconDescriptor | IconDescriptor[]
|
|
175
|
-
}
|
|
176
|
-
|
|
177
|
-
export interface ResolvedIcons {
|
|
178
|
-
icon: IconDescriptor[]
|
|
179
|
-
apple: IconDescriptor[]
|
|
180
|
-
shortcut: IconDescriptor[]
|
|
181
|
-
other: IconDescriptor[]
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
// ============================================================================
|
|
185
|
-
// Alternate URLs
|
|
186
|
-
// ============================================================================
|
|
187
|
-
|
|
188
|
-
export interface Languages<T> {
|
|
189
|
-
[locale: string]: T
|
|
190
|
-
}
|
|
191
|
-
|
|
192
|
-
export interface AlternateURLs {
|
|
193
|
-
canonical?: string | URL | null
|
|
194
|
-
languages?: Languages<string | URL | null>
|
|
195
|
-
media?: Record<string, string | URL>
|
|
196
|
-
types?: Record<string, string | URL>
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
export interface ResolvedAlternateURLs {
|
|
200
|
-
canonical: URL | null
|
|
201
|
-
languages: Record<string, URL> | null
|
|
202
|
-
media: Record<string, URL> | null
|
|
203
|
-
types: Record<string, URL> | null
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
// ============================================================================
|
|
207
|
-
// Verification
|
|
208
|
-
// ============================================================================
|
|
209
|
-
|
|
210
|
-
export interface Verification {
|
|
211
|
-
google?: string | string[]
|
|
212
|
-
yahoo?: string | string[]
|
|
213
|
-
yandex?: string | string[]
|
|
214
|
-
me?: string | string[]
|
|
215
|
-
other?: Record<string, string | string[]>
|
|
216
|
-
}
|
|
217
|
-
|
|
218
|
-
export interface ResolvedVerification {
|
|
219
|
-
google: string[] | null
|
|
220
|
-
yahoo: string[] | null
|
|
221
|
-
yandex: string[] | null
|
|
222
|
-
me: string[] | null
|
|
223
|
-
other: Record<string, string[]> | null
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
// ============================================================================
|
|
227
|
-
// Open Graph Types
|
|
228
|
-
// ============================================================================
|
|
229
|
-
|
|
230
|
-
export interface OpenGraphImage {
|
|
231
|
-
url: string | URL
|
|
232
|
-
secureUrl?: string | URL
|
|
233
|
-
alt?: string
|
|
234
|
-
type?: string
|
|
235
|
-
width?: string | number
|
|
236
|
-
height?: string | number
|
|
237
|
-
}
|
|
238
|
-
|
|
239
|
-
export interface OpenGraphVideo {
|
|
240
|
-
url: string | URL
|
|
241
|
-
secureUrl?: string | URL
|
|
242
|
-
type?: string
|
|
243
|
-
width?: string | number
|
|
244
|
-
height?: string | number
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
export interface OpenGraphAudio {
|
|
248
|
-
url: string | URL
|
|
249
|
-
secureUrl?: string | URL
|
|
250
|
-
type?: string
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
export interface OpenGraphArticle {
|
|
254
|
-
publishedTime?: string
|
|
255
|
-
modifiedTime?: string
|
|
256
|
-
expirationTime?: string
|
|
257
|
-
authors?: string | string[]
|
|
258
|
-
section?: string
|
|
259
|
-
tags?: string[]
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
export interface OpenGraphProfile {
|
|
263
|
-
firstName?: string
|
|
264
|
-
lastName?: string
|
|
265
|
-
username?: string
|
|
266
|
-
gender?: string
|
|
267
|
-
}
|
|
268
|
-
|
|
269
|
-
export interface OpenGraphBook {
|
|
270
|
-
isbn?: string
|
|
271
|
-
releaseDate?: string
|
|
272
|
-
authors?: string | string[]
|
|
273
|
-
tags?: string[]
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
export type OpenGraphType =
|
|
277
|
-
| 'article'
|
|
278
|
-
| 'book'
|
|
279
|
-
| 'music.song'
|
|
280
|
-
| 'music.album'
|
|
281
|
-
| 'music.playlist'
|
|
282
|
-
| 'music.radio_station'
|
|
283
|
-
| 'profile'
|
|
284
|
-
| 'video.movie'
|
|
285
|
-
| 'video.episode'
|
|
286
|
-
| 'video.tv_show'
|
|
287
|
-
| 'video.other'
|
|
288
|
-
| 'website'
|
|
289
|
-
|
|
290
|
-
export interface OpenGraph {
|
|
291
|
-
type?: OpenGraphType
|
|
292
|
-
url?: string | URL
|
|
293
|
-
title?: string
|
|
294
|
-
description?: string
|
|
295
|
-
siteName?: string
|
|
296
|
-
locale?: string
|
|
297
|
-
images?: string | URL | OpenGraphImage | (string | URL | OpenGraphImage)[]
|
|
298
|
-
videos?: string | URL | OpenGraphVideo | (string | URL | OpenGraphVideo)[]
|
|
299
|
-
audio?: string | URL | OpenGraphAudio | (string | URL | OpenGraphAudio)[]
|
|
300
|
-
determiner?: 'a' | 'an' | 'the' | 'auto' | ''
|
|
301
|
-
// Type-specific
|
|
302
|
-
article?: OpenGraphArticle
|
|
303
|
-
profile?: OpenGraphProfile
|
|
304
|
-
book?: OpenGraphBook
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
export interface ResolvedOpenGraph {
|
|
308
|
-
type: OpenGraphType
|
|
309
|
-
url: URL | null
|
|
310
|
-
title: string | null
|
|
311
|
-
description: string | null
|
|
312
|
-
siteName: string | null
|
|
313
|
-
locale: string | null
|
|
314
|
-
images: OpenGraphImage[] | null
|
|
315
|
-
videos: OpenGraphVideo[] | null
|
|
316
|
-
audio: OpenGraphAudio[] | null
|
|
317
|
-
determiner: string | null
|
|
318
|
-
article: OpenGraphArticle | null
|
|
319
|
-
profile: OpenGraphProfile | null
|
|
320
|
-
book: OpenGraphBook | null
|
|
321
|
-
}
|
|
322
|
-
|
|
323
|
-
// ============================================================================
|
|
324
|
-
// Twitter Types
|
|
325
|
-
// ============================================================================
|
|
326
|
-
|
|
327
|
-
export type TwitterCardType = 'summary' | 'summary_large_image' | 'app' | 'player'
|
|
328
|
-
|
|
329
|
-
export interface TwitterImage {
|
|
330
|
-
url: string | URL
|
|
331
|
-
alt?: string
|
|
332
|
-
}
|
|
333
|
-
|
|
334
|
-
export interface TwitterPlayer {
|
|
335
|
-
playerUrl: string | URL
|
|
336
|
-
streamUrl?: string | URL
|
|
337
|
-
width: number
|
|
338
|
-
height: number
|
|
339
|
-
}
|
|
340
|
-
|
|
341
|
-
export interface TwitterApp {
|
|
342
|
-
id: {
|
|
343
|
-
iphone?: string | number
|
|
344
|
-
ipad?: string | number
|
|
345
|
-
googleplay?: string
|
|
346
|
-
}
|
|
347
|
-
url?: {
|
|
348
|
-
iphone?: string | URL
|
|
349
|
-
ipad?: string | URL
|
|
350
|
-
googleplay?: string | URL
|
|
351
|
-
}
|
|
352
|
-
name?: string
|
|
353
|
-
}
|
|
354
|
-
|
|
355
|
-
export interface Twitter {
|
|
356
|
-
card?: TwitterCardType
|
|
357
|
-
site?: string
|
|
358
|
-
siteId?: string
|
|
359
|
-
creator?: string
|
|
360
|
-
creatorId?: string
|
|
361
|
-
title?: string
|
|
362
|
-
description?: string
|
|
363
|
-
images?: string | URL | TwitterImage | (string | URL | TwitterImage)[]
|
|
364
|
-
// Player card
|
|
365
|
-
players?: TwitterPlayer | TwitterPlayer[]
|
|
366
|
-
// App card
|
|
367
|
-
app?: TwitterApp
|
|
368
|
-
}
|
|
369
|
-
|
|
370
|
-
export interface ResolvedTwitter {
|
|
371
|
-
card: TwitterCardType
|
|
372
|
-
site: string | null
|
|
373
|
-
siteId: string | null
|
|
374
|
-
creator: string | null
|
|
375
|
-
creatorId: string | null
|
|
376
|
-
title: string | null
|
|
377
|
-
description: string | null
|
|
378
|
-
images: TwitterImage[] | null
|
|
379
|
-
players: TwitterPlayer[] | null
|
|
380
|
-
app: TwitterApp | null
|
|
381
|
-
}
|
|
382
|
-
|
|
383
|
-
// ============================================================================
|
|
384
|
-
// JSON-LD Types
|
|
385
|
-
// ============================================================================
|
|
386
|
-
|
|
387
|
-
export type JsonLdType =
|
|
388
|
-
| 'Article'
|
|
389
|
-
| 'BlogPosting'
|
|
390
|
-
| 'NewsArticle'
|
|
391
|
-
| 'WebSite'
|
|
392
|
-
| 'WebPage'
|
|
393
|
-
| 'Organization'
|
|
394
|
-
| 'Person'
|
|
395
|
-
| 'Product'
|
|
396
|
-
| 'BreadcrumbList'
|
|
397
|
-
| 'FAQPage'
|
|
398
|
-
| 'HowTo'
|
|
399
|
-
| 'Recipe'
|
|
400
|
-
| 'Event'
|
|
401
|
-
| 'LocalBusiness'
|
|
402
|
-
| 'SoftwareApplication'
|
|
403
|
-
|
|
404
|
-
export interface JsonLd {
|
|
405
|
-
'@context'?: string
|
|
406
|
-
'@type': JsonLdType | string
|
|
407
|
-
[key: string]: unknown
|
|
408
|
-
}
|
|
409
|
-
|
|
410
|
-
// ============================================================================
|
|
411
|
-
// Main Metadata Interface
|
|
412
|
-
// ============================================================================
|
|
413
|
-
|
|
414
|
-
export interface Metadata {
|
|
415
|
-
// Base URL for resolving relative URLs
|
|
416
|
-
metadataBase?: string | URL | null
|
|
417
|
-
|
|
418
|
-
// Basic
|
|
419
|
-
title?: Title | null
|
|
420
|
-
description?: string | null
|
|
421
|
-
applicationName?: string | null
|
|
422
|
-
authors?: Author | Author[] | null
|
|
423
|
-
generator?: string | null
|
|
424
|
-
keywords?: string | string[] | null
|
|
425
|
-
referrer?: ReferrerEnum | null
|
|
426
|
-
creator?: string | null
|
|
427
|
-
publisher?: string | null
|
|
428
|
-
robots?: string | Robots | null
|
|
429
|
-
|
|
430
|
-
// Alternate URLs
|
|
431
|
-
alternates?: AlternateURLs | null
|
|
432
|
-
|
|
433
|
-
// Icons
|
|
434
|
-
icons?: IconURL | Icon[] | Icons | null
|
|
435
|
-
|
|
436
|
-
// Manifest
|
|
437
|
-
manifest?: string | URL | null
|
|
438
|
-
|
|
439
|
-
// Open Graph
|
|
440
|
-
openGraph?: OpenGraph | null
|
|
441
|
-
|
|
442
|
-
// Twitter
|
|
443
|
-
twitter?: Twitter | null
|
|
444
|
-
|
|
445
|
-
// Verification
|
|
446
|
-
verification?: Verification | null
|
|
447
|
-
|
|
448
|
-
// Category
|
|
449
|
-
category?: string | null
|
|
450
|
-
classification?: string | null
|
|
451
|
-
|
|
452
|
-
// JSON-LD
|
|
453
|
-
jsonLd?: JsonLd | JsonLd[] | null
|
|
454
|
-
|
|
455
|
-
// === Google SEO 최적화 ===
|
|
456
|
-
|
|
457
|
-
/** Google 전용 메타 설정 */
|
|
458
|
-
google?: GoogleMeta | null
|
|
459
|
-
|
|
460
|
-
/** 전화번호/이메일 자동 감지 설정 */
|
|
461
|
-
formatDetection?: FormatDetection | null
|
|
462
|
-
|
|
463
|
-
/** 리소스 힌트 (성능 최적화) */
|
|
464
|
-
resourceHints?: ResourceHint | null
|
|
465
|
-
|
|
466
|
-
/** Theme Color (브라우저 UI, PWA) */
|
|
467
|
-
themeColor?: string | ThemeColor | ThemeColor[] | null
|
|
468
|
-
|
|
469
|
-
/** Viewport 설정 (기본값: width=device-width, initial-scale=1) */
|
|
470
|
-
viewport?: string | {
|
|
471
|
-
width?: string | number
|
|
472
|
-
height?: string | number
|
|
473
|
-
initialScale?: number
|
|
474
|
-
minimumScale?: number
|
|
475
|
-
maximumScale?: number
|
|
476
|
-
userScalable?: boolean
|
|
477
|
-
viewportFit?: 'auto' | 'cover' | 'contain'
|
|
478
|
-
} | null
|
|
479
|
-
|
|
480
|
-
/** App Links (iOS/Android 앱 연동) */
|
|
481
|
-
appLinks?: AppLinks | null
|
|
482
|
-
|
|
483
|
-
// Other custom meta tags
|
|
484
|
-
other?: Record<string, string | number | (string | number)[]> | null
|
|
485
|
-
}
|
|
486
|
-
|
|
487
|
-
// ============================================================================
|
|
488
|
-
// Resolved Metadata (after processing)
|
|
489
|
-
// ============================================================================
|
|
490
|
-
|
|
491
|
-
export interface ResolvedMetadata {
|
|
492
|
-
metadataBase: URL | null
|
|
493
|
-
title: AbsoluteTemplateString | null
|
|
494
|
-
description: string | null
|
|
495
|
-
applicationName: string | null
|
|
496
|
-
authors: Author[] | null
|
|
497
|
-
generator: string | null
|
|
498
|
-
keywords: string[] | null
|
|
499
|
-
referrer: ReferrerEnum | null
|
|
500
|
-
creator: string | null
|
|
501
|
-
publisher: string | null
|
|
502
|
-
robots: ResolvedRobots | null
|
|
503
|
-
alternates: ResolvedAlternateURLs | null
|
|
504
|
-
icons: ResolvedIcons | null
|
|
505
|
-
manifest: URL | null
|
|
506
|
-
openGraph: ResolvedOpenGraph | null
|
|
507
|
-
twitter: ResolvedTwitter | null
|
|
508
|
-
verification: ResolvedVerification | null
|
|
509
|
-
category: string | null
|
|
510
|
-
classification: string | null
|
|
511
|
-
jsonLd: JsonLd[] | null
|
|
512
|
-
// Google SEO 최적화
|
|
513
|
-
google: GoogleMeta | null
|
|
514
|
-
formatDetection: FormatDetection | null
|
|
515
|
-
resourceHints: ResourceHint | null
|
|
516
|
-
themeColor: ThemeColor[] | null
|
|
517
|
-
viewport: string | null
|
|
518
|
-
appLinks: AppLinks | null
|
|
519
|
-
other: Record<string, string | number | (string | number)[]> | null
|
|
520
|
-
}
|
|
521
|
-
|
|
522
|
-
// ============================================================================
|
|
523
|
-
// Metadata Route Types (sitemap.ts, robots.ts)
|
|
524
|
-
// ============================================================================
|
|
525
|
-
|
|
526
|
-
export interface SitemapEntry {
|
|
527
|
-
url: string
|
|
528
|
-
lastModified?: string | Date
|
|
529
|
-
changeFrequency?: 'always' | 'hourly' | 'daily' | 'weekly' | 'monthly' | 'yearly' | 'never'
|
|
530
|
-
priority?: number
|
|
531
|
-
alternates?: {
|
|
532
|
-
languages?: Languages<string>
|
|
533
|
-
}
|
|
534
|
-
images?: string[]
|
|
535
|
-
}
|
|
536
|
-
|
|
537
|
-
export type Sitemap = SitemapEntry[]
|
|
538
|
-
|
|
539
|
-
export interface RobotsRule {
|
|
540
|
-
userAgent?: string | string[]
|
|
541
|
-
allow?: string | string[]
|
|
542
|
-
disallow?: string | string[]
|
|
543
|
-
crawlDelay?: number
|
|
544
|
-
}
|
|
545
|
-
|
|
546
|
-
export interface RobotsFile {
|
|
547
|
-
rules: RobotsRule | RobotsRule[]
|
|
548
|
-
sitemap?: string | string[]
|
|
549
|
-
host?: string
|
|
550
|
-
}
|
|
551
|
-
|
|
552
|
-
// ============================================================================
|
|
553
|
-
// Metadata Route Namespace
|
|
554
|
-
// ============================================================================
|
|
555
|
-
|
|
556
|
-
export namespace MetadataRoute {
|
|
557
|
-
export type Sitemap = SitemapEntry[]
|
|
558
|
-
export type Robots = RobotsFile
|
|
559
|
-
}
|
|
560
|
-
|
|
561
|
-
// ============================================================================
|
|
562
|
-
// Generator Function Types
|
|
563
|
-
// ============================================================================
|
|
564
|
-
|
|
565
|
-
export interface MetadataParams {
|
|
566
|
-
params: Record<string, string>
|
|
567
|
-
searchParams: Record<string, string>
|
|
568
|
-
}
|
|
569
|
-
|
|
570
|
-
export type GenerateMetadata = (
|
|
571
|
-
props: MetadataParams,
|
|
572
|
-
parent: Promise<ResolvedMetadata>
|
|
573
|
-
) => Metadata | Promise<Metadata>
|
|
574
|
-
|
|
575
|
-
export type MetadataItem = Metadata | GenerateMetadata | null
|
|
1
|
+
/**
|
|
2
|
+
* Mandu SEO - Type Definitions
|
|
3
|
+
*
|
|
4
|
+
* Next.js Metadata API 패턴 기반
|
|
5
|
+
* @see https://nextjs.org/docs/app/api-reference/functions/generate-metadata
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
// ============================================================================
|
|
9
|
+
// Basic Types
|
|
10
|
+
// ============================================================================
|
|
11
|
+
|
|
12
|
+
export type ReferrerEnum =
|
|
13
|
+
| 'no-referrer'
|
|
14
|
+
| 'no-referrer-when-downgrade'
|
|
15
|
+
| 'origin'
|
|
16
|
+
| 'origin-when-cross-origin'
|
|
17
|
+
| 'same-origin'
|
|
18
|
+
| 'strict-origin'
|
|
19
|
+
| 'strict-origin-when-cross-origin'
|
|
20
|
+
| 'unsafe-url'
|
|
21
|
+
|
|
22
|
+
export type ColorSchemeEnum = 'normal' | 'light' | 'dark' | 'light dark' | 'dark light' | 'only light'
|
|
23
|
+
|
|
24
|
+
// ============================================================================
|
|
25
|
+
// Title Types
|
|
26
|
+
// ============================================================================
|
|
27
|
+
|
|
28
|
+
export interface TemplateString {
|
|
29
|
+
default: string
|
|
30
|
+
template?: string // "%s | My Site" - %s is replaced with page title
|
|
31
|
+
absolute?: string // Ignores parent template
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* 단축형 absolute 타이틀 (템플릿 무시)
|
|
36
|
+
*/
|
|
37
|
+
export interface AbsoluteString {
|
|
38
|
+
absolute: string
|
|
39
|
+
template?: string
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
export type Title = string | TemplateString | AbsoluteString
|
|
43
|
+
|
|
44
|
+
export interface AbsoluteTemplateString {
|
|
45
|
+
absolute: string
|
|
46
|
+
template: string | null
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// ============================================================================
|
|
50
|
+
// Author & Creator
|
|
51
|
+
// ============================================================================
|
|
52
|
+
|
|
53
|
+
export interface Author {
|
|
54
|
+
name?: string
|
|
55
|
+
url?: string | URL
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
// ============================================================================
|
|
59
|
+
// Robots
|
|
60
|
+
// ============================================================================
|
|
61
|
+
|
|
62
|
+
export interface Robots {
|
|
63
|
+
index?: boolean
|
|
64
|
+
follow?: boolean
|
|
65
|
+
noarchive?: boolean
|
|
66
|
+
nosnippet?: boolean
|
|
67
|
+
noimageindex?: boolean
|
|
68
|
+
nocache?: boolean
|
|
69
|
+
notranslate?: boolean
|
|
70
|
+
'max-snippet'?: number
|
|
71
|
+
'max-image-preview'?: 'none' | 'standard' | 'large'
|
|
72
|
+
'max-video-preview'?: number
|
|
73
|
+
/** Google 전용 설정 (다르게 적용할 경우) */
|
|
74
|
+
googleBot?: Omit<Robots, 'googleBot'>
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
export interface ResolvedRobots {
|
|
78
|
+
basic: string | null
|
|
79
|
+
googleBot: string | null
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
// ============================================================================
|
|
83
|
+
// Google SEO Specific
|
|
84
|
+
// ============================================================================
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Google 전용 메타 설정
|
|
88
|
+
*/
|
|
89
|
+
export interface GoogleMeta {
|
|
90
|
+
/** Google 사이트링크 검색창 비활성화 */
|
|
91
|
+
nositelinkssearchbox?: boolean
|
|
92
|
+
/** Google 번역 제안 비활성화 */
|
|
93
|
+
notranslate?: boolean
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* 전화번호/이메일 자동 감지 설정
|
|
98
|
+
*/
|
|
99
|
+
export interface FormatDetection {
|
|
100
|
+
telephone?: boolean
|
|
101
|
+
date?: boolean
|
|
102
|
+
address?: boolean
|
|
103
|
+
email?: boolean
|
|
104
|
+
url?: boolean
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* 리소스 힌트 (성능 최적화)
|
|
109
|
+
*/
|
|
110
|
+
export interface ResourceHint {
|
|
111
|
+
/** preconnect URLs (외부 도메인 미리 연결) */
|
|
112
|
+
preconnect?: string[]
|
|
113
|
+
/** dns-prefetch URLs (DNS 미리 조회) */
|
|
114
|
+
dnsPrefetch?: string[]
|
|
115
|
+
/** preload resources */
|
|
116
|
+
preload?: Array<{
|
|
117
|
+
href: string
|
|
118
|
+
as: 'script' | 'style' | 'font' | 'image' | 'fetch'
|
|
119
|
+
type?: string
|
|
120
|
+
crossOrigin?: 'anonymous' | 'use-credentials'
|
|
121
|
+
}>
|
|
122
|
+
/** prefetch resources (다음 페이지용) */
|
|
123
|
+
prefetch?: string[]
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
/**
|
|
127
|
+
* App 관련 메타 (PWA, iOS)
|
|
128
|
+
*/
|
|
129
|
+
export interface AppLinks {
|
|
130
|
+
/** iOS App Store ID */
|
|
131
|
+
iosAppStoreId?: string
|
|
132
|
+
/** iOS App 이름 */
|
|
133
|
+
iosAppName?: string
|
|
134
|
+
/** iOS App URL Scheme */
|
|
135
|
+
iosUrl?: string
|
|
136
|
+
/** Android Package */
|
|
137
|
+
androidPackage?: string
|
|
138
|
+
/** Android App 이름 */
|
|
139
|
+
androidAppName?: string
|
|
140
|
+
/** Android URL */
|
|
141
|
+
androidUrl?: string
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
/**
|
|
145
|
+
* Theme Color 설정
|
|
146
|
+
*/
|
|
147
|
+
export interface ThemeColor {
|
|
148
|
+
color: string
|
|
149
|
+
media?: string // e.g., '(prefers-color-scheme: dark)'
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// ============================================================================
|
|
153
|
+
// Icons
|
|
154
|
+
// ============================================================================
|
|
155
|
+
|
|
156
|
+
export type IconURL = string | URL
|
|
157
|
+
|
|
158
|
+
export interface IconDescriptor {
|
|
159
|
+
url: string | URL
|
|
160
|
+
type?: string
|
|
161
|
+
sizes?: string
|
|
162
|
+
color?: string
|
|
163
|
+
rel?: string
|
|
164
|
+
media?: string
|
|
165
|
+
fetchPriority?: 'auto' | 'high' | 'low'
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
export type Icon = IconURL | IconDescriptor
|
|
169
|
+
|
|
170
|
+
export interface Icons {
|
|
171
|
+
icon?: Icon | Icon[]
|
|
172
|
+
shortcut?: Icon | Icon[]
|
|
173
|
+
apple?: Icon | Icon[]
|
|
174
|
+
other?: IconDescriptor | IconDescriptor[]
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
export interface ResolvedIcons {
|
|
178
|
+
icon: IconDescriptor[]
|
|
179
|
+
apple: IconDescriptor[]
|
|
180
|
+
shortcut: IconDescriptor[]
|
|
181
|
+
other: IconDescriptor[]
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
// ============================================================================
|
|
185
|
+
// Alternate URLs
|
|
186
|
+
// ============================================================================
|
|
187
|
+
|
|
188
|
+
export interface Languages<T> {
|
|
189
|
+
[locale: string]: T
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
export interface AlternateURLs {
|
|
193
|
+
canonical?: string | URL | null
|
|
194
|
+
languages?: Languages<string | URL | null>
|
|
195
|
+
media?: Record<string, string | URL>
|
|
196
|
+
types?: Record<string, string | URL>
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
export interface ResolvedAlternateURLs {
|
|
200
|
+
canonical: URL | null
|
|
201
|
+
languages: Record<string, URL> | null
|
|
202
|
+
media: Record<string, URL> | null
|
|
203
|
+
types: Record<string, URL> | null
|
|
204
|
+
}
|
|
205
|
+
|
|
206
|
+
// ============================================================================
|
|
207
|
+
// Verification
|
|
208
|
+
// ============================================================================
|
|
209
|
+
|
|
210
|
+
export interface Verification {
|
|
211
|
+
google?: string | string[]
|
|
212
|
+
yahoo?: string | string[]
|
|
213
|
+
yandex?: string | string[]
|
|
214
|
+
me?: string | string[]
|
|
215
|
+
other?: Record<string, string | string[]>
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
export interface ResolvedVerification {
|
|
219
|
+
google: string[] | null
|
|
220
|
+
yahoo: string[] | null
|
|
221
|
+
yandex: string[] | null
|
|
222
|
+
me: string[] | null
|
|
223
|
+
other: Record<string, string[]> | null
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
// ============================================================================
|
|
227
|
+
// Open Graph Types
|
|
228
|
+
// ============================================================================
|
|
229
|
+
|
|
230
|
+
export interface OpenGraphImage {
|
|
231
|
+
url: string | URL
|
|
232
|
+
secureUrl?: string | URL
|
|
233
|
+
alt?: string
|
|
234
|
+
type?: string
|
|
235
|
+
width?: string | number
|
|
236
|
+
height?: string | number
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
export interface OpenGraphVideo {
|
|
240
|
+
url: string | URL
|
|
241
|
+
secureUrl?: string | URL
|
|
242
|
+
type?: string
|
|
243
|
+
width?: string | number
|
|
244
|
+
height?: string | number
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
export interface OpenGraphAudio {
|
|
248
|
+
url: string | URL
|
|
249
|
+
secureUrl?: string | URL
|
|
250
|
+
type?: string
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
export interface OpenGraphArticle {
|
|
254
|
+
publishedTime?: string
|
|
255
|
+
modifiedTime?: string
|
|
256
|
+
expirationTime?: string
|
|
257
|
+
authors?: string | string[]
|
|
258
|
+
section?: string
|
|
259
|
+
tags?: string[]
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
export interface OpenGraphProfile {
|
|
263
|
+
firstName?: string
|
|
264
|
+
lastName?: string
|
|
265
|
+
username?: string
|
|
266
|
+
gender?: string
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
export interface OpenGraphBook {
|
|
270
|
+
isbn?: string
|
|
271
|
+
releaseDate?: string
|
|
272
|
+
authors?: string | string[]
|
|
273
|
+
tags?: string[]
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
export type OpenGraphType =
|
|
277
|
+
| 'article'
|
|
278
|
+
| 'book'
|
|
279
|
+
| 'music.song'
|
|
280
|
+
| 'music.album'
|
|
281
|
+
| 'music.playlist'
|
|
282
|
+
| 'music.radio_station'
|
|
283
|
+
| 'profile'
|
|
284
|
+
| 'video.movie'
|
|
285
|
+
| 'video.episode'
|
|
286
|
+
| 'video.tv_show'
|
|
287
|
+
| 'video.other'
|
|
288
|
+
| 'website'
|
|
289
|
+
|
|
290
|
+
export interface OpenGraph {
|
|
291
|
+
type?: OpenGraphType
|
|
292
|
+
url?: string | URL
|
|
293
|
+
title?: string
|
|
294
|
+
description?: string
|
|
295
|
+
siteName?: string
|
|
296
|
+
locale?: string
|
|
297
|
+
images?: string | URL | OpenGraphImage | (string | URL | OpenGraphImage)[]
|
|
298
|
+
videos?: string | URL | OpenGraphVideo | (string | URL | OpenGraphVideo)[]
|
|
299
|
+
audio?: string | URL | OpenGraphAudio | (string | URL | OpenGraphAudio)[]
|
|
300
|
+
determiner?: 'a' | 'an' | 'the' | 'auto' | ''
|
|
301
|
+
// Type-specific
|
|
302
|
+
article?: OpenGraphArticle
|
|
303
|
+
profile?: OpenGraphProfile
|
|
304
|
+
book?: OpenGraphBook
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
export interface ResolvedOpenGraph {
|
|
308
|
+
type: OpenGraphType
|
|
309
|
+
url: URL | null
|
|
310
|
+
title: string | null
|
|
311
|
+
description: string | null
|
|
312
|
+
siteName: string | null
|
|
313
|
+
locale: string | null
|
|
314
|
+
images: OpenGraphImage[] | null
|
|
315
|
+
videos: OpenGraphVideo[] | null
|
|
316
|
+
audio: OpenGraphAudio[] | null
|
|
317
|
+
determiner: string | null
|
|
318
|
+
article: OpenGraphArticle | null
|
|
319
|
+
profile: OpenGraphProfile | null
|
|
320
|
+
book: OpenGraphBook | null
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
// ============================================================================
|
|
324
|
+
// Twitter Types
|
|
325
|
+
// ============================================================================
|
|
326
|
+
|
|
327
|
+
export type TwitterCardType = 'summary' | 'summary_large_image' | 'app' | 'player'
|
|
328
|
+
|
|
329
|
+
export interface TwitterImage {
|
|
330
|
+
url: string | URL
|
|
331
|
+
alt?: string
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
export interface TwitterPlayer {
|
|
335
|
+
playerUrl: string | URL
|
|
336
|
+
streamUrl?: string | URL
|
|
337
|
+
width: number
|
|
338
|
+
height: number
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
export interface TwitterApp {
|
|
342
|
+
id: {
|
|
343
|
+
iphone?: string | number
|
|
344
|
+
ipad?: string | number
|
|
345
|
+
googleplay?: string
|
|
346
|
+
}
|
|
347
|
+
url?: {
|
|
348
|
+
iphone?: string | URL
|
|
349
|
+
ipad?: string | URL
|
|
350
|
+
googleplay?: string | URL
|
|
351
|
+
}
|
|
352
|
+
name?: string
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
export interface Twitter {
|
|
356
|
+
card?: TwitterCardType
|
|
357
|
+
site?: string
|
|
358
|
+
siteId?: string
|
|
359
|
+
creator?: string
|
|
360
|
+
creatorId?: string
|
|
361
|
+
title?: string
|
|
362
|
+
description?: string
|
|
363
|
+
images?: string | URL | TwitterImage | (string | URL | TwitterImage)[]
|
|
364
|
+
// Player card
|
|
365
|
+
players?: TwitterPlayer | TwitterPlayer[]
|
|
366
|
+
// App card
|
|
367
|
+
app?: TwitterApp
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
export interface ResolvedTwitter {
|
|
371
|
+
card: TwitterCardType
|
|
372
|
+
site: string | null
|
|
373
|
+
siteId: string | null
|
|
374
|
+
creator: string | null
|
|
375
|
+
creatorId: string | null
|
|
376
|
+
title: string | null
|
|
377
|
+
description: string | null
|
|
378
|
+
images: TwitterImage[] | null
|
|
379
|
+
players: TwitterPlayer[] | null
|
|
380
|
+
app: TwitterApp | null
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
// ============================================================================
|
|
384
|
+
// JSON-LD Types
|
|
385
|
+
// ============================================================================
|
|
386
|
+
|
|
387
|
+
export type JsonLdType =
|
|
388
|
+
| 'Article'
|
|
389
|
+
| 'BlogPosting'
|
|
390
|
+
| 'NewsArticle'
|
|
391
|
+
| 'WebSite'
|
|
392
|
+
| 'WebPage'
|
|
393
|
+
| 'Organization'
|
|
394
|
+
| 'Person'
|
|
395
|
+
| 'Product'
|
|
396
|
+
| 'BreadcrumbList'
|
|
397
|
+
| 'FAQPage'
|
|
398
|
+
| 'HowTo'
|
|
399
|
+
| 'Recipe'
|
|
400
|
+
| 'Event'
|
|
401
|
+
| 'LocalBusiness'
|
|
402
|
+
| 'SoftwareApplication'
|
|
403
|
+
|
|
404
|
+
export interface JsonLd {
|
|
405
|
+
'@context'?: string
|
|
406
|
+
'@type': JsonLdType | string
|
|
407
|
+
[key: string]: unknown
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
// ============================================================================
|
|
411
|
+
// Main Metadata Interface
|
|
412
|
+
// ============================================================================
|
|
413
|
+
|
|
414
|
+
export interface Metadata {
|
|
415
|
+
// Base URL for resolving relative URLs
|
|
416
|
+
metadataBase?: string | URL | null
|
|
417
|
+
|
|
418
|
+
// Basic
|
|
419
|
+
title?: Title | null
|
|
420
|
+
description?: string | null
|
|
421
|
+
applicationName?: string | null
|
|
422
|
+
authors?: Author | Author[] | null
|
|
423
|
+
generator?: string | null
|
|
424
|
+
keywords?: string | string[] | null
|
|
425
|
+
referrer?: ReferrerEnum | null
|
|
426
|
+
creator?: string | null
|
|
427
|
+
publisher?: string | null
|
|
428
|
+
robots?: string | Robots | null
|
|
429
|
+
|
|
430
|
+
// Alternate URLs
|
|
431
|
+
alternates?: AlternateURLs | null
|
|
432
|
+
|
|
433
|
+
// Icons
|
|
434
|
+
icons?: IconURL | Icon[] | Icons | null
|
|
435
|
+
|
|
436
|
+
// Manifest
|
|
437
|
+
manifest?: string | URL | null
|
|
438
|
+
|
|
439
|
+
// Open Graph
|
|
440
|
+
openGraph?: OpenGraph | null
|
|
441
|
+
|
|
442
|
+
// Twitter
|
|
443
|
+
twitter?: Twitter | null
|
|
444
|
+
|
|
445
|
+
// Verification
|
|
446
|
+
verification?: Verification | null
|
|
447
|
+
|
|
448
|
+
// Category
|
|
449
|
+
category?: string | null
|
|
450
|
+
classification?: string | null
|
|
451
|
+
|
|
452
|
+
// JSON-LD
|
|
453
|
+
jsonLd?: JsonLd | JsonLd[] | null
|
|
454
|
+
|
|
455
|
+
// === Google SEO 최적화 ===
|
|
456
|
+
|
|
457
|
+
/** Google 전용 메타 설정 */
|
|
458
|
+
google?: GoogleMeta | null
|
|
459
|
+
|
|
460
|
+
/** 전화번호/이메일 자동 감지 설정 */
|
|
461
|
+
formatDetection?: FormatDetection | null
|
|
462
|
+
|
|
463
|
+
/** 리소스 힌트 (성능 최적화) */
|
|
464
|
+
resourceHints?: ResourceHint | null
|
|
465
|
+
|
|
466
|
+
/** Theme Color (브라우저 UI, PWA) */
|
|
467
|
+
themeColor?: string | ThemeColor | ThemeColor[] | null
|
|
468
|
+
|
|
469
|
+
/** Viewport 설정 (기본값: width=device-width, initial-scale=1) */
|
|
470
|
+
viewport?: string | {
|
|
471
|
+
width?: string | number
|
|
472
|
+
height?: string | number
|
|
473
|
+
initialScale?: number
|
|
474
|
+
minimumScale?: number
|
|
475
|
+
maximumScale?: number
|
|
476
|
+
userScalable?: boolean
|
|
477
|
+
viewportFit?: 'auto' | 'cover' | 'contain'
|
|
478
|
+
} | null
|
|
479
|
+
|
|
480
|
+
/** App Links (iOS/Android 앱 연동) */
|
|
481
|
+
appLinks?: AppLinks | null
|
|
482
|
+
|
|
483
|
+
// Other custom meta tags
|
|
484
|
+
other?: Record<string, string | number | (string | number)[]> | null
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
// ============================================================================
|
|
488
|
+
// Resolved Metadata (after processing)
|
|
489
|
+
// ============================================================================
|
|
490
|
+
|
|
491
|
+
export interface ResolvedMetadata {
|
|
492
|
+
metadataBase: URL | null
|
|
493
|
+
title: AbsoluteTemplateString | null
|
|
494
|
+
description: string | null
|
|
495
|
+
applicationName: string | null
|
|
496
|
+
authors: Author[] | null
|
|
497
|
+
generator: string | null
|
|
498
|
+
keywords: string[] | null
|
|
499
|
+
referrer: ReferrerEnum | null
|
|
500
|
+
creator: string | null
|
|
501
|
+
publisher: string | null
|
|
502
|
+
robots: ResolvedRobots | null
|
|
503
|
+
alternates: ResolvedAlternateURLs | null
|
|
504
|
+
icons: ResolvedIcons | null
|
|
505
|
+
manifest: URL | null
|
|
506
|
+
openGraph: ResolvedOpenGraph | null
|
|
507
|
+
twitter: ResolvedTwitter | null
|
|
508
|
+
verification: ResolvedVerification | null
|
|
509
|
+
category: string | null
|
|
510
|
+
classification: string | null
|
|
511
|
+
jsonLd: JsonLd[] | null
|
|
512
|
+
// Google SEO 최적화
|
|
513
|
+
google: GoogleMeta | null
|
|
514
|
+
formatDetection: FormatDetection | null
|
|
515
|
+
resourceHints: ResourceHint | null
|
|
516
|
+
themeColor: ThemeColor[] | null
|
|
517
|
+
viewport: string | null
|
|
518
|
+
appLinks: AppLinks | null
|
|
519
|
+
other: Record<string, string | number | (string | number)[]> | null
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
// ============================================================================
|
|
523
|
+
// Metadata Route Types (sitemap.ts, robots.ts)
|
|
524
|
+
// ============================================================================
|
|
525
|
+
|
|
526
|
+
export interface SitemapEntry {
|
|
527
|
+
url: string
|
|
528
|
+
lastModified?: string | Date
|
|
529
|
+
changeFrequency?: 'always' | 'hourly' | 'daily' | 'weekly' | 'monthly' | 'yearly' | 'never'
|
|
530
|
+
priority?: number
|
|
531
|
+
alternates?: {
|
|
532
|
+
languages?: Languages<string>
|
|
533
|
+
}
|
|
534
|
+
images?: string[]
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
export type Sitemap = SitemapEntry[]
|
|
538
|
+
|
|
539
|
+
export interface RobotsRule {
|
|
540
|
+
userAgent?: string | string[]
|
|
541
|
+
allow?: string | string[]
|
|
542
|
+
disallow?: string | string[]
|
|
543
|
+
crawlDelay?: number
|
|
544
|
+
}
|
|
545
|
+
|
|
546
|
+
export interface RobotsFile {
|
|
547
|
+
rules: RobotsRule | RobotsRule[]
|
|
548
|
+
sitemap?: string | string[]
|
|
549
|
+
host?: string
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
// ============================================================================
|
|
553
|
+
// Metadata Route Namespace
|
|
554
|
+
// ============================================================================
|
|
555
|
+
|
|
556
|
+
export namespace MetadataRoute {
|
|
557
|
+
export type Sitemap = SitemapEntry[]
|
|
558
|
+
export type Robots = RobotsFile
|
|
559
|
+
}
|
|
560
|
+
|
|
561
|
+
// ============================================================================
|
|
562
|
+
// Generator Function Types
|
|
563
|
+
// ============================================================================
|
|
564
|
+
|
|
565
|
+
export interface MetadataParams {
|
|
566
|
+
params: Record<string, string>
|
|
567
|
+
searchParams: Record<string, string>
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
export type GenerateMetadata = (
|
|
571
|
+
props: MetadataParams,
|
|
572
|
+
parent: Promise<ResolvedMetadata>
|
|
573
|
+
) => Metadata | Promise<Metadata>
|
|
574
|
+
|
|
575
|
+
export type MetadataItem = Metadata | GenerateMetadata | null
|