@flightdev/loader 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024-2026 Flight Contributors
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,147 @@
1
+ # @flight-framework/loader
2
+
3
+ Optional ESM loader for TypeScript extension resolution in Node.js. This package enables seamless imports without explicit file extensions.
4
+
5
+ ## When to Use
6
+
7
+ This package is **optional**. Modern Node.js versions (22.18+) include native TypeScript support. Use this loader only if:
8
+
9
+ - You are on Node.js < 22.18
10
+ - You need custom extension resolution behavior
11
+ - You want consistent resolution across all Node.js versions
12
+
13
+ ## Installation
14
+
15
+ ```bash
16
+ npm install @flight-framework/loader
17
+ ```
18
+
19
+ ## Usage
20
+
21
+ ### Option 1: Node.js Native TypeScript (Recommended)
22
+
23
+ Node.js v22.18+ includes native TypeScript type stripping:
24
+
25
+ ```bash
26
+ # v22.18+ (enabled by default in v23.6+)
27
+ node --experimental-strip-types ./server.ts
28
+
29
+ # v25.2+ (stable, no flag needed)
30
+ node ./server.ts
31
+ ```
32
+
33
+ ### Option 2: Flight Loader
34
+
35
+ For older Node.js versions or custom resolution:
36
+
37
+ ```bash
38
+ node --import @flight-framework/loader/register ./server.js
39
+ ```
40
+
41
+ ### Option 3: tsconfig.json Configuration
42
+
43
+ Configure TypeScript to rewrite imports during compilation:
44
+
45
+ ```json
46
+ {
47
+ "compilerOptions": {
48
+ "module": "nodenext",
49
+ "moduleResolution": "nodenext",
50
+ "rewriteRelativeImportExtensions": true,
51
+ "erasableSyntaxOnly": true,
52
+ "verbatimModuleSyntax": true
53
+ }
54
+ }
55
+ ```
56
+
57
+ The `rewriteRelativeImportExtensions` option (TypeScript 5.7+) rewrites `.ts` imports to `.js` in output.
58
+
59
+ ## How It Works
60
+
61
+ The loader implements Node.js module customization hooks to:
62
+
63
+ 1. **Resolve** - Find files without explicit extensions by trying `.ts`, `.tsx`, `.js`, etc.
64
+ 2. **Load** - Pass TypeScript files to Node.js native type stripping (v22.18+)
65
+
66
+ ### Extension Priority
67
+
68
+ When importing without an extension (e.g., `import { x } from './utils'`):
69
+
70
+ 1. `./utils.ts`
71
+ 2. `./utils.tsx`
72
+ 3. `./utils.mts`
73
+ 4. `./utils.js`
74
+ 5. `./utils.jsx`
75
+ 6. `./utils.mjs`
76
+ 7. `./utils.json`
77
+ 8. `./utils/index.ts`
78
+ 9. `./utils/index.js`
79
+
80
+ ## API
81
+
82
+ ```typescript
83
+ import {
84
+ supportsNativeTypeScript,
85
+ getRecommendedFlags,
86
+ resolveWithExtensions,
87
+ RESOLVE_EXTENSIONS
88
+ } from '@flight-framework/loader';
89
+
90
+ // Check Node.js capability
91
+ if (supportsNativeTypeScript()) {
92
+ // Node.js can handle TypeScript natively
93
+ }
94
+
95
+ // Get recommended CLI flags
96
+ const flags = getRecommendedFlags();
97
+ // ['--experimental-strip-types'] or [] for v25+
98
+
99
+ // Resolve specifier with extensions
100
+ const paths = resolveWithExtensions('./utils');
101
+ // ['./utils.ts', './utils.tsx', './utils.mts', ...]
102
+ ```
103
+
104
+ ## Bundler Integration
105
+
106
+ Flight's bundlers (Vite, esbuild, Rolldown) include automatic extension resolution. This loader is only needed for runtime Node.js execution outside of the bundler.
107
+
108
+ ### Vite
109
+
110
+ ```typescript
111
+ // Automatic - resolve.extensions is configured by default
112
+ import { defineConfig } from '@flight-framework/core';
113
+ import { vite } from '@flight-framework/bundler-vite';
114
+
115
+ export default defineConfig({
116
+ bundler: vite(),
117
+ });
118
+ ```
119
+
120
+ ### esbuild
121
+
122
+ ```typescript
123
+ // Automatic - resolveExtensions is configured by default
124
+ import { esbuild } from '@flight-framework/bundler-esbuild';
125
+ ```
126
+
127
+ ### Rolldown
128
+
129
+ ```typescript
130
+ // Automatic - resolve.extensions is configured by default
131
+ import { rolldown } from '@flight-framework/bundler-rolldown';
132
+ ```
133
+
134
+ ## Requirements
135
+
136
+ - Node.js >= 20.0.0
137
+ - For native TypeScript: Node.js >= 22.18.0
138
+
139
+ ## Related
140
+
141
+ - [Module Resolution Guide](../../docs/module-resolution.md)
142
+ - [RSC Boundaries](../../docs/rsc-boundaries.md)
143
+ - [TypeScript Configuration](../../docs/typescript.md)
144
+
145
+ ## License
146
+
147
+ MIT
@@ -0,0 +1,79 @@
1
+ /**
2
+ * ESM Loader Hooks for Node.js
3
+ *
4
+ * These hooks implement the Node.js module customization API
5
+ * to resolve TypeScript extensions automatically.
6
+ *
7
+ * @see https://nodejs.org/api/module.html#customization-hooks
8
+ */
9
+ /**
10
+ * Context passed to the resolve hook
11
+ */
12
+ interface ResolveContext {
13
+ conditions: string[];
14
+ importAttributes: Record<string, string>;
15
+ parentURL?: string;
16
+ }
17
+ /**
18
+ * Result from the resolve hook
19
+ */
20
+ interface ResolveResult {
21
+ url: string;
22
+ format?: 'builtin' | 'commonjs' | 'json' | 'module' | 'wasm';
23
+ shortCircuit?: boolean;
24
+ }
25
+ /**
26
+ * Context passed to the load hook
27
+ */
28
+ interface LoadContext {
29
+ conditions: string[];
30
+ format?: string;
31
+ importAttributes: Record<string, string>;
32
+ }
33
+ /**
34
+ * Result from the load hook
35
+ */
36
+ interface LoadResult {
37
+ format: 'builtin' | 'commonjs' | 'json' | 'module' | 'wasm';
38
+ source?: string | ArrayBuffer | SharedArrayBuffer;
39
+ shortCircuit?: boolean;
40
+ }
41
+
42
+ /**
43
+ * @flightdev/loader
44
+ *
45
+ * Optional ESM loader for TypeScript extension resolution in Node.js.
46
+ * This package provides automatic resolution of TypeScript file extensions
47
+ * for transitive imports when running in Node.js ESM mode.
48
+ *
49
+ * @example
50
+ * ```bash
51
+ * # Option 1: Use Node.js native TypeScript (v22.18+, recommended)
52
+ * node --experimental-strip-types ./server.ts
53
+ *
54
+ * # Option 2: Use Flight loader for older Node.js or custom resolution
55
+ * node --import @flightdev/loader/register ./server.js
56
+ * ```
57
+ */
58
+ /**
59
+ * TypeScript file extensions that will be resolved automatically
60
+ */
61
+ declare const TYPESCRIPT_EXTENSIONS: readonly [".ts", ".tsx", ".mts", ".cts"];
62
+ /**
63
+ * All resolvable extensions in order of priority
64
+ */
65
+ declare const RESOLVE_EXTENSIONS: readonly [".ts", ".tsx", ".mts", ".cts", ".js", ".jsx", ".mjs", ".cjs", ".json"];
66
+ /**
67
+ * Check if Node.js version supports native TypeScript stripping
68
+ */
69
+ declare function supportsNativeTypeScript(): boolean;
70
+ /**
71
+ * Get recommended Node.js flags for TypeScript execution
72
+ */
73
+ declare function getRecommendedFlags(): string[];
74
+ /**
75
+ * Resolve a specifier with TypeScript extension fallbacks
76
+ */
77
+ declare function resolveWithExtensions(specifier: string, extensions?: readonly string[]): string[];
78
+
79
+ export { type LoadContext, type LoadResult, RESOLVE_EXTENSIONS, type ResolveContext, type ResolveResult, TYPESCRIPT_EXTENSIONS, getRecommendedFlags, resolveWithExtensions, supportsNativeTypeScript };
package/dist/index.js ADDED
@@ -0,0 +1,41 @@
1
+ // src/index.ts
2
+ var TYPESCRIPT_EXTENSIONS = [".ts", ".tsx", ".mts", ".cts"];
3
+ var RESOLVE_EXTENSIONS = [
4
+ ".ts",
5
+ ".tsx",
6
+ ".mts",
7
+ ".cts",
8
+ ".js",
9
+ ".jsx",
10
+ ".mjs",
11
+ ".cjs",
12
+ ".json"
13
+ ];
14
+ function supportsNativeTypeScript() {
15
+ const [major, minor] = process.versions.node.split(".").map(Number);
16
+ return major === 22 && minor >= 18 || major >= 23;
17
+ }
18
+ function getRecommendedFlags() {
19
+ if (supportsNativeTypeScript()) {
20
+ const [major] = process.versions.node.split(".").map(Number);
21
+ if (major >= 25 || major === 23 && parseInt(process.versions.node.split(".")[1]) >= 6) {
22
+ return [];
23
+ }
24
+ return ["--experimental-strip-types"];
25
+ }
26
+ return ["--import", "@flightdev/loader/register"];
27
+ }
28
+ function resolveWithExtensions(specifier, extensions = RESOLVE_EXTENSIONS) {
29
+ if (extensions.some((ext) => specifier.endsWith(ext))) {
30
+ return [specifier];
31
+ }
32
+ return extensions.map((ext) => `${specifier}${ext}`);
33
+ }
34
+ export {
35
+ RESOLVE_EXTENSIONS,
36
+ TYPESCRIPT_EXTENSIONS,
37
+ getRecommendedFlags,
38
+ resolveWithExtensions,
39
+ supportsNativeTypeScript
40
+ };
41
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts"],"sourcesContent":["/**\r\n * @flightdev/loader\r\n * \r\n * Optional ESM loader for TypeScript extension resolution in Node.js.\r\n * This package provides automatic resolution of TypeScript file extensions\r\n * for transitive imports when running in Node.js ESM mode.\r\n * \r\n * @example\r\n * ```bash\r\n * # Option 1: Use Node.js native TypeScript (v22.18+, recommended)\r\n * node --experimental-strip-types ./server.ts\r\n * \r\n * # Option 2: Use Flight loader for older Node.js or custom resolution\r\n * node --import @flightdev/loader/register ./server.js\r\n * ```\r\n */\r\n\r\n/**\r\n * TypeScript file extensions that will be resolved automatically\r\n */\r\nexport const TYPESCRIPT_EXTENSIONS = ['.ts', '.tsx', '.mts', '.cts'] as const;\r\n\r\n/**\r\n * All resolvable extensions in order of priority\r\n */\r\nexport const RESOLVE_EXTENSIONS = [\r\n '.ts',\r\n '.tsx',\r\n '.mts',\r\n '.cts',\r\n '.js',\r\n '.jsx',\r\n '.mjs',\r\n '.cjs',\r\n '.json',\r\n] as const;\r\n\r\n/**\r\n * Check if Node.js version supports native TypeScript stripping\r\n */\r\nexport function supportsNativeTypeScript(): boolean {\r\n const [major, minor] = process.versions.node.split('.').map(Number);\r\n // Node.js v22.18+ has stable type stripping (enabled by default in v23.6+)\r\n return (major === 22 && minor >= 18) || major >= 23;\r\n}\r\n\r\n/**\r\n * Get recommended Node.js flags for TypeScript execution\r\n */\r\nexport function getRecommendedFlags(): string[] {\r\n if (supportsNativeTypeScript()) {\r\n const [major] = process.versions.node.split('.').map(Number);\r\n // v23.6+ and v25.2+ have it enabled by default\r\n if (major >= 25 || (major === 23 && parseInt(process.versions.node.split('.')[1]) >= 6)) {\r\n return []; // No flags needed\r\n }\r\n return ['--experimental-strip-types'];\r\n }\r\n return ['--import', '@flightdev/loader/register'];\r\n}\r\n\r\n/**\r\n * Resolve a specifier with TypeScript extension fallbacks\r\n */\r\nexport function resolveWithExtensions(\r\n specifier: string,\r\n extensions: readonly string[] = RESOLVE_EXTENSIONS\r\n): string[] {\r\n // If specifier already has an extension, return as-is\r\n if (extensions.some(ext => specifier.endsWith(ext))) {\r\n return [specifier];\r\n }\r\n\r\n // Generate possible paths with extensions\r\n return extensions.map(ext => `${specifier}${ext}`);\r\n}\r\n\r\nexport type { ResolveContext, LoadContext, ResolveResult, LoadResult } from './hooks';\r\n"],"mappings":";AAoBO,IAAM,wBAAwB,CAAC,OAAO,QAAQ,QAAQ,MAAM;AAK5D,IAAM,qBAAqB;AAAA,EAC9B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACJ;AAKO,SAAS,2BAAoC;AAChD,QAAM,CAAC,OAAO,KAAK,IAAI,QAAQ,SAAS,KAAK,MAAM,GAAG,EAAE,IAAI,MAAM;AAElE,SAAQ,UAAU,MAAM,SAAS,MAAO,SAAS;AACrD;AAKO,SAAS,sBAAgC;AAC5C,MAAI,yBAAyB,GAAG;AAC5B,UAAM,CAAC,KAAK,IAAI,QAAQ,SAAS,KAAK,MAAM,GAAG,EAAE,IAAI,MAAM;AAE3D,QAAI,SAAS,MAAO,UAAU,MAAM,SAAS,QAAQ,SAAS,KAAK,MAAM,GAAG,EAAE,CAAC,CAAC,KAAK,GAAI;AACrF,aAAO,CAAC;AAAA,IACZ;AACA,WAAO,CAAC,4BAA4B;AAAA,EACxC;AACA,SAAO,CAAC,YAAY,4BAA4B;AACpD;AAKO,SAAS,sBACZ,WACA,aAAgC,oBACxB;AAER,MAAI,WAAW,KAAK,SAAO,UAAU,SAAS,GAAG,CAAC,GAAG;AACjD,WAAO,CAAC,SAAS;AAAA,EACrB;AAGA,SAAO,WAAW,IAAI,SAAO,GAAG,SAAS,GAAG,GAAG,EAAE;AACrD;","names":[]}
@@ -0,0 +1,2 @@
1
+
2
+ export { }
@@ -0,0 +1,6 @@
1
+ // src/register.ts
2
+ import { register } from "module";
3
+ import { pathToFileURL } from "url";
4
+ register("./hooks.js", pathToFileURL(import.meta.url));
5
+ console.log("[Flight Loader] TypeScript extension resolution enabled");
6
+ //# sourceMappingURL=register.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/register.ts"],"sourcesContent":["/**\r\n * Auto-registration entry point for Node.js --import flag\r\n * \r\n * @example\r\n * ```bash\r\n * node --import @flightdev/loader/register ./server.js\r\n * ```\r\n */\r\n\r\nimport { register } from 'node:module';\r\nimport { pathToFileURL } from 'node:url';\r\n\r\n// Register the hooks\r\nregister('./hooks.js', pathToFileURL(import.meta.url));\r\n\r\nconsole.log('[Flight Loader] TypeScript extension resolution enabled');\r\n"],"mappings":";AASA,SAAS,gBAAgB;AACzB,SAAS,qBAAqB;AAG9B,SAAS,cAAc,cAAc,YAAY,GAAG,CAAC;AAErD,QAAQ,IAAI,yDAAyD;","names":[]}
package/package.json ADDED
@@ -0,0 +1,45 @@
1
+ {
2
+ "name": "@flightdev/loader",
3
+ "version": "0.2.0",
4
+ "description": "Optional ESM loader for TypeScript extension resolution in Node.js",
5
+ "keywords": [
6
+ "flight",
7
+ "framework",
8
+ "loader",
9
+ "esm",
10
+ "typescript"
11
+ ],
12
+ "license": "MIT",
13
+ "author": "Flight Contributors",
14
+ "type": "module",
15
+ "exports": {
16
+ ".": {
17
+ "types": "./dist/index.d.ts",
18
+ "import": "./dist/index.js"
19
+ },
20
+ "./register": {
21
+ "types": "./dist/register.d.ts",
22
+ "import": "./dist/register.js"
23
+ }
24
+ },
25
+ "main": "./dist/index.js",
26
+ "types": "./dist/index.d.ts",
27
+ "files": [
28
+ "dist"
29
+ ],
30
+ "devDependencies": {
31
+ "@types/node": "^22.0.0",
32
+ "rimraf": "^6.0.0",
33
+ "tsup": "^8.0.0",
34
+ "typescript": "^5.7.0"
35
+ },
36
+ "engines": {
37
+ "node": ">=20.0.0"
38
+ },
39
+ "scripts": {
40
+ "build": "tsup",
41
+ "dev": "tsup --watch",
42
+ "clean": "rimraf dist",
43
+ "typecheck": "tsc --noEmit"
44
+ }
45
+ }