@lithia-js/core 1.0.0-canary.1 → 1.0.0-canary.3

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/CHANGELOG.md CHANGED
@@ -1,5 +1,23 @@
1
1
  # @lithia-js/core
2
2
 
3
+ ## 1.0.0-canary.3
4
+
5
+ ### Patch Changes
6
+
7
+ - d536a2f: Fixed exports from @lithia-js/native
8
+ - Updated dependencies [d536a2f]
9
+ - @lithia-js/native@1.0.0-canary.3
10
+ - @lithia-js/utils@1.0.0-canary.3
11
+
12
+ ## 1.0.0-canary.2
13
+
14
+ ### Patch Changes
15
+
16
+ - .npmignore update
17
+ - Updated dependencies
18
+ - @lithia-js/native@1.0.0-canary.2
19
+ - @lithia-js/utils@1.0.0-canary.2
20
+
3
21
  ## 1.0.0-canary.1
4
22
 
5
23
  ### Patch Changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lithia-js/core",
3
- "version": "1.0.0-canary.1",
3
+ "version": "1.0.0-canary.3",
4
4
  "private": false,
5
5
  "main": "dist/lib.js",
6
6
  "types": "dist/lib.d.ts",
@@ -27,8 +27,8 @@
27
27
  "socket.io": "^4.8.1",
28
28
  "source-map-support": "^0.5.21",
29
29
  "zod": "^4.2.1",
30
- "@lithia-js/native": "1.0.0-canary.1",
31
- "@lithia-js/utils": "1.0.0-canary.1"
30
+ "@lithia-js/native": "1.0.0-canary.3",
31
+ "@lithia-js/utils": "1.0.0-canary.3"
32
32
  },
33
33
  "engines": {
34
34
  "node": ">=20"
@@ -1,4 +0,0 @@
1
-
2
- > @lithia-js/core@1.0.0-canary.1 build /home/runner/work/lithia/lithia/packages/core
3
- > tsc -p tsconfig.build.json
4
-
package/src/config.ts DELETED
@@ -1,212 +0,0 @@
1
- import type { DeepPartial } from "@lithia-js/utils";
2
- import {
3
- type C12InputConfig,
4
- loadConfig,
5
- type WatchConfigOptions,
6
- watchConfig,
7
- } from "c12";
8
- import { klona } from "klona";
9
-
10
- /** Result type for lifecycle hooks — may be synchronous or async. */
11
- export type HookResult = void | Promise<void>;
12
-
13
- /** Available lifecycle hooks supported by the runtime. */
14
- export interface LithiaHooks {
15
- /** Called before the HTTP server starts. */
16
- "before:start": () => HookResult;
17
- /** Called after the HTTP server has started. */
18
- "after:start": () => HookResult;
19
- }
20
-
21
- /** Shape of the runtime configuration used by Lithia. */
22
- export interface LithiaOptions {
23
- debug: boolean;
24
- http: {
25
- port: number;
26
- host: string;
27
- maxBodySize?: number;
28
- ssl?: {
29
- key: string;
30
- cert: string;
31
- passphrase?: string;
32
- };
33
- cors: {
34
- origin?: string[];
35
- methods?: string[];
36
- allowedHeaders?: string[];
37
- exposedHeaders?: string[];
38
- credentials?: boolean;
39
- maxAge?: number;
40
- };
41
- mimeTypes?: Record<string, string>;
42
- };
43
- static?: {
44
- root: string;
45
- prefix?: string;
46
- };
47
- studio: {
48
- enabled: boolean;
49
- };
50
- logging: {
51
- /** Enable request logging. Critical errors (5xx) are always logged. */
52
- requests: boolean;
53
- /** Enable event logging. Critical errors are always logged. */
54
- events: boolean;
55
- };
56
- hooks: {
57
- [K in keyof LithiaHooks]: LithiaHooks[K];
58
- };
59
- }
60
-
61
- /** Partial configuration accepted by `defineConfig` and the config loader. */
62
- export interface LithiaConfig
63
- extends DeepPartial<LithiaOptions>,
64
- C12InputConfig<LithiaConfig> {}
65
-
66
- /** Default runtime configuration used when no overrides are provided. */
67
- export const DEFAULT_CONFIG: LithiaConfig = {
68
- debug: false,
69
- http: {
70
- port: 3000,
71
- host: "localhost",
72
- maxBodySize: 1024 * 1024,
73
- cors: {
74
- origin: ["*"],
75
- methods: ["*"],
76
- allowedHeaders: ["*"],
77
- exposedHeaders: ["X-Powered-By"],
78
- credentials: false,
79
- maxAge: 86400,
80
- },
81
- },
82
- logging: {
83
- requests: true,
84
- events: true,
85
- },
86
- hooks: {},
87
- studio: {
88
- enabled: false,
89
- },
90
- };
91
-
92
- type LoadConfigOptions = {
93
- watch?: boolean;
94
- c12?: WatchConfigOptions;
95
- overrides?: LithiaConfig;
96
- };
97
-
98
- /** Error thrown when configuration validation fails. */
99
- export class ConfigValidationError extends Error {
100
- constructor(
101
- message: string,
102
- public readonly field?: string,
103
- ) {
104
- super(message);
105
- this.name = "ConfigValidationError";
106
- }
107
- }
108
-
109
- /** Context passed to `watchConfig` callbacks describing the updated config. */
110
- export interface ConfigUpdateContext {
111
- /** Returns a list of diffs between old and new config. */
112
- getDiff: () => Array<{
113
- key: string;
114
- type: string;
115
- newValue: unknown;
116
- oldValue: unknown;
117
- }>;
118
- /** The new fully materialized config. */
119
- newConfig: LithiaOptions;
120
- /** The previous config prior to the update. */
121
- oldConfig: LithiaOptions;
122
- }
123
-
124
- /** Provider responsible for loading and optionally watching the runtime config. */
125
- export class ConfigProvider {
126
- /**
127
- * Load the configuration, applying optional overrides.
128
- *
129
- * This delegates to `c12` for reading configuration files and defaults
130
- * and validates the resulting `LithiaOptions` before returning them.
131
- */
132
- async loadConfig(overrides: LithiaConfig = {}, opts: LoadConfigOptions = {}) {
133
- overrides = klona(overrides);
134
-
135
- const configOptions = {
136
- name: "lithia",
137
- configFile: "lithia.config",
138
- cwd: process.cwd(),
139
- dotenv: true,
140
- overrides,
141
- defaults: DEFAULT_CONFIG,
142
- ...opts.c12,
143
- };
144
-
145
- const loadedConfig = await loadConfig<LithiaConfig>(configOptions);
146
- const options = klona(loadedConfig.config) as LithiaOptions;
147
-
148
- // overrides are already applied by c12; no need to re-assign here
149
-
150
- this.validateConfig(options);
151
-
152
- return options;
153
- }
154
-
155
- /**
156
- * Watch the configuration for changes and invoke `onChange` when updates occur.
157
- *
158
- * Returns a handle with a `close()` method to stop watching.
159
- */
160
- async watchConfig(
161
- onChange: (ctx: ConfigUpdateContext) => void | Promise<void>,
162
- overrides: LithiaConfig = {},
163
- opts: LoadConfigOptions = {},
164
- ) {
165
- overrides = klona(overrides);
166
-
167
- const configOptions = {
168
- name: "lithia",
169
- configFile: "lithia.config",
170
- cwd: process.cwd(),
171
- dotenv: true,
172
- overrides,
173
- defaults: DEFAULT_CONFIG,
174
- ...opts.c12,
175
- watch: true,
176
- onUpdate: async (context: any) => {
177
- const newOptions = klona(context.newConfig.config) as LithiaOptions;
178
- this.validateConfig(newOptions);
179
-
180
- await onChange({
181
- getDiff: context.getDiff,
182
- newConfig: newOptions,
183
- oldConfig: context.oldConfig.config as LithiaOptions,
184
- });
185
- },
186
- };
187
-
188
- const handle = await watchConfig<LithiaConfig>(configOptions as any);
189
-
190
- return {
191
- close: () => {
192
- if (typeof (handle as any)?.close === "function") {
193
- (handle as any).close();
194
- }
195
- },
196
- };
197
- }
198
-
199
- private validateConfig(config: LithiaOptions): void {
200
- if (config.http.port < 1 || config.http.port > 65535) {
201
- throw new ConfigValidationError(
202
- `HTTP port must be between 1 and 65535, got ${config.http.port}`,
203
- "http.port",
204
- );
205
- }
206
- }
207
- }
208
-
209
- /** Utility helper used by users to define their config with IDE type hints. */
210
- export function defineConfig(config: LithiaConfig): LithiaConfig {
211
- return config;
212
- }
@@ -1,66 +0,0 @@
1
- /**
2
- * Event context module for Socket.IO events.
3
- *
4
- * Provides context specific to Socket.IO event handling, including access
5
- * to event data passed from the client.
6
- *
7
- * @module context/event-context
8
- */
9
-
10
- import { AsyncLocalStorage } from "node:async_hooks";
11
- import type { Socket } from "socket.io";
12
-
13
- /**
14
- * Socket.IO event handler context.
15
- *
16
- * Contains event-specific information available to event handlers
17
- * during Socket.IO event processing.
18
- */
19
- export type EventContext = {
20
- /**
21
- * Data payload sent with the event.
22
- *
23
- * Contains the data passed from the client when emitting the event.
24
- * The structure depends on what the client sends.
25
- */
26
- data: any;
27
-
28
- /**
29
- * The Socket.IO socket instance.
30
- *
31
- * Represents the client connection that triggered the event.
32
- */
33
- socket: Socket;
34
- };
35
-
36
- /**
37
- * AsyncLocalStorage instance for event context.
38
- *
39
- * Uses Node.js AsyncLocalStorage to provide implicit context propagation
40
- * for Socket.IO event handling across async boundaries.
41
- *
42
- * @see https://nodejs.org/api/async_hooks.html#class-asynclocalstorage
43
- */
44
- export const eventContext = new AsyncLocalStorage<EventContext>();
45
-
46
- /**
47
- * Gets the current event context.
48
- *
49
- * @returns The current EventContext
50
- * @throws {Error} If called outside of a Socket.IO event handler
51
- *
52
- * @example
53
- * ```typescript
54
- * const ctx = getEventContext();
55
- * console.log('Event data:', ctx.data);
56
- * ```
57
- */
58
- export function getEventContext(): EventContext {
59
- const ctx = eventContext.getStore();
60
- if (!ctx) {
61
- throw new Error(
62
- "Lithia event context not found. Are you calling a hook outside of an event handler?",
63
- );
64
- }
65
- return ctx;
66
- }
@@ -1,32 +0,0 @@
1
- /**
2
- * Context management for Lithia.
3
- *
4
- * This module provides three separate context types using AsyncLocalStorage:
5
- * - **LithiaContext**: Global application context with DI container
6
- * - **RouteContext**: HTTP request-specific context
7
- * - **EventContext**: Socket.IO event-specific context
8
- *
9
- * Each context is isolated and provides different information based on
10
- * the execution environment (HTTP request vs Socket.IO event).
11
- *
12
- * @module context
13
- */
14
-
15
- // Socket.IO event context
16
- export {
17
- type EventContext,
18
- eventContext,
19
- getEventContext,
20
- } from "./event-context";
21
- // Lithia global context
22
- export {
23
- getLithiaContext,
24
- type LithiaContext,
25
- lithiaContext,
26
- } from "./lithia-context";
27
- // HTTP route context
28
- export {
29
- getRouteContext,
30
- type RouteContext,
31
- routeContext,
32
- } from "./route-context";
@@ -1,59 +0,0 @@
1
- /**
2
- * Lithia global context module.
3
- *
4
- * Provides the main application-level context that holds the global
5
- * dependency injection container. This context is available throughout
6
- * the entire request/event lifecycle.
7
- *
8
- * @module context/lithia-context
9
- */
10
-
11
- import { AsyncLocalStorage } from "node:async_hooks";
12
-
13
- /**
14
- * Global Lithia application context.
15
- *
16
- * Holds the dependency injection container that is shared across
17
- * the entire application and accessible in all request/event handlers.
18
- */
19
- export interface LithiaContext {
20
- /**
21
- * Global dependency injection container.
22
- *
23
- * Stores dependencies registered via `provide()` that can be injected
24
- * into handlers using `inject()` or `injectOptional()`.
25
- */
26
- dependencies: Map<any, any>;
27
- }
28
-
29
- /**
30
- * AsyncLocalStorage instance for Lithia application context.
31
- *
32
- * Uses Node.js AsyncLocalStorage to provide implicit context propagation
33
- * across async boundaries without explicit parameter passing.
34
- *
35
- * @see https://nodejs.org/api/async_hooks.html#class-asynclocalstorage
36
- */
37
- export const lithiaContext = new AsyncLocalStorage<LithiaContext>();
38
-
39
- /**
40
- * Gets the current Lithia context.
41
- *
42
- * @returns The current LithiaContext
43
- * @throws {Error} If called outside of a request or event handler context
44
- *
45
- * @example
46
- * ```typescript
47
- * const ctx = getLithiaContext();
48
- * const db = ctx.dependencies.get(dbKey);
49
- * ```
50
- */
51
- export function getLithiaContext(): LithiaContext {
52
- const ctx = lithiaContext.getStore();
53
- if (!ctx) {
54
- throw new Error(
55
- "Lithia context not found. Are you accessing dependencies outside of a request or event handler?",
56
- );
57
- }
58
- return ctx;
59
- }
@@ -1,89 +0,0 @@
1
- /**
2
- * Route context module for HTTP requests.
3
- *
4
- * Provides context specific to HTTP route handling, including access to
5
- * the current request, response, and matched route information.
6
- *
7
- * @module context/route-context
8
- */
9
-
10
- import { AsyncLocalStorage } from "node:async_hooks";
11
- import type { Route } from "@lithia-js/native";
12
- import type { Server } from "socket.io";
13
- import type { LithiaRequest } from "../server/request";
14
- import type { LithiaResponse } from "../server/response";
15
-
16
- /**
17
- * HTTP route handler context.
18
- *
19
- * Contains request-specific information available to route handlers
20
- * and middlewares during HTTP request processing.
21
- */
22
- export interface RouteContext {
23
- /**
24
- * The current HTTP request object.
25
- *
26
- * Provides access to request data like params, query, headers, and body.
27
- */
28
- req: LithiaRequest;
29
-
30
- /**
31
- * The current HTTP response object.
32
- *
33
- * Used to send responses back to the client.
34
- */
35
- res: LithiaResponse;
36
-
37
- /**
38
- * The matched route definition.
39
- *
40
- * Contains metadata about the current route including path, method,
41
- * and handler information. May be undefined before route resolution
42
- * or in 404 handlers.
43
- */
44
- route?: Route;
45
-
46
- /**
47
- * The Socket.IO server instance.
48
- *
49
- * Provides access to the Socket.IO server, allowing you to emit events
50
- * to all connected clients, manage rooms, or access server-level features
51
- * from within HTTP route handlers.
52
- *
53
- * This is useful for scenarios where an HTTP request needs to trigger
54
- * real-time updates to connected Socket.IO clients.
55
- */
56
- socketServer: Server;
57
- }
58
-
59
- /**
60
- * AsyncLocalStorage instance for route context.
61
- *
62
- * Uses Node.js AsyncLocalStorage to provide implicit context propagation
63
- * for HTTP request handling across async boundaries.
64
- *
65
- * @see https://nodejs.org/api/async_hooks.html#class-asynclocalstorage
66
- */
67
- export const routeContext = new AsyncLocalStorage<RouteContext>();
68
-
69
- /**
70
- * Gets the current route context.
71
- *
72
- * @returns The current RouteContext
73
- * @throws {Error} If called outside of an HTTP request handler
74
- *
75
- * @example
76
- * ```typescript
77
- * const ctx = getRouteContext();
78
- * console.log(ctx.req.method, ctx.req.url);
79
- * ```
80
- */
81
- export function getRouteContext(): RouteContext {
82
- const ctx = routeContext.getStore();
83
- if (!ctx) {
84
- throw new Error(
85
- "Lithia route context not found. Are you calling a hook outside of a request handler?",
86
- );
87
- }
88
- return ctx;
89
- }
package/src/env.ts DELETED
@@ -1,31 +0,0 @@
1
- import { existsSync, readFileSync } from "node:fs";
2
- import { resolve } from "node:path";
3
- import { parse } from "dotenv";
4
-
5
- export function loadEnv(cwd: string) {
6
- const envFiles = [".env", ".env.local"];
7
- const envVars: Record<string, string> = {};
8
-
9
- for (const file of envFiles) {
10
- const filePath = resolve(cwd, file);
11
- if (existsSync(filePath)) {
12
- try {
13
- const parsed = parse(readFileSync(filePath));
14
- Object.assign(envVars, parsed);
15
- } catch {
16
- // Ignore errors parsing env file
17
- }
18
- }
19
- }
20
-
21
- // Apply variables to process.env, but don't overwrite existing ones
22
- for (const key in envVars) {
23
- if (Object.hasOwn(envVars, key)) {
24
- if (process.env[key] === undefined) {
25
- process.env[key] = envVars[key];
26
- }
27
- }
28
- }
29
-
30
- return envVars;
31
- }
package/src/errors.ts DELETED
@@ -1,96 +0,0 @@
1
- /** Possible severity levels for a `LithiaError`. */
2
- export type LithiaErrorLevel = "fatal" | "error" | "warning" | "info";
3
-
4
- /** Base error class for Lithia runtime errors.
5
- *
6
- * All custom runtime errors extend `LithiaError` and provide a machine
7
- * readable `code` and a `level` used for logging and control-flow (for
8
- * instance `fatal` errors may terminate the process).
9
- */
10
- export class LithiaError extends Error {
11
- constructor(
12
- /** Machine-readable error code. */
13
- public code: string,
14
- message: string,
15
- /** Severity level. */
16
- public level: LithiaErrorLevel = "error",
17
- /** Optional underlying cause. */
18
- public cause?: any,
19
- ) {
20
- super(message);
21
- this.name = "LithiaError";
22
- Error.captureStackTrace?.(this, this.constructor as any);
23
- }
24
- }
25
-
26
- /** Error raised when the manifest version does not match the native schema. */
27
- export class SchemaVersionMismatchError extends LithiaError {
28
- constructor(expected: string, received: string) {
29
- super(
30
- "SCHEMA_VERSION_MISMATCH",
31
- `Manifest version ${received} does not match expected version ${expected}`,
32
- "fatal",
33
- undefined,
34
- );
35
- }
36
- }
37
-
38
- /** Error used when reading or parsing the manifest fails. */
39
- export class ManifestLoadError extends LithiaError {
40
- constructor(cause: any) {
41
- super("MANIFEST_LOAD_ERROR", "Failed to load manifest.", "fatal", cause);
42
- }
43
- }
44
-
45
- /** Error raised when serving a static file but no MIME type is configured for its extension. */
46
- export class StaticFileMimeMissingError extends LithiaError {
47
- constructor(extension: string, filePath: string) {
48
- super(
49
- "STATIC_FILE_MIME_MISSING",
50
- `No MIME type configured for extension '${extension}' when serving '${filePath}'. Please configure a MIME type for this extension in your Lithia config.`,
51
- "error",
52
- );
53
- }
54
- }
55
-
56
- /** Error raised when request data validation fails. */
57
- export class ValidationError extends LithiaError {
58
- constructor(
59
- message: string,
60
- public issues?: any[],
61
- ) {
62
- super("VALIDATION_ERROR", message, "error");
63
- }
64
- }
65
-
66
- /** Error raised when a route module does not export a default async function. */
67
- export class InvalidRouteModuleError extends LithiaError {
68
- constructor(filePath: string, reason: string) {
69
- super(
70
- "INVALID_ROUTE_MODULE",
71
- `Invalid route module at '${filePath}': ${reason}. Route modules must export a default async function.`,
72
- "error",
73
- );
74
- }
75
- }
76
-
77
- export class InvalidEventModuleError extends LithiaError {
78
- constructor(filePath: string, reason: string) {
79
- super(
80
- "INVALID_EVENT_MODULE",
81
- `Invalid event module at '${filePath}': ${reason}. Event modules must export a default function that accepts a Lithia instance.`,
82
- "error",
83
- );
84
- }
85
- }
86
-
87
- /** Error raised when the server bootstrap module (_server.ts) is invalid. */
88
- export class InvalidBootstrapModuleError extends LithiaError {
89
- constructor(filePath: string, reason: string) {
90
- super(
91
- "INVALID_BOOTSTRAP_MODULE",
92
- `Invalid server bootstrap module at '${filePath}': ${reason}. The module must export a default async function.`,
93
- "fatal",
94
- );
95
- }
96
- }