@gravito/core 1.0.0-beta.6

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 ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 Carl Lee
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,180 @@
1
+ # @gravito/core
2
+
3
+ > The Micro-kernel for Galaxy Architecture. Lightweight, extensible, and built on Photon & Bun.
4
+
5
+ [![npm version](https://img.shields.io/npm/v/@gravito/core.svg)](https://www.npmjs.com/package/@gravito/core)
6
+ [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
7
+ [![TypeScript](https://img.shields.io/badge/TypeScript-5.0+-blue.svg)](https://www.typescriptlang.org/)
8
+ [![Bun](https://img.shields.io/badge/Bun-1.0+-black.svg)](https://bun.sh/)
9
+
10
+ **@gravito/core** is the foundation for building modular backend applications using the **Galaxy Architecture**. It provides a robust Hook system (Filters & Actions) and an Orbit mounting mechanism, allowing you to build loosely coupled, highly extensible systems.
11
+
12
+ ## ✨ Features
13
+
14
+ - đŸĒ **PlanetCore** - A centralized Photon-based kernel to manage your application lifecycle.
15
+ - đŸ“Ļ **IoC Container** - A lightweight dependency injection container with binding and singleton support.
16
+ - 🧩 **Service Providers** - Modular service registration and booting lifecycle.
17
+ - đŸĒ **Hook System** - WordPress-style async **Filters** and **Actions** for powerful extensibility.
18
+ - đŸ›°ī¸ **Orbit Mounting** - Easily mount external Photon applications (Orbits) to specific paths.
19
+ - 📝 **Logger System** - PSR-3 style logger interface with default standard output implementation.
20
+ - âš™ī¸ **Config Manager** - Unified configuration management supporting environment variables (`Bun.env`) and runtime injection.
21
+ - đŸ›Ąī¸ **Error Handling** - Built-in standardized JSON error responses and 404 handling.
22
+ - 🚀 **Modern** - Built for **Bun** runtime with native TypeScript support.
23
+ - đŸĒļ **Lightweight** - Zero external dependencies (except `@gravito/photon`).
24
+
25
+ ## đŸ“Ļ Installation
26
+
27
+ ```bash
28
+ bun add @gravito/core
29
+ ```
30
+
31
+ ## 🚀 Quick Start
32
+
33
+ ### 1. Initialize the Core
34
+
35
+ ```typescript
36
+ import { PlanetCore } from '@gravito/core';
37
+
38
+ // Initialize with options (v0.2.0+)
39
+ const core = new PlanetCore({
40
+ config: {
41
+ PORT: 4000,
42
+ DEBUG: true
43
+ }
44
+ });
45
+ ```
46
+
47
+ ### 2. Dependency Injection
48
+
49
+ Use the IoC Container to manage your application services:
50
+
51
+ ```typescript
52
+ import { ServiceProvider, Container } from '@gravito/core';
53
+
54
+ class CacheServiceProvider extends ServiceProvider {
55
+ register(container: Container) {
56
+ // Bind a singleton service
57
+ container.singleton('cache', (c) => {
58
+ return new RedisCache(process.env.REDIS_URL);
59
+ });
60
+ }
61
+
62
+ async boot(core: PlanetCore) {
63
+ // Perform boot logic
64
+ core.logger.info('Cache provider booted');
65
+ }
66
+ }
67
+
68
+ // Register the provider
69
+ core.register(new CacheServiceProvider());
70
+
71
+ // Bootstrap the application (runs register() and boot())
72
+ await core.bootstrap();
73
+
74
+ // Resolve services
75
+ const cache = core.container.make('cache');
76
+ ```
77
+
78
+ ### 3. Register Hooks
79
+
80
+ Use **Filters** to modify data:
81
+
82
+ ```typescript
83
+ core.hooks.addFilter('modify_content', async (content: string) => {
84
+ return content.toUpperCase();
85
+ });
86
+
87
+ const result = await core.hooks.applyFilters('modify_content', 'hello galaxy');
88
+ // result: "HELLO GALAXY"
89
+ ```
90
+
91
+ Use **Actions** to trigger side-effects:
92
+
93
+ ```typescript
94
+ core.hooks.addAction('user_registered', async (userId: string) => {
95
+ core.logger.info(`Sending welcome email to ${userId}`);
96
+ });
97
+
98
+ await core.hooks.doAction('user_registered', 'user_123');
99
+ ```
100
+
101
+ ### 4. Mount an Orbit
102
+
103
+ Orbits are just standard Photon applications that plug into the core.
104
+
105
+ ```typescript
106
+ import { Photon } from '@gravito/photon';
107
+
108
+ const blogOrbit = new Photon();
109
+ blogOrbit.get('/posts', (c) => c.json({ posts: [] }));
110
+
111
+ // Mount the orbit to /api/blog
112
+ core.mountOrbit('/api/blog', blogOrbit);
113
+ ```
114
+
115
+ ### 5. Liftoff! 🚀
116
+
117
+ ```typescript
118
+ // Export for Bun.serve
119
+ export default core.liftoff(); // Automatically uses PORT from config/env
120
+ ```
121
+
122
+ ### 6. Process-level Error Handling (Recommended)
123
+
124
+ Request-level errors are handled by `PlanetCore` automatically, but background jobs and startup code can still fail outside the request lifecycle.
125
+
126
+ ```ts
127
+ // Register `unhandledRejection` / `uncaughtException`
128
+ const unregister = core.registerGlobalErrorHandlers()
129
+
130
+ // Optional: report to Sentry / custom reporter
131
+ core.hooks.addAction('processError:report', async (ctx) => {
132
+ // ctx.kind: 'unhandledRejection' | 'uncaughtException'
133
+ // ctx.error: unknown
134
+ })
135
+ ```
136
+
137
+ ## 📖 API Reference
138
+
139
+ ### `PlanetCore`
140
+
141
+ - **`constructor(options?)`**: Initialize the core with optional Logger and Config.
142
+ - **`register(provider: ServiceProvider)`**: Register a service provider.
143
+ - **`bootstrap()`**: Boot all registered providers.
144
+ - **`mountOrbit(path: string, app: Photon)`**: Mount a Photon app to a sub-path.
145
+ - **`liftoff(port?: number)`**: Returns the configuration object for `Bun.serve`.
146
+ - **`container`**: Access the IoC Container.
147
+ - **`app`**: Access the internal Photon instance.
148
+ - **`hooks`**: Access the HookManager.
149
+ - **`logger`**: Access the Logger instance.
150
+ - **`config`**: Access the ConfigManager.
151
+
152
+ ### `Container`
153
+
154
+ - **`bind(key, factory)`**: Register a transient binding.
155
+ - **`singleton(key, factory)`**: Register a shared binding.
156
+ - **`make<T>(key)`**: Resolve a service instance.
157
+ - **`instance(key, instance)`**: Register an existing object instance.
158
+ - **`has(key)`**: Check if a service is bound.
159
+
160
+ ### `HookManager`
161
+
162
+ - **`addFilter(hook, callback)`**: Register a filter.
163
+ - **`applyFilters(hook, initialValue, ...args)`**: Execute filters sequentially.
164
+ - **`addAction(hook, callback)`**: Register an action.
165
+ - **`doAction(hook, ...args)`**: Execute actions.
166
+
167
+ ### `ConfigManager`
168
+
169
+ - **`get(key, default?)`**: Retrieve a config value.
170
+ - **`set(key, value)`**: Set a config value.
171
+ - **`has(key)`**: Check if a config key exists.
172
+
173
+ ## 🤝 Contributing
174
+
175
+ Contributions, issues and feature requests are welcome!
176
+ Feel free to check the [issues page](https://github.com/gravito-framework/gravito/issues).
177
+
178
+ ## 📝 License
179
+
180
+ MIT Š [Carl Lee](https://github.com/gravito-framework/gravito)
@@ -0,0 +1,24 @@
1
+ # @gravito/core
2
+
3
+ > Galaxy æžļæ§‹įš„åžŽæ ¸åŋƒīŧŒåŸēæ–ŧ Photon 與 Bun įš„čŧ•é‡å¯æ“´å……æĄ†æžļæ ¸åŋƒã€‚
4
+
5
+ ## åŽ‰čŖ
6
+
7
+ ```bash
8
+ bun add @gravito/core
9
+ ```
10
+
11
+ ## åŋĢ速開始
12
+
13
+ ```typescript
14
+ import { PlanetCore } from '@gravito/core'
15
+
16
+ const core = new PlanetCore({
17
+ config: {
18
+ PORT: 4000,
19
+ DEBUG: true
20
+ }
21
+ })
22
+
23
+ export default core.liftoff()
24
+ ```
@@ -0,0 +1,18 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __copyProps = (to, from, except, desc) => {
7
+ if (from && typeof from === "object" || typeof from === "function") {
8
+ for (let key of __getOwnPropNames(from))
9
+ if (!__hasOwnProp.call(to, key) && key !== except)
10
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
11
+ }
12
+ return to;
13
+ };
14
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
15
+
16
+ // src/compat.ts
17
+ var compat_exports = {};
18
+ module.exports = __toCommonJS(compat_exports);
@@ -0,0 +1,313 @@
1
+ /**
2
+ * @fileoverview Core HTTP Types for Gravito Framework
3
+ *
4
+ * These types provide a unified abstraction layer that decouples the framework
5
+ * from any specific HTTP engine (Photon, Express, custom, etc.).
6
+ *
7
+ * @module @gravito/core/http
8
+ * @since 2.0.0
9
+ */
10
+ declare global {
11
+ interface ExecutionContext {
12
+ waitUntil(promise: Promise<unknown>): void;
13
+ passThroughOnException(): void;
14
+ }
15
+ }
16
+ /**
17
+ * Standard HTTP methods supported by Gravito
18
+ */
19
+ type HttpMethod = 'get' | 'post' | 'put' | 'delete' | 'patch' | 'options' | 'head';
20
+ /**
21
+ * HTTP status codes
22
+ */
23
+ type StatusCode = number;
24
+ /**
25
+ * Content-bearing HTTP status codes (excludes 1xx, 204, 304)
26
+ */
27
+ type ContentfulStatusCode = Exclude<StatusCode, 100 | 101 | 102 | 103 | 204 | 304>;
28
+ /**
29
+ * Base context variables available in every request
30
+ * Orbits can extend this interface via module augmentation
31
+ *
32
+ * @example
33
+ * ```typescript
34
+ * // Extending variables in your orbit:
35
+ * declare module '@gravito/core' {
36
+ * interface GravitoVariables {
37
+ * myService: MyService
38
+ * }
39
+ * }
40
+ * ```
41
+ */
42
+ interface GravitoVariables {
43
+ /**
44
+ * The PlanetCore instance
45
+ * @remarks Always available in PlanetCore-managed contexts
46
+ */
47
+ core?: unknown;
48
+ /**
49
+ * Logger instance
50
+ */
51
+ logger?: unknown;
52
+ /**
53
+ * Configuration manager
54
+ */
55
+ config?: unknown;
56
+ /**
57
+ * Cookie jar for managing response cookies
58
+ */
59
+ cookieJar?: unknown;
60
+ /**
61
+ * URL generator helper
62
+ */
63
+ route?: (name: string, params?: Record<string, unknown>, query?: Record<string, unknown>) => string;
64
+ [key: string]: unknown;
65
+ }
66
+ /**
67
+ * Validated request data targets
68
+ */
69
+ type ValidationTarget = 'json' | 'query' | 'param' | 'header' | 'form' | 'cookie';
70
+ /**
71
+ * GravitoRequest - Unified request interface
72
+ *
73
+ * Provides a consistent API for accessing request data regardless of
74
+ * the underlying HTTP engine.
75
+ *
76
+ * @example
77
+ * ```typescript
78
+ * const userId = ctx.req.param('id')
79
+ * const search = ctx.req.query('q')
80
+ * const body = await ctx.req.json<CreateUserDto>()
81
+ * ```
82
+ */
83
+ interface GravitoRequest {
84
+ /** Full request URL */
85
+ readonly url: string;
86
+ /** HTTP method (uppercase) */
87
+ readonly method: string;
88
+ /** Request path without query string */
89
+ readonly path: string;
90
+ /**
91
+ * Get a route parameter value
92
+ * @param name - Parameter name (e.g., 'id' for route '/users/:id')
93
+ */
94
+ param(name: string): string | undefined;
95
+ /**
96
+ * Get all route parameters
97
+ */
98
+ params(): Record<string, string>;
99
+ /**
100
+ * Get a query string parameter
101
+ * @param name - Query parameter name
102
+ */
103
+ query(name: string): string | undefined;
104
+ /**
105
+ * Get all query parameters
106
+ */
107
+ queries(): Record<string, string | string[]>;
108
+ /**
109
+ * Get a request header value
110
+ * @param name - Header name (case-insensitive)
111
+ */
112
+ header(name: string): string | undefined;
113
+ /**
114
+ * Get all request headers
115
+ */
116
+ header(): Record<string, string>;
117
+ /**
118
+ * Parse request body as JSON
119
+ * @throws {Error} If body is not valid JSON
120
+ */
121
+ json<T = unknown>(): Promise<T>;
122
+ /**
123
+ * Parse request body as text
124
+ */
125
+ text(): Promise<string>;
126
+ /**
127
+ * Parse request body as FormData
128
+ */
129
+ formData(): Promise<FormData>;
130
+ /**
131
+ * Parse request body as ArrayBuffer
132
+ */
133
+ arrayBuffer(): Promise<ArrayBuffer>;
134
+ /**
135
+ * Parse form data (urlencoded or multipart)
136
+ */
137
+ parseBody<T = unknown>(): Promise<T>;
138
+ /**
139
+ * Get the raw Request object
140
+ */
141
+ readonly raw: Request;
142
+ /**
143
+ * Get validated data from a specific source
144
+ * @param target - The validation target
145
+ * @throws {Error} If validation was not performed for this target
146
+ */
147
+ valid<T = unknown>(target: ValidationTarget): T;
148
+ }
149
+ /**
150
+ * GravitoContext - Unified request context
151
+ *
152
+ * This interface encapsulates all HTTP request/response operations,
153
+ * enabling seamless replacement of the underlying HTTP engine.
154
+ *
155
+ * @typeParam V - Context variables type
156
+ *
157
+ * @example
158
+ * ```typescript
159
+ * // In a controller
160
+ * async show(ctx: GravitoContext) {
161
+ * const id = ctx.req.param('id')
162
+ * const user = await User.find(id)
163
+ * return ctx.json({ user })
164
+ * }
165
+ * ```
166
+ */
167
+ interface GravitoContext<V extends GravitoVariables = GravitoVariables> {
168
+ /** The incoming request */
169
+ readonly req: GravitoRequest;
170
+ /**
171
+ * Send a JSON response
172
+ * @param data - Data to serialize as JSON
173
+ * @param status - HTTP status code (default: 200)
174
+ */
175
+ json<T>(data: T, status?: ContentfulStatusCode): Response;
176
+ /**
177
+ * Send a plain text response
178
+ * @param text - Text content
179
+ * @param status - HTTP status code (default: 200)
180
+ */
181
+ text(text: string, status?: ContentfulStatusCode): Response;
182
+ /**
183
+ * Send an HTML response
184
+ * @param html - HTML content
185
+ * @param status - HTTP status code (default: 200)
186
+ */
187
+ html(html: string, status?: ContentfulStatusCode): Response;
188
+ /**
189
+ * Send a redirect response
190
+ * @param url - Target URL
191
+ * @param status - Redirect status code (default: 302)
192
+ */
193
+ redirect(url: string, status?: 301 | 302 | 303 | 307 | 308): Response;
194
+ /**
195
+ * Create a Response with no body
196
+ * @param status - HTTP status code
197
+ */
198
+ body(data: BodyInit | null, status?: StatusCode): Response;
199
+ /**
200
+ * Stream a response
201
+ * @param stream - ReadableStream to send
202
+ * @param status - HTTP status code (default: 200)
203
+ */
204
+ stream(stream: ReadableStream, status?: ContentfulStatusCode): Response;
205
+ /**
206
+ * Send a 404 Not Found response
207
+ */
208
+ notFound(message?: string): Response;
209
+ /**
210
+ * Send a 403 Forbidden response
211
+ */
212
+ forbidden(message?: string): Response;
213
+ /**
214
+ * Send a 401 Unauthorized response
215
+ */
216
+ unauthorized(message?: string): Response;
217
+ /**
218
+ * Send a 400 Bad Request response
219
+ */
220
+ badRequest(message?: string): Response;
221
+ /**
222
+ * Set a response header
223
+ * @param name - Header name
224
+ * @param value - Header value
225
+ * @param options - Options (append: true to add multiple values)
226
+ */
227
+ header(name: string, value: string, options?: {
228
+ append?: boolean;
229
+ }): void;
230
+ /**
231
+ * Get a request header
232
+ * @param name - Header name (case-insensitive)
233
+ */
234
+ header(name: string): string | undefined;
235
+ /**
236
+ * Set the response status code
237
+ * @param code - HTTP status code
238
+ */
239
+ status(code: StatusCode): void;
240
+ /**
241
+ * Get a context variable
242
+ * @param key - Variable key
243
+ */
244
+ get<K extends keyof V>(key: K): V[K];
245
+ /**
246
+ * Set a context variable
247
+ * @param key - Variable key
248
+ * @param value - Variable value
249
+ */
250
+ set<K extends keyof V>(key: K, value: V[K]): void;
251
+ /**
252
+ * Get the execution context (for Cloudflare Workers, etc.)
253
+ */
254
+ readonly executionCtx?: ExecutionContext;
255
+ /**
256
+ * Get environment bindings (for Cloudflare Workers, etc.)
257
+ */
258
+ readonly env?: Record<string, unknown>;
259
+ /**
260
+ * Access the native context object from the underlying HTTP engine.
261
+ *
262
+ * âš ī¸ WARNING: Using this ties your code to a specific adapter.
263
+ * Prefer using the abstraction methods when possible.
264
+ *
265
+ * @example
266
+ * ```typescript
267
+ * // Only when absolutely necessary
268
+ * const photonCtx = ctx.native as Context // Photon Context
269
+ * ```
270
+ */
271
+ readonly native: unknown;
272
+ }
273
+ /**
274
+ * Next function for middleware chain
275
+ */
276
+ type GravitoNext = () => Promise<void>;
277
+ /**
278
+ * GravitoHandler - Standard route handler type
279
+ *
280
+ * @typeParam V - Context variables type
281
+ *
282
+ * @example
283
+ * ```typescript
284
+ * const handler: GravitoHandler = async (ctx) => {
285
+ * return ctx.json({ message: 'Hello, World!' })
286
+ * }
287
+ * ```
288
+ */
289
+ type GravitoHandler<V extends GravitoVariables = GravitoVariables> = (ctx: GravitoContext<V>) => Response | Promise<Response>;
290
+ /**
291
+ * GravitoMiddleware - Standard middleware type
292
+ *
293
+ * @typeParam V - Context variables type
294
+ *
295
+ * @example
296
+ * ```typescript
297
+ * const logger: GravitoMiddleware = async (ctx, next) => {
298
+ * console.log(`${ctx.req.method} ${ctx.req.path}`)
299
+ * await next()
300
+ * }
301
+ * ```
302
+ */
303
+ type GravitoMiddleware<V extends GravitoVariables = GravitoVariables> = (ctx: GravitoContext<V>, next: GravitoNext) => Response | undefined | Promise<Response | undefined | undefined>;
304
+ /**
305
+ * Error handler type
306
+ */
307
+ type GravitoErrorHandler<V extends GravitoVariables = GravitoVariables> = (error: Error, ctx: GravitoContext<V>) => Response | Promise<Response>;
308
+ /**
309
+ * Not found handler type
310
+ */
311
+ type GravitoNotFoundHandler<V extends GravitoVariables = GravitoVariables> = (ctx: GravitoContext<V>) => Response | Promise<Response>;
312
+
313
+ export type { ContentfulStatusCode, GravitoContext as Context, GravitoContext, GravitoErrorHandler, GravitoHandler, GravitoMiddleware, GravitoNext, GravitoNotFoundHandler, GravitoRequest, GravitoVariables, GravitoHandler as Handler, HttpMethod, GravitoMiddleware as MiddlewareHandler, GravitoNext as Next, StatusCode, ValidationTarget, GravitoVariables as Variables };