@singhey/spa-ssr-renderer 1.0.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/LICENSE +21 -0
- package/README.md +247 -0
- package/dist/__tests__/setup.test.d.ts +2 -0
- package/dist/__tests__/setup.test.d.ts.map +1 -0
- package/dist/__tests__/setup.test.js +22 -0
- package/dist/__tests__/setup.test.js.map +1 -0
- package/dist/components/BotDetector.d.ts +12 -0
- package/dist/components/BotDetector.d.ts.map +1 -0
- package/dist/components/BotDetector.js +46 -0
- package/dist/components/BotDetector.js.map +1 -0
- package/dist/components/CacheManager.d.ts +13 -0
- package/dist/components/CacheManager.d.ts.map +1 -0
- package/dist/components/CacheManager.js +46 -0
- package/dist/components/CacheManager.js.map +1 -0
- package/dist/components/FileServer.d.ts +7 -0
- package/dist/components/FileServer.d.ts.map +1 -0
- package/dist/components/FileServer.js +15 -0
- package/dist/components/FileServer.js.map +1 -0
- package/dist/components/RequestRouter.d.ts +7 -0
- package/dist/components/RequestRouter.d.ts.map +1 -0
- package/dist/components/RequestRouter.js +15 -0
- package/dist/components/RequestRouter.js.map +1 -0
- package/dist/components/SSRRenderer.d.ts +9 -0
- package/dist/components/SSRRenderer.d.ts.map +1 -0
- package/dist/components/SSRRenderer.js +55 -0
- package/dist/components/SSRRenderer.js.map +1 -0
- package/dist/components/index.d.ts +6 -0
- package/dist/components/index.d.ts.map +1 -0
- package/dist/components/index.js +6 -0
- package/dist/components/index.js.map +1 -0
- package/dist/config/index.d.ts +4 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +44 -0
- package/dist/config/index.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +21 -0
- package/dist/index.js.map +1 -0
- package/dist/server.d.ts +27 -0
- package/dist/server.d.ts.map +1 -0
- package/dist/server.js +245 -0
- package/dist/server.js.map +1 -0
- package/dist/types/index.d.ts +101 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +2 -0
- package/dist/types/index.js.map +1 -0
- package/dist/utils/index.d.ts +2 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/dist/utils/index.js +2 -0
- package/dist/utils/index.js.map +1 -0
- package/dist/utils/logger.d.ts +13 -0
- package/dist/utils/logger.d.ts.map +1 -0
- package/dist/utils/logger.js +17 -0
- package/dist/utils/logger.js.map +1 -0
- package/package.json +80 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 singhey
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
# @singhey/spa-ssr-renderer
|
|
2
|
+
|
|
3
|
+
A Node.js server application that intelligently serves Single Page Applications (SPAs) by providing server-side rendered content to bots and crawlers while serving the original SPA files to regular users.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- **Bot Detection**: Identifies web crawlers and search engine bots using ua-parser-js
|
|
8
|
+
- **Server-Side Rendering**: Uses Playwright for headless browser rendering
|
|
9
|
+
- **Intelligent Caching**: TTL-based cache with `@isaacs/ttlcache`
|
|
10
|
+
- **Static File Serving**: Efficient serving of static assets with SPA fallback
|
|
11
|
+
- **Sitemap Support**: Parse sitemaps to discover paths for pre-rendering
|
|
12
|
+
- **Exclusion Patterns**: Flexible path exclusion with wildcard support
|
|
13
|
+
- **Graceful Fallbacks**: Continues operation even when components fail
|
|
14
|
+
- **Library & CLI**: Can be used as an importable library or standalone CLI tool
|
|
15
|
+
|
|
16
|
+
## Installation
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
npm install @singhey/spa-ssr-renderer
|
|
20
|
+
# or
|
|
21
|
+
pnpm add @singhey/spa-ssr-renderer
|
|
22
|
+
# or
|
|
23
|
+
yarn add @singhey/spa-ssr-renderer
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Usage
|
|
27
|
+
|
|
28
|
+
### As a Library
|
|
29
|
+
|
|
30
|
+
Import and use the server in your Node.js application:
|
|
31
|
+
|
|
32
|
+
```typescript
|
|
33
|
+
import { SPASSRServer, ServerConfig } from '@singhey/spa-ssr-renderer';
|
|
34
|
+
|
|
35
|
+
// Define your configuration
|
|
36
|
+
const config: ServerConfig = {
|
|
37
|
+
port: 3000,
|
|
38
|
+
staticDir: 'public',
|
|
39
|
+
spaEntryPoint: 'index.html',
|
|
40
|
+
prerender: {
|
|
41
|
+
// Explicit paths to pre-render
|
|
42
|
+
paths: ['/', '/about', '/products'],
|
|
43
|
+
|
|
44
|
+
// Sitemaps to parse (URLs or local file paths)
|
|
45
|
+
sitemaps: ['https://example.com/sitemap.xml', './public/sitemap.xml'],
|
|
46
|
+
|
|
47
|
+
// Paths or patterns to exclude (supports wildcards)
|
|
48
|
+
exclude: ['/admin/*', '/api/*', '/private']
|
|
49
|
+
},
|
|
50
|
+
cache: {
|
|
51
|
+
type: 'memory',
|
|
52
|
+
ttl: 300000, // 5 minutes
|
|
53
|
+
maxSize: 100,
|
|
54
|
+
},
|
|
55
|
+
renderer: {
|
|
56
|
+
timeout: 30000,
|
|
57
|
+
viewport: { width: 1280, height: 720 },
|
|
58
|
+
waitForNetworkIdle: false,
|
|
59
|
+
},
|
|
60
|
+
botDetection: {
|
|
61
|
+
customPatterns: [],
|
|
62
|
+
enableVerification: false,
|
|
63
|
+
},
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
// Create and start server
|
|
67
|
+
const server = new SPASSRServer({ config });
|
|
68
|
+
|
|
69
|
+
await server.start();
|
|
70
|
+
console.log('Server running!');
|
|
71
|
+
|
|
72
|
+
// Access underlying Fastify instance for custom routes
|
|
73
|
+
const fastifyInstance = server.getServer();
|
|
74
|
+
fastifyInstance.get('/api/custom', async () => {
|
|
75
|
+
return { message: 'Custom endpoint' };
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
// Graceful shutdown
|
|
79
|
+
process.on('SIGTERM', async () => {
|
|
80
|
+
await server.stop();
|
|
81
|
+
});
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
### As a CLI Tool
|
|
85
|
+
|
|
86
|
+
Run directly from the command line:
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
# Using npx
|
|
90
|
+
npx @singhey/spa-ssr-renderer
|
|
91
|
+
|
|
92
|
+
# Or install globally
|
|
93
|
+
npm install -g @singhey/spa-ssr-renderer
|
|
94
|
+
spa-ssr-renderer
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### Environment Variables
|
|
98
|
+
|
|
99
|
+
Configure the server using environment variables:
|
|
100
|
+
|
|
101
|
+
- `PORT` - Server port (default: 3000)
|
|
102
|
+
- `STATIC_DIR` - Static files directory (default: public)
|
|
103
|
+
- `SPA_ENTRY_POINT` - SPA entry file (default: index.html)
|
|
104
|
+
- **Pre-rendering Configuration:**
|
|
105
|
+
- `PRERENDER_PATHS` - Comma-separated list of paths to pre-render (e.g., "/,/about,/products")
|
|
106
|
+
- `PRERENDER_SITEMAPS` - Comma-separated list of sitemap URLs or file paths (e.g., "https://example.com/sitemap.xml,./public/sitemap.xml")
|
|
107
|
+
- `PRERENDER_EXCLUDE` - Comma-separated list of paths or patterns to exclude (supports wildcards: `*` and `?`)
|
|
108
|
+
- `CACHE_TYPE` - Cache type: memory|redis (default: memory)
|
|
109
|
+
- `CACHE_TTL` - Cache TTL in ms (default: 300000)
|
|
110
|
+
- `RENDER_TIMEOUT` - Render timeout in ms (default: 30000)
|
|
111
|
+
- `VIEWPORT_WIDTH` - Render viewport width (default: 1280)
|
|
112
|
+
- `VIEWPORT_HEIGHT` - Render viewport height (default: 720)
|
|
113
|
+
|
|
114
|
+
## How It Works
|
|
115
|
+
|
|
116
|
+
1. **Static Files**: If a file exists in the static directory, it's served directly
|
|
117
|
+
2. **Pre-rendering**: On startup, specified paths are rendered using Playwright and cached
|
|
118
|
+
- **Explicit Paths**: Define specific paths to pre-render
|
|
119
|
+
- **Sitemap Support**: Parse sitemaps (URLs or local files) to discover paths
|
|
120
|
+
- **Exclusions**: Use patterns to exclude paths from pre-rendering (e.g., `/admin/*`, `/api/*`)
|
|
121
|
+
3. **Bot Detection**: Incoming requests are analyzed for bot User-Agents using ua-parser-js
|
|
122
|
+
4. **Smart Serving**:
|
|
123
|
+
- **Bots**: Served pre-rendered, cached HTML for instant SEO-friendly content
|
|
124
|
+
- **Regular Users**: Served the SPA entry point for full client-side interactivity
|
|
125
|
+
5. **SPA Fallback**: For routes without file extensions, serves the SPA entry point (index.html)
|
|
126
|
+
6. **Caching**: Pre-rendered content is cached using `@isaacs/ttlcache` with configurable TTL
|
|
127
|
+
|
|
128
|
+
### Pre-rendering Configuration Examples
|
|
129
|
+
|
|
130
|
+
**Explicit paths only:**
|
|
131
|
+
```typescript
|
|
132
|
+
prerender: {
|
|
133
|
+
paths: ['/', '/about', '/products', '/contact']
|
|
134
|
+
}
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
**Using sitemaps:**
|
|
138
|
+
```typescript
|
|
139
|
+
prerender: {
|
|
140
|
+
sitemaps: [
|
|
141
|
+
'https://example.com/sitemap.xml', // Remote sitemap
|
|
142
|
+
'./public/sitemap.xml' // Local sitemap
|
|
143
|
+
]
|
|
144
|
+
}
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
**With exclusions (supports wildcards):**
|
|
148
|
+
```typescript
|
|
149
|
+
prerender: {
|
|
150
|
+
paths: ['/', '/about', '/products'],
|
|
151
|
+
sitemaps: ['./public/sitemap.xml'],
|
|
152
|
+
exclude: [
|
|
153
|
+
'/admin/*', // Exclude all admin paths
|
|
154
|
+
'/api/*', // Exclude all API paths
|
|
155
|
+
'/private', // Exclude specific path
|
|
156
|
+
'*/draft' // Exclude all draft pages
|
|
157
|
+
]
|
|
158
|
+
}
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
**Combined configuration:**
|
|
162
|
+
```typescript
|
|
163
|
+
prerender: {
|
|
164
|
+
paths: ['/', '/about'], // Always pre-render these
|
|
165
|
+
sitemaps: ['./public/sitemap.xml'], // Plus paths from sitemap
|
|
166
|
+
exclude: ['/admin/*', '/api/*'] // But exclude these patterns
|
|
167
|
+
}
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
## Project Structure
|
|
171
|
+
|
|
172
|
+
```
|
|
173
|
+
src/
|
|
174
|
+
├── components/ # Core application components
|
|
175
|
+
│ ├── BotDetector.ts # Bot detection logic
|
|
176
|
+
│ ├── FileServer.ts # Static file serving
|
|
177
|
+
│ ├── RequestRouter.ts # Request routing and classification
|
|
178
|
+
│ ├── CacheManager.ts # Caching system
|
|
179
|
+
│ ├── SSRRenderer.ts # Server-side rendering
|
|
180
|
+
│ └── index.ts # Component exports
|
|
181
|
+
├── config/ # Configuration management
|
|
182
|
+
│ └── index.ts # Default config and environment loading
|
|
183
|
+
├── types/ # TypeScript interfaces and types
|
|
184
|
+
│ └── index.ts # All type definitions
|
|
185
|
+
├── utils/ # Shared utilities
|
|
186
|
+
│ ├── logger.ts # Logging utilities
|
|
187
|
+
│ └── index.ts # Utility exports
|
|
188
|
+
├── __tests__/ # Test files
|
|
189
|
+
│ └── setup.test.ts # Foundation tests
|
|
190
|
+
└── index.ts # Main application entry point
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
## Development
|
|
194
|
+
|
|
195
|
+
### Prerequisites
|
|
196
|
+
|
|
197
|
+
- Node.js 18+
|
|
198
|
+
- pnpm
|
|
199
|
+
|
|
200
|
+
### Installation
|
|
201
|
+
|
|
202
|
+
```bash
|
|
203
|
+
pnpm install
|
|
204
|
+
npx playwright install
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
### Scripts
|
|
208
|
+
|
|
209
|
+
- `pnpm dev` - Start development server with hot reload
|
|
210
|
+
- `pnpm build` - Build for production
|
|
211
|
+
- `pnpm start` - Start production server
|
|
212
|
+
- `pnpm test` - Run tests
|
|
213
|
+
- `pnpm test:watch` - Run tests in watch mode
|
|
214
|
+
- `pnpm test:coverage` - Run tests with coverage
|
|
215
|
+
|
|
216
|
+
### Environment Variables
|
|
217
|
+
|
|
218
|
+
- `PORT` - Server port (default: 3000)
|
|
219
|
+
- `STATIC_DIR` - Static files directory (default: public)
|
|
220
|
+
- `SPA_ENTRY_POINT` - SPA entry file (default: index.html)
|
|
221
|
+
- `CACHE_TYPE` - Cache type: memory|redis (default: memory)
|
|
222
|
+
- `CACHE_TTL` - Cache TTL in ms (default: 300000)
|
|
223
|
+
- `RENDER_TIMEOUT` - Render timeout in ms (default: 30000)
|
|
224
|
+
- `VIEWPORT_WIDTH` - Render viewport width (default: 1280)
|
|
225
|
+
- `VIEWPORT_HEIGHT` - Render viewport height (default: 720)
|
|
226
|
+
|
|
227
|
+
## Implementation Status
|
|
228
|
+
|
|
229
|
+
This is the foundation setup. Core functionality will be implemented in subsequent tasks:
|
|
230
|
+
|
|
231
|
+
- [x] Task 1: Project foundation and interfaces
|
|
232
|
+
- [ ] Task 2: Bot Detection System
|
|
233
|
+
- [ ] Task 3: File Server Component
|
|
234
|
+
- [ ] Task 4: Request Router
|
|
235
|
+
- [ ] Task 5: Cache Manager
|
|
236
|
+
- [ ] Task 6: SSR Renderer
|
|
237
|
+
- [ ] Task 7: Main Server Integration
|
|
238
|
+
- [ ] Task 8: Configuration System
|
|
239
|
+
- [ ] Task 9: Final Integration
|
|
240
|
+
|
|
241
|
+
## Testing
|
|
242
|
+
|
|
243
|
+
The project uses Jest for unit testing and fast-check for property-based testing. Each component will have comprehensive test coverage including:
|
|
244
|
+
|
|
245
|
+
- Unit tests for specific scenarios
|
|
246
|
+
- Property-based tests for universal behaviors
|
|
247
|
+
- Integration tests for component interactions
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"setup.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/setup.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { loadConfig } from '../config/index.js';
|
|
2
|
+
import { ConsoleLogger } from '../utils/index.js';
|
|
3
|
+
describe('Project Foundation Setup', () => {
|
|
4
|
+
test('should load default configuration', () => {
|
|
5
|
+
const config = loadConfig();
|
|
6
|
+
expect(config).toBeDefined();
|
|
7
|
+
expect(config.port).toBe(3000);
|
|
8
|
+
expect(config.staticDir).toBe('public');
|
|
9
|
+
expect(config.spaEntryPoint).toBe('index.html');
|
|
10
|
+
expect(config.cache.type).toBe('memory');
|
|
11
|
+
expect(config.renderer.timeout).toBe(30000);
|
|
12
|
+
});
|
|
13
|
+
test('should create logger instance', () => {
|
|
14
|
+
const logger = new ConsoleLogger();
|
|
15
|
+
expect(logger).toBeDefined();
|
|
16
|
+
expect(typeof logger.info).toBe('function');
|
|
17
|
+
expect(typeof logger.warn).toBe('function');
|
|
18
|
+
expect(typeof logger.error).toBe('function');
|
|
19
|
+
expect(typeof logger.debug).toBe('function');
|
|
20
|
+
});
|
|
21
|
+
});
|
|
22
|
+
//# sourceMappingURL=setup.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"setup.test.js","sourceRoot":"","sources":["../../src/__tests__/setup.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,oBAAoB,CAAC;AAChD,OAAO,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAElD,QAAQ,CAAC,0BAA0B,EAAE,GAAG,EAAE;IACxC,IAAI,CAAC,mCAAmC,EAAE,GAAG,EAAE;QAC7C,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC;QAE5B,MAAM,CAAC,MAAM,CAAC,CAAC,WAAW,EAAE,CAAC;QAC7B,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC/B,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACxC,MAAM,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;QAChD,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACzC,MAAM,CAAC,MAAM,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC9C,CAAC,CAAC,CAAC;IAEH,IAAI,CAAC,+BAA+B,EAAE,GAAG,EAAE;QACzC,MAAM,MAAM,GAAG,IAAI,aAAa,EAAE,CAAC;QAEnC,MAAM,CAAC,MAAM,CAAC,CAAC,WAAW,EAAE,CAAC;QAC7B,MAAM,CAAC,OAAO,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QAC5C,MAAM,CAAC,OAAO,MAAM,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QAC5C,MAAM,CAAC,OAAO,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;QAC7C,MAAM,CAAC,OAAO,MAAM,CAAC,KAAK,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IAC/C,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { BotDetector as IBotDetector, BotInfo } from '../types/index.js';
|
|
2
|
+
export declare class BotDetector implements IBotDetector {
|
|
3
|
+
private customPatterns;
|
|
4
|
+
private parser;
|
|
5
|
+
private readonly knownBots;
|
|
6
|
+
constructor();
|
|
7
|
+
isBot(userAgent: string): boolean;
|
|
8
|
+
addBotPattern(pattern: RegExp): void;
|
|
9
|
+
getBotInfo(userAgent: string): BotInfo | null;
|
|
10
|
+
parseUserAgent(userAgent: string): UAParser.IResult;
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=BotDetector.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BotDetector.d.ts","sourceRoot":"","sources":["../../src/components/BotDetector.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,IAAI,YAAY,EAAE,OAAO,EAAE,MAAM,mBAAmB,CAAC;AAIzE,qBAAa,WAAY,YAAW,YAAY;IAC9C,OAAO,CAAC,cAAc,CAAgB;IACtC,OAAO,CAAC,MAAM,CAAW;IAGzB,OAAO,CAAC,QAAQ,CAAC,SAAS,CAuBxB;;IAMF,KAAK,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO;IAIjC,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAIpC,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,GAAG,IAAI;IAI7C,cAAc,CAAC,SAAS,EAAE,MAAM,GAAG,QAAQ,CAAC,OAAO;CAGpD"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { UAParser } from 'ua-parser-js';
|
|
2
|
+
import { isBot } from 'ua-parser-js/bot-detection';
|
|
3
|
+
export class BotDetector {
|
|
4
|
+
constructor() {
|
|
5
|
+
this.customPatterns = [];
|
|
6
|
+
// Known bot patterns organized by type
|
|
7
|
+
this.knownBots = {
|
|
8
|
+
search: [
|
|
9
|
+
{ name: 'Googlebot', patterns: ['googlebot', 'google'] },
|
|
10
|
+
{ name: 'Bingbot', patterns: ['bingbot', 'msnbot'] },
|
|
11
|
+
{ name: 'Yahoo Slurp', patterns: ['slurp'] },
|
|
12
|
+
{ name: 'DuckDuckBot', patterns: ['duckduckbot'] },
|
|
13
|
+
{ name: 'Baiduspider', patterns: ['baiduspider'] },
|
|
14
|
+
{ name: 'YandexBot', patterns: ['yandexbot'] }
|
|
15
|
+
],
|
|
16
|
+
social: [
|
|
17
|
+
{ name: 'Facebook', patterns: ['facebookexternalhit', 'facebookcatalog'] },
|
|
18
|
+
{ name: 'Twitter', patterns: ['twitterbot'] },
|
|
19
|
+
{ name: 'LinkedIn', patterns: ['linkedinbot'] },
|
|
20
|
+
{ name: 'Pinterest', patterns: ['pinterest'] },
|
|
21
|
+
{ name: 'WhatsApp', patterns: ['whatsapp'] },
|
|
22
|
+
{ name: 'Telegram', patterns: ['telegrambot'] }
|
|
23
|
+
],
|
|
24
|
+
ai: [
|
|
25
|
+
{ name: 'ChatGPT', patterns: ['chatgpt-user', 'gptbot'] },
|
|
26
|
+
{ name: 'Claude', patterns: ['claude-web', 'anthropic'] },
|
|
27
|
+
{ name: 'Perplexity', patterns: ['perplexitybot'] },
|
|
28
|
+
{ name: 'Bing AI', patterns: ['edgechat', 'sydney'] }
|
|
29
|
+
]
|
|
30
|
+
};
|
|
31
|
+
this.parser = new UAParser();
|
|
32
|
+
}
|
|
33
|
+
isBot(userAgent) {
|
|
34
|
+
return isBot(userAgent);
|
|
35
|
+
}
|
|
36
|
+
addBotPattern(pattern) {
|
|
37
|
+
this.customPatterns.push(pattern);
|
|
38
|
+
}
|
|
39
|
+
getBotInfo(userAgent) {
|
|
40
|
+
return null;
|
|
41
|
+
}
|
|
42
|
+
parseUserAgent(userAgent) {
|
|
43
|
+
return this.parser.setUA(userAgent).getResult();
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=BotDetector.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"BotDetector.js","sourceRoot":"","sources":["../../src/components/BotDetector.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AACxC,OAAO,EAAE,KAAK,EAAE,MAAM,4BAA4B,CAAA;AAElD,MAAM,OAAO,WAAW;IA8BtB;QA7BQ,mBAAc,GAAa,EAAE,CAAC;QAGtC,uCAAuC;QACtB,cAAS,GAAG;YAC3B,MAAM,EAAE;gBACN,EAAE,IAAI,EAAE,WAAW,EAAE,QAAQ,EAAE,CAAC,WAAW,EAAE,QAAQ,CAAC,EAAE;gBACxD,EAAE,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,CAAC,SAAS,EAAE,QAAQ,CAAC,EAAE;gBACpD,EAAE,IAAI,EAAE,aAAa,EAAE,QAAQ,EAAE,CAAC,OAAO,CAAC,EAAE;gBAC5C,EAAE,IAAI,EAAE,aAAa,EAAE,QAAQ,EAAE,CAAC,aAAa,CAAC,EAAE;gBAClD,EAAE,IAAI,EAAE,aAAa,EAAE,QAAQ,EAAE,CAAC,aAAa,CAAC,EAAE;gBAClD,EAAE,IAAI,EAAE,WAAW,EAAE,QAAQ,EAAE,CAAC,WAAW,CAAC,EAAE;aAC/C;YACD,MAAM,EAAE;gBACN,EAAE,IAAI,EAAE,UAAU,EAAE,QAAQ,EAAE,CAAC,qBAAqB,EAAE,iBAAiB,CAAC,EAAE;gBAC1E,EAAE,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,CAAC,YAAY,CAAC,EAAE;gBAC7C,EAAE,IAAI,EAAE,UAAU,EAAE,QAAQ,EAAE,CAAC,aAAa,CAAC,EAAE;gBAC/C,EAAE,IAAI,EAAE,WAAW,EAAE,QAAQ,EAAE,CAAC,WAAW,CAAC,EAAE;gBAC9C,EAAE,IAAI,EAAE,UAAU,EAAE,QAAQ,EAAE,CAAC,UAAU,CAAC,EAAE;gBAC5C,EAAE,IAAI,EAAE,UAAU,EAAE,QAAQ,EAAE,CAAC,aAAa,CAAC,EAAE;aAChD;YACD,EAAE,EAAE;gBACF,EAAE,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,CAAC,cAAc,EAAE,QAAQ,CAAC,EAAE;gBACzD,EAAE,IAAI,EAAE,QAAQ,EAAE,QAAQ,EAAE,CAAC,YAAY,EAAE,WAAW,CAAC,EAAE;gBACzD,EAAE,IAAI,EAAE,YAAY,EAAE,QAAQ,EAAE,CAAC,eAAe,CAAC,EAAE;gBACnD,EAAE,IAAI,EAAE,SAAS,EAAE,QAAQ,EAAE,CAAC,UAAU,EAAE,QAAQ,CAAC,EAAE;aACtD;SACF,CAAC;QAGA,IAAI,CAAC,MAAM,GAAG,IAAI,QAAQ,EAAE,CAAC;IAC/B,CAAC;IAED,KAAK,CAAC,SAAiB;QACrB,OAAO,KAAK,CAAC,SAAS,CAAC,CAAA;IACzB,CAAC;IAED,aAAa,CAAC,OAAe;QAC3B,IAAI,CAAC,cAAc,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;IACpC,CAAC;IAED,UAAU,CAAC,SAAiB;QAC1B,OAAO,IAAI,CAAA;IACb,CAAC;IAED,cAAc,CAAC,SAAiB;QAC9B,OAAO,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,SAAS,EAAE,CAAC;IAClD,CAAC;CACF"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { CacheManager as ICacheManager, CacheStats } from '../types/index.js';
|
|
2
|
+
export declare class CacheManager implements ICacheManager {
|
|
3
|
+
private cache;
|
|
4
|
+
private stats;
|
|
5
|
+
private defaultTTL;
|
|
6
|
+
constructor(maxSize?: number, defaultTTL?: number);
|
|
7
|
+
get(key: string): Promise<string | null>;
|
|
8
|
+
set(key: string, value: string, ttl?: number): Promise<void>;
|
|
9
|
+
delete(key: string): Promise<void>;
|
|
10
|
+
clear(): Promise<void>;
|
|
11
|
+
getStats(): CacheStats;
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=CacheManager.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CacheManager.d.ts","sourceRoot":"","sources":["../../src/components/CacheManager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,IAAI,aAAa,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAG9E,qBAAa,YAAa,YAAW,aAAa;IAChD,OAAO,CAAC,KAAK,CAA2B;IACxC,OAAO,CAAC,KAAK,CAGX;IACF,OAAO,CAAC,UAAU,CAAS;gBAEf,OAAO,GAAE,MAAY,EAAE,UAAU,GAAE,MAAe;IAQxD,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC;IAYxC,GAAG,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAK5D,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAIlC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAM5B,QAAQ,IAAI,UAAU;CAWvB"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import { TTLCache } from '@isaacs/ttlcache';
|
|
2
|
+
export class CacheManager {
|
|
3
|
+
constructor(maxSize = 100, defaultTTL = 300000) {
|
|
4
|
+
this.stats = {
|
|
5
|
+
hits: 0,
|
|
6
|
+
misses: 0,
|
|
7
|
+
};
|
|
8
|
+
this.defaultTTL = defaultTTL;
|
|
9
|
+
this.cache = new TTLCache({
|
|
10
|
+
max: maxSize,
|
|
11
|
+
ttl: defaultTTL,
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
async get(key) {
|
|
15
|
+
const value = this.cache.get(key);
|
|
16
|
+
if (value === undefined) {
|
|
17
|
+
this.stats.misses++;
|
|
18
|
+
return null;
|
|
19
|
+
}
|
|
20
|
+
this.stats.hits++;
|
|
21
|
+
return value;
|
|
22
|
+
}
|
|
23
|
+
async set(key, value, ttl) {
|
|
24
|
+
const effectiveTTL = ttl || this.defaultTTL;
|
|
25
|
+
this.cache.set(key, value, { ttl: effectiveTTL });
|
|
26
|
+
}
|
|
27
|
+
async delete(key) {
|
|
28
|
+
this.cache.delete(key);
|
|
29
|
+
}
|
|
30
|
+
async clear() {
|
|
31
|
+
this.cache.clear();
|
|
32
|
+
this.stats.hits = 0;
|
|
33
|
+
this.stats.misses = 0;
|
|
34
|
+
}
|
|
35
|
+
getStats() {
|
|
36
|
+
const totalRequests = this.stats.hits + this.stats.misses;
|
|
37
|
+
const hitRate = totalRequests > 0 ? this.stats.hits / totalRequests : 0;
|
|
38
|
+
return {
|
|
39
|
+
hits: this.stats.hits,
|
|
40
|
+
misses: this.stats.misses,
|
|
41
|
+
size: this.cache.size,
|
|
42
|
+
hitRate,
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
//# sourceMappingURL=CacheManager.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"CacheManager.js","sourceRoot":"","sources":["../../src/components/CacheManager.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAE5C,MAAM,OAAO,YAAY;IAQvB,YAAY,UAAkB,GAAG,EAAE,aAAqB,MAAM;QANtD,UAAK,GAAG;YACd,IAAI,EAAE,CAAC;YACP,MAAM,EAAE,CAAC;SACV,CAAC;QAIA,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;QAC7B,IAAI,CAAC,KAAK,GAAG,IAAI,QAAQ,CAAC;YACxB,GAAG,EAAE,OAAO;YACZ,GAAG,EAAE,UAAU;SAChB,CAAC,CAAC;IACL,CAAC;IAED,KAAK,CAAC,GAAG,CAAC,GAAW;QACnB,MAAM,KAAK,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;QAElC,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;YACxB,IAAI,CAAC,KAAK,CAAC,MAAM,EAAE,CAAC;YACpB,OAAO,IAAI,CAAC;QACd,CAAC;QAED,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC;QAClB,OAAO,KAAK,CAAC;IACf,CAAC;IAED,KAAK,CAAC,GAAG,CAAC,GAAW,EAAE,KAAa,EAAE,GAAY;QAChD,MAAM,YAAY,GAAG,GAAG,IAAI,IAAI,CAAC,UAAU,CAAC;QAC5C,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,EAAE,EAAE,GAAG,EAAE,YAAY,EAAE,CAAC,CAAC;IACpD,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,GAAW;QACtB,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;IACzB,CAAC;IAED,KAAK,CAAC,KAAK;QACT,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAC;QACnB,IAAI,CAAC,KAAK,CAAC,IAAI,GAAG,CAAC,CAAC;QACpB,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC;IACxB,CAAC;IAED,QAAQ;QACN,MAAM,aAAa,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC;QAC1D,MAAM,OAAO,GAAG,aAAa,GAAG,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,GAAG,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC;QAExE,OAAO;YACL,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI;YACrB,MAAM,EAAE,IAAI,CAAC,KAAK,CAAC,MAAM;YACzB,IAAI,EAAE,IAAI,CAAC,KAAK,CAAC,IAAI;YACrB,OAAO;SACR,CAAC;IACJ,CAAC;CACF"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { FileServer as IFileServer, Response } from '../types/index.js';
|
|
2
|
+
export declare class FileServer implements IFileServer {
|
|
3
|
+
serveFile(filePath: string, res: Response): Promise<void>;
|
|
4
|
+
getMimeType(extension: string): string;
|
|
5
|
+
setSecurityHeaders(res: Response): void;
|
|
6
|
+
}
|
|
7
|
+
//# sourceMappingURL=FileServer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FileServer.d.ts","sourceRoot":"","sources":["../../src/components/FileServer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,IAAI,WAAW,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAExE,qBAAa,UAAW,YAAW,WAAW;IACtC,SAAS,CAAC,QAAQ,EAAE,MAAM,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;IAK/D,WAAW,CAAC,SAAS,EAAE,MAAM,GAAG,MAAM;IAKtC,kBAAkB,CAAC,GAAG,EAAE,QAAQ,GAAG,IAAI;CAIxC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export class FileServer {
|
|
2
|
+
async serveFile(filePath, res) {
|
|
3
|
+
// Implementation will be added in task 3
|
|
4
|
+
throw new Error('Method not implemented.');
|
|
5
|
+
}
|
|
6
|
+
getMimeType(extension) {
|
|
7
|
+
// Implementation will be added in task 3
|
|
8
|
+
throw new Error('Method not implemented.');
|
|
9
|
+
}
|
|
10
|
+
setSecurityHeaders(res) {
|
|
11
|
+
// Implementation will be added in task 3
|
|
12
|
+
throw new Error('Method not implemented.');
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=FileServer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FileServer.js","sourceRoot":"","sources":["../../src/components/FileServer.ts"],"names":[],"mappings":"AAEA,MAAM,OAAO,UAAU;IACrB,KAAK,CAAC,SAAS,CAAC,QAAgB,EAAE,GAAa;QAC7C,yCAAyC;QACzC,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC;IAC7C,CAAC;IAED,WAAW,CAAC,SAAiB;QAC3B,yCAAyC;QACzC,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC;IAC7C,CAAC;IAED,kBAAkB,CAAC,GAAa;QAC9B,yCAAyC;QACzC,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC;IAC7C,CAAC;CACF"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { RequestRouter as IRequestRouter, Request, Response } from '../types/index.js';
|
|
2
|
+
export declare class RequestRouter implements IRequestRouter {
|
|
3
|
+
handleRequest(req: Request, res: Response): Promise<void>;
|
|
4
|
+
isFileRequest(path: string): boolean;
|
|
5
|
+
fileExists(path: string): boolean;
|
|
6
|
+
}
|
|
7
|
+
//# sourceMappingURL=RequestRouter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RequestRouter.d.ts","sourceRoot":"","sources":["../../src/components/RequestRouter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,IAAI,cAAc,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAEvF,qBAAa,aAAc,YAAW,cAAc;IAC5C,aAAa,CAAC,GAAG,EAAE,OAAO,EAAE,GAAG,EAAE,QAAQ,GAAG,OAAO,CAAC,IAAI,CAAC;IAK/D,aAAa,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAKpC,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;CAIlC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export class RequestRouter {
|
|
2
|
+
async handleRequest(req, res) {
|
|
3
|
+
// Implementation will be added in task 4
|
|
4
|
+
throw new Error('Method not implemented.');
|
|
5
|
+
}
|
|
6
|
+
isFileRequest(path) {
|
|
7
|
+
// Implementation will be added in task 4
|
|
8
|
+
throw new Error('Method not implemented.');
|
|
9
|
+
}
|
|
10
|
+
fileExists(path) {
|
|
11
|
+
// Implementation will be added in task 4
|
|
12
|
+
throw new Error('Method not implemented.');
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=RequestRouter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RequestRouter.js","sourceRoot":"","sources":["../../src/components/RequestRouter.ts"],"names":[],"mappings":"AAEA,MAAM,OAAO,aAAa;IACxB,KAAK,CAAC,aAAa,CAAC,GAAY,EAAE,GAAa;QAC7C,yCAAyC;QACzC,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC;IAC7C,CAAC;IAED,aAAa,CAAC,IAAY;QACxB,yCAAyC;QACzC,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC;IAC7C,CAAC;IAED,UAAU,CAAC,IAAY;QACrB,yCAAyC;QACzC,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC;IAC7C,CAAC;CACF"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { SSRRenderer as ISSRRenderer, RenderOptions } from '../types/index.js';
|
|
2
|
+
export declare class SSRRenderer implements ISSRRenderer {
|
|
3
|
+
private browser;
|
|
4
|
+
private isInitialized;
|
|
5
|
+
initialize(): Promise<void>;
|
|
6
|
+
render(url: string, options?: RenderOptions): Promise<string>;
|
|
7
|
+
cleanup(): Promise<void>;
|
|
8
|
+
}
|
|
9
|
+
//# sourceMappingURL=SSRRenderer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SSRRenderer.d.ts","sourceRoot":"","sources":["../../src/components/SSRRenderer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,IAAI,YAAY,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AAG/E,qBAAa,WAAY,YAAW,YAAY;IAC9C,OAAO,CAAC,OAAO,CAAwB;IACvC,OAAO,CAAC,aAAa,CAAS;IAExB,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;IAY3B,MAAM,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,aAAa,GAAG,OAAO,CAAC,MAAM,CAAC;IAsC7D,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;CAO/B"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { chromium } from 'playwright';
|
|
2
|
+
export class SSRRenderer {
|
|
3
|
+
constructor() {
|
|
4
|
+
this.browser = null;
|
|
5
|
+
this.isInitialized = false;
|
|
6
|
+
}
|
|
7
|
+
async initialize() {
|
|
8
|
+
if (this.isInitialized) {
|
|
9
|
+
return;
|
|
10
|
+
}
|
|
11
|
+
this.browser = await chromium.launch({
|
|
12
|
+
headless: true,
|
|
13
|
+
args: ['--no-sandbox', '--disable-setuid-sandbox'],
|
|
14
|
+
});
|
|
15
|
+
this.isInitialized = true;
|
|
16
|
+
}
|
|
17
|
+
async render(url, options) {
|
|
18
|
+
if (!this.browser) {
|
|
19
|
+
await this.initialize();
|
|
20
|
+
}
|
|
21
|
+
if (!this.browser) {
|
|
22
|
+
throw new Error('Browser not initialized');
|
|
23
|
+
}
|
|
24
|
+
const page = await this.browser.newPage({
|
|
25
|
+
viewport: options?.viewport || { width: 1280, height: 720 },
|
|
26
|
+
});
|
|
27
|
+
try {
|
|
28
|
+
const timeout = options?.timeout || 30000;
|
|
29
|
+
await page.goto(url, {
|
|
30
|
+
waitUntil: options?.waitForNetworkIdle ? 'networkidle' : 'domcontentloaded',
|
|
31
|
+
timeout,
|
|
32
|
+
});
|
|
33
|
+
// Wait for specific selector if provided
|
|
34
|
+
if (options?.waitForSelector) {
|
|
35
|
+
await page.waitForSelector(options.waitForSelector, { timeout });
|
|
36
|
+
}
|
|
37
|
+
// Get the rendered HTML
|
|
38
|
+
const html = await page.content();
|
|
39
|
+
await page.close();
|
|
40
|
+
return html;
|
|
41
|
+
}
|
|
42
|
+
catch (error) {
|
|
43
|
+
await page.close();
|
|
44
|
+
throw error;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
async cleanup() {
|
|
48
|
+
if (this.browser) {
|
|
49
|
+
await this.browser.close();
|
|
50
|
+
this.browser = null;
|
|
51
|
+
this.isInitialized = false;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=SSRRenderer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SSRRenderer.js","sourceRoot":"","sources":["../../src/components/SSRRenderer.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAiB,MAAM,YAAY,CAAC;AAErD,MAAM,OAAO,WAAW;IAAxB;QACU,YAAO,GAAmB,IAAI,CAAC;QAC/B,kBAAa,GAAG,KAAK,CAAC;IA2DhC,CAAC;IAzDC,KAAK,CAAC,UAAU;QACd,IAAI,IAAI,CAAC,aAAa,EAAE,CAAC;YACvB,OAAO;QACT,CAAC;QAED,IAAI,CAAC,OAAO,GAAG,MAAM,QAAQ,CAAC,MAAM,CAAC;YACnC,QAAQ,EAAE,IAAI;YACd,IAAI,EAAE,CAAC,cAAc,EAAE,0BAA0B,CAAC;SACnD,CAAC,CAAC;QACH,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC;IAC5B,CAAC;IAED,KAAK,CAAC,MAAM,CAAC,GAAW,EAAE,OAAuB;QAC/C,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;YAClB,MAAM,IAAI,CAAC,UAAU,EAAE,CAAC;QAC1B,CAAC;QAED,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;YAClB,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC;QAC7C,CAAC;QAED,MAAM,IAAI,GAAS,MAAM,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC;YAC5C,QAAQ,EAAE,OAAO,EAAE,QAAQ,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE;SAC5D,CAAC,CAAC;QAEH,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,OAAO,EAAE,OAAO,IAAI,KAAK,CAAC;YAE1C,MAAM,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE;gBACnB,SAAS,EAAE,OAAO,EAAE,kBAAkB,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,kBAAkB;gBAC3E,OAAO;aACR,CAAC,CAAC;YAEH,yCAAyC;YACzC,IAAI,OAAO,EAAE,eAAe,EAAE,CAAC;gBAC7B,MAAM,IAAI,CAAC,eAAe,CAAC,OAAO,CAAC,eAAe,EAAE,EAAE,OAAO,EAAE,CAAC,CAAC;YACnE,CAAC;YAED,wBAAwB;YACxB,MAAM,IAAI,GAAG,MAAM,IAAI,CAAC,OAAO,EAAE,CAAC;YAElC,MAAM,IAAI,CAAC,KAAK,EAAE,CAAC;YAEnB,OAAO,IAAI,CAAC;QACd,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,IAAI,CAAC,KAAK,EAAE,CAAC;YACnB,MAAM,KAAK,CAAC;QACd,CAAC;IACH,CAAC;IAED,KAAK,CAAC,OAAO;QACX,IAAI,IAAI,CAAC,OAAO,EAAE,CAAC;YACjB,MAAM,IAAI,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC;YAC3B,IAAI,CAAC,OAAO,GAAG,IAAI,CAAC;YACpB,IAAI,CAAC,aAAa,GAAG,KAAK,CAAC;QAC7B,CAAC;IACH,CAAC;CACF"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { BotDetector } from './BotDetector.js';
|
|
2
|
+
export { FileServer } from './FileServer.js';
|
|
3
|
+
export { RequestRouter } from './RequestRouter.js';
|
|
4
|
+
export { CacheManager } from './CacheManager.js';
|
|
5
|
+
export { SSRRenderer } from './SSRRenderer.js';
|
|
6
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/components/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { BotDetector } from './BotDetector.js';
|
|
2
|
+
export { FileServer } from './FileServer.js';
|
|
3
|
+
export { RequestRouter } from './RequestRouter.js';
|
|
4
|
+
export { CacheManager } from './CacheManager.js';
|
|
5
|
+
export { SSRRenderer } from './SSRRenderer.js';
|
|
6
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/components/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC/C,OAAO,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAC7C,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AACjD,OAAO,EAAE,WAAW,EAAE,MAAM,kBAAkB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/config/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,mBAAmB,CAAC;AAIjD,eAAO,MAAM,aAAa,EAAE,YAqC3B,CAAC;AAEF,wBAAgB,UAAU,IAAI,YAAY,CAEzC"}
|