@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/bin/favicon.mjs +0 -0
- package/bin/m1kkit.mjs +49 -0
- package/bin/postinstall.mjs +28 -0
- package/bin/skills/m1kapp-init.md +159 -0
- package/bin/skills/m1kapp-pwa.md +62 -0
- package/bin/skills/m1kapp-seo.md +66 -0
- package/bin/skills.mjs +97 -0
- package/dist/index.d.mts +51 -23
- package/dist/index.d.ts +51 -23
- package/dist/index.js +7 -8
- package/dist/index.mjs +7 -8
- package/dist/pwa.js +2 -2
- package/dist/pwa.mjs +1 -1
- package/dist/seo.d.mts +260 -0
- package/dist/seo.d.ts +260 -0
- package/dist/seo.js +4 -0
- package/dist/seo.mjs +4 -0
- package/dist/styles.css +1 -1
- package/package.json +8 -2
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};
|