@thoughtpivot/flight 1.0.7 → 1.1.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/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Flight
2
2
 
3
- Flight is a modern, high-performance web application server built on Node.js, designed for building scalable, component-driven applications. It represents the evolution of the [Avian](https://github.com/ispyhumanfly/avian) component application server, incorporating modern best practices and improved developer experience.
3
+ Flight is a modern, high-performance web application server built on Node.js, designed for building scalable, component-driven applications. It is the successor to [Avian](https://github.com/ispyhumanfly/avian): originally created by ThoughtPivot, handed to FlyPaper Technologies, LLC, where Avian matured—Flight builds on those advancements with modern tooling and developer experience.
4
4
 
5
5
  ## Overview
6
6
 
@@ -29,6 +29,10 @@ yarn add @thoughtpivot/flight
29
29
 
30
30
  Previously published on npm as `@spytech/flight`; switch your dependency to `@thoughtpivot/flight`.
31
31
 
32
+ ### Downstream apps (tsx / patch-package)
33
+
34
+ From **v1.0.8** onward, Flight normalizes `require('yargs/yargs')` when loaders such as **tsx** expose it as `{ default: factory }` instead of the factory. If you only added **patch-package** for that workaround, upgrade `@thoughtpivot/flight`, delete `patches/@thoughtpivot+flight+*.patch`, and remove any **postinstall** hook that existed solely to apply it.
35
+
32
36
  ## Quick Start
33
37
 
34
38
  1. Create a new project directory and initialize:
@@ -93,6 +97,7 @@ node flight.js --mode production --app_home .
93
97
  Available CLI options:
94
98
 
95
99
  - `--app_home`: Application root directory (default: current directory)
100
+ - `--exclude_paths` / `--exclude-paths`: Directories under `app_home` to omit when discovering `**/*.backend.ts` routes. Repeat the flag (`--exclude_paths node_modules --exclude_paths dist`) or use commas (`--exclude_paths node_modules,dist`). Also accepts `FLIGHT_EXCLUDE_PATHS` (comma-separated). Paths must stay inside `app_home`.
96
101
  - `--app_key`: Application key for sessions (default: 'flightApp')
97
102
  - `--app_secret`: Secret key for session encryption (default: 'the best secret key in the world')
98
103
  - `--mode`: 'development' or 'production' (default: 'production')
@@ -259,8 +264,10 @@ Contributions are welcome! Please feel free to submit a Pull Request.
259
264
 
260
265
  ## Acknowledgments
261
266
 
262
- Flight is built upon the solid foundation laid by the [Avian](https://github.com/ispyhumanfly/avian) framework, created by FlyPaper Technologies, LLC. We're grateful for their pioneering work in component-driven architecture.
267
+ Flight succeeds the [Avian](https://github.com/ispyhumanfly/avian) framework. Avian began at ThoughtPivot and was later handed to FlyPaper Technologies, LLC, where it grew into the platform many teams relied on. Flight is born from that lineage—the ideas and hardening FlyPaper contributed to Avian—carried forward as ThoughtPivot’s next-generation server.
268
+
269
+ We’re grateful to FlyPaper Technologies for stewarding Avian and advancing component-driven architecture.
263
270
 
264
271
  ## ThoughtPivot
265
272
 
266
- Flight is a [ThoughtPivot](https://github.com/thoughtpivot) technology: developed and maintained as part of the ThoughtPivot organization and ecosystem.
273
+ Today Flight is an official ThoughtPivot technology: developed and maintained by the [ThoughtPivot](https://github.com/thoughtpivot) organization as part of its ecosystem.
package/dist/flight.js CHANGED
@@ -21,7 +21,54 @@ const path_1 = __importDefault(require("path"));
21
21
  const koa_ratelimit_1 = __importDefault(require("koa-ratelimit"));
22
22
  const koa_static_1 = __importDefault(require("koa-static"));
23
23
  const koa_session_1 = __importDefault(require("koa-session"));
24
- const argv = require('yargs/yargs')(process.argv.slice(2)).argv;
24
+ function normalizeExcludePaths(value) {
25
+ if (value == null || value === '')
26
+ return [];
27
+ const parts = Array.isArray(value) ? value : [value];
28
+ const out = [];
29
+ for (const p of parts) {
30
+ const s = String(p).trim();
31
+ if (!s)
32
+ continue;
33
+ out.push(...s
34
+ .split(',')
35
+ .map((x) => x.trim())
36
+ .filter(Boolean));
37
+ }
38
+ return out;
39
+ }
40
+ function dedupeStrings(items) {
41
+ return [...new Set(items)];
42
+ }
43
+ /** Build fast-glob ignore globs for trees rooted under `appRootAbs`. */
44
+ function backendDiscoveryIgnorePatterns(appRootAbs, excludeRelativeDirs) {
45
+ const patterns = [];
46
+ for (const raw of excludeRelativeDirs) {
47
+ const trimmed = raw.trim();
48
+ if (!trimmed)
49
+ continue;
50
+ const resolved = path_1.default.resolve(appRootAbs, trimmed);
51
+ const rel = path_1.default.relative(appRootAbs, resolved);
52
+ const relPosix = rel.replace(/\\/g, '/');
53
+ if (!relPosix || relPosix.startsWith('..') || path_1.default.isAbsolute(rel)) {
54
+ console.warn(`Flight: exclude_paths entry skipped (outside app_home): ${trimmed}`);
55
+ continue;
56
+ }
57
+ patterns.push(`${relPosix}/**`);
58
+ }
59
+ return patterns;
60
+ }
61
+ const _yargs = require('yargs/yargs');
62
+ const yargsEntry = typeof _yargs === 'function' ? _yargs : _yargs.default;
63
+ const argv = yargsEntry(process.argv.slice(2))
64
+ .option('exclude_paths', {
65
+ alias: 'exclude-paths',
66
+ type: 'array',
67
+ string: true,
68
+ default: [],
69
+ describe: 'Directories under app_home to skip when discovering **/*.backend.ts (repeat flag or comma-separated)'
70
+ })
71
+ .parseSync();
25
72
  // Set default session duration (24 hours in milliseconds)
26
73
  const DEFAULT_SESSION_DURATION = 86400000; // 24 hours in milliseconds
27
74
  // Get session duration from environment variable or command line argument
@@ -63,8 +110,16 @@ if (argv.disable_vite === undefined) {
63
110
  // Ensure the value is a boolean
64
111
  argv.disable_vite = Boolean(argv.disable_vite);
65
112
  const appHomePath = path_1.default.resolve(argv.app_home);
113
+ const excludePathsConfigured = dedupeStrings([
114
+ ...normalizeExcludePaths(argv.exclude_paths),
115
+ ...normalizeExcludePaths(process.env.FLIGHT_EXCLUDE_PATHS)
116
+ ]);
117
+ const backendDiscoveryIgnores = backendDiscoveryIgnorePatterns(appHomePath, excludePathsConfigured);
66
118
  process.chdir(appHomePath);
67
119
  console.log(appHomePath);
120
+ if (backendDiscoveryIgnores.length > 0) {
121
+ console.log('Flight: excluding **/*.backend.ts discovery under:', backendDiscoveryIgnores.map((g) => g.replace(/\*\*$/, '')).join(', '));
122
+ }
68
123
  const mode = process.env.FLIGHT_MODE || argv.mode || 'production';
69
124
  /** Prefix without breaking printf-style logs (koa-logger uses `%s` as the first argument). */
70
125
  const flightModeLabel = `Flight (${mode}):`;
@@ -113,7 +168,9 @@ else {
113
168
  app.use((0, cors_1.default)()).use((0, koa_bodyparser_1.default)({
114
169
  jsonLimit: argv.payload_limit
115
170
  }));
116
- const backEndFiles = fast_glob_1.default.sync('**/*.backend.ts');
171
+ const backEndFiles = fast_glob_1.default.sync('**/*.backend.ts', {
172
+ ignore: backendDiscoveryIgnores
173
+ });
117
174
  backEndFiles.forEach((file) => {
118
175
  const serverRoutes = require(path_1.default.resolve(file));
119
176
  console.log('Found component backend file: ' + path_1.default.resolve(file));
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@thoughtpivot/flight",
3
- "version": "1.0.7",
3
+ "version": "1.1.0",
4
4
  "description": "A web server designed for running full stack, component based applications at enterprise scale.",
5
5
  "main": "src/flight.ts",
6
6
  "publishConfig": {
package/src/flight.ts CHANGED
@@ -19,7 +19,75 @@ import ratelimit from 'koa-ratelimit'
19
19
  import serve from 'koa-static'
20
20
  import session from 'koa-session'
21
21
 
22
- const argv = require('yargs/yargs')(process.argv.slice(2)).argv
22
+ /** CLI argv shape after Flight applies defaults (see block below). */
23
+ interface FlightArgv {
24
+ session_duration?: number
25
+ app_home?: string
26
+ app_key?: string
27
+ app_secret?: string
28
+ port?: number | string
29
+ payload_limit?: string
30
+ disable_vite?: boolean
31
+ mode?: string
32
+ exclude_paths?: string[]
33
+ }
34
+
35
+ function normalizeExcludePaths(value: unknown): string[] {
36
+ if (value == null || value === '') return []
37
+ const parts = Array.isArray(value) ? value : [value]
38
+ const out: string[] = []
39
+ for (const p of parts) {
40
+ const s = String(p).trim()
41
+ if (!s) continue
42
+ out.push(
43
+ ...s
44
+ .split(',')
45
+ .map((x) => x.trim())
46
+ .filter(Boolean)
47
+ )
48
+ }
49
+ return out
50
+ }
51
+
52
+ function dedupeStrings(items: string[]): string[] {
53
+ return [...new Set(items)]
54
+ }
55
+
56
+ /** Build fast-glob ignore globs for trees rooted under `appRootAbs`. */
57
+ function backendDiscoveryIgnorePatterns(appRootAbs: string, excludeRelativeDirs: string[]): string[] {
58
+ const patterns: string[] = []
59
+ for (const raw of excludeRelativeDirs) {
60
+ const trimmed = raw.trim()
61
+ if (!trimmed) continue
62
+ const resolved = path.resolve(appRootAbs, trimmed)
63
+ const rel = path.relative(appRootAbs, resolved)
64
+ const relPosix = rel.replace(/\\/g, '/')
65
+ if (!relPosix || relPosix.startsWith('..') || path.isAbsolute(rel)) {
66
+ console.warn(`Flight: exclude_paths entry skipped (outside app_home): ${trimmed}`)
67
+ continue
68
+ }
69
+ patterns.push(`${relPosix}/**`)
70
+ }
71
+ return patterns
72
+ }
73
+
74
+ // tsx (and similar loaders) may expose require('yargs/yargs') as { default: factory } instead of factory.
75
+ interface YargsInstance {
76
+ option(key: string, opts: Record<string, unknown>): YargsInstance
77
+ parseSync(): FlightArgv
78
+ }
79
+ type YargsFn = (args: string[]) => YargsInstance
80
+ const _yargs = require('yargs/yargs') as YargsFn | { default: YargsFn }
81
+ const yargsEntry: YargsFn = typeof _yargs === 'function' ? _yargs : _yargs.default
82
+ const argv = yargsEntry(process.argv.slice(2))
83
+ .option('exclude_paths', {
84
+ alias: 'exclude-paths',
85
+ type: 'array',
86
+ string: true,
87
+ default: [],
88
+ describe: 'Directories under app_home to skip when discovering **/*.backend.ts (repeat flag or comma-separated)'
89
+ })
90
+ .parseSync() as FlightArgv
23
91
 
24
92
  // Set default session duration (24 hours in milliseconds)
25
93
  const DEFAULT_SESSION_DURATION = 86400000 // 24 hours in milliseconds
@@ -74,9 +142,21 @@ if (argv.disable_vite === undefined) {
74
142
  argv.disable_vite = Boolean(argv.disable_vite)
75
143
 
76
144
  const appHomePath = path.resolve(argv.app_home)
145
+ const excludePathsConfigured = dedupeStrings([
146
+ ...normalizeExcludePaths(argv.exclude_paths),
147
+ ...normalizeExcludePaths(process.env.FLIGHT_EXCLUDE_PATHS)
148
+ ])
149
+ const backendDiscoveryIgnores = backendDiscoveryIgnorePatterns(appHomePath, excludePathsConfigured)
150
+
77
151
  process.chdir(appHomePath)
78
152
 
79
153
  console.log(appHomePath)
154
+ if (backendDiscoveryIgnores.length > 0) {
155
+ console.log(
156
+ 'Flight: excluding **/*.backend.ts discovery under:',
157
+ backendDiscoveryIgnores.map((g) => g.replace(/\*\*$/, '')).join(', ')
158
+ )
159
+ }
80
160
 
81
161
  const mode = process.env.FLIGHT_MODE || argv.mode || 'production'
82
162
 
@@ -136,7 +216,9 @@ if (cluster.isPrimary) {
136
216
  })
137
217
  )
138
218
 
139
- const backEndFiles = fg.sync('**/*.backend.ts')
219
+ const backEndFiles = fg.sync('**/*.backend.ts', {
220
+ ignore: backendDiscoveryIgnores
221
+ })
140
222
  backEndFiles.forEach((file) => {
141
223
  const serverRoutes = require(path.resolve(file))
142
224