@cruxjs/base 0.0.1
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 +516 -0
- package/dist/index.cjs +3 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +164 -0
- package/dist/index.d.ts +164 -0
- package/dist/index.js +3 -0
- package/dist/index.js.map +1 -0
- package/package.json +58 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Maysara Elshewehy (https://github.com/maysara-elshewehy)
|
|
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,516 @@
|
|
|
1
|
+
<!-- ╔══════════════════════════════ BEG ══════════════════════════════╗ -->
|
|
2
|
+
|
|
3
|
+
<br>
|
|
4
|
+
<div align="center">
|
|
5
|
+
<p>
|
|
6
|
+
<img src="./assets/img/logo.png" alt="logo" style="" height="60" />
|
|
7
|
+
</p>
|
|
8
|
+
</div>
|
|
9
|
+
|
|
10
|
+
<div align="center">
|
|
11
|
+
<img src="https://img.shields.io/badge/v-0.0.1-black"/>
|
|
12
|
+
<img src="https://img.shields.io/badge/🔥-@cruxjs-black"/>
|
|
13
|
+
<br>
|
|
14
|
+
<img src="https://img.shields.io/github/issues/crux/base?style=flat" alt="Github Repo Issues" />
|
|
15
|
+
<img src="https://img.shields.io/github/stars/crux/base?style=social" alt="GitHub Repo stars" />
|
|
16
|
+
</div>
|
|
17
|
+
<br>
|
|
18
|
+
|
|
19
|
+
<!-- ╚═════════════════════════════════════════════════════════════════╝ -->
|
|
20
|
+
|
|
21
|
+
<br>
|
|
22
|
+
|
|
23
|
+
- ## Quick Start 🔥
|
|
24
|
+
|
|
25
|
+
> **_Core types and utilities for building CruxJS applications and plugins. A shared foundation for @cruxjs/app and plugin packages._**
|
|
26
|
+
|
|
27
|
+
- ### Overview
|
|
28
|
+
|
|
29
|
+
> `@cruxjs/base` is the **shared foundation** for the entire CruxJS ecosystem. It provides:
|
|
30
|
+
|
|
31
|
+
- **Type Definitions**: Core interfaces for plugins, app configuration, lifecycle management, and routing
|
|
32
|
+
|
|
33
|
+
- **Logger**: Debug-aware logging for CruxJS operations and plugins
|
|
34
|
+
|
|
35
|
+
- **PluginRegistry**: Plugin registration and lifecycle hook management
|
|
36
|
+
|
|
37
|
+
- **ResourceMerger**: Smart merging of routes, schemas, and static configs with user priority
|
|
38
|
+
|
|
39
|
+
> This package enables clean separation between **@cruxjs/app** (the framework) and **@cruxjs-plugins/** (domain-specific plugins), allowing plugins to be created independently without importing the entire app framework.
|
|
40
|
+
|
|
41
|
+
<div align="center"> <img src="./assets/img/line.png" alt="line" style="display: block; margin-top:20px;margin-bottom:20px;width:500px;"/> <br> </div>
|
|
42
|
+
|
|
43
|
+
- ### Setup
|
|
44
|
+
|
|
45
|
+
> install [`hmm`](https://github.com/minejs-org/hmm) first.
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
hmm i @cruxjs/base
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
<div align="center"> <img src="./assets/img/line.png" alt="line" style="display: block; margin-top:20px;margin-bottom:20px;width:500px;"/> <br> </div>
|
|
52
|
+
|
|
53
|
+
- ### Usage
|
|
54
|
+
|
|
55
|
+
- ### 1. Type Definitions (Core Types)
|
|
56
|
+
|
|
57
|
+
> Import shared types for building apps and plugins:
|
|
58
|
+
|
|
59
|
+
```typescript
|
|
60
|
+
import {
|
|
61
|
+
// App Configuration & Instance
|
|
62
|
+
AppConfig,
|
|
63
|
+
AppInstance,
|
|
64
|
+
AppContext,
|
|
65
|
+
AppMiddleware,
|
|
66
|
+
|
|
67
|
+
// Plugin System
|
|
68
|
+
CruxPlugin,
|
|
69
|
+
MiddlewareExport,
|
|
70
|
+
|
|
71
|
+
// Lifecycle
|
|
72
|
+
LifecycleContext,
|
|
73
|
+
LifecycleHooks,
|
|
74
|
+
|
|
75
|
+
// Routing & Resources
|
|
76
|
+
RouteDefinition,
|
|
77
|
+
StaticConfig,
|
|
78
|
+
TableSchema
|
|
79
|
+
} from '@cruxjs/base'
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
**Key Types:**
|
|
83
|
+
|
|
84
|
+
```typescript
|
|
85
|
+
// Plugin Interface - what every plugin must implement
|
|
86
|
+
export interface CruxPlugin {
|
|
87
|
+
name : string
|
|
88
|
+
version : string
|
|
89
|
+
|
|
90
|
+
// Resources the plugin provides
|
|
91
|
+
routes? : RouteDefinition[]
|
|
92
|
+
schemas? : TableSchema[]
|
|
93
|
+
middlewares? : MiddlewareExport[]
|
|
94
|
+
static? : StaticConfig[]
|
|
95
|
+
|
|
96
|
+
// Lifecycle hooks
|
|
97
|
+
onRegister? : (app: AppInstance) => Promise<void>
|
|
98
|
+
onAwake? : (ctx: LifecycleContext) => Promise<void>
|
|
99
|
+
onStart? : (ctx: LifecycleContext) => Promise<void>
|
|
100
|
+
onReady? : (ctx: LifecycleContext) => Promise<void>
|
|
101
|
+
onShutdown? : (ctx: LifecycleContext) => Promise<void>
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// App Configuration
|
|
105
|
+
export interface AppConfig {
|
|
106
|
+
server?: {
|
|
107
|
+
port? : number
|
|
108
|
+
host? : string
|
|
109
|
+
logging? : boolean | LoggingConfig
|
|
110
|
+
}
|
|
111
|
+
client?: {
|
|
112
|
+
entry : string
|
|
113
|
+
output : string
|
|
114
|
+
minify? : boolean
|
|
115
|
+
sourcemap? : boolean
|
|
116
|
+
}
|
|
117
|
+
database? : DatabaseConfig | DatabaseConfig[]
|
|
118
|
+
i18n? : I18nConfig
|
|
119
|
+
static? : StaticConfig | StaticConfig[]
|
|
120
|
+
api? : ApiConfig
|
|
121
|
+
security? : SecurityConfig
|
|
122
|
+
routes? : RouteDefinition[]
|
|
123
|
+
middlewares? : AppMiddleware[]
|
|
124
|
+
plugins? : CruxPlugin[]
|
|
125
|
+
debug? : boolean
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
// Route Definition
|
|
129
|
+
export interface RouteDefinition {
|
|
130
|
+
method : 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH' | 'OPTIONS' | 'HEAD'
|
|
131
|
+
path : string
|
|
132
|
+
handler : (c: AppContext) => any
|
|
133
|
+
middlewares? : AppMiddleware[]
|
|
134
|
+
}
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
<div align="center"> <img src="./assets/img/line.png" alt="line" style="display: block; margin-top:20px;margin-bottom:20px;width:500px;"/> <br> </div>
|
|
138
|
+
|
|
139
|
+
- ### 2. Logger Utility
|
|
140
|
+
|
|
141
|
+
Unified logging for CruxJS operations and plugins with debug mode support:
|
|
142
|
+
|
|
143
|
+
```typescript
|
|
144
|
+
import { Logger } from '@cruxjs/base'
|
|
145
|
+
|
|
146
|
+
// Initialize logger (second param: debug mode)
|
|
147
|
+
const logger = new Logger(true)
|
|
148
|
+
|
|
149
|
+
// Log lifecycle phases
|
|
150
|
+
logger.phase('Database Setup')
|
|
151
|
+
|
|
152
|
+
// General info logs (only shown in debug mode)
|
|
153
|
+
logger.info('Loading configuration...')
|
|
154
|
+
|
|
155
|
+
// Success logs (only shown in debug mode)
|
|
156
|
+
logger.success('Server running on port 3000')
|
|
157
|
+
|
|
158
|
+
// Error logs (always shown)
|
|
159
|
+
logger.error('Failed to connect to database', err)
|
|
160
|
+
|
|
161
|
+
// Plugin-specific logs
|
|
162
|
+
logger.plugin('@cruxjs-plugins/auth', 'Initializing JWT strategy')
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
**Output Example:**
|
|
166
|
+
```
|
|
167
|
+
[CruxJS] ⚡ Phase: Database Setup
|
|
168
|
+
[CruxJS] Loading configuration...
|
|
169
|
+
[CruxJS] ✓ Server running on port 3000
|
|
170
|
+
[CruxJS:@cruxjs-plugins/auth] Initializing JWT strategy
|
|
171
|
+
[CruxJS] ✗ Failed to connect to database
|
|
172
|
+
Error: Connection timeout
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
<div align="center"> <img src="./assets/img/line.png" alt="line" style="display: block; margin-top:20px;margin-bottom:20px;width:500px;"/> <br> </div>
|
|
176
|
+
|
|
177
|
+
- ### 3. Plugin Registry
|
|
178
|
+
|
|
179
|
+
Manage plugin registration and lifecycle hooks:
|
|
180
|
+
|
|
181
|
+
```typescript
|
|
182
|
+
import { PluginRegistry, Logger } from '@cruxjs/base'
|
|
183
|
+
import type { AppInstance, LifecycleContext } from '@cruxjs/base'
|
|
184
|
+
|
|
185
|
+
const logger = new Logger(true)
|
|
186
|
+
const registry = new PluginRegistry(logger)
|
|
187
|
+
|
|
188
|
+
// Register a plugin
|
|
189
|
+
const myPlugin = {
|
|
190
|
+
name: '@cruxjs-plugins/auth',
|
|
191
|
+
version: '1.0.0',
|
|
192
|
+
routes: [{ method: 'POST', path: '/login', handler: (c) => c.json({}) }],
|
|
193
|
+
async onRegister(app: AppInstance) {
|
|
194
|
+
console.log('Plugin registered!')
|
|
195
|
+
}
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
await registry.register(myPlugin, appInstance)
|
|
199
|
+
|
|
200
|
+
// Collect resources from all registered plugins
|
|
201
|
+
const allRoutes = registry.collectRoutes()
|
|
202
|
+
const allSchemas = registry.collectSchemas()
|
|
203
|
+
const allMiddlewares = registry.collectMiddlewares()
|
|
204
|
+
const allStatic = registry.collectStatic()
|
|
205
|
+
|
|
206
|
+
// Call lifecycle hooks across all plugins
|
|
207
|
+
await registry.callHook('onStart', lifecycleContext)
|
|
208
|
+
await registry.callHook('onReady', lifecycleContext)
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
**Registry Methods:**
|
|
212
|
+
|
|
213
|
+
```typescript
|
|
214
|
+
// Register a plugin and call its onRegister hook
|
|
215
|
+
register(plugin: CruxPlugin, app: AppInstance): Promise<void>
|
|
216
|
+
|
|
217
|
+
// Get all registered plugins
|
|
218
|
+
getAll(): CruxPlugin[]
|
|
219
|
+
|
|
220
|
+
// Call a lifecycle hook on all plugins that have it
|
|
221
|
+
callHook(hook: 'onAwake' | 'onStart' | 'onReady' | 'onShutdown', ctx: LifecycleContext): Promise<void>
|
|
222
|
+
|
|
223
|
+
// Collect resources from all plugins
|
|
224
|
+
collectRoutes(): RouteDefinition[]
|
|
225
|
+
collectSchemas(): TableSchema[]
|
|
226
|
+
collectMiddlewares(): Map<string, AppMiddleware>
|
|
227
|
+
collectStatic(): StaticConfig[]
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
<div align="center"> <img src="./assets/img/line.png" alt="line" style="display: block; margin-top:20px;margin-bottom:20px;width:500px;"/> <br> </div>
|
|
231
|
+
|
|
232
|
+
- ### 4. Resource Merger
|
|
233
|
+
|
|
234
|
+
Intelligently merge routes, schemas, and static configs with user-defined resources taking priority:
|
|
235
|
+
|
|
236
|
+
```typescript
|
|
237
|
+
import { ResourceMerger, Logger } from '@cruxjs/base'
|
|
238
|
+
import type { RouteDefinition, TableSchema, StaticConfig } from '@cruxjs/base'
|
|
239
|
+
|
|
240
|
+
const logger = new Logger(false)
|
|
241
|
+
const merger = new ResourceMerger(logger)
|
|
242
|
+
|
|
243
|
+
// User routes have priority over plugin routes
|
|
244
|
+
const userRoutes: RouteDefinition[] = [
|
|
245
|
+
{ method: 'GET', path: '/api/users', handler: (c) => c.json([]) }
|
|
246
|
+
]
|
|
247
|
+
const pluginRoutes: RouteDefinition[] = [
|
|
248
|
+
{ method: 'GET', path: '/api/users', handler: (c) => c.json({}) },
|
|
249
|
+
{ method: 'POST', path: '/api/users', handler: (c) => c.json({}) }
|
|
250
|
+
]
|
|
251
|
+
|
|
252
|
+
const merged = merger.mergeRoutes(userRoutes, pluginRoutes)
|
|
253
|
+
// Result: GET /api/users uses user handler, POST /api/users uses plugin handler
|
|
254
|
+
|
|
255
|
+
// Same priority system for schemas
|
|
256
|
+
const schemas = merger.mergeSchemas(userSchemas, pluginSchemas)
|
|
257
|
+
|
|
258
|
+
// Static files are simply concatenated
|
|
259
|
+
const statics = merger.mergeStatic(userStatic, pluginStatic)
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
**Merge Behavior:**
|
|
263
|
+
|
|
264
|
+
| Resource | Priority | Behavior |
|
|
265
|
+
| -------- | ---------- | ------------------------------------------------------- |
|
|
266
|
+
| Routes | User first | Duplicate routes (method + path) override plugin routes |
|
|
267
|
+
| Schemas | User first | Duplicate schemas (by name) override plugin schemas |
|
|
268
|
+
| Static | Both | All configs are included (no deduplication) |
|
|
269
|
+
|
|
270
|
+
<div align="center"> <img src="./assets/img/line.png" alt="line" style="display: block; margin-top:20px;margin-bottom:20px;width:500px;"/> <br> </div>
|
|
271
|
+
|
|
272
|
+
- ### 5. Creating a Plugin
|
|
273
|
+
|
|
274
|
+
Here's a complete example of creating a plugin using `@cruxjs/base`:
|
|
275
|
+
|
|
276
|
+
```typescript
|
|
277
|
+
// plugins/auth/index.ts
|
|
278
|
+
import type { CruxPlugin, AppInstance, LifecycleContext } from '@cruxjs/base'
|
|
279
|
+
|
|
280
|
+
export function authPlugin(): CruxPlugin {
|
|
281
|
+
return {
|
|
282
|
+
name: '@cruxjs-plugins/auth',
|
|
283
|
+
version: '1.0.0',
|
|
284
|
+
|
|
285
|
+
// Routes provided by this plugin
|
|
286
|
+
routes: [
|
|
287
|
+
{
|
|
288
|
+
method: 'POST',
|
|
289
|
+
path: '/api/auth/login',
|
|
290
|
+
handler: async (c) => {
|
|
291
|
+
const { email, password } = await c.req.json()
|
|
292
|
+
// Authentication logic
|
|
293
|
+
return c.json({ token: 'jwt-token' })
|
|
294
|
+
}
|
|
295
|
+
},
|
|
296
|
+
{
|
|
297
|
+
method: 'POST',
|
|
298
|
+
path: '/api/auth/logout',
|
|
299
|
+
handler: (c) => c.json({ success: true })
|
|
300
|
+
}
|
|
301
|
+
],
|
|
302
|
+
|
|
303
|
+
// Database schemas
|
|
304
|
+
schemas: [
|
|
305
|
+
{
|
|
306
|
+
name: 'users',
|
|
307
|
+
columns: [
|
|
308
|
+
{ name: 'id', type: 'INTEGER', primaryKey: true },
|
|
309
|
+
{ name: 'email', type: 'TEXT', unique: true },
|
|
310
|
+
{ name: 'password_hash', type: 'TEXT' }
|
|
311
|
+
]
|
|
312
|
+
}
|
|
313
|
+
],
|
|
314
|
+
|
|
315
|
+
// Middleware exports
|
|
316
|
+
middlewares: [
|
|
317
|
+
{
|
|
318
|
+
name: 'authRequired',
|
|
319
|
+
handler: async (c, next) => {
|
|
320
|
+
const token = c.req.header('Authorization')
|
|
321
|
+
if (!token) return c.json({ error: 'Unauthorized' }, 401)
|
|
322
|
+
await next()
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
],
|
|
326
|
+
|
|
327
|
+
// Static files (e.g., docs)
|
|
328
|
+
static: [
|
|
329
|
+
{ path: '/auth-docs', directory: './docs/auth' }
|
|
330
|
+
],
|
|
331
|
+
|
|
332
|
+
// Lifecycle hooks
|
|
333
|
+
async onRegister(app: AppInstance) {
|
|
334
|
+
console.log('Auth plugin registered')
|
|
335
|
+
},
|
|
336
|
+
|
|
337
|
+
async onStart(ctx: LifecycleContext) {
|
|
338
|
+
console.log('Auth plugin started - creating tables...')
|
|
339
|
+
// Initialize database tables
|
|
340
|
+
},
|
|
341
|
+
|
|
342
|
+
async onReady(ctx: LifecycleContext) {
|
|
343
|
+
console.log('Auth plugin ready!')
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
**Export from your plugin:**
|
|
350
|
+
|
|
351
|
+
```typescript
|
|
352
|
+
// plugins/auth/package.json
|
|
353
|
+
{
|
|
354
|
+
"name": "@cruxjs-plugins/auth",
|
|
355
|
+
"version": "1.0.0",
|
|
356
|
+
"main": "./dist/index.js",
|
|
357
|
+
"types": "./dist/index.d.ts",
|
|
358
|
+
"exports": {
|
|
359
|
+
".": {
|
|
360
|
+
"import": "./dist/index.js",
|
|
361
|
+
"types": "./dist/index.d.ts"
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
```
|
|
366
|
+
|
|
367
|
+
<div align="center"> <img src="./assets/img/line.png" alt="line" style="display: block; margin-top:20px;margin-bottom:20px;width:500px;"/> <br> </div>
|
|
368
|
+
|
|
369
|
+
- ### 6. Using Plugins in @cruxjs/app
|
|
370
|
+
|
|
371
|
+
```typescript
|
|
372
|
+
import { createApp } from '@cruxjs/app'
|
|
373
|
+
import { authPlugin } from '@cruxjs-plugins/auth'
|
|
374
|
+
import { blogPlugin } from '@cruxjs-plugins/blog'
|
|
375
|
+
|
|
376
|
+
const app = createApp({
|
|
377
|
+
server: { port: 3000 },
|
|
378
|
+
database: { connection: './app.db' },
|
|
379
|
+
plugins: [
|
|
380
|
+
authPlugin(),
|
|
381
|
+
blogPlugin({ defaultLanguage: 'en' })
|
|
382
|
+
]
|
|
383
|
+
})
|
|
384
|
+
|
|
385
|
+
await app.start()
|
|
386
|
+
```
|
|
387
|
+
|
|
388
|
+
All plugins are automatically:
|
|
389
|
+
- ✅ Registered with their `onRegister` hooks called
|
|
390
|
+
- ✅ Resources (routes, schemas, middlewares, static) merged intelligently
|
|
391
|
+
- ✅ Lifecycle hooks called in correct sequence
|
|
392
|
+
- ✅ Available in the app instance
|
|
393
|
+
|
|
394
|
+
<div align="center"> <img src="./assets/img/line.png" alt="line" style="display: block; margin-top:20px;margin-bottom:20px;width:500px;"/> <br> </div>
|
|
395
|
+
|
|
396
|
+
- ### Architecture
|
|
397
|
+
|
|
398
|
+
**The Three-Layer CruxJS Architecture:**
|
|
399
|
+
|
|
400
|
+
```
|
|
401
|
+
┌───────────────────────────────────┐
|
|
402
|
+
│ @cruxjs/app (Framework) │
|
|
403
|
+
│ - Creates HTTP server │
|
|
404
|
+
│ - Manages lifecycle │
|
|
405
|
+
│ - Orchestrates plugins │
|
|
406
|
+
└───────────────────────────────────┘
|
|
407
|
+
↓
|
|
408
|
+
┌───────────────────────────────────┐
|
|
409
|
+
│ @cruxjs-plugins/* (Logic Layer) │
|
|
410
|
+
│ - Business logic │
|
|
411
|
+
│ - API routes & schemas │
|
|
412
|
+
│ - Independent plugins │
|
|
413
|
+
│ (Uses @cruxjs/base types only) │
|
|
414
|
+
└───────────────────────────────────┘
|
|
415
|
+
↓
|
|
416
|
+
┌───────────────────────────────────┐
|
|
417
|
+
│ @cruxjs-kit/* (UI Layer) │
|
|
418
|
+
│ - JSX components + @mineui style │
|
|
419
|
+
│ - Client-side logic │
|
|
420
|
+
│ - No business logic │
|
|
421
|
+
└───────────────────────────────────┘
|
|
422
|
+
```
|
|
423
|
+
|
|
424
|
+
<div align="center"> <img src="./assets/img/line.png" alt="line" style="display: block; margin-top:20px;margin-bottom:20px;width:500px;"/> <br> </div>
|
|
425
|
+
|
|
426
|
+
- ### API Reference
|
|
427
|
+
|
|
428
|
+
- #### Logger
|
|
429
|
+
|
|
430
|
+
```typescript
|
|
431
|
+
class Logger {
|
|
432
|
+
constructor(debug: boolean = false)
|
|
433
|
+
|
|
434
|
+
phase(name: string): void
|
|
435
|
+
info(msg: string): void
|
|
436
|
+
success(msg: string): void
|
|
437
|
+
error(msg: string, err?: Error): void
|
|
438
|
+
plugin(name: string, msg: string): void
|
|
439
|
+
}
|
|
440
|
+
```
|
|
441
|
+
|
|
442
|
+
- #### PluginRegistry
|
|
443
|
+
|
|
444
|
+
```typescript
|
|
445
|
+
class PluginRegistry {
|
|
446
|
+
constructor(logger: Logger)
|
|
447
|
+
|
|
448
|
+
register(plugin: CruxPlugin, app: AppInstance): Promise<void>
|
|
449
|
+
getAll(): CruxPlugin[]
|
|
450
|
+
callHook(hook: HookName, ctx: LifecycleContext): Promise<void>
|
|
451
|
+
collectRoutes(): RouteDefinition[]
|
|
452
|
+
collectSchemas(): TableSchema[]
|
|
453
|
+
collectMiddlewares(): Map<string, AppMiddleware>
|
|
454
|
+
collectStatic(): StaticConfig[]
|
|
455
|
+
}
|
|
456
|
+
```
|
|
457
|
+
|
|
458
|
+
- #### ResourceMerger
|
|
459
|
+
|
|
460
|
+
```typescript
|
|
461
|
+
class ResourceMerger {
|
|
462
|
+
constructor(logger: Logger)
|
|
463
|
+
|
|
464
|
+
mergeRoutes(userRoutes?: RouteDefinition[], pluginRoutes?: RouteDefinition[]): RouteDefinition[]
|
|
465
|
+
mergeSchemas(userSchemas?: TableSchema[], pluginSchemas?: TableSchema[]): TableSchema[]
|
|
466
|
+
mergeStatic(userStatic?: StaticConfig[], pluginStatic?: StaticConfig[]): StaticConfig[]
|
|
467
|
+
}
|
|
468
|
+
```
|
|
469
|
+
|
|
470
|
+
<div align="center"> <img src="./assets/img/line.png" alt="line" style="display: block; margin-top:20px;margin-bottom:20px;width:500px;"/> <br> </div>
|
|
471
|
+
|
|
472
|
+
- ### FAQ
|
|
473
|
+
|
|
474
|
+
- #### Q: When should I use @cruxjs/base vs @cruxjs/app?
|
|
475
|
+
|
|
476
|
+
- Use `@cruxjs/base` when:
|
|
477
|
+
|
|
478
|
+
> Creating a plugin for the CruxJS ecosystem
|
|
479
|
+
|
|
480
|
+
> You only need types and utilities, not the full framework
|
|
481
|
+
|
|
482
|
+
> You want minimal dependencies in your plugin package
|
|
483
|
+
|
|
484
|
+
- Use `@cruxjs/app` when:
|
|
485
|
+
|
|
486
|
+
> Building a complete CruxJS application
|
|
487
|
+
|
|
488
|
+
> You need to orchestrate plugins and start a server
|
|
489
|
+
|
|
490
|
+
- #### Q: Can I use @cruxjs/base without @cruxjs/app?
|
|
491
|
+
|
|
492
|
+
> Absolutely! `@cruxjs/base` is a standalone package with no dependency on `@cruxjs/app`. Plugins can use it independently.
|
|
493
|
+
|
|
494
|
+
- #### Q: How does resource merging prioritize user-defined resources?
|
|
495
|
+
|
|
496
|
+
> **Routes & Schemas**: User-defined resources override plugins. If both define the same route (method + path) or schema (by name), user wins.
|
|
497
|
+
|
|
498
|
+
> **Static**: All configs are combined without deduplication.
|
|
499
|
+
|
|
500
|
+
- #### Q: What if two plugins define the same route?
|
|
501
|
+
|
|
502
|
+
> The first plugin to register wins. However, if the user defines the same route, the user's definition takes priority. Use the `debug` flag to see what's being merged.
|
|
503
|
+
|
|
504
|
+
<!-- ╚═════════════════════════════════════════════════════════════════╝ -->
|
|
505
|
+
|
|
506
|
+
<!-- ╔══════════════════════════════ END ══════════════════════════════╗ -->
|
|
507
|
+
|
|
508
|
+
<br>
|
|
509
|
+
|
|
510
|
+
---
|
|
511
|
+
|
|
512
|
+
<div align="center">
|
|
513
|
+
<a href="https://github.com/maysara-elshewehy"><img src="https://img.shields.io/badge/by-Maysara-black"/></a>
|
|
514
|
+
</div>
|
|
515
|
+
|
|
516
|
+
<!-- ╚═════════════════════════════════════════════════════════════════╝ -->
|
package/dist/index.cjs
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
'use strict';var g=class{constructor(e=false){this.debug=e;}phase(e){this.debug&&console.log(`
|
|
2
|
+
[CruxJS] \u26A1 Phase: ${e}`);}info(e){this.debug&&console.log(`[CruxJS] ${e}`);}success(e){this.debug&&console.log(`[CruxJS] \u2713 ${e}`);}error(e,t){console.error(`[CruxJS] \u2717 ${e}`),t&&console.error(t);}plugin(e,t){this.debug&&console.log(`[CruxJS:${e}] ${t}`);}};var a=class{constructor(e){this.logger=e;}mergeRoutes(e=[],t=[]){let o=[...e],i=new Set(e.map(s=>`${s.method}:${s.path}`));for(let s of t){let n=`${s.method}:${s.path}`;i.has(n)?this.logger.info(`Skipping plugin route ${n} (overridden by user)`):o.push(s);}return o}mergeSchemas(e=[],t=[]){let o=[...e],i=new Set(e.map(s=>s.name));for(let s of t)i.has(s.name)?this.logger.info(`Skipping plugin schema ${s.name} (overridden by user)`):o.push(s);return o}mergeStatic(e=[],t=[]){return [...e,...t]}};var l=class{constructor(e){this.plugins=[];this.logger=e;}async register(e,t){this.logger.info(`Registering plugin: ${e.name}`),this.plugins.push(e),e.onRegister&&await e.onRegister(t),this.logger.success(`Plugin registered: ${e.name} v${e.version}`);}getAll(){return this.plugins}async callHook(e,t){for(let o of this.plugins)o[e]&&(this.logger.plugin(o.name,`Calling ${e}`),await o[e](t));}collectRoutes(){let e=[];for(let t of this.plugins)t.routes&&(e.push(...t.routes),this.logger.plugin(t.name,`Provided ${t.routes.length} routes`));return e}collectSchemas(){let e=[];for(let t of this.plugins)t.schemas&&(e.push(...t.schemas),this.logger.plugin(t.name,`Provided ${t.schemas.length} schemas`));return e}collectMiddlewares(){let e=new Map;for(let t of this.plugins)if(t.middlewares)for(let o of t.middlewares)e.set(`${t.name}:${o.name}`,o.handler),this.logger.plugin(t.name,`Provided middleware: ${o.name}`);return e}collectStatic(){let e=[];for(let t of this.plugins)t.static&&(e.push(...t.static),this.logger.plugin(t.name,`Provided ${t.static.length} static configs`));return e}};exports.Logger=g;exports.PluginRegistry=l;exports.ResourceMerger=a;//# sourceMappingURL=index.cjs.map
|
|
3
|
+
//# sourceMappingURL=index.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/mod/logger.ts","../src/mod/resource_merger.ts","../src/mod/plugin_registry.ts"],"names":["Logger","debug","name","msg","err","ResourceMerger","logger","userRoutes","pluginRoutes","merged","userPaths","r","route","key","userSchemas","pluginSchemas","userTables","schema","userStatic","pluginStatic","PluginRegistry","plugin","app","hook","ctx","routes","schemas","middlewares","mw","statics"],"mappings":"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","file":"index.cjs","sourcesContent":["// src/mod/logger.ts\r\n//\r\n// Made with ❤️ by Maysara.\r\n\r\n\r\n\r\n// ╔════════════════════════════════════════ PACK ════════════════════════════════════════╗\r\n\r\n\r\n// ╚══════════════════════════════════════════════════════════════════════════════════════╝\r\n\r\n\r\n\r\n// ╔════════════════════════════════════════ CORE ════════════════════════════════════════╗\r\n\r\n export class Logger {\r\n constructor(private debug: boolean = false) {}\r\n\r\n phase(name: string) {\r\n if (!this.debug) return;\r\n console.log(`\\n[CruxJS] ⚡ Phase: ${name}`);\r\n }\r\n\r\n info(msg: string) {\r\n if (!this.debug) return;\r\n console.log(`[CruxJS] ${msg}`);\r\n }\r\n\r\n success(msg: string) {\r\n if (!this.debug) return;\r\n console.log(`[CruxJS] ✓ ${msg}`);\r\n }\r\n\r\n error(msg: string, err?: Error) {\r\n console.error(`[CruxJS] ✗ ${msg}`);\r\n if (err) console.error(err);\r\n }\r\n\r\n plugin(name: string, msg: string) {\r\n if (!this.debug) return;\r\n console.log(`[CruxJS:${name}] ${msg}`);\r\n }\r\n }\r\n\r\n// ╚══════════════════════════════════════════════════════════════════════════════════════╝","// src/mod/resource_merger.ts\r\n//\r\n// Made with ❤️ by Maysara.\r\n\r\n\r\n\r\n// ╔════════════════════════════════════════ PACK ════════════════════════════════════════╗\r\n\r\n import { RouteDefinition, TableSchema, StaticConfig } from '../types';\r\n import { Logger } from './logger';\r\n\r\n// ╚══════════════════════════════════════════════════════════════════════════════════════╝\r\n\r\n\r\n\r\n// ╔════════════════════════════════════════ CORE ════════════════════════════════════════╗\r\n\r\n export class ResourceMerger {\r\n private logger: Logger;\r\n\r\n constructor(logger: Logger) {\r\n this.logger = logger;\r\n }\r\n\r\n mergeRoutes(\r\n userRoutes: RouteDefinition[] = [],\r\n pluginRoutes: RouteDefinition[] = []\r\n ): RouteDefinition[] {\r\n // User routes have priority\r\n const merged = [...userRoutes];\r\n const userPaths = new Set(userRoutes.map(r => `${r.method}:${r.path}`));\r\n\r\n for (const route of pluginRoutes) {\r\n const key = `${route.method}:${route.path}`;\r\n\r\n if (!userPaths.has(key)) {\r\n merged.push(route);\r\n } else {\r\n this.logger.info(`Skipping plugin route ${key} (overridden by user)`);\r\n }\r\n }\r\n\r\n return merged;\r\n }\r\n\r\n mergeSchemas(\r\n userSchemas: TableSchema[] = [],\r\n pluginSchemas: TableSchema[] = []\r\n ): TableSchema[] {\r\n // User schemas have priority\r\n const merged = [...userSchemas];\r\n const userTables = new Set(userSchemas.map(s => s.name));\r\n\r\n for (const schema of pluginSchemas) {\r\n if (!userTables.has(schema.name)) {\r\n merged.push(schema);\r\n } else {\r\n this.logger.info(`Skipping plugin schema ${schema.name} (overridden by user)`);\r\n }\r\n }\r\n\r\n return merged;\r\n }\r\n\r\n mergeStatic(\r\n userStatic: StaticConfig[] = [],\r\n pluginStatic: StaticConfig[] = []\r\n ): StaticConfig[] {\r\n return [...userStatic, ...pluginStatic];\r\n }\r\n }\r\n\r\n// ╚══════════════════════════════════════════════════════════════════════════════════════╝","// src/mod/plugin_registry.ts\r\n//\r\n// Made with ❤️ by Maysara.\r\n\r\n\r\n\r\n// ╔════════════════════════════════════════ PACK ════════════════════════════════════════╗\r\n\r\n import * as types from '../types';\r\n import { Logger } from './logger';\r\n\r\n// ╚══════════════════════════════════════════════════════════════════════════════════════╝\r\n\r\n\r\n\r\n// ╔════════════════════════════════════════ CORE ════════════════════════════════════════╗\r\n\r\n export class PluginRegistry {\r\n private plugins: types.CruxPlugin[] = [];\r\n private logger: Logger;\r\n\r\n constructor(logger: Logger) {\r\n this.logger = logger;\r\n }\r\n\r\n async register(plugin: types.CruxPlugin, app: types.AppInstance) {\r\n this.logger.info(`Registering plugin: ${plugin.name}`);\r\n\r\n this.plugins.push(plugin);\r\n\r\n // Call plugin's onRegister hook\r\n if (plugin.onRegister) {\r\n await plugin.onRegister(app);\r\n }\r\n\r\n this.logger.success(`Plugin registered: ${plugin.name} v${plugin.version}`);\r\n }\r\n\r\n getAll(): types.CruxPlugin[] {\r\n return this.plugins;\r\n }\r\n\r\n async callHook(\r\n hook: keyof Pick<types.CruxPlugin, 'onAwake' | 'onStart' | 'onReady' | 'onShutdown'>,\r\n ctx: types.LifecycleContext\r\n ) {\r\n for (const plugin of this.plugins) {\r\n if (plugin[hook]) {\r\n this.logger.plugin(plugin.name, `Calling ${hook}`);\r\n await plugin[hook]!(ctx);\r\n }\r\n }\r\n }\r\n\r\n collectRoutes(): types.RouteDefinition[] {\r\n const routes: types.RouteDefinition[] = [];\r\n\r\n for (const plugin of this.plugins) {\r\n if (plugin.routes) {\r\n routes.push(...plugin.routes);\r\n this.logger.plugin(plugin.name, `Provided ${plugin.routes.length} routes`);\r\n }\r\n }\r\n\r\n return routes;\r\n }\r\n\r\n collectSchemas(): types.TableSchema[] {\r\n const schemas: types.TableSchema[] = [];\r\n\r\n for (const plugin of this.plugins) {\r\n if (plugin.schemas) {\r\n schemas.push(...plugin.schemas);\r\n this.logger.plugin(plugin.name, `Provided ${plugin.schemas.length} schemas`);\r\n }\r\n }\r\n\r\n return schemas;\r\n }\r\n\r\n collectMiddlewares(): Map<string, types.AppMiddleware> {\r\n const middlewares = new Map<string, types.AppMiddleware>();\r\n\r\n for (const plugin of this.plugins) {\r\n if (plugin.middlewares) {\r\n for (const mw of plugin.middlewares) {\r\n middlewares.set(`${plugin.name}:${mw.name}`, mw.handler);\r\n this.logger.plugin(plugin.name, `Provided middleware: ${mw.name}`);\r\n }\r\n }\r\n }\r\n\r\n return middlewares;\r\n }\r\n\r\n collectStatic(): types.StaticConfig[] {\r\n const statics: types.StaticConfig[] = [];\r\n\r\n for (const plugin of this.plugins) {\r\n if (plugin.static) {\r\n statics.push(...plugin.static);\r\n this.logger.plugin(plugin.name, `Provided ${plugin.static.length} static configs`);\r\n }\r\n }\r\n\r\n return statics;\r\n }\r\n }\r\n\r\n// ╚══════════════════════════════════════════════════════════════════════════════════════╝"]}
|
package/dist/index.d.cts
ADDED
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
import { TableSchema as TableSchema$1, DB } from '@minejs/db';
|
|
2
|
+
import { AppContext as AppContext$1 } from '@minejs/server';
|
|
3
|
+
|
|
4
|
+
type AppContext = AppContext$1;
|
|
5
|
+
type TableSchema = TableSchema$1;
|
|
6
|
+
interface CruxPlugin {
|
|
7
|
+
name: string;
|
|
8
|
+
version: string;
|
|
9
|
+
routes?: RouteDefinition[];
|
|
10
|
+
schemas?: TableSchema$1[];
|
|
11
|
+
middlewares?: MiddlewareExport[];
|
|
12
|
+
static?: StaticConfig[];
|
|
13
|
+
onRegister?: (app: AppInstance) => void | Promise<void>;
|
|
14
|
+
onAwake?: (ctx: LifecycleContext) => void | Promise<void>;
|
|
15
|
+
onStart?: (ctx: LifecycleContext) => void | Promise<void>;
|
|
16
|
+
onReady?: (ctx: LifecycleContext) => void | Promise<void>;
|
|
17
|
+
onShutdown?: (ctx: LifecycleContext) => void | Promise<void>;
|
|
18
|
+
}
|
|
19
|
+
interface MiddlewareExport {
|
|
20
|
+
name: string;
|
|
21
|
+
handler: AppMiddleware;
|
|
22
|
+
}
|
|
23
|
+
type AppMiddleware = (c: AppContext$1, next: () => void | Promise<void>) => any;
|
|
24
|
+
interface AppConfig {
|
|
25
|
+
server?: {
|
|
26
|
+
port?: number;
|
|
27
|
+
host?: string;
|
|
28
|
+
logging?: boolean | {
|
|
29
|
+
level?: 'debug' | 'info' | 'warn' | 'error';
|
|
30
|
+
pretty?: boolean;
|
|
31
|
+
};
|
|
32
|
+
};
|
|
33
|
+
client?: {
|
|
34
|
+
entry: string;
|
|
35
|
+
output: string;
|
|
36
|
+
minify?: boolean;
|
|
37
|
+
sourcemap?: boolean;
|
|
38
|
+
target?: 'browser' | 'bun';
|
|
39
|
+
external?: string[];
|
|
40
|
+
};
|
|
41
|
+
database?: {
|
|
42
|
+
connection: string;
|
|
43
|
+
schema?: string;
|
|
44
|
+
name?: string;
|
|
45
|
+
timeout?: number;
|
|
46
|
+
} | {
|
|
47
|
+
connection: string;
|
|
48
|
+
schema?: string;
|
|
49
|
+
name?: string;
|
|
50
|
+
timeout?: number;
|
|
51
|
+
}[];
|
|
52
|
+
i18n?: {
|
|
53
|
+
defaultLanguage: string;
|
|
54
|
+
supportedLanguages: string[];
|
|
55
|
+
basePath: string;
|
|
56
|
+
fileExtension?: string;
|
|
57
|
+
};
|
|
58
|
+
static?: {
|
|
59
|
+
path: string;
|
|
60
|
+
directory: string;
|
|
61
|
+
maxAge?: number;
|
|
62
|
+
index?: string[];
|
|
63
|
+
} | {
|
|
64
|
+
path: string;
|
|
65
|
+
directory: string;
|
|
66
|
+
maxAge?: number;
|
|
67
|
+
index?: string[];
|
|
68
|
+
}[];
|
|
69
|
+
api?: {
|
|
70
|
+
path: string;
|
|
71
|
+
directory: string;
|
|
72
|
+
autoLoad?: boolean;
|
|
73
|
+
};
|
|
74
|
+
security?: {
|
|
75
|
+
cors?: boolean | {
|
|
76
|
+
origin?: string | string[];
|
|
77
|
+
credentials?: boolean;
|
|
78
|
+
maxAge?: number;
|
|
79
|
+
};
|
|
80
|
+
rateLimit?: boolean | {
|
|
81
|
+
windowMs?: number;
|
|
82
|
+
max?: number;
|
|
83
|
+
};
|
|
84
|
+
};
|
|
85
|
+
routes?: RouteDefinition[];
|
|
86
|
+
middlewares?: AppMiddleware[];
|
|
87
|
+
plugins?: CruxPlugin[];
|
|
88
|
+
debug?: boolean;
|
|
89
|
+
}
|
|
90
|
+
interface RouteDefinition {
|
|
91
|
+
method: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH' | 'OPTIONS' | 'HEAD' | ('GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH' | 'OPTIONS' | 'HEAD')[];
|
|
92
|
+
path: string;
|
|
93
|
+
handler: (c: AppContext$1) => any;
|
|
94
|
+
middlewares?: AppMiddleware[];
|
|
95
|
+
}
|
|
96
|
+
interface StaticConfig {
|
|
97
|
+
path: string;
|
|
98
|
+
directory: string;
|
|
99
|
+
maxAge?: number;
|
|
100
|
+
index?: string[];
|
|
101
|
+
}
|
|
102
|
+
interface LifecycleContext {
|
|
103
|
+
config: AppConfig;
|
|
104
|
+
databases: Map<string, DB>;
|
|
105
|
+
plugins: CruxPlugin[];
|
|
106
|
+
server?: any;
|
|
107
|
+
clientBuild?: {
|
|
108
|
+
success: boolean;
|
|
109
|
+
outputs: string[];
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
interface LifecycleHooks {
|
|
113
|
+
onConfig?: (config: AppConfig) => AppConfig | Promise<AppConfig>;
|
|
114
|
+
onAwake?: (ctx: LifecycleContext) => void | Promise<void>;
|
|
115
|
+
onStart?: (ctx: LifecycleContext) => void | Promise<void>;
|
|
116
|
+
onReady?: (ctx: LifecycleContext) => void | Promise<void>;
|
|
117
|
+
onFinish?: (ctx: LifecycleContext) => void | Promise<void>;
|
|
118
|
+
onError?: (ctx: LifecycleContext, phase: string, error: Error) => void | Promise<void>;
|
|
119
|
+
}
|
|
120
|
+
interface AppInstance {
|
|
121
|
+
config: AppConfig;
|
|
122
|
+
server: any;
|
|
123
|
+
databases: Map<string, DB>;
|
|
124
|
+
plugins: CruxPlugin[];
|
|
125
|
+
middlewares: Map<string, AppMiddleware>;
|
|
126
|
+
start(): Promise<void>;
|
|
127
|
+
stop(): Promise<void>;
|
|
128
|
+
restart(): Promise<void>;
|
|
129
|
+
getContext(): LifecycleContext;
|
|
130
|
+
getMiddleware(name: string): AppMiddleware | undefined;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
declare class Logger {
|
|
134
|
+
private debug;
|
|
135
|
+
constructor(debug?: boolean);
|
|
136
|
+
phase(name: string): void;
|
|
137
|
+
info(msg: string): void;
|
|
138
|
+
success(msg: string): void;
|
|
139
|
+
error(msg: string, err?: Error): void;
|
|
140
|
+
plugin(name: string, msg: string): void;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
declare class ResourceMerger {
|
|
144
|
+
private logger;
|
|
145
|
+
constructor(logger: Logger);
|
|
146
|
+
mergeRoutes(userRoutes?: RouteDefinition[], pluginRoutes?: RouteDefinition[]): RouteDefinition[];
|
|
147
|
+
mergeSchemas(userSchemas?: TableSchema[], pluginSchemas?: TableSchema[]): TableSchema[];
|
|
148
|
+
mergeStatic(userStatic?: StaticConfig[], pluginStatic?: StaticConfig[]): StaticConfig[];
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
declare class PluginRegistry {
|
|
152
|
+
private plugins;
|
|
153
|
+
private logger;
|
|
154
|
+
constructor(logger: Logger);
|
|
155
|
+
register(plugin: CruxPlugin, app: AppInstance): Promise<void>;
|
|
156
|
+
getAll(): CruxPlugin[];
|
|
157
|
+
callHook(hook: keyof Pick<CruxPlugin, 'onAwake' | 'onStart' | 'onReady' | 'onShutdown'>, ctx: LifecycleContext): Promise<void>;
|
|
158
|
+
collectRoutes(): RouteDefinition[];
|
|
159
|
+
collectSchemas(): TableSchema[];
|
|
160
|
+
collectMiddlewares(): Map<string, AppMiddleware>;
|
|
161
|
+
collectStatic(): StaticConfig[];
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
export { type AppConfig, type AppContext, type AppInstance, type AppMiddleware, type CruxPlugin, type LifecycleContext, type LifecycleHooks, Logger, type MiddlewareExport, PluginRegistry, ResourceMerger, type RouteDefinition, type StaticConfig, type TableSchema };
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,164 @@
|
|
|
1
|
+
import { TableSchema as TableSchema$1, DB } from '@minejs/db';
|
|
2
|
+
import { AppContext as AppContext$1 } from '@minejs/server';
|
|
3
|
+
|
|
4
|
+
type AppContext = AppContext$1;
|
|
5
|
+
type TableSchema = TableSchema$1;
|
|
6
|
+
interface CruxPlugin {
|
|
7
|
+
name: string;
|
|
8
|
+
version: string;
|
|
9
|
+
routes?: RouteDefinition[];
|
|
10
|
+
schemas?: TableSchema$1[];
|
|
11
|
+
middlewares?: MiddlewareExport[];
|
|
12
|
+
static?: StaticConfig[];
|
|
13
|
+
onRegister?: (app: AppInstance) => void | Promise<void>;
|
|
14
|
+
onAwake?: (ctx: LifecycleContext) => void | Promise<void>;
|
|
15
|
+
onStart?: (ctx: LifecycleContext) => void | Promise<void>;
|
|
16
|
+
onReady?: (ctx: LifecycleContext) => void | Promise<void>;
|
|
17
|
+
onShutdown?: (ctx: LifecycleContext) => void | Promise<void>;
|
|
18
|
+
}
|
|
19
|
+
interface MiddlewareExport {
|
|
20
|
+
name: string;
|
|
21
|
+
handler: AppMiddleware;
|
|
22
|
+
}
|
|
23
|
+
type AppMiddleware = (c: AppContext$1, next: () => void | Promise<void>) => any;
|
|
24
|
+
interface AppConfig {
|
|
25
|
+
server?: {
|
|
26
|
+
port?: number;
|
|
27
|
+
host?: string;
|
|
28
|
+
logging?: boolean | {
|
|
29
|
+
level?: 'debug' | 'info' | 'warn' | 'error';
|
|
30
|
+
pretty?: boolean;
|
|
31
|
+
};
|
|
32
|
+
};
|
|
33
|
+
client?: {
|
|
34
|
+
entry: string;
|
|
35
|
+
output: string;
|
|
36
|
+
minify?: boolean;
|
|
37
|
+
sourcemap?: boolean;
|
|
38
|
+
target?: 'browser' | 'bun';
|
|
39
|
+
external?: string[];
|
|
40
|
+
};
|
|
41
|
+
database?: {
|
|
42
|
+
connection: string;
|
|
43
|
+
schema?: string;
|
|
44
|
+
name?: string;
|
|
45
|
+
timeout?: number;
|
|
46
|
+
} | {
|
|
47
|
+
connection: string;
|
|
48
|
+
schema?: string;
|
|
49
|
+
name?: string;
|
|
50
|
+
timeout?: number;
|
|
51
|
+
}[];
|
|
52
|
+
i18n?: {
|
|
53
|
+
defaultLanguage: string;
|
|
54
|
+
supportedLanguages: string[];
|
|
55
|
+
basePath: string;
|
|
56
|
+
fileExtension?: string;
|
|
57
|
+
};
|
|
58
|
+
static?: {
|
|
59
|
+
path: string;
|
|
60
|
+
directory: string;
|
|
61
|
+
maxAge?: number;
|
|
62
|
+
index?: string[];
|
|
63
|
+
} | {
|
|
64
|
+
path: string;
|
|
65
|
+
directory: string;
|
|
66
|
+
maxAge?: number;
|
|
67
|
+
index?: string[];
|
|
68
|
+
}[];
|
|
69
|
+
api?: {
|
|
70
|
+
path: string;
|
|
71
|
+
directory: string;
|
|
72
|
+
autoLoad?: boolean;
|
|
73
|
+
};
|
|
74
|
+
security?: {
|
|
75
|
+
cors?: boolean | {
|
|
76
|
+
origin?: string | string[];
|
|
77
|
+
credentials?: boolean;
|
|
78
|
+
maxAge?: number;
|
|
79
|
+
};
|
|
80
|
+
rateLimit?: boolean | {
|
|
81
|
+
windowMs?: number;
|
|
82
|
+
max?: number;
|
|
83
|
+
};
|
|
84
|
+
};
|
|
85
|
+
routes?: RouteDefinition[];
|
|
86
|
+
middlewares?: AppMiddleware[];
|
|
87
|
+
plugins?: CruxPlugin[];
|
|
88
|
+
debug?: boolean;
|
|
89
|
+
}
|
|
90
|
+
interface RouteDefinition {
|
|
91
|
+
method: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH' | 'OPTIONS' | 'HEAD' | ('GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH' | 'OPTIONS' | 'HEAD')[];
|
|
92
|
+
path: string;
|
|
93
|
+
handler: (c: AppContext$1) => any;
|
|
94
|
+
middlewares?: AppMiddleware[];
|
|
95
|
+
}
|
|
96
|
+
interface StaticConfig {
|
|
97
|
+
path: string;
|
|
98
|
+
directory: string;
|
|
99
|
+
maxAge?: number;
|
|
100
|
+
index?: string[];
|
|
101
|
+
}
|
|
102
|
+
interface LifecycleContext {
|
|
103
|
+
config: AppConfig;
|
|
104
|
+
databases: Map<string, DB>;
|
|
105
|
+
plugins: CruxPlugin[];
|
|
106
|
+
server?: any;
|
|
107
|
+
clientBuild?: {
|
|
108
|
+
success: boolean;
|
|
109
|
+
outputs: string[];
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
interface LifecycleHooks {
|
|
113
|
+
onConfig?: (config: AppConfig) => AppConfig | Promise<AppConfig>;
|
|
114
|
+
onAwake?: (ctx: LifecycleContext) => void | Promise<void>;
|
|
115
|
+
onStart?: (ctx: LifecycleContext) => void | Promise<void>;
|
|
116
|
+
onReady?: (ctx: LifecycleContext) => void | Promise<void>;
|
|
117
|
+
onFinish?: (ctx: LifecycleContext) => void | Promise<void>;
|
|
118
|
+
onError?: (ctx: LifecycleContext, phase: string, error: Error) => void | Promise<void>;
|
|
119
|
+
}
|
|
120
|
+
interface AppInstance {
|
|
121
|
+
config: AppConfig;
|
|
122
|
+
server: any;
|
|
123
|
+
databases: Map<string, DB>;
|
|
124
|
+
plugins: CruxPlugin[];
|
|
125
|
+
middlewares: Map<string, AppMiddleware>;
|
|
126
|
+
start(): Promise<void>;
|
|
127
|
+
stop(): Promise<void>;
|
|
128
|
+
restart(): Promise<void>;
|
|
129
|
+
getContext(): LifecycleContext;
|
|
130
|
+
getMiddleware(name: string): AppMiddleware | undefined;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
declare class Logger {
|
|
134
|
+
private debug;
|
|
135
|
+
constructor(debug?: boolean);
|
|
136
|
+
phase(name: string): void;
|
|
137
|
+
info(msg: string): void;
|
|
138
|
+
success(msg: string): void;
|
|
139
|
+
error(msg: string, err?: Error): void;
|
|
140
|
+
plugin(name: string, msg: string): void;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
declare class ResourceMerger {
|
|
144
|
+
private logger;
|
|
145
|
+
constructor(logger: Logger);
|
|
146
|
+
mergeRoutes(userRoutes?: RouteDefinition[], pluginRoutes?: RouteDefinition[]): RouteDefinition[];
|
|
147
|
+
mergeSchemas(userSchemas?: TableSchema[], pluginSchemas?: TableSchema[]): TableSchema[];
|
|
148
|
+
mergeStatic(userStatic?: StaticConfig[], pluginStatic?: StaticConfig[]): StaticConfig[];
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
declare class PluginRegistry {
|
|
152
|
+
private plugins;
|
|
153
|
+
private logger;
|
|
154
|
+
constructor(logger: Logger);
|
|
155
|
+
register(plugin: CruxPlugin, app: AppInstance): Promise<void>;
|
|
156
|
+
getAll(): CruxPlugin[];
|
|
157
|
+
callHook(hook: keyof Pick<CruxPlugin, 'onAwake' | 'onStart' | 'onReady' | 'onShutdown'>, ctx: LifecycleContext): Promise<void>;
|
|
158
|
+
collectRoutes(): RouteDefinition[];
|
|
159
|
+
collectSchemas(): TableSchema[];
|
|
160
|
+
collectMiddlewares(): Map<string, AppMiddleware>;
|
|
161
|
+
collectStatic(): StaticConfig[];
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
export { type AppConfig, type AppContext, type AppInstance, type AppMiddleware, type CruxPlugin, type LifecycleContext, type LifecycleHooks, Logger, type MiddlewareExport, PluginRegistry, ResourceMerger, type RouteDefinition, type StaticConfig, type TableSchema };
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
var g=class{constructor(e=false){this.debug=e;}phase(e){this.debug&&console.log(`
|
|
2
|
+
[CruxJS] \u26A1 Phase: ${e}`);}info(e){this.debug&&console.log(`[CruxJS] ${e}`);}success(e){this.debug&&console.log(`[CruxJS] \u2713 ${e}`);}error(e,t){console.error(`[CruxJS] \u2717 ${e}`),t&&console.error(t);}plugin(e,t){this.debug&&console.log(`[CruxJS:${e}] ${t}`);}};var a=class{constructor(e){this.logger=e;}mergeRoutes(e=[],t=[]){let o=[...e],i=new Set(e.map(s=>`${s.method}:${s.path}`));for(let s of t){let n=`${s.method}:${s.path}`;i.has(n)?this.logger.info(`Skipping plugin route ${n} (overridden by user)`):o.push(s);}return o}mergeSchemas(e=[],t=[]){let o=[...e],i=new Set(e.map(s=>s.name));for(let s of t)i.has(s.name)?this.logger.info(`Skipping plugin schema ${s.name} (overridden by user)`):o.push(s);return o}mergeStatic(e=[],t=[]){return [...e,...t]}};var l=class{constructor(e){this.plugins=[];this.logger=e;}async register(e,t){this.logger.info(`Registering plugin: ${e.name}`),this.plugins.push(e),e.onRegister&&await e.onRegister(t),this.logger.success(`Plugin registered: ${e.name} v${e.version}`);}getAll(){return this.plugins}async callHook(e,t){for(let o of this.plugins)o[e]&&(this.logger.plugin(o.name,`Calling ${e}`),await o[e](t));}collectRoutes(){let e=[];for(let t of this.plugins)t.routes&&(e.push(...t.routes),this.logger.plugin(t.name,`Provided ${t.routes.length} routes`));return e}collectSchemas(){let e=[];for(let t of this.plugins)t.schemas&&(e.push(...t.schemas),this.logger.plugin(t.name,`Provided ${t.schemas.length} schemas`));return e}collectMiddlewares(){let e=new Map;for(let t of this.plugins)if(t.middlewares)for(let o of t.middlewares)e.set(`${t.name}:${o.name}`,o.handler),this.logger.plugin(t.name,`Provided middleware: ${o.name}`);return e}collectStatic(){let e=[];for(let t of this.plugins)t.static&&(e.push(...t.static),this.logger.plugin(t.name,`Provided ${t.static.length} static configs`));return e}};export{g as Logger,l as PluginRegistry,a as ResourceMerger};//# sourceMappingURL=index.js.map
|
|
3
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/mod/logger.ts","../src/mod/resource_merger.ts","../src/mod/plugin_registry.ts"],"names":["Logger","debug","name","msg","err","ResourceMerger","logger","userRoutes","pluginRoutes","merged","userPaths","r","route","key","userSchemas","pluginSchemas","userTables","schema","userStatic","pluginStatic","PluginRegistry","plugin","app","hook","ctx","routes","schemas","middlewares","mw","statics"],"mappings":"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","file":"index.js","sourcesContent":["// src/mod/logger.ts\r\n//\r\n// Made with ❤️ by Maysara.\r\n\r\n\r\n\r\n// ╔════════════════════════════════════════ PACK ════════════════════════════════════════╗\r\n\r\n\r\n// ╚══════════════════════════════════════════════════════════════════════════════════════╝\r\n\r\n\r\n\r\n// ╔════════════════════════════════════════ CORE ════════════════════════════════════════╗\r\n\r\n export class Logger {\r\n constructor(private debug: boolean = false) {}\r\n\r\n phase(name: string) {\r\n if (!this.debug) return;\r\n console.log(`\\n[CruxJS] ⚡ Phase: ${name}`);\r\n }\r\n\r\n info(msg: string) {\r\n if (!this.debug) return;\r\n console.log(`[CruxJS] ${msg}`);\r\n }\r\n\r\n success(msg: string) {\r\n if (!this.debug) return;\r\n console.log(`[CruxJS] ✓ ${msg}`);\r\n }\r\n\r\n error(msg: string, err?: Error) {\r\n console.error(`[CruxJS] ✗ ${msg}`);\r\n if (err) console.error(err);\r\n }\r\n\r\n plugin(name: string, msg: string) {\r\n if (!this.debug) return;\r\n console.log(`[CruxJS:${name}] ${msg}`);\r\n }\r\n }\r\n\r\n// ╚══════════════════════════════════════════════════════════════════════════════════════╝","// src/mod/resource_merger.ts\r\n//\r\n// Made with ❤️ by Maysara.\r\n\r\n\r\n\r\n// ╔════════════════════════════════════════ PACK ════════════════════════════════════════╗\r\n\r\n import { RouteDefinition, TableSchema, StaticConfig } from '../types';\r\n import { Logger } from './logger';\r\n\r\n// ╚══════════════════════════════════════════════════════════════════════════════════════╝\r\n\r\n\r\n\r\n// ╔════════════════════════════════════════ CORE ════════════════════════════════════════╗\r\n\r\n export class ResourceMerger {\r\n private logger: Logger;\r\n\r\n constructor(logger: Logger) {\r\n this.logger = logger;\r\n }\r\n\r\n mergeRoutes(\r\n userRoutes: RouteDefinition[] = [],\r\n pluginRoutes: RouteDefinition[] = []\r\n ): RouteDefinition[] {\r\n // User routes have priority\r\n const merged = [...userRoutes];\r\n const userPaths = new Set(userRoutes.map(r => `${r.method}:${r.path}`));\r\n\r\n for (const route of pluginRoutes) {\r\n const key = `${route.method}:${route.path}`;\r\n\r\n if (!userPaths.has(key)) {\r\n merged.push(route);\r\n } else {\r\n this.logger.info(`Skipping plugin route ${key} (overridden by user)`);\r\n }\r\n }\r\n\r\n return merged;\r\n }\r\n\r\n mergeSchemas(\r\n userSchemas: TableSchema[] = [],\r\n pluginSchemas: TableSchema[] = []\r\n ): TableSchema[] {\r\n // User schemas have priority\r\n const merged = [...userSchemas];\r\n const userTables = new Set(userSchemas.map(s => s.name));\r\n\r\n for (const schema of pluginSchemas) {\r\n if (!userTables.has(schema.name)) {\r\n merged.push(schema);\r\n } else {\r\n this.logger.info(`Skipping plugin schema ${schema.name} (overridden by user)`);\r\n }\r\n }\r\n\r\n return merged;\r\n }\r\n\r\n mergeStatic(\r\n userStatic: StaticConfig[] = [],\r\n pluginStatic: StaticConfig[] = []\r\n ): StaticConfig[] {\r\n return [...userStatic, ...pluginStatic];\r\n }\r\n }\r\n\r\n// ╚══════════════════════════════════════════════════════════════════════════════════════╝","// src/mod/plugin_registry.ts\r\n//\r\n// Made with ❤️ by Maysara.\r\n\r\n\r\n\r\n// ╔════════════════════════════════════════ PACK ════════════════════════════════════════╗\r\n\r\n import * as types from '../types';\r\n import { Logger } from './logger';\r\n\r\n// ╚══════════════════════════════════════════════════════════════════════════════════════╝\r\n\r\n\r\n\r\n// ╔════════════════════════════════════════ CORE ════════════════════════════════════════╗\r\n\r\n export class PluginRegistry {\r\n private plugins: types.CruxPlugin[] = [];\r\n private logger: Logger;\r\n\r\n constructor(logger: Logger) {\r\n this.logger = logger;\r\n }\r\n\r\n async register(plugin: types.CruxPlugin, app: types.AppInstance) {\r\n this.logger.info(`Registering plugin: ${plugin.name}`);\r\n\r\n this.plugins.push(plugin);\r\n\r\n // Call plugin's onRegister hook\r\n if (plugin.onRegister) {\r\n await plugin.onRegister(app);\r\n }\r\n\r\n this.logger.success(`Plugin registered: ${plugin.name} v${plugin.version}`);\r\n }\r\n\r\n getAll(): types.CruxPlugin[] {\r\n return this.plugins;\r\n }\r\n\r\n async callHook(\r\n hook: keyof Pick<types.CruxPlugin, 'onAwake' | 'onStart' | 'onReady' | 'onShutdown'>,\r\n ctx: types.LifecycleContext\r\n ) {\r\n for (const plugin of this.plugins) {\r\n if (plugin[hook]) {\r\n this.logger.plugin(plugin.name, `Calling ${hook}`);\r\n await plugin[hook]!(ctx);\r\n }\r\n }\r\n }\r\n\r\n collectRoutes(): types.RouteDefinition[] {\r\n const routes: types.RouteDefinition[] = [];\r\n\r\n for (const plugin of this.plugins) {\r\n if (plugin.routes) {\r\n routes.push(...plugin.routes);\r\n this.logger.plugin(plugin.name, `Provided ${plugin.routes.length} routes`);\r\n }\r\n }\r\n\r\n return routes;\r\n }\r\n\r\n collectSchemas(): types.TableSchema[] {\r\n const schemas: types.TableSchema[] = [];\r\n\r\n for (const plugin of this.plugins) {\r\n if (plugin.schemas) {\r\n schemas.push(...plugin.schemas);\r\n this.logger.plugin(plugin.name, `Provided ${plugin.schemas.length} schemas`);\r\n }\r\n }\r\n\r\n return schemas;\r\n }\r\n\r\n collectMiddlewares(): Map<string, types.AppMiddleware> {\r\n const middlewares = new Map<string, types.AppMiddleware>();\r\n\r\n for (const plugin of this.plugins) {\r\n if (plugin.middlewares) {\r\n for (const mw of plugin.middlewares) {\r\n middlewares.set(`${plugin.name}:${mw.name}`, mw.handler);\r\n this.logger.plugin(plugin.name, `Provided middleware: ${mw.name}`);\r\n }\r\n }\r\n }\r\n\r\n return middlewares;\r\n }\r\n\r\n collectStatic(): types.StaticConfig[] {\r\n const statics: types.StaticConfig[] = [];\r\n\r\n for (const plugin of this.plugins) {\r\n if (plugin.static) {\r\n statics.push(...plugin.static);\r\n this.logger.plugin(plugin.name, `Provided ${plugin.static.length} static configs`);\r\n }\r\n }\r\n\r\n return statics;\r\n }\r\n }\r\n\r\n// ╚══════════════════════════════════════════════════════════════════════════════════════╝"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@cruxjs/base",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "Core types and utilities for building CruxJS applications and plugins. A shared foundation for @cruxjs/app and plugin packages.",
|
|
5
|
+
"keywords": ["cruxjs", "base", "types"],
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"homepage": "https://github.com/cruxjs-org/base#readme",
|
|
8
|
+
"bugs": {
|
|
9
|
+
"url": "https://github.com/cruxjs-org/base/issues"
|
|
10
|
+
},
|
|
11
|
+
"author": {
|
|
12
|
+
"name": "Maysara",
|
|
13
|
+
"email": "maysara.elshewehy@gmail.com",
|
|
14
|
+
"url": "https://github.com/maysara-elshewehy"
|
|
15
|
+
},
|
|
16
|
+
"repository": {
|
|
17
|
+
"type": "git",
|
|
18
|
+
"url": "git+https://github.com/cruxjs-org/base.git"
|
|
19
|
+
},
|
|
20
|
+
"type": "module",
|
|
21
|
+
"main": "./dist/index.js",
|
|
22
|
+
"types": "./dist/index.d.ts",
|
|
23
|
+
"files": ["dist"],
|
|
24
|
+
"exports": {
|
|
25
|
+
".": {
|
|
26
|
+
"types": "./dist/index.d.ts",
|
|
27
|
+
"import": "./dist/index.js",
|
|
28
|
+
"require": "./dist/index.js"
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
"scripts": {
|
|
32
|
+
"build": "tsup",
|
|
33
|
+
"lint": "eslint src --ext .ts",
|
|
34
|
+
"test": "bun test"
|
|
35
|
+
},
|
|
36
|
+
"engines": {
|
|
37
|
+
"bun": ">=1.3.3"
|
|
38
|
+
},
|
|
39
|
+
"peerDependencies": {
|
|
40
|
+
"bun": "^1.3.3"
|
|
41
|
+
},
|
|
42
|
+
"dependencies": {
|
|
43
|
+
"@minejs/db": "^0.0.3",
|
|
44
|
+
"@minejs/server": "^0.0.5"
|
|
45
|
+
},
|
|
46
|
+
"devDependencies": {
|
|
47
|
+
"@eslint/js": "^9.39.2",
|
|
48
|
+
"@stylistic/eslint-plugin": "^5.6.1",
|
|
49
|
+
"@types/bun": "^1.3.5",
|
|
50
|
+
"@types/node": "^20.19.27",
|
|
51
|
+
"bun-plugin-dts": "^0.3.0",
|
|
52
|
+
"bun-types": "^1.3.5",
|
|
53
|
+
"ts-node": "^10.9.2",
|
|
54
|
+
"tsup": "^8.5.1",
|
|
55
|
+
"typescript": "^5.9.3",
|
|
56
|
+
"typescript-eslint": "^8.51.0"
|
|
57
|
+
}
|
|
58
|
+
}
|