@gravito/constellation 3.0.1 → 3.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +96 -251
- package/README.zh-TW.md +130 -13
- package/dist/{DiskSitemapStorage-7ZZMGC4K.js → DiskSitemapStorage-VLN5I24C.js} +1 -1
- package/dist/chunk-3IZTXYU7.js +166 -0
- package/dist/index.cjs +1893 -196
- package/dist/index.d.cts +1597 -171
- package/dist/index.d.ts +1597 -171
- package/dist/index.js +1774 -199
- package/package.json +7 -5
- package/dist/chunk-7WHLC3OJ.js +0 -56
package/README.md
CHANGED
|
@@ -2,333 +2,178 @@
|
|
|
2
2
|
title: Constellation
|
|
3
3
|
---
|
|
4
4
|
|
|
5
|
-
# Constellation
|
|
5
|
+
# Constellation 🛰️
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
Powerful, high-performance SEO and Sitemap orchestration module for **Gravito applications**. Built for enterprise-scale indexing, intelligent redirect management, and atomic deployments.
|
|
8
8
|
|
|
9
|
-
**Constellation** provides a flexible way to
|
|
9
|
+
**Constellation** provides a flexible way to manage your site's search engine visibility, supporting both dynamic on-the-fly generation and static build-time generation with cloud storage integration.
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## 🌟 Key Features
|
|
12
14
|
|
|
13
|
-
|
|
14
|
-
- **
|
|
15
|
-
- **
|
|
16
|
-
- **
|
|
17
|
-
- **
|
|
18
|
-
- **
|
|
19
|
-
|
|
20
|
-
- **Shadow Processing**: Atomic switching and versioning for safe deployments
|
|
21
|
-
- **Background Jobs**: Non-blocking generation with progress tracking
|
|
22
|
-
- **Incremental Generation**: Only update changed URLs, not the entire sitemap
|
|
23
|
-
- **301 Redirect Handling**: Comprehensive redirect detection and processing
|
|
24
|
-
- **Progress Tracking**: Real-time progress monitoring via API
|
|
15
|
+
### 🚀 High Performance & Scalability
|
|
16
|
+
- **Streaming Generation**: Uses `SitemapStream` for memory-efficient XML building.
|
|
17
|
+
- **Stream Writing (v3.1+)**: Reduces memory peaks by 40%+ with async iterable streaming to storage.
|
|
18
|
+
- **Gzip Compression (v3.1+)**: Automatically compress sitemaps to reduce file size by 70%+ and save bandwidth.
|
|
19
|
+
- **Auto-Sharding**: Automatically splits large sitemaps into multiple files (50,000 URLs limit) and generates sitemap indexes.
|
|
20
|
+
- **Async Iterators**: Support for streaming data directly from databases via async generators.
|
|
21
|
+
- **Distributed Locking**: Prevents "cache stampedes" in distributed environments (e.g., Kubernetes) using Redis locks.
|
|
25
22
|
|
|
26
|
-
|
|
23
|
+
### 🏢 Enterprise SEO Orchestration
|
|
24
|
+
- **Incremental Generation**: Only update modified URLs instead of regenerating the entire sitemap.
|
|
25
|
+
- **Shadow Processing**: Atomic "blue-green" deployments for sitemaps using temporary staging and swapping.
|
|
26
|
+
- **301/302 Redirect Handling**: Intelligent detection and removal/replacement of redirected URLs to ensure search engines only see canonical links.
|
|
27
|
+
- **Cloud Storage Integration**: Built-in support for AWS S3 and Google Cloud Storage (GCS).
|
|
28
|
+
|
|
29
|
+
### 🛠️ Advanced Capabilities
|
|
30
|
+
- **Rich Extensions**: Support for Images, Videos, News, and i18n alternate links (hreflang).
|
|
31
|
+
- **Background Jobs**: Non-blocking generation with persistent progress tracking.
|
|
32
|
+
- **Admin API**: Built-in endpoints for triggering generation and monitoring status.
|
|
33
|
+
- **Auto Route Scanning**: Automatically extracts URLs from Gravito's router.
|
|
34
|
+
|
|
35
|
+
---
|
|
36
|
+
|
|
37
|
+
## 📦 Installation
|
|
27
38
|
|
|
28
39
|
```bash
|
|
29
40
|
bun add @gravito/constellation
|
|
30
41
|
```
|
|
31
42
|
|
|
32
|
-
|
|
43
|
+
---
|
|
33
44
|
|
|
34
|
-
|
|
45
|
+
## 🚀 Quick Start
|
|
35
46
|
|
|
36
|
-
|
|
47
|
+
### 1. Dynamic Mode (Runtime)
|
|
48
|
+
Ideal for small to medium sites where data changes frequently.
|
|
37
49
|
|
|
38
50
|
```typescript
|
|
39
|
-
// gravito.config.ts or index.ts
|
|
40
51
|
import { OrbitSitemap, routeScanner } from '@gravito/constellation'
|
|
41
52
|
|
|
42
|
-
OrbitSitemap.dynamic({
|
|
53
|
+
const sitemap = OrbitSitemap.dynamic({
|
|
43
54
|
baseUrl: 'https://example.com',
|
|
44
55
|
providers: [
|
|
45
|
-
// Automatically scan routes
|
|
56
|
+
// Automatically scan Gravito routes
|
|
46
57
|
routeScanner(core.router, {
|
|
47
58
|
exclude: ['/api/*', '/admin/*'],
|
|
48
59
|
defaultChangefreq: 'daily'
|
|
49
60
|
}),
|
|
50
61
|
|
|
51
|
-
// Custom provider
|
|
62
|
+
// Custom database provider
|
|
52
63
|
{
|
|
53
64
|
async getEntries() {
|
|
54
|
-
const posts = await db.
|
|
65
|
+
const posts = await db.posts.findMany()
|
|
55
66
|
return posts.map(post => ({
|
|
56
67
|
url: `/blog/${post.slug}`,
|
|
57
|
-
lastmod: post.
|
|
68
|
+
lastmod: post.updatedAt
|
|
58
69
|
}))
|
|
59
70
|
}
|
|
60
71
|
}
|
|
61
72
|
],
|
|
62
|
-
cacheSeconds: 3600 //
|
|
63
|
-
})
|
|
64
|
-
```
|
|
73
|
+
cacheSeconds: 3600 // HTTP cache headers
|
|
74
|
+
})
|
|
65
75
|
|
|
66
|
-
|
|
76
|
+
sitemap.install(core)
|
|
77
|
+
```
|
|
67
78
|
|
|
68
|
-
|
|
79
|
+
### 2. Static Mode (Build Time)
|
|
80
|
+
Recommended for large-scale sites or when serving from a CDN.
|
|
69
81
|
|
|
70
82
|
```typescript
|
|
71
|
-
import { OrbitSitemap,
|
|
83
|
+
import { OrbitSitemap, DiskSitemapStorage } from '@gravito/constellation'
|
|
72
84
|
|
|
73
85
|
const sitemap = OrbitSitemap.static({
|
|
74
86
|
baseUrl: 'https://example.com',
|
|
75
|
-
outDir: './dist',
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
]
|
|
87
|
+
outDir: './dist/sitemaps',
|
|
88
|
+
storage: new DiskSitemapStorage('./dist/sitemaps'),
|
|
89
|
+
shadow: { enabled: true, mode: 'atomic' }, // Safe deployment
|
|
90
|
+
providers: [...]
|
|
80
91
|
})
|
|
81
92
|
|
|
82
93
|
await sitemap.generate()
|
|
83
94
|
```
|
|
84
95
|
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
Use the low-level API for custom needs:
|
|
88
|
-
|
|
89
|
-
```typescript
|
|
90
|
-
import { SitemapStream } from '@gravito/constellation'
|
|
91
|
-
|
|
92
|
-
const sitemap = new SitemapStream({ baseUrl: 'https://example.com' })
|
|
93
|
-
|
|
94
|
-
sitemap.add('/')
|
|
95
|
-
sitemap.add({
|
|
96
|
-
url: '/about',
|
|
97
|
-
changefreq: 'monthly',
|
|
98
|
-
priority: 0.8,
|
|
99
|
-
alternates: [
|
|
100
|
-
{ lang: 'en', url: '/about' },
|
|
101
|
-
{ lang: 'zh-TW', url: '/zh/about' }
|
|
102
|
-
],
|
|
103
|
-
images: [
|
|
104
|
-
{ loc: '/img/team.jpg', title: 'Our Team' }
|
|
105
|
-
]
|
|
106
|
-
})
|
|
107
|
-
|
|
108
|
-
console.log(sitemap.toXML())
|
|
109
|
-
```
|
|
110
|
-
|
|
111
|
-
## Extensions
|
|
112
|
-
|
|
113
|
-
### Video Sitemap
|
|
114
|
-
```typescript
|
|
115
|
-
sitemap.add({
|
|
116
|
-
url: '/video-page',
|
|
117
|
-
videos: [{
|
|
118
|
-
thumbnail_loc: 'https://...',
|
|
119
|
-
title: 'Video Title',
|
|
120
|
-
description: 'Description',
|
|
121
|
-
player_loc: 'https://...',
|
|
122
|
-
duration: 600
|
|
123
|
-
}]
|
|
124
|
-
})
|
|
125
|
-
```
|
|
126
|
-
|
|
127
|
-
### News Sitemap
|
|
128
|
-
```typescript
|
|
129
|
-
sitemap.add({
|
|
130
|
-
url: '/news/article',
|
|
131
|
-
news: {
|
|
132
|
-
publication: { name: 'The Daily', language: 'en' },
|
|
133
|
-
publication_date: '2024-01-01',
|
|
134
|
-
title: 'Article Title'
|
|
135
|
-
}
|
|
136
|
-
})
|
|
137
|
-
```
|
|
138
|
-
|
|
139
|
-
## Scaling & Distributed (Advanced)
|
|
140
|
-
|
|
141
|
-
### Large Scale Sharding
|
|
142
|
-
Orbit Sitemap automatically handles large datasets by splitting them into multiple files (default 50,000 URLs per file).
|
|
143
|
-
|
|
144
|
-
```typescript
|
|
145
|
-
OrbitSitemap.dynamic({
|
|
146
|
-
// ...
|
|
147
|
-
maxEntriesPerFile: 10000, // Custom split limit
|
|
148
|
-
storage: new RedisSitemapStorage({ ... }) // Store generated files in Redis/S3
|
|
149
|
-
})
|
|
150
|
-
```
|
|
151
|
-
|
|
152
|
-
### Async Iterators (Streaming)
|
|
153
|
-
For large datasets, use Async Generators in your providers to stream URLs without loading them all into memory.
|
|
96
|
+
---
|
|
154
97
|
|
|
155
|
-
|
|
156
|
-
{
|
|
157
|
-
async *getEntries() {
|
|
158
|
-
for await (const row of db.cursor('SELECT * FROM massive_table')) {
|
|
159
|
-
yield { url: `/item/${row.id}` }
|
|
160
|
-
}
|
|
161
|
-
}
|
|
162
|
-
}
|
|
163
|
-
```
|
|
98
|
+
## 🏗️ Architecture & Modules
|
|
164
99
|
|
|
165
|
-
|
|
166
|
-
In a distributed environment (e.g. Kubernetes), use `lock` to prevent concurrent sitemap generation.
|
|
100
|
+
Constellation is composed of several specialized sub-modules:
|
|
167
101
|
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
102
|
+
| Component | Responsibility |
|
|
103
|
+
|---|---|
|
|
104
|
+
| **SitemapGenerator** | Core engine for building XML files and indexes. |
|
|
105
|
+
| **IncrementalGenerator** | Handles partial updates based on change tracking. |
|
|
106
|
+
| **RedirectHandler** | Processes URL lists against redirect rules. |
|
|
107
|
+
| **ShadowProcessor** | Manages atomic staging and versioning of files. |
|
|
108
|
+
| **RouteScanner** | Integrates with Gravito router for auto-discovery. |
|
|
109
|
+
| **SitemapStorage** | Abstraction for Local Disk, S3, GCS, or Memory. |
|
|
175
110
|
|
|
176
|
-
|
|
111
|
+
---
|
|
177
112
|
|
|
178
|
-
|
|
113
|
+
## 💎 Advanced Usage
|
|
179
114
|
|
|
180
|
-
|
|
115
|
+
### Stream Writing & Compression (v3.1+)
|
|
116
|
+
Reduce memory usage and file size with streaming and gzip compression:
|
|
181
117
|
|
|
182
118
|
```typescript
|
|
183
|
-
import {
|
|
119
|
+
import { SitemapGenerator, DiskSitemapStorage } from '@gravito/constellation'
|
|
184
120
|
|
|
185
|
-
const
|
|
121
|
+
const generator = new SitemapGenerator({
|
|
186
122
|
baseUrl: 'https://example.com',
|
|
187
|
-
storage: new
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
enabled: true,
|
|
192
|
-
mode: 'atomic' // or 'versioned'
|
|
193
|
-
}
|
|
194
|
-
}),
|
|
195
|
-
providers: [...]
|
|
196
|
-
})
|
|
197
|
-
```
|
|
198
|
-
|
|
199
|
-
### Shadow Processing
|
|
200
|
-
|
|
201
|
-
Generate sitemaps safely with atomic switching or versioning:
|
|
202
|
-
|
|
203
|
-
```typescript
|
|
204
|
-
const sitemap = OrbitSitemap.static({
|
|
205
|
-
// ...
|
|
206
|
-
shadow: {
|
|
123
|
+
storage: new DiskSitemapStorage('./public/sitemaps', 'https://example.com/sitemaps'),
|
|
124
|
+
providers: [...],
|
|
125
|
+
// 啟用 gzip 壓縮,減少檔案大小 70%+
|
|
126
|
+
compression: {
|
|
207
127
|
enabled: true,
|
|
208
|
-
|
|
209
|
-
// or 'versioned' // Versioning: keep old versions, switch when ready
|
|
128
|
+
level: 6 // 1-9,預設 6(平衡速度與壓縮率)
|
|
210
129
|
}
|
|
211
130
|
})
|
|
212
|
-
```
|
|
213
|
-
|
|
214
|
-
### Background Generation with Progress Tracking
|
|
215
|
-
|
|
216
|
-
Generate sitemaps asynchronously without blocking:
|
|
217
131
|
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
const sitemap = OrbitSitemap.static({
|
|
222
|
-
// ...
|
|
223
|
-
progressStorage: new MemoryProgressStorage()
|
|
224
|
-
})
|
|
225
|
-
|
|
226
|
-
// Trigger background generation
|
|
227
|
-
const jobId = await sitemap.generateAsync({
|
|
228
|
-
onProgress: (progress) => {
|
|
229
|
-
console.log(`${progress.percentage}% (${progress.processed}/${progress.total})`)
|
|
230
|
-
},
|
|
231
|
-
onComplete: () => {
|
|
232
|
-
console.log('Generation completed!')
|
|
233
|
-
}
|
|
234
|
-
})
|
|
235
|
-
|
|
236
|
-
// Query progress via API
|
|
237
|
-
// GET /admin/sitemap/status/:jobId
|
|
132
|
+
await generator.run()
|
|
133
|
+
// 產生 sitemap.xml.gz(而非 sitemap.xml)
|
|
238
134
|
```
|
|
239
135
|
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
136
|
+
**效益**:
|
|
137
|
+
- 🔥 記憶體峰值降低 40%+(大型 sitemap 使用串流寫入)
|
|
138
|
+
- 📦 檔案大小減少 70%+(啟用 gzip 壓縮)
|
|
139
|
+
- ⚡ 自動偵測 Storage 是否支援串流寫入
|
|
243
140
|
|
|
141
|
+
### Cloud Storage (AWS S3)
|
|
244
142
|
```typescript
|
|
245
|
-
import {
|
|
143
|
+
import { S3SitemapStorage } from '@gravito/constellation'
|
|
246
144
|
|
|
247
145
|
const sitemap = OrbitSitemap.static({
|
|
146
|
+
storage: new S3SitemapStorage({
|
|
147
|
+
bucket: 'my-bucket',
|
|
148
|
+
region: 'us-west-2'
|
|
149
|
+
}),
|
|
150
|
+
compression: { enabled: true }, // 壓縮後上傳,節省 S3 儲存成本
|
|
248
151
|
// ...
|
|
249
|
-
incremental: {
|
|
250
|
-
enabled: true,
|
|
251
|
-
changeTracker: new MemoryChangeTracker(),
|
|
252
|
-
autoTrack: true
|
|
253
|
-
}
|
|
254
152
|
})
|
|
255
|
-
|
|
256
|
-
// Full generation (first time)
|
|
257
|
-
await sitemap.generate()
|
|
258
|
-
|
|
259
|
-
// Incremental update (only changed URLs)
|
|
260
|
-
await sitemap.generateIncremental(new Date('2024-01-01'))
|
|
261
153
|
```
|
|
262
154
|
|
|
263
|
-
###
|
|
264
|
-
|
|
265
|
-
Automatically handle URL redirects in your sitemap:
|
|
266
|
-
|
|
155
|
+
### Background Progress Tracking
|
|
267
156
|
```typescript
|
|
268
|
-
import {
|
|
269
|
-
|
|
270
|
-
const redirectManager = new MemoryRedirectManager()
|
|
271
|
-
const detector = new RedirectDetector({
|
|
272
|
-
baseUrl: 'https://example.com',
|
|
273
|
-
autoDetect: {
|
|
274
|
-
enabled: true,
|
|
275
|
-
timeout: 5000,
|
|
276
|
-
cache: true
|
|
277
|
-
}
|
|
278
|
-
})
|
|
279
|
-
|
|
280
|
-
// Auto-detect redirects
|
|
281
|
-
const redirects = await detector.detectBatch(['/old-page', '/another-old'])
|
|
282
|
-
|
|
283
|
-
// Register redirects
|
|
284
|
-
for (const [from, rule] of redirects) {
|
|
285
|
-
if (rule) {
|
|
286
|
-
await redirectManager.register(rule)
|
|
287
|
-
}
|
|
288
|
-
}
|
|
157
|
+
import { MemoryProgressStorage } from '@gravito/constellation'
|
|
289
158
|
|
|
290
159
|
const sitemap = OrbitSitemap.static({
|
|
160
|
+
progressStorage: new MemoryProgressStorage(),
|
|
291
161
|
// ...
|
|
292
|
-
redirect: {
|
|
293
|
-
enabled: true,
|
|
294
|
-
manager: redirectManager,
|
|
295
|
-
strategy: 'remove_old_add_new', // or 'keep_relation', 'update_url', 'dual_mark'
|
|
296
|
-
followChains: true,
|
|
297
|
-
maxChainLength: 5
|
|
298
|
-
}
|
|
299
162
|
})
|
|
300
|
-
```
|
|
301
|
-
|
|
302
|
-
### API Endpoints
|
|
303
|
-
|
|
304
|
-
Install API endpoints for triggering generation and querying progress:
|
|
305
|
-
|
|
306
|
-
```typescript
|
|
307
|
-
const sitemap = OrbitSitemap.static({ ... })
|
|
308
|
-
|
|
309
|
-
// Install API endpoints
|
|
310
|
-
sitemap.installApiEndpoints(core, '/admin/sitemap')
|
|
311
163
|
|
|
312
|
-
//
|
|
313
|
-
|
|
314
|
-
// GET /admin/sitemap/status/:jobId - Query progress
|
|
315
|
-
// GET /admin/sitemap/history - List generation history
|
|
164
|
+
// Trigger background job
|
|
165
|
+
const jobId = await sitemap.generateAsync()
|
|
316
166
|
```
|
|
317
167
|
|
|
318
|
-
###
|
|
319
|
-
|
|
320
|
-
|
|
168
|
+
### API Endpoints
|
|
169
|
+
Install admin routes to manage sitemaps remotely:
|
|
321
170
|
```typescript
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
class MyLock implements SitemapLock { ... }
|
|
171
|
+
sitemap.installApiEndpoints(core, '/admin/seo/sitemap')
|
|
172
|
+
// POST /admin/seo/sitemap/generate
|
|
173
|
+
// GET /admin/seo/sitemap/status/:jobId
|
|
326
174
|
```
|
|
327
175
|
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
See `dist/index.d.ts` for full type definitions including `SitemapEntry`, `SitemapImage`, `SitemapVideo`, etc.
|
|
331
|
-
|
|
332
|
-
## License
|
|
176
|
+
---
|
|
333
177
|
|
|
334
|
-
|
|
178
|
+
## 📄 License
|
|
179
|
+
MIT © Carl Lee
|
package/README.zh-TW.md
CHANGED
|
@@ -1,33 +1,150 @@
|
|
|
1
|
-
|
|
1
|
+
---
|
|
2
|
+
title: Constellation
|
|
3
|
+
---
|
|
2
4
|
|
|
3
|
-
|
|
5
|
+
# Constellation 🛰️
|
|
4
6
|
|
|
5
|
-
|
|
7
|
+
強大且高效能的 SEO 與 Sitemap 編排模組,專為 **Gravito 應用程式**量身打造。支援企業級索引規模、智慧重新導向管理以及原子化部署。
|
|
6
8
|
|
|
7
|
-
|
|
8
|
-
- **靜態生成**:建置時輸出檔案
|
|
9
|
-
- **路由掃描**:自動掃描已註冊路由
|
|
10
|
-
- **擴充支援**:Images、Videos、News、i18n
|
|
9
|
+
**Constellation** 提供彈性的方式來管理網站的搜尋引擎能見度,支援動態即時生成(Dynamic)以及建構時生成(Static),並可整合雲端儲存空間。
|
|
11
10
|
|
|
12
|
-
|
|
11
|
+
---
|
|
12
|
+
|
|
13
|
+
## 🌟 核心特性
|
|
14
|
+
|
|
15
|
+
### 🚀 高效能與可擴展性
|
|
16
|
+
- **串流生成 (Streaming)**:使用 `SitemapStream` 進行記憶體效率極高的 XML 建立。
|
|
17
|
+
- **自動分片 (Auto-Sharding)**:自動將大型 Sitemap 分割成多個檔案(預設單檔 50,000 條 URL)並生成 Sitemap Index 索引檔。
|
|
18
|
+
- **非同步迭代器 (Async Iterators)**:支援透過 Async Generators 直接從資料庫串流讀取數據。
|
|
19
|
+
- **分散式鎖定 (Distributed Locking)**:利用 Redis 鎖防止在分散式環境(如 Kubernetes)中發生「快取擊穿」(Cache Stampede)。
|
|
20
|
+
|
|
21
|
+
### 🏢 企業級 SEO 編排
|
|
22
|
+
- **增量生成 (Incremental Generation)**:僅更新有變動的 URL,而非重新生成整個 Sitemap。
|
|
23
|
+
- **影子處理 (Shadow Processing)**:支援「藍綠部署」概念的原子化更新,透過暫存區進行驗證與切換。
|
|
24
|
+
- **301/302 重新導向處理**:智慧偵測並移除或替換重新導向的 URL,確保搜尋引擎只抓取標準鏈結 (Canonical Links)。
|
|
25
|
+
- **雲端儲存整合**:內建支援 AWS S3 與 Google Cloud Storage (GCS)。
|
|
26
|
+
|
|
27
|
+
### 🛠️ 進階功能
|
|
28
|
+
- **豐富的擴充協定**:支援圖片 (Images)、影片 (Videos)、新聞 (News) 以及 i18n 多語系交替連結 (hreflang)。
|
|
29
|
+
- **背景任務 (Background Jobs)**:非阻塞式生成流程,並具備持久化的進度追蹤功能。
|
|
30
|
+
- **管理 API**:內建端點可用於遠端觸發生成任務與監控狀態。
|
|
31
|
+
- **自動路徑掃描**:自動從 Gravito 的路由系統中提取 URL。
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
## 📦 安裝
|
|
13
36
|
|
|
14
37
|
```bash
|
|
15
38
|
bun add @gravito/constellation
|
|
16
39
|
```
|
|
17
40
|
|
|
18
|
-
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
## 🚀 快速上手
|
|
44
|
+
|
|
45
|
+
### 1. 動態模式 (Dynamic Mode - 執行階段)
|
|
46
|
+
適合中小型網站或資料變動頻繁的情境。
|
|
19
47
|
|
|
20
48
|
```typescript
|
|
21
49
|
import { OrbitSitemap, routeScanner } from '@gravito/constellation'
|
|
22
50
|
|
|
23
|
-
OrbitSitemap.dynamic({
|
|
51
|
+
const sitemap = OrbitSitemap.dynamic({
|
|
24
52
|
baseUrl: 'https://example.com',
|
|
25
53
|
providers: [
|
|
54
|
+
// 自動掃描 Gravito 路由
|
|
26
55
|
routeScanner(core.router, {
|
|
27
56
|
exclude: ['/api/*', '/admin/*'],
|
|
28
57
|
defaultChangefreq: 'daily'
|
|
29
|
-
})
|
|
58
|
+
}),
|
|
59
|
+
|
|
60
|
+
// 自定義資料庫提供者
|
|
61
|
+
{
|
|
62
|
+
async getEntries() {
|
|
63
|
+
const posts = await db.posts.findMany()
|
|
64
|
+
return posts.map(post => ({
|
|
65
|
+
url: `/blog/${post.slug}`,
|
|
66
|
+
lastmod: post.updatedAt
|
|
67
|
+
}))
|
|
68
|
+
}
|
|
69
|
+
}
|
|
30
70
|
],
|
|
31
|
-
cacheSeconds: 3600
|
|
32
|
-
})
|
|
71
|
+
cacheSeconds: 3600 // HTTP 快取標頭
|
|
72
|
+
})
|
|
73
|
+
|
|
74
|
+
sitemap.install(core)
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
### 2. 靜態模式 (Static Mode - 建構階段)
|
|
78
|
+
推薦用於大型網站或需要透過 CDN 發佈的情境。
|
|
79
|
+
|
|
80
|
+
```typescript
|
|
81
|
+
import { OrbitSitemap, DiskSitemapStorage } from '@gravito/constellation'
|
|
82
|
+
|
|
83
|
+
const sitemap = OrbitSitemap.static({
|
|
84
|
+
baseUrl: 'https://example.com',
|
|
85
|
+
outDir: './dist/sitemaps',
|
|
86
|
+
storage: new DiskSitemapStorage('./dist/sitemaps'),
|
|
87
|
+
shadow: { enabled: true, mode: 'atomic' }, // 安全部署
|
|
88
|
+
providers: [...]
|
|
89
|
+
})
|
|
90
|
+
|
|
91
|
+
await sitemap.generate()
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
---
|
|
95
|
+
|
|
96
|
+
## 🏗️ 架構與模組
|
|
97
|
+
|
|
98
|
+
Constellation 由多個專業子模組組成:
|
|
99
|
+
|
|
100
|
+
| 元件 | 職責 |
|
|
101
|
+
|---|---|
|
|
102
|
+
| **SitemapGenerator** | 負責建立 XML 檔案與索引的核心引擎。 |
|
|
103
|
+
| **IncrementalGenerator** | 處理基於異動追蹤的局部更新。 |
|
|
104
|
+
| **RedirectHandler** | 根據重新導向規則處理 URL 列表。 |
|
|
105
|
+
| **ShadowProcessor** | 管理檔案的原子化暫存與版本控制。 |
|
|
106
|
+
| **RouteScanner** | 整合 Gravito 路由實現自動發現。 |
|
|
107
|
+
| **SitemapStorage** | 抽象化儲存層(本地磁碟、S3、GCS 或記憶體)。 |
|
|
108
|
+
|
|
109
|
+
---
|
|
110
|
+
|
|
111
|
+
## 💎 進階用法
|
|
112
|
+
|
|
113
|
+
### 雲端儲存 (AWS S3)
|
|
114
|
+
```typescript
|
|
115
|
+
import { S3SitemapStorage } from '@gravito/constellation'
|
|
116
|
+
|
|
117
|
+
const sitemap = OrbitSitemap.static({
|
|
118
|
+
storage: new S3SitemapStorage({
|
|
119
|
+
bucket: 'my-bucket',
|
|
120
|
+
region: 'us-west-2'
|
|
121
|
+
}),
|
|
122
|
+
// ...
|
|
123
|
+
})
|
|
124
|
+
```
|
|
125
|
+
|
|
126
|
+
### 背景任務進度追蹤
|
|
127
|
+
```typescript
|
|
128
|
+
import { MemoryProgressStorage } from '@gravito/constellation'
|
|
129
|
+
|
|
130
|
+
const sitemap = OrbitSitemap.static({
|
|
131
|
+
progressStorage: new MemoryProgressStorage(),
|
|
132
|
+
// ...
|
|
133
|
+
})
|
|
134
|
+
|
|
135
|
+
// 觸發背景任務
|
|
136
|
+
const jobId = await sitemap.generateAsync()
|
|
33
137
|
```
|
|
138
|
+
|
|
139
|
+
### 管理端 API 端點
|
|
140
|
+
安裝管理路由以便遠端控管 Sitemap:
|
|
141
|
+
```typescript
|
|
142
|
+
sitemap.installApiEndpoints(core, '/admin/seo/sitemap')
|
|
143
|
+
// POST /admin/seo/sitemap/generate - 觸發生成
|
|
144
|
+
// GET /admin/seo/sitemap/status/:jobId - 查詢進度
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
---
|
|
148
|
+
|
|
149
|
+
## 📄 授權
|
|
150
|
+
MIT © Carl Lee
|