@m1kapp/kit 0.0.15 → 0.0.16

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/dist/seo.d.mts ADDED
@@ -0,0 +1,260 @@
1
+ interface CreateMetadataOptions {
2
+ title: string;
3
+ description: string;
4
+ url: string;
5
+ /** Site name shown in og:site_name */
6
+ siteName?: string;
7
+ /** Absolute URL to OG image */
8
+ image?: string;
9
+ /** "website" | "article" — default: "website" */
10
+ type?: "website" | "article";
11
+ /** Article-specific fields */
12
+ article?: {
13
+ publishedTime?: string;
14
+ modifiedTime?: string;
15
+ authors?: string[];
16
+ tags?: string[];
17
+ };
18
+ /** Canonical URL override (defaults to url) */
19
+ canonical?: string;
20
+ /** Prevent indexing */
21
+ noIndex?: boolean;
22
+ /** Twitter card type — default: "summary_large_image" */
23
+ twitterCard?: "summary" | "summary_large_image";
24
+ /** Twitter handle e.g. "@m1kapp" */
25
+ twitterSite?: string;
26
+ keywords?: string[];
27
+ }
28
+ /**
29
+ * Generates a Next.js-compatible Metadata object with full SEO coverage.
30
+ *
31
+ * @example
32
+ * // app/layout.tsx
33
+ * export const metadata = createMetadata({
34
+ * title: "My App",
35
+ * description: "앱 설명",
36
+ * url: "https://myapp.com",
37
+ * siteName: "My App",
38
+ * image: "https://myapp.com/og.png",
39
+ * });
40
+ */
41
+ declare function createMetadata({ title, description, url, siteName, image, type, article, canonical, noIndex, twitterCard, twitterSite, keywords, }: CreateMetadataOptions): {
42
+ metadataBase: URL;
43
+ alternates: {
44
+ canonical: string;
45
+ };
46
+ robots: {
47
+ index: boolean;
48
+ follow: boolean;
49
+ googleBot?: undefined;
50
+ } | {
51
+ index: boolean;
52
+ follow: boolean;
53
+ googleBot: {
54
+ index: boolean;
55
+ follow: boolean;
56
+ };
57
+ };
58
+ openGraph: {
59
+ publishedTime?: string | undefined;
60
+ modifiedTime?: string | undefined;
61
+ authors?: string[] | undefined;
62
+ tags?: string[] | undefined;
63
+ images?: {
64
+ url: string;
65
+ width: number;
66
+ height: number;
67
+ }[] | undefined;
68
+ type: "website" | "article";
69
+ siteName?: string | undefined;
70
+ title: string;
71
+ description: string;
72
+ url: string;
73
+ };
74
+ twitter: {
75
+ site?: string | undefined;
76
+ images?: string[] | undefined;
77
+ card: "summary" | "summary_large_image";
78
+ title: string;
79
+ description: string;
80
+ };
81
+ keywords?: string[] | undefined;
82
+ title: string;
83
+ description: string;
84
+ };
85
+ /**
86
+ * Generates a title template for use with Next.js metadata.
87
+ *
88
+ * @example
89
+ * export const metadata = { title: titleTemplate("My App") };
90
+ * // child pages: export const metadata = { title: "Page Name" };
91
+ * // renders as: "Page Name | My App"
92
+ */
93
+ declare function titleTemplate(siteName: string, separator?: string): {
94
+ default: string;
95
+ template: string;
96
+ };
97
+
98
+ /**
99
+ * JSON-LD structured data helpers.
100
+ * Use with Next.js script tag:
101
+ *
102
+ * @example
103
+ * <script
104
+ * type="application/ld+json"
105
+ * dangerouslySetInnerHTML={{ __html: jsonLd.website({ name: "My App", url: "https://myapp.com" }) }}
106
+ * />
107
+ */
108
+ declare const jsonLd: {
109
+ /** WebSite — site name + sitelinks searchbox */
110
+ website({ name, url, description, searchUrl, }: {
111
+ name: string;
112
+ url: string;
113
+ description?: string;
114
+ /** URL template for sitelinks searchbox e.g. "https://myapp.com/search?q={search_term_string}" */
115
+ searchUrl?: string;
116
+ }): string;
117
+ /** Article / BlogPosting */
118
+ article({ title, description, url, image, datePublished, dateModified, authorName, authorUrl, publisherName, publisherLogo, }: {
119
+ title: string;
120
+ description?: string;
121
+ url: string;
122
+ image?: string;
123
+ datePublished: string;
124
+ dateModified?: string;
125
+ authorName: string;
126
+ authorUrl?: string;
127
+ publisherName: string;
128
+ publisherLogo?: string;
129
+ }): string;
130
+ /** BreadcrumbList */
131
+ breadcrumb(items: {
132
+ name: string;
133
+ url: string;
134
+ }[]): string;
135
+ /** Product */
136
+ product({ name, description, image, url, price, currency, availability, ratingValue, reviewCount, }: {
137
+ name: string;
138
+ description?: string;
139
+ image?: string;
140
+ url: string;
141
+ price: number;
142
+ currency?: string;
143
+ availability?: "InStock" | "OutOfStock" | "PreOrder";
144
+ ratingValue?: number;
145
+ reviewCount?: number;
146
+ }): string;
147
+ /** Organization */
148
+ organization({ name, url, logo, sameAs, }: {
149
+ name: string;
150
+ url: string;
151
+ logo?: string;
152
+ /** Social profile URLs */
153
+ sameAs?: string[];
154
+ }): string;
155
+ /** FAQPage */
156
+ faq(items: {
157
+ question: string;
158
+ answer: string;
159
+ }[]): string;
160
+ };
161
+
162
+ type ChangeFreq = "always" | "hourly" | "daily" | "weekly" | "monthly" | "yearly" | "never";
163
+ interface SitemapEntry {
164
+ url: string;
165
+ lastModified?: string | Date;
166
+ changeFrequency?: ChangeFreq;
167
+ /** 0.0 ~ 1.0 */
168
+ priority?: number;
169
+ }
170
+ /**
171
+ * Generates a sitemap.xml string.
172
+ *
173
+ * @example
174
+ * // app/sitemap.xml/route.ts (Next.js Route Handler)
175
+ * export function GET() {
176
+ * const xml = createSitemap([
177
+ * { url: "https://myapp.com", priority: 1.0 },
178
+ * { url: "https://myapp.com/about", changeFrequency: "monthly" },
179
+ * ]);
180
+ * return new Response(xml, { headers: { "Content-Type": "application/xml" } });
181
+ * }
182
+ */
183
+ declare function createSitemap(entries: SitemapEntry[]): string;
184
+ /**
185
+ * Next.js App Router 방식 — MetadataRoute.Sitemap 형태로 반환.
186
+ *
187
+ * @example
188
+ * // app/sitemap.ts
189
+ * export default function sitemap() {
190
+ * return nextSitemap("https://myapp.com", [
191
+ * { path: "/", priority: 1 },
192
+ * { path: "/about", changeFrequency: "monthly" },
193
+ * ]);
194
+ * }
195
+ */
196
+ declare function nextSitemap(baseUrl: string, pages: {
197
+ path: string;
198
+ lastModified?: string | Date;
199
+ changeFrequency?: ChangeFreq;
200
+ priority?: number;
201
+ }[]): {
202
+ lastModified?: string | Date;
203
+ changeFrequency?: ChangeFreq;
204
+ priority?: number;
205
+ url: string;
206
+ }[];
207
+
208
+ interface RobotsOptions {
209
+ /** Default rules applied to all bots (User-agent: *) */
210
+ allow?: string[];
211
+ disallow?: string[];
212
+ /** Absolute URL to sitemap */
213
+ sitemap?: string | string[];
214
+ /** Per-bot overrides */
215
+ agents?: {
216
+ userAgent: string;
217
+ allow?: string[];
218
+ disallow?: string[];
219
+ }[];
220
+ }
221
+ /**
222
+ * Generates a robots.txt string.
223
+ *
224
+ * @example
225
+ * // app/robots.txt/route.ts
226
+ * export function GET() {
227
+ * const txt = createRobots({
228
+ * disallow: ["/admin", "/api"],
229
+ * sitemap: "https://myapp.com/sitemap.xml",
230
+ * });
231
+ * return new Response(txt, { headers: { "Content-Type": "text/plain" } });
232
+ * }
233
+ */
234
+ declare function createRobots({ allow, disallow, sitemap, agents, }?: RobotsOptions): string;
235
+ /**
236
+ * Next.js App Router 방식 — MetadataRoute.Robots 형태로 반환.
237
+ *
238
+ * @example
239
+ * // app/robots.ts
240
+ * export default function robots() {
241
+ * return nextRobots({
242
+ * sitemap: "https://myapp.com/sitemap.xml",
243
+ * disallow: ["/admin"],
244
+ * });
245
+ * }
246
+ */
247
+ declare function nextRobots({ allow, disallow, sitemap, }: {
248
+ allow?: string[];
249
+ disallow?: string[];
250
+ sitemap?: string | string[];
251
+ }): {
252
+ sitemap?: string | string[] | undefined;
253
+ rules: {
254
+ userAgent: string;
255
+ allow: string[];
256
+ disallow: string[];
257
+ };
258
+ };
259
+
260
+ export { type ChangeFreq, type CreateMetadataOptions, type RobotsOptions, type SitemapEntry, createMetadata, createRobots, createSitemap, jsonLd, nextRobots, nextSitemap, titleTemplate };
package/dist/seo.d.ts ADDED
@@ -0,0 +1,260 @@
1
+ interface CreateMetadataOptions {
2
+ title: string;
3
+ description: string;
4
+ url: string;
5
+ /** Site name shown in og:site_name */
6
+ siteName?: string;
7
+ /** Absolute URL to OG image */
8
+ image?: string;
9
+ /** "website" | "article" — default: "website" */
10
+ type?: "website" | "article";
11
+ /** Article-specific fields */
12
+ article?: {
13
+ publishedTime?: string;
14
+ modifiedTime?: string;
15
+ authors?: string[];
16
+ tags?: string[];
17
+ };
18
+ /** Canonical URL override (defaults to url) */
19
+ canonical?: string;
20
+ /** Prevent indexing */
21
+ noIndex?: boolean;
22
+ /** Twitter card type — default: "summary_large_image" */
23
+ twitterCard?: "summary" | "summary_large_image";
24
+ /** Twitter handle e.g. "@m1kapp" */
25
+ twitterSite?: string;
26
+ keywords?: string[];
27
+ }
28
+ /**
29
+ * Generates a Next.js-compatible Metadata object with full SEO coverage.
30
+ *
31
+ * @example
32
+ * // app/layout.tsx
33
+ * export const metadata = createMetadata({
34
+ * title: "My App",
35
+ * description: "앱 설명",
36
+ * url: "https://myapp.com",
37
+ * siteName: "My App",
38
+ * image: "https://myapp.com/og.png",
39
+ * });
40
+ */
41
+ declare function createMetadata({ title, description, url, siteName, image, type, article, canonical, noIndex, twitterCard, twitterSite, keywords, }: CreateMetadataOptions): {
42
+ metadataBase: URL;
43
+ alternates: {
44
+ canonical: string;
45
+ };
46
+ robots: {
47
+ index: boolean;
48
+ follow: boolean;
49
+ googleBot?: undefined;
50
+ } | {
51
+ index: boolean;
52
+ follow: boolean;
53
+ googleBot: {
54
+ index: boolean;
55
+ follow: boolean;
56
+ };
57
+ };
58
+ openGraph: {
59
+ publishedTime?: string | undefined;
60
+ modifiedTime?: string | undefined;
61
+ authors?: string[] | undefined;
62
+ tags?: string[] | undefined;
63
+ images?: {
64
+ url: string;
65
+ width: number;
66
+ height: number;
67
+ }[] | undefined;
68
+ type: "website" | "article";
69
+ siteName?: string | undefined;
70
+ title: string;
71
+ description: string;
72
+ url: string;
73
+ };
74
+ twitter: {
75
+ site?: string | undefined;
76
+ images?: string[] | undefined;
77
+ card: "summary" | "summary_large_image";
78
+ title: string;
79
+ description: string;
80
+ };
81
+ keywords?: string[] | undefined;
82
+ title: string;
83
+ description: string;
84
+ };
85
+ /**
86
+ * Generates a title template for use with Next.js metadata.
87
+ *
88
+ * @example
89
+ * export const metadata = { title: titleTemplate("My App") };
90
+ * // child pages: export const metadata = { title: "Page Name" };
91
+ * // renders as: "Page Name | My App"
92
+ */
93
+ declare function titleTemplate(siteName: string, separator?: string): {
94
+ default: string;
95
+ template: string;
96
+ };
97
+
98
+ /**
99
+ * JSON-LD structured data helpers.
100
+ * Use with Next.js script tag:
101
+ *
102
+ * @example
103
+ * <script
104
+ * type="application/ld+json"
105
+ * dangerouslySetInnerHTML={{ __html: jsonLd.website({ name: "My App", url: "https://myapp.com" }) }}
106
+ * />
107
+ */
108
+ declare const jsonLd: {
109
+ /** WebSite — site name + sitelinks searchbox */
110
+ website({ name, url, description, searchUrl, }: {
111
+ name: string;
112
+ url: string;
113
+ description?: string;
114
+ /** URL template for sitelinks searchbox e.g. "https://myapp.com/search?q={search_term_string}" */
115
+ searchUrl?: string;
116
+ }): string;
117
+ /** Article / BlogPosting */
118
+ article({ title, description, url, image, datePublished, dateModified, authorName, authorUrl, publisherName, publisherLogo, }: {
119
+ title: string;
120
+ description?: string;
121
+ url: string;
122
+ image?: string;
123
+ datePublished: string;
124
+ dateModified?: string;
125
+ authorName: string;
126
+ authorUrl?: string;
127
+ publisherName: string;
128
+ publisherLogo?: string;
129
+ }): string;
130
+ /** BreadcrumbList */
131
+ breadcrumb(items: {
132
+ name: string;
133
+ url: string;
134
+ }[]): string;
135
+ /** Product */
136
+ product({ name, description, image, url, price, currency, availability, ratingValue, reviewCount, }: {
137
+ name: string;
138
+ description?: string;
139
+ image?: string;
140
+ url: string;
141
+ price: number;
142
+ currency?: string;
143
+ availability?: "InStock" | "OutOfStock" | "PreOrder";
144
+ ratingValue?: number;
145
+ reviewCount?: number;
146
+ }): string;
147
+ /** Organization */
148
+ organization({ name, url, logo, sameAs, }: {
149
+ name: string;
150
+ url: string;
151
+ logo?: string;
152
+ /** Social profile URLs */
153
+ sameAs?: string[];
154
+ }): string;
155
+ /** FAQPage */
156
+ faq(items: {
157
+ question: string;
158
+ answer: string;
159
+ }[]): string;
160
+ };
161
+
162
+ type ChangeFreq = "always" | "hourly" | "daily" | "weekly" | "monthly" | "yearly" | "never";
163
+ interface SitemapEntry {
164
+ url: string;
165
+ lastModified?: string | Date;
166
+ changeFrequency?: ChangeFreq;
167
+ /** 0.0 ~ 1.0 */
168
+ priority?: number;
169
+ }
170
+ /**
171
+ * Generates a sitemap.xml string.
172
+ *
173
+ * @example
174
+ * // app/sitemap.xml/route.ts (Next.js Route Handler)
175
+ * export function GET() {
176
+ * const xml = createSitemap([
177
+ * { url: "https://myapp.com", priority: 1.0 },
178
+ * { url: "https://myapp.com/about", changeFrequency: "monthly" },
179
+ * ]);
180
+ * return new Response(xml, { headers: { "Content-Type": "application/xml" } });
181
+ * }
182
+ */
183
+ declare function createSitemap(entries: SitemapEntry[]): string;
184
+ /**
185
+ * Next.js App Router 방식 — MetadataRoute.Sitemap 형태로 반환.
186
+ *
187
+ * @example
188
+ * // app/sitemap.ts
189
+ * export default function sitemap() {
190
+ * return nextSitemap("https://myapp.com", [
191
+ * { path: "/", priority: 1 },
192
+ * { path: "/about", changeFrequency: "monthly" },
193
+ * ]);
194
+ * }
195
+ */
196
+ declare function nextSitemap(baseUrl: string, pages: {
197
+ path: string;
198
+ lastModified?: string | Date;
199
+ changeFrequency?: ChangeFreq;
200
+ priority?: number;
201
+ }[]): {
202
+ lastModified?: string | Date;
203
+ changeFrequency?: ChangeFreq;
204
+ priority?: number;
205
+ url: string;
206
+ }[];
207
+
208
+ interface RobotsOptions {
209
+ /** Default rules applied to all bots (User-agent: *) */
210
+ allow?: string[];
211
+ disallow?: string[];
212
+ /** Absolute URL to sitemap */
213
+ sitemap?: string | string[];
214
+ /** Per-bot overrides */
215
+ agents?: {
216
+ userAgent: string;
217
+ allow?: string[];
218
+ disallow?: string[];
219
+ }[];
220
+ }
221
+ /**
222
+ * Generates a robots.txt string.
223
+ *
224
+ * @example
225
+ * // app/robots.txt/route.ts
226
+ * export function GET() {
227
+ * const txt = createRobots({
228
+ * disallow: ["/admin", "/api"],
229
+ * sitemap: "https://myapp.com/sitemap.xml",
230
+ * });
231
+ * return new Response(txt, { headers: { "Content-Type": "text/plain" } });
232
+ * }
233
+ */
234
+ declare function createRobots({ allow, disallow, sitemap, agents, }?: RobotsOptions): string;
235
+ /**
236
+ * Next.js App Router 방식 — MetadataRoute.Robots 형태로 반환.
237
+ *
238
+ * @example
239
+ * // app/robots.ts
240
+ * export default function robots() {
241
+ * return nextRobots({
242
+ * sitemap: "https://myapp.com/sitemap.xml",
243
+ * disallow: ["/admin"],
244
+ * });
245
+ * }
246
+ */
247
+ declare function nextRobots({ allow, disallow, sitemap, }: {
248
+ allow?: string[];
249
+ disallow?: string[];
250
+ sitemap?: string | string[];
251
+ }): {
252
+ sitemap?: string | string[] | undefined;
253
+ rules: {
254
+ userAgent: string;
255
+ allow: string[];
256
+ disallow: string[];
257
+ };
258
+ };
259
+
260
+ export { type ChangeFreq, type CreateMetadataOptions, type RobotsOptions, type SitemapEntry, createMetadata, createRobots, createSitemap, jsonLd, nextRobots, nextSitemap, titleTemplate };
package/dist/seo.js ADDED
@@ -0,0 +1,4 @@
1
+ "use strict";var u=Object.defineProperty;var $=Object.getOwnPropertyDescriptor;var O=Object.getOwnPropertyNames;var A=Object.prototype.hasOwnProperty;var q=(e,t)=>{for(var r in t)u(e,r,{get:t[r],enumerable:!0})},C=(e,t,r,i)=>{if(t&&typeof t=="object"||typeof t=="function")for(let n of O(t))!A.call(e,n)&&n!==r&&u(e,n,{get:()=>t[n],enumerable:!(i=$(t,n))||i.enumerable});return e};var R=e=>C(u({},"__esModule",{value:!0}),e);var T={};q(T,{createMetadata:()=>h,createRobots:()=>w,createSitemap:()=>d,jsonLd:()=>y,nextRobots:()=>b,nextSitemap:()=>x,titleTemplate:()=>f});module.exports=R(T);function h({title:e,description:t,url:r,siteName:i,image:n,type:o="website",article:s,canonical:a,noIndex:l=!1,twitterCard:p="summary_large_image",twitterSite:m,keywords:c}){let S=a??r;return{title:e,description:t,...c?.length?{keywords:c}:{},metadataBase:new URL(r),alternates:{canonical:S},robots:l?{index:!1,follow:!1}:{index:!0,follow:!0,googleBot:{index:!0,follow:!0}},openGraph:{title:e,description:t,url:r,...i?{siteName:i}:{},type:o,...n?{images:[{url:n,width:1200,height:630}]}:{},...o==="article"&&s?{publishedTime:s.publishedTime,modifiedTime:s.modifiedTime,authors:s.authors,tags:s.tags}:{}},twitter:{card:p,title:e,description:t,...n?{images:[n]}:{},...m?{site:m}:{}}}}function f(e,t="|"){return{default:e,template:`%s ${t} ${e}`}}function g(e){return JSON.stringify(e)}var y={website({name:e,url:t,description:r,searchUrl:i}){return g({"@context":"https://schema.org","@type":"WebSite",name:e,url:t,...r?{description:r}:{},...i?{potentialAction:{"@type":"SearchAction",target:{"@type":"EntryPoint",urlTemplate:i},"query-input":"required name=search_term_string"}}:{}})},article({title:e,description:t,url:r,image:i,datePublished:n,dateModified:o,authorName:s,authorUrl:a,publisherName:l,publisherLogo:p}){return g({"@context":"https://schema.org","@type":"Article",headline:e,...t?{description:t}:{},url:r,...i?{image:i}:{},datePublished:n,dateModified:o??n,author:{"@type":"Person",name:s,...a?{url:a}:{}},publisher:{"@type":"Organization",name:l,...p?{logo:{"@type":"ImageObject",url:p}}:{}}})},breadcrumb(e){return g({"@context":"https://schema.org","@type":"BreadcrumbList",itemListElement:e.map((t,r)=>({"@type":"ListItem",position:r+1,name:t.name,item:t.url}))})},product({name:e,description:t,image:r,url:i,price:n,currency:o="KRW",availability:s="InStock",ratingValue:a,reviewCount:l}){return g({"@context":"https://schema.org","@type":"Product",name:e,...t?{description:t}:{},...r?{image:r}:{},url:i,offers:{"@type":"Offer",price:n,priceCurrency:o,availability:`https://schema.org/${s}`,url:i},...a!=null?{aggregateRating:{"@type":"AggregateRating",ratingValue:a,reviewCount:l??1}}:{}})},organization({name:e,url:t,logo:r,sameAs:i}){return g({"@context":"https://schema.org","@type":"Organization",name:e,url:t,...r?{logo:r}:{},...i?.length?{sameAs:i}:{}})},faq(e){return g({"@context":"https://schema.org","@type":"FAQPage",mainEntity:e.map(t=>({"@type":"Question",name:t.question,acceptedAnswer:{"@type":"Answer",text:t.answer}}))})}};function d(e){return['<?xml version="1.0" encoding="UTF-8"?>','<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">',...e.map(({url:r,lastModified:i,changeFrequency:n,priority:o})=>{let s=i?typeof i=="string"?i:i.toISOString().split("T")[0]:null;return[" <url>",` <loc>${r}</loc>`,s?` <lastmod>${s}</lastmod>`:null,n?` <changefreq>${n}</changefreq>`:null,o!=null?` <priority>${o.toFixed(1)}</priority>`:null," </url>"].filter(Boolean).join(`
2
+ `)}),"</urlset>"].join(`
3
+ `)}function x(e,t){return t.map(({path:r,...i})=>({url:`${e.replace(/\/$/,"")}${r}`,...i}))}function w({allow:e=["/"],disallow:t=[],sitemap:r,agents:i=[]}={}){let n=[];n.push("User-agent: *");for(let s of e)n.push(`Allow: ${s}`);for(let s of t)n.push(`Disallow: ${s}`);for(let s of i){n.push(""),n.push(`User-agent: ${s.userAgent}`);for(let a of s.allow??[])n.push(`Allow: ${a}`);for(let a of s.disallow??[])n.push(`Disallow: ${a}`)}let o=r?Array.isArray(r)?r:[r]:[];for(let s of o)n.push(""),n.push(`Sitemap: ${s}`);return n.join(`
4
+ `)}function b({allow:e=["/"],disallow:t=[],sitemap:r}){return{rules:{userAgent:"*",allow:e,disallow:t},...r?{sitemap:r}:{}}}0&&(module.exports={createMetadata,createRobots,createSitemap,jsonLd,nextRobots,nextSitemap,titleTemplate});
package/dist/seo.mjs ADDED
@@ -0,0 +1,4 @@
1
+ function h({title:t,description:e,url:r,siteName:n,image:i,type:o="website",article:s,canonical:a,noIndex:l=!1,twitterCard:p="summary_large_image",twitterSite:u,keywords:m}){let c=a??r;return{title:t,description:e,...m?.length?{keywords:m}:{},metadataBase:new URL(r),alternates:{canonical:c},robots:l?{index:!1,follow:!1}:{index:!0,follow:!0,googleBot:{index:!0,follow:!0}},openGraph:{title:t,description:e,url:r,...n?{siteName:n}:{},type:o,...i?{images:[{url:i,width:1200,height:630}]}:{},...o==="article"&&s?{publishedTime:s.publishedTime,modifiedTime:s.modifiedTime,authors:s.authors,tags:s.tags}:{}},twitter:{card:p,title:t,description:e,...i?{images:[i]}:{},...u?{site:u}:{}}}}function f(t,e="|"){return{default:t,template:`%s ${e} ${t}`}}function g(t){return JSON.stringify(t)}var y={website({name:t,url:e,description:r,searchUrl:n}){return g({"@context":"https://schema.org","@type":"WebSite",name:t,url:e,...r?{description:r}:{},...n?{potentialAction:{"@type":"SearchAction",target:{"@type":"EntryPoint",urlTemplate:n},"query-input":"required name=search_term_string"}}:{}})},article({title:t,description:e,url:r,image:n,datePublished:i,dateModified:o,authorName:s,authorUrl:a,publisherName:l,publisherLogo:p}){return g({"@context":"https://schema.org","@type":"Article",headline:t,...e?{description:e}:{},url:r,...n?{image:n}:{},datePublished:i,dateModified:o??i,author:{"@type":"Person",name:s,...a?{url:a}:{}},publisher:{"@type":"Organization",name:l,...p?{logo:{"@type":"ImageObject",url:p}}:{}}})},breadcrumb(t){return g({"@context":"https://schema.org","@type":"BreadcrumbList",itemListElement:t.map((e,r)=>({"@type":"ListItem",position:r+1,name:e.name,item:e.url}))})},product({name:t,description:e,image:r,url:n,price:i,currency:o="KRW",availability:s="InStock",ratingValue:a,reviewCount:l}){return g({"@context":"https://schema.org","@type":"Product",name:t,...e?{description:e}:{},...r?{image:r}:{},url:n,offers:{"@type":"Offer",price:i,priceCurrency:o,availability:`https://schema.org/${s}`,url:n},...a!=null?{aggregateRating:{"@type":"AggregateRating",ratingValue:a,reviewCount:l??1}}:{}})},organization({name:t,url:e,logo:r,sameAs:n}){return g({"@context":"https://schema.org","@type":"Organization",name:t,url:e,...r?{logo:r}:{},...n?.length?{sameAs:n}:{}})},faq(t){return g({"@context":"https://schema.org","@type":"FAQPage",mainEntity:t.map(e=>({"@type":"Question",name:e.question,acceptedAnswer:{"@type":"Answer",text:e.answer}}))})}};function d(t){return['<?xml version="1.0" encoding="UTF-8"?>','<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">',...t.map(({url:r,lastModified:n,changeFrequency:i,priority:o})=>{let s=n?typeof n=="string"?n:n.toISOString().split("T")[0]:null;return[" <url>",` <loc>${r}</loc>`,s?` <lastmod>${s}</lastmod>`:null,i?` <changefreq>${i}</changefreq>`:null,o!=null?` <priority>${o.toFixed(1)}</priority>`:null," </url>"].filter(Boolean).join(`
2
+ `)}),"</urlset>"].join(`
3
+ `)}function x(t,e){return e.map(({path:r,...n})=>({url:`${t.replace(/\/$/,"")}${r}`,...n}))}function w({allow:t=["/"],disallow:e=[],sitemap:r,agents:n=[]}={}){let i=[];i.push("User-agent: *");for(let s of t)i.push(`Allow: ${s}`);for(let s of e)i.push(`Disallow: ${s}`);for(let s of n){i.push(""),i.push(`User-agent: ${s.userAgent}`);for(let a of s.allow??[])i.push(`Allow: ${a}`);for(let a of s.disallow??[])i.push(`Disallow: ${a}`)}let o=r?Array.isArray(r)?r:[r]:[];for(let s of o)i.push(""),i.push(`Sitemap: ${s}`);return i.join(`
4
+ `)}function b({allow:t=["/"],disallow:e=[],sitemap:r}){return{rules:{userAgent:"*",allow:t,disallow:e},...r?{sitemap:r}:{}}}export{h as createMetadata,w as createRobots,d as createSitemap,y as jsonLd,b as nextRobots,x as nextSitemap,f as titleTemplate};