@onebun/core 0.1.16 → 0.1.18
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/package.json
CHANGED
|
@@ -432,6 +432,236 @@ describe('OneBunApplication', () => {
|
|
|
432
432
|
expect(prodApp).toBeInstanceOf(OneBunApplication);
|
|
433
433
|
});
|
|
434
434
|
|
|
435
|
+
test('should use PORT env variable when port is not explicitly provided', () => {
|
|
436
|
+
const originalPort = process.env.PORT;
|
|
437
|
+
const originalHost = process.env.HOST;
|
|
438
|
+
try {
|
|
439
|
+
process.env.PORT = '4567';
|
|
440
|
+
delete process.env.HOST; // Clear HOST to get default
|
|
441
|
+
|
|
442
|
+
@Module({})
|
|
443
|
+
class TestModule {}
|
|
444
|
+
|
|
445
|
+
const app = createTestApp(TestModule);
|
|
446
|
+
expect(app.getHttpUrl()).toBe('http://0.0.0.0:4567');
|
|
447
|
+
} finally {
|
|
448
|
+
if (originalPort === undefined) {
|
|
449
|
+
delete process.env.PORT;
|
|
450
|
+
} else {
|
|
451
|
+
process.env.PORT = originalPort;
|
|
452
|
+
}
|
|
453
|
+
if (originalHost === undefined) {
|
|
454
|
+
delete process.env.HOST;
|
|
455
|
+
} else {
|
|
456
|
+
process.env.HOST = originalHost;
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
});
|
|
460
|
+
|
|
461
|
+
test('should use HOST env variable when host is not explicitly provided', () => {
|
|
462
|
+
const originalHost = process.env.HOST;
|
|
463
|
+
const originalPort = process.env.PORT;
|
|
464
|
+
try {
|
|
465
|
+
process.env.HOST = '192.168.1.100';
|
|
466
|
+
delete process.env.PORT; // Clear PORT to get default
|
|
467
|
+
|
|
468
|
+
@Module({})
|
|
469
|
+
class TestModule {}
|
|
470
|
+
|
|
471
|
+
const app = createTestApp(TestModule);
|
|
472
|
+
expect(app.getHttpUrl()).toBe('http://192.168.1.100:3000');
|
|
473
|
+
} finally {
|
|
474
|
+
if (originalHost === undefined) {
|
|
475
|
+
delete process.env.HOST;
|
|
476
|
+
} else {
|
|
477
|
+
process.env.HOST = originalHost;
|
|
478
|
+
}
|
|
479
|
+
if (originalPort === undefined) {
|
|
480
|
+
delete process.env.PORT;
|
|
481
|
+
} else {
|
|
482
|
+
process.env.PORT = originalPort;
|
|
483
|
+
}
|
|
484
|
+
}
|
|
485
|
+
});
|
|
486
|
+
|
|
487
|
+
test('should use both PORT and HOST env variables when not explicitly provided', () => {
|
|
488
|
+
const originalPort = process.env.PORT;
|
|
489
|
+
const originalHost = process.env.HOST;
|
|
490
|
+
try {
|
|
491
|
+
process.env.PORT = '8888';
|
|
492
|
+
process.env.HOST = '10.0.0.1';
|
|
493
|
+
|
|
494
|
+
@Module({})
|
|
495
|
+
class TestModule {}
|
|
496
|
+
|
|
497
|
+
const app = createTestApp(TestModule);
|
|
498
|
+
expect(app.getHttpUrl()).toBe('http://10.0.0.1:8888');
|
|
499
|
+
} finally {
|
|
500
|
+
if (originalPort === undefined) {
|
|
501
|
+
delete process.env.PORT;
|
|
502
|
+
} else {
|
|
503
|
+
process.env.PORT = originalPort;
|
|
504
|
+
}
|
|
505
|
+
if (originalHost === undefined) {
|
|
506
|
+
delete process.env.HOST;
|
|
507
|
+
} else {
|
|
508
|
+
process.env.HOST = originalHost;
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
});
|
|
512
|
+
|
|
513
|
+
test('should prefer explicit port over PORT env variable', () => {
|
|
514
|
+
const originalPort = process.env.PORT;
|
|
515
|
+
const originalHost = process.env.HOST;
|
|
516
|
+
try {
|
|
517
|
+
process.env.PORT = '9999';
|
|
518
|
+
delete process.env.HOST; // Clear HOST to get default
|
|
519
|
+
|
|
520
|
+
@Module({})
|
|
521
|
+
class TestModule {}
|
|
522
|
+
|
|
523
|
+
const app = createTestApp(TestModule, { port: 5555 });
|
|
524
|
+
expect(app.getHttpUrl()).toBe('http://0.0.0.0:5555');
|
|
525
|
+
} finally {
|
|
526
|
+
if (originalPort === undefined) {
|
|
527
|
+
delete process.env.PORT;
|
|
528
|
+
} else {
|
|
529
|
+
process.env.PORT = originalPort;
|
|
530
|
+
}
|
|
531
|
+
if (originalHost === undefined) {
|
|
532
|
+
delete process.env.HOST;
|
|
533
|
+
} else {
|
|
534
|
+
process.env.HOST = originalHost;
|
|
535
|
+
}
|
|
536
|
+
}
|
|
537
|
+
});
|
|
538
|
+
|
|
539
|
+
test('should prefer explicit host over HOST env variable', () => {
|
|
540
|
+
const originalHost = process.env.HOST;
|
|
541
|
+
const originalPort = process.env.PORT;
|
|
542
|
+
try {
|
|
543
|
+
process.env.HOST = '192.168.1.100';
|
|
544
|
+
delete process.env.PORT; // Clear PORT to get default
|
|
545
|
+
|
|
546
|
+
@Module({})
|
|
547
|
+
class TestModule {}
|
|
548
|
+
|
|
549
|
+
const app = createTestApp(TestModule, { host: 'localhost' });
|
|
550
|
+
expect(app.getHttpUrl()).toBe('http://localhost:3000');
|
|
551
|
+
} finally {
|
|
552
|
+
if (originalHost === undefined) {
|
|
553
|
+
delete process.env.HOST;
|
|
554
|
+
} else {
|
|
555
|
+
process.env.HOST = originalHost;
|
|
556
|
+
}
|
|
557
|
+
if (originalPort === undefined) {
|
|
558
|
+
delete process.env.PORT;
|
|
559
|
+
} else {
|
|
560
|
+
process.env.PORT = originalPort;
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
});
|
|
564
|
+
|
|
565
|
+
test('should use defaults when env variables are not set', () => {
|
|
566
|
+
const originalPort = process.env.PORT;
|
|
567
|
+
const originalHost = process.env.HOST;
|
|
568
|
+
try {
|
|
569
|
+
delete process.env.PORT;
|
|
570
|
+
delete process.env.HOST;
|
|
571
|
+
|
|
572
|
+
@Module({})
|
|
573
|
+
class TestModule {}
|
|
574
|
+
|
|
575
|
+
const app = createTestApp(TestModule);
|
|
576
|
+
expect(app.getHttpUrl()).toBe('http://0.0.0.0:3000');
|
|
577
|
+
} finally {
|
|
578
|
+
if (originalPort !== undefined) {
|
|
579
|
+
process.env.PORT = originalPort;
|
|
580
|
+
}
|
|
581
|
+
if (originalHost !== undefined) {
|
|
582
|
+
process.env.HOST = originalHost;
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
});
|
|
586
|
+
|
|
587
|
+
test('should ignore invalid PORT env variable and use default', () => {
|
|
588
|
+
const originalPort = process.env.PORT;
|
|
589
|
+
const originalHost = process.env.HOST;
|
|
590
|
+
try {
|
|
591
|
+
process.env.PORT = 'invalid';
|
|
592
|
+
delete process.env.HOST; // Clear HOST to get default
|
|
593
|
+
|
|
594
|
+
@Module({})
|
|
595
|
+
class TestModule {}
|
|
596
|
+
|
|
597
|
+
const app = createTestApp(TestModule);
|
|
598
|
+
expect(app.getHttpUrl()).toBe('http://0.0.0.0:3000');
|
|
599
|
+
} finally {
|
|
600
|
+
if (originalPort === undefined) {
|
|
601
|
+
delete process.env.PORT;
|
|
602
|
+
} else {
|
|
603
|
+
process.env.PORT = originalPort;
|
|
604
|
+
}
|
|
605
|
+
if (originalHost === undefined) {
|
|
606
|
+
delete process.env.HOST;
|
|
607
|
+
} else {
|
|
608
|
+
process.env.HOST = originalHost;
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
});
|
|
612
|
+
|
|
613
|
+
test('should ignore empty PORT env variable and use default', () => {
|
|
614
|
+
const originalPort = process.env.PORT;
|
|
615
|
+
const originalHost = process.env.HOST;
|
|
616
|
+
try {
|
|
617
|
+
process.env.PORT = '';
|
|
618
|
+
delete process.env.HOST; // Clear HOST to get default
|
|
619
|
+
|
|
620
|
+
@Module({})
|
|
621
|
+
class TestModule {}
|
|
622
|
+
|
|
623
|
+
const app = createTestApp(TestModule);
|
|
624
|
+
expect(app.getHttpUrl()).toBe('http://0.0.0.0:3000');
|
|
625
|
+
} finally {
|
|
626
|
+
if (originalPort === undefined) {
|
|
627
|
+
delete process.env.PORT;
|
|
628
|
+
} else {
|
|
629
|
+
process.env.PORT = originalPort;
|
|
630
|
+
}
|
|
631
|
+
if (originalHost === undefined) {
|
|
632
|
+
delete process.env.HOST;
|
|
633
|
+
} else {
|
|
634
|
+
process.env.HOST = originalHost;
|
|
635
|
+
}
|
|
636
|
+
}
|
|
637
|
+
});
|
|
638
|
+
|
|
639
|
+
test('should ignore empty HOST env variable and use default', () => {
|
|
640
|
+
const originalHost = process.env.HOST;
|
|
641
|
+
const originalPort = process.env.PORT;
|
|
642
|
+
try {
|
|
643
|
+
process.env.HOST = '';
|
|
644
|
+
delete process.env.PORT; // Clear PORT to get default
|
|
645
|
+
|
|
646
|
+
@Module({})
|
|
647
|
+
class TestModule {}
|
|
648
|
+
|
|
649
|
+
const app = createTestApp(TestModule);
|
|
650
|
+
expect(app.getHttpUrl()).toBe('http://0.0.0.0:3000');
|
|
651
|
+
} finally {
|
|
652
|
+
if (originalHost === undefined) {
|
|
653
|
+
delete process.env.HOST;
|
|
654
|
+
} else {
|
|
655
|
+
process.env.HOST = originalHost;
|
|
656
|
+
}
|
|
657
|
+
if (originalPort === undefined) {
|
|
658
|
+
delete process.env.PORT;
|
|
659
|
+
} else {
|
|
660
|
+
process.env.PORT = originalPort;
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
});
|
|
664
|
+
|
|
435
665
|
test('should handle complex envSchema configuration', () => {
|
|
436
666
|
@Module({})
|
|
437
667
|
class TestModule {}
|
|
@@ -112,17 +112,48 @@ function normalizePath(path: string): string {
|
|
|
112
112
|
return path.endsWith('/') ? path.slice(0, -1) : path;
|
|
113
113
|
}
|
|
114
114
|
|
|
115
|
+
/**
|
|
116
|
+
* Resolve port from options, environment variable, or default.
|
|
117
|
+
* Priority: explicit option > PORT env > default (3000)
|
|
118
|
+
*/
|
|
119
|
+
function resolvePort(explicitPort: number | undefined): number {
|
|
120
|
+
if (explicitPort !== undefined) {
|
|
121
|
+
return explicitPort;
|
|
122
|
+
}
|
|
123
|
+
const envPort = process.env.PORT;
|
|
124
|
+
if (envPort !== undefined && envPort !== '') {
|
|
125
|
+
const parsed = parseInt(envPort, 10);
|
|
126
|
+
if (!isNaN(parsed) && parsed > 0) {
|
|
127
|
+
return parsed;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
return 3000;
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
/**
|
|
135
|
+
* Resolve host from options, environment variable, or default.
|
|
136
|
+
* Priority: explicit option > HOST env > default ('0.0.0.0')
|
|
137
|
+
*/
|
|
138
|
+
function resolveHost(explicitHost: string | undefined): string {
|
|
139
|
+
if (explicitHost !== undefined) {
|
|
140
|
+
return explicitHost;
|
|
141
|
+
}
|
|
142
|
+
const envHost = process.env.HOST;
|
|
143
|
+
if (envHost !== undefined && envHost !== '') {
|
|
144
|
+
return envHost;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
return '0.0.0.0';
|
|
148
|
+
}
|
|
149
|
+
|
|
115
150
|
/**
|
|
116
151
|
* OneBun Application
|
|
117
152
|
*/
|
|
118
153
|
export class OneBunApplication {
|
|
119
154
|
private rootModule: ModuleInstance;
|
|
120
155
|
private server: ReturnType<typeof Bun.serve> | null = null;
|
|
121
|
-
private options: ApplicationOptions
|
|
122
|
-
port: 3000,
|
|
123
|
-
host: '0.0.0.0',
|
|
124
|
-
development: process.env.NODE_ENV !== 'production',
|
|
125
|
-
};
|
|
156
|
+
private options: ApplicationOptions;
|
|
126
157
|
private logger: SyncLogger;
|
|
127
158
|
private config: IConfig<OneBunAppConfig>;
|
|
128
159
|
private configService: ConfigServiceImpl | null = null;
|
|
@@ -144,9 +175,13 @@ export class OneBunApplication {
|
|
|
144
175
|
moduleClass: new (...args: unknown[]) => object,
|
|
145
176
|
options?: Partial<ApplicationOptions>,
|
|
146
177
|
) {
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
178
|
+
// Resolve port and host with priority: explicit > env > default
|
|
179
|
+
this.options = {
|
|
180
|
+
port: resolvePort(options?.port),
|
|
181
|
+
host: resolveHost(options?.host),
|
|
182
|
+
development: options?.development ?? process.env.NODE_ENV !== 'production',
|
|
183
|
+
...options,
|
|
184
|
+
};
|
|
150
185
|
|
|
151
186
|
// Initialize configuration - TypedEnv if schema provided, otherwise NotInitializedConfig
|
|
152
187
|
if (this.options.envSchema) {
|
package/src/module/module.ts
CHANGED
|
@@ -326,11 +326,12 @@ export class OneBunModule implements ModuleInstance {
|
|
|
326
326
|
}
|
|
327
327
|
}
|
|
328
328
|
|
|
329
|
-
if
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
329
|
+
// Only report circular dependency if there are still unresolved services
|
|
330
|
+
const unresolvedServices = pendingProviders
|
|
331
|
+
.filter((p) => typeof p === 'function')
|
|
332
|
+
.map((p) => p.name);
|
|
333
333
|
|
|
334
|
+
if (iterations >= maxIterations && unresolvedServices.length > 0) {
|
|
334
335
|
const details = unresolvedServices
|
|
335
336
|
.map((serviceName) => {
|
|
336
337
|
const deps = unresolvedDeps.get(serviceName) || [];
|