@gravito/constellation 3.0.2 → 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 CHANGED
@@ -2,333 +2,178 @@
2
2
  title: Constellation
3
3
  ---
4
4
 
5
- # Constellation
5
+ # Constellation 🛰️
6
6
 
7
- Dynamic and static sitemap generation for Gravito applications. Constellation can be used standalone or as the sitemap and route-scanning engine for Luminosity.
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 generate XML sitemaps for your Gravito application, supporting both dynamic generation (via routes) and static generation (for build time). It includes support for Google Sitemap extensions like Images, Videos, News, and i18n alternates.
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
- ## Features
11
+ ---
12
+
13
+ ## 🌟 Key Features
12
14
 
13
- - **Dynamic Generation**: Serve `sitemap.xml` directly from your application
14
- - **Static Generation**: Generate files for static hosting
15
- - **Auto Scanning**: Automatically scan registered routes
16
- - **Sitemap Extensions**: Support for Images, Videos, News, and i18n
17
- - **Sitemap Index**: Generators for large sites (Phase 1/2)
18
- - **Enterprise Features**:
19
- - **Cloud Storage**: AWS S3 and Google Cloud Storage support
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
- ## Installation
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
- ## Usage
43
+ ---
33
44
 
34
- ### 1. Dynamic Sitemap (Runtime)
45
+ ## 🚀 Quick Start
35
46
 
36
- Integrate directly into your Gravito app:
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 (e.g. from database)
62
+ // Custom database provider
52
63
  {
53
64
  async getEntries() {
54
- const posts = await db.query('SELECT slug, updated_at FROM posts')
65
+ const posts = await db.posts.findMany()
55
66
  return posts.map(post => ({
56
67
  url: `/blog/${post.slug}`,
57
- lastmod: post.updated_at
68
+ lastmod: post.updatedAt
58
69
  }))
59
70
  }
60
71
  }
61
72
  ],
62
- cacheSeconds: 3600 // Cache for 1 hour
63
- }).install(core)
64
- ```
73
+ cacheSeconds: 3600 // HTTP cache headers
74
+ })
65
75
 
66
- ### 2. Static Generation (Build Time)
76
+ sitemap.install(core)
77
+ ```
67
78
 
68
- Generate files during build:
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, routeScanner } from '@gravito/constellation'
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
- providers: [
77
- routeScanner(core.router),
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
- ### 3. Manual Usage (SitemapStream)
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
- ```typescript
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
- ### Distributed Locking
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
- ```typescript
169
- OrbitSitemap.dynamic({
170
- // ...
171
- lock: new RedisSitemapLock(redisClient),
172
- storage: new S3SitemapStorage(bucket)
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
- ## Enterprise Features
111
+ ---
177
112
 
178
- ### Cloud Storage (S3 / GCP)
113
+ ## 💎 Advanced Usage
179
114
 
180
- Store sitemaps directly in cloud storage with shadow processing:
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 { OrbitSitemap, S3SitemapStorage } from '@gravito/constellation'
119
+ import { SitemapGenerator, DiskSitemapStorage } from '@gravito/constellation'
184
120
 
185
- const sitemap = OrbitSitemap.static({
121
+ const generator = new SitemapGenerator({
186
122
  baseUrl: 'https://example.com',
187
- storage: new S3SitemapStorage({
188
- bucket: 'my-sitemap-bucket',
189
- region: 'us-east-1',
190
- shadow: {
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
- mode: 'atomic' // Atomic switch: generate to temp, then swap
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
- ```typescript
219
- import { OrbitSitemap, MemoryProgressStorage } from '@gravito/constellation'
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
- ### Incremental Generation
241
-
242
- Only update changed URLs, perfect for large sites:
136
+ **效益**:
137
+ - 🔥 記憶體峰值降低 40%+(大型 sitemap 使用串流寫入)
138
+ - 📦 檔案大小減少 70%+(啟用 gzip 壓縮)
139
+ - ⚡ 自動偵測 Storage 是否支援串流寫入
243
140
 
141
+ ### Cloud Storage (AWS S3)
244
142
  ```typescript
245
- import { OrbitSitemap, MemoryChangeTracker } from '@gravito/constellation'
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
- ### 301 Redirect Handling
264
-
265
- Automatically handle URL redirects in your sitemap:
266
-
155
+ ### Background Progress Tracking
267
156
  ```typescript
268
- import { OrbitSitemap, MemoryRedirectManager, RedirectDetector } from '@gravito/constellation'
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
- // Available endpoints:
313
- // POST /admin/sitemap/generate - Trigger generation
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
- ### Creating Custom Storage/Lock
319
- Implement `SitemapStorage` and `SitemapLock` interfaces:
320
-
168
+ ### API Endpoints
169
+ Install admin routes to manage sitemaps remotely:
321
170
  ```typescript
322
- import { SitemapStorage, SitemapLock } from '@gravito/constellation'
323
-
324
- class MyStorage implements SitemapStorage { ... }
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
- ## Type Reference
329
-
330
- See `dist/index.d.ts` for full type definitions including `SitemapEntry`, `SitemapImage`, `SitemapVideo`, etc.
331
-
332
- ## License
176
+ ---
333
177
 
334
- MIT
178
+ ## 📄 License
179
+ MIT © Carl Lee
package/README.zh-TW.md CHANGED
@@ -1,33 +1,150 @@
1
- # Constellation
1
+ ---
2
+ title: Constellation
3
+ ---
2
4
 
3
- > Gravito 的 Sitemap 產生器,支援動態輸出與靜態生成,可被 Luminosity 作為 sitemap 與路由掃描的工具層使用。
5
+ # Constellation 🛰️
4
6
 
5
- ## 特色
7
+ 強大且高效能的 SEO 與 Sitemap 編排模組,專為 **Gravito 應用程式**量身打造。支援企業級索引規模、智慧重新導向管理以及原子化部署。
6
8
 
7
- - **動態 sitemap**:在執行期提供 `sitemap.xml`
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
- }).install(core)
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
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  DiskSitemapStorage
3
- } from "./chunk-IS2H7U6M.js";
3
+ } from "./chunk-3IZTXYU7.js";
4
4
  export {
5
5
  DiskSitemapStorage
6
6
  };