@gravito/core 2.0.6 → 3.0.1

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.
Files changed (72) hide show
  1. package/README.md +64 -25
  2. package/dist/Application.d.ts +2 -9
  3. package/dist/Container.d.ts +18 -1
  4. package/dist/GravitoServer.d.ts +8 -8
  5. package/dist/HookManager.d.ts +36 -34
  6. package/dist/PlanetCore.d.ts +54 -0
  7. package/dist/Route.d.ts +5 -0
  8. package/dist/Router.d.ts +14 -1
  9. package/dist/adapters/bun/BunContext.d.ts +1 -1
  10. package/dist/adapters/bun/BunNativeAdapter.d.ts +11 -1
  11. package/dist/adapters/bun/FastPathRegistry.d.ts +31 -0
  12. package/dist/adapters/bun/RadixNode.d.ts +4 -3
  13. package/dist/adapters/bun/RadixRouter.d.ts +2 -2
  14. package/dist/adapters/bun/types.d.ts +7 -0
  15. package/dist/adapters/types.d.ts +20 -0
  16. package/dist/compat/async-local-storage.d.ts +5 -1
  17. package/dist/compat/async-local-storage.js.map +2 -2
  18. package/dist/compat/crypto.d.ts +6 -1
  19. package/dist/compat/crypto.js.map +2 -2
  20. package/dist/engine/AOTRouter.d.ts +1 -1
  21. package/dist/engine/FastContext.d.ts +4 -4
  22. package/dist/engine/MinimalContext.d.ts +3 -3
  23. package/dist/engine/index.js +29 -8
  24. package/dist/engine/index.js.map +10 -10
  25. package/dist/engine/types.d.ts +5 -5
  26. package/dist/events/CircuitBreaker.d.ts +12 -0
  27. package/dist/events/MessageQueueBridge.d.ts +2 -1
  28. package/dist/events/observability/EventMetrics.d.ts +1 -2
  29. package/dist/events/observability/ObservableHookManager.d.ts +1 -1
  30. package/dist/exceptions/AuthException.d.ts +19 -0
  31. package/dist/exceptions/AuthenticationException.d.ts +9 -3
  32. package/dist/exceptions/AuthorizationException.d.ts +2 -2
  33. package/dist/exceptions/CacheException.d.ts +9 -0
  34. package/dist/exceptions/CircularDependencyException.d.ts +2 -1
  35. package/dist/exceptions/ConfigurationException.d.ts +9 -0
  36. package/dist/exceptions/ContainerBindingCollisionException.d.ts +10 -0
  37. package/dist/exceptions/DatabaseException.d.ts +9 -0
  38. package/dist/exceptions/DomainException.d.ts +9 -0
  39. package/dist/exceptions/InfrastructureException.d.ts +17 -0
  40. package/dist/exceptions/MiddlewareDriftException.d.ts +10 -0
  41. package/dist/exceptions/QueueException.d.ts +9 -0
  42. package/dist/exceptions/StorageException.d.ts +9 -0
  43. package/dist/exceptions/StreamException.d.ts +9 -0
  44. package/dist/exceptions/SystemException.d.ts +9 -0
  45. package/dist/exceptions/ValidationException.d.ts +2 -2
  46. package/dist/exceptions/index.d.ts +12 -0
  47. package/dist/ffi/NativeAccelerator.js.map +3 -3
  48. package/dist/ffi/NativeHasher.d.ts +14 -0
  49. package/dist/ffi/NativeHasher.js +24 -1
  50. package/dist/ffi/NativeHasher.js.map +4 -4
  51. package/dist/ffi/cbor-fallback.js.map +1 -1
  52. package/dist/ffi/hash-fallback.d.ts +15 -0
  53. package/dist/ffi/hash-fallback.js +12 -1
  54. package/dist/ffi/hash-fallback.js.map +3 -3
  55. package/dist/ffi/types.d.ts +13 -0
  56. package/dist/ffi/types.js.map +1 -1
  57. package/dist/hooks/types.d.ts +7 -3
  58. package/dist/http/types.d.ts +2 -2
  59. package/dist/index.browser.d.ts +5 -5
  60. package/dist/index.browser.js +190 -47
  61. package/dist/index.browser.js.map +50 -46
  62. package/dist/index.d.ts +17 -7
  63. package/dist/index.js +613 -202
  64. package/dist/index.js.map +82 -68
  65. package/dist/runtime/NativeOrbitDetector.d.ts +59 -0
  66. package/dist/runtime/index.browser.d.ts +1 -1
  67. package/dist/runtime/index.d.ts +7 -0
  68. package/dist/runtime.d.ts +1 -1
  69. package/dist/testing/HttpTester.d.ts +4 -4
  70. package/dist/testing/TestResponse.d.ts +4 -4
  71. package/dist/types.d.ts +3 -3
  72. package/package.json +4 -3
package/dist/index.js CHANGED
@@ -1552,12 +1552,23 @@ var randomBytes = randomBytesFn;
1552
1552
  import { createHash, createHmac } from "crypto";
1553
1553
 
1554
1554
  class HashFallback {
1555
+ blake2bWarned = false;
1555
1556
  sha256(input) {
1556
1557
  return createHash("sha256").update(input).digest("hex");
1557
1558
  }
1558
1559
  hmacSha256(key, data) {
1559
1560
  return createHmac("sha256", key).update(data).digest("hex");
1560
1561
  }
1562
+ sha512(input) {
1563
+ return createHash("sha512").update(input).digest("hex");
1564
+ }
1565
+ blake2b(input) {
1566
+ if (!this.blake2bWarned) {
1567
+ console.warn("[gravito] BLAKE2b not available in node:crypto \u2014 using SHA-256 fallback");
1568
+ this.blake2bWarned = true;
1569
+ }
1570
+ return createHash("sha256").update(input).digest("hex");
1571
+ }
1561
1572
  }
1562
1573
 
1563
1574
  // src/ffi/NativeHasher.ts
@@ -1568,6 +1579,12 @@ class BunCryptoHasher {
1568
1579
  hmacSha256(key, data) {
1569
1580
  return new Bun.CryptoHasher("sha256", key).update(data).digest("hex");
1570
1581
  }
1582
+ sha512(input) {
1583
+ return new Bun.CryptoHasher("sha512").update(input).digest("hex");
1584
+ }
1585
+ blake2b(input) {
1586
+ return new Bun.CryptoHasher("blake2b256").update(input).digest("hex");
1587
+ }
1571
1588
  }
1572
1589
 
1573
1590
  class NativeHasher {
@@ -1601,6 +1618,12 @@ class NativeHasher {
1601
1618
  runtime
1602
1619
  };
1603
1620
  }
1621
+ static sha512(input) {
1622
+ return this.getAccelerator().sha512(input);
1623
+ }
1624
+ static blake2b(input) {
1625
+ return this.getAccelerator().blake2b(input);
1626
+ }
1604
1627
  static sha256(input) {
1605
1628
  return this.getAccelerator().sha256(input);
1606
1629
  }
@@ -1648,6 +1671,7 @@ class RadixNode {
1648
1671
  paramChild = null;
1649
1672
  wildcardChild = null;
1650
1673
  handlers = new Map;
1674
+ options = new Map;
1651
1675
  paramName = null;
1652
1676
  regex = null;
1653
1677
  constructor(segment = "", type = 0 /* STATIC */) {
@@ -1661,13 +1685,15 @@ class RadixNode {
1661
1685
  children: Array.from(this.children.entries()).map(([k, v]) => [k, v.toJSON()]),
1662
1686
  paramChild: this.paramChild?.toJSON() || null,
1663
1687
  wildcardChild: this.wildcardChild?.toJSON() || null,
1688
+ handlers: Array.from(this.handlers.entries()),
1689
+ options: Array.from(this.options.entries()),
1664
1690
  paramName: this.paramName,
1665
1691
  regex: this.regex ? this.regex.source : null
1666
1692
  };
1667
1693
  }
1668
1694
  static fromJSON(json) {
1669
1695
  const node = new RadixNode(json.segment, json.type);
1670
- node.paramName = json.paramName;
1696
+ node.paramName = json.paramName ?? null;
1671
1697
  if (json.regex) {
1672
1698
  node.regex = new RegExp(json.regex);
1673
1699
  }
@@ -1682,6 +1708,16 @@ class RadixNode {
1682
1708
  if (json.wildcardChild) {
1683
1709
  node.wildcardChild = RadixNode.fromJSON(json.wildcardChild);
1684
1710
  }
1711
+ if (json.handlers) {
1712
+ for (const [method, handlers] of json.handlers) {
1713
+ node.handlers.set(method, handlers);
1714
+ }
1715
+ }
1716
+ if (json.options) {
1717
+ for (const [method, options2] of json.options) {
1718
+ node.options.set(method, options2);
1719
+ }
1720
+ }
1685
1721
  return node;
1686
1722
  }
1687
1723
  }
@@ -1717,7 +1753,7 @@ class RadixRouter {
1717
1753
  where(param, regex) {
1718
1754
  this.globalConstraints.set(param, regex);
1719
1755
  }
1720
- add(method, path2, handlers) {
1756
+ add(method, path2, handlers, options2) {
1721
1757
  let node = this.root;
1722
1758
  const segments = this.splitPath(path2);
1723
1759
  for (let i = 0;i < segments.length; i++) {
@@ -1747,7 +1783,11 @@ class RadixRouter {
1747
1783
  node = node.children.get(segment);
1748
1784
  }
1749
1785
  }
1750
- node.handlers.set(method.toLowerCase(), handlers);
1786
+ const normalizedMethod = method.toLowerCase();
1787
+ node.handlers.set(normalizedMethod, handlers);
1788
+ if (options2) {
1789
+ node.options.set(normalizedMethod, options2);
1790
+ }
1751
1791
  this.routeCache.clear();
1752
1792
  }
1753
1793
  match(method, path2) {
@@ -1755,7 +1795,7 @@ class RadixRouter {
1755
1795
  if (path2 === "/" || path2 === "") {
1756
1796
  const handlers = this.root.handlers.get(normalizedMethod);
1757
1797
  if (handlers) {
1758
- return { handlers, params: {} };
1798
+ return { handlers, params: {}, options: this.root.options.get(normalizedMethod) };
1759
1799
  }
1760
1800
  return null;
1761
1801
  }
@@ -1772,11 +1812,13 @@ class RadixRouter {
1772
1812
  matchRecursive(node, segments, depth, params, method) {
1773
1813
  if (depth >= segments.length) {
1774
1814
  let handlers = node.handlers.get(method);
1815
+ let options2 = node.options.get(method);
1775
1816
  if (!handlers) {
1776
1817
  handlers = node.handlers.get("all");
1818
+ options2 = node.options.get("all");
1777
1819
  }
1778
1820
  if (handlers) {
1779
- return { handlers, params };
1821
+ return { handlers, params, options: options2 };
1780
1822
  }
1781
1823
  return null;
1782
1824
  }
@@ -1803,11 +1845,13 @@ class RadixRouter {
1803
1845
  }
1804
1846
  if (node.wildcardChild) {
1805
1847
  let handlers = node.wildcardChild.handlers.get(method);
1848
+ let options2 = node.wildcardChild.options.get(method);
1806
1849
  if (!handlers) {
1807
1850
  handlers = node.wildcardChild.handlers.get("all");
1851
+ options2 = node.wildcardChild.options.get("all");
1808
1852
  }
1809
1853
  if (handlers) {
1810
- return { handlers, params };
1854
+ return { handlers, params, options: options2 };
1811
1855
  }
1812
1856
  }
1813
1857
  return null;
@@ -2289,7 +2333,7 @@ class RequestScopeManager {
2289
2333
  let servicesCleaned = 0;
2290
2334
  for (const [, instance] of this.scoped) {
2291
2335
  if (instance && typeof instance === "object" && "cleanup" in instance) {
2292
- const fn = instance.cleanup;
2336
+ const fn = instance["cleanup"];
2293
2337
  if (typeof fn === "function") {
2294
2338
  try {
2295
2339
  await fn.call(instance);
@@ -3300,7 +3344,7 @@ class Gravito {
3300
3344
  // package.json
3301
3345
  var package_default = {
3302
3346
  name: "@gravito/core",
3303
- version: "2.0.6",
3347
+ version: "3.0.1",
3304
3348
  description: "",
3305
3349
  module: "./dist/index.js",
3306
3350
  main: "./dist/index.js",
@@ -3309,9 +3353,9 @@ var package_default = {
3309
3353
  types: "./dist/index.d.ts",
3310
3354
  exports: {
3311
3355
  ".": {
3356
+ types: "./dist/index.d.ts",
3312
3357
  browser: "./dist/index.browser.js",
3313
3358
  bun: "./dist/index.js",
3314
- types: "./dist/index.d.ts",
3315
3359
  default: "./dist/index.js"
3316
3360
  },
3317
3361
  "./compat": {
@@ -3357,7 +3401,8 @@ var package_default = {
3357
3401
  typecheck: "bun tsc -p tsconfig.json --noEmit --skipLibCheck",
3358
3402
  prepublishOnly: "bun run typecheck && bun run test && bun run build",
3359
3403
  "test:unit": "bun test $(find tests -name '*.test.ts' ! -name '*.integration.test.ts' 2>/dev/null | tr '\\n' ' ') --timeout=10000",
3360
- "test:integration": "test $(find tests -name '*.integration.test.ts' 2>/dev/null | wc -l) -gt 0 && find tests -name '*.integration.test.ts' -print0 | xargs -0 bun test --timeout=10000 || echo 'No integration tests found'"
3404
+ "test:integration": "test $(find tests -name '*.integration.test.ts' 2>/dev/null | wc -l) -gt 0 && find tests -name '*.integration.test.ts' -print0 | xargs -0 bun test --timeout=10000 || echo 'No integration tests found'",
3405
+ publint: "publint"
3361
3406
  },
3362
3407
  keywords: [],
3363
3408
  author: "Carl Lee <carllee0520@gmail.com>",
@@ -3755,6 +3800,250 @@ class BunWebSocketHandler {
3755
3800
  }
3756
3801
  }
3757
3802
 
3803
+ // src/adapters/bun/FastPathRegistry.ts
3804
+ class FastPathRegistry {
3805
+ routes = new Map;
3806
+ register(method, path2, handler) {
3807
+ const upperMethod = method.toUpperCase();
3808
+ let methodRoutes = this.routes.get(upperMethod);
3809
+ if (!methodRoutes) {
3810
+ methodRoutes = new Map;
3811
+ this.routes.set(upperMethod, methodRoutes);
3812
+ }
3813
+ methodRoutes.set(path2, handler);
3814
+ }
3815
+ match(method, path2) {
3816
+ const methodRoutes = this.routes.get(method.toUpperCase());
3817
+ if (!methodRoutes) {
3818
+ return;
3819
+ }
3820
+ return methodRoutes.get(path2);
3821
+ }
3822
+ getAll() {
3823
+ return this.routes;
3824
+ }
3825
+ }
3826
+
3827
+ // src/exceptions/GravitoException.ts
3828
+ class GravitoException extends Error {
3829
+ status;
3830
+ code;
3831
+ i18nKey;
3832
+ i18nParams;
3833
+ constructor(status, code, options2 = {}) {
3834
+ super(options2.message);
3835
+ this.name = "GravitoException";
3836
+ this.status = status;
3837
+ this.cause = options2.cause;
3838
+ this.code = code;
3839
+ if (options2.i18nKey) {
3840
+ this.i18nKey = options2.i18nKey;
3841
+ }
3842
+ if (options2.i18nParams) {
3843
+ this.i18nParams = options2.i18nParams;
3844
+ }
3845
+ Object.setPrototypeOf(this, new.target.prototype);
3846
+ }
3847
+ getLocalizedMessage(t) {
3848
+ if (this.i18nKey) {
3849
+ return t(this.i18nKey, this.i18nParams);
3850
+ }
3851
+ return this.message;
3852
+ }
3853
+ }
3854
+
3855
+ // src/exceptions/DomainException.ts
3856
+ class DomainException extends GravitoException {
3857
+ constructor(status, code, options2 = {}) {
3858
+ super(status, code, options2);
3859
+ this.name = "DomainException";
3860
+ Object.setPrototypeOf(this, new.target.prototype);
3861
+ }
3862
+ }
3863
+
3864
+ // src/exceptions/AuthException.ts
3865
+ class AuthException extends DomainException {
3866
+ constructor(status, code, options2 = {}) {
3867
+ super(status, code, options2);
3868
+ this.name = "AuthException";
3869
+ Object.setPrototypeOf(this, new.target.prototype);
3870
+ }
3871
+ }
3872
+
3873
+ // src/exceptions/AuthenticationException.ts
3874
+ class AuthenticationException extends DomainException {
3875
+ constructor(message = "Unauthenticated.") {
3876
+ super(401, "UNAUTHENTICATED", {
3877
+ message,
3878
+ i18nKey: "errors.authentication.unauthenticated"
3879
+ });
3880
+ this.name = "AuthenticationException";
3881
+ }
3882
+ }
3883
+
3884
+ // src/exceptions/AuthorizationException.ts
3885
+ class AuthorizationException extends DomainException {
3886
+ constructor(message = "This action is unauthorized.") {
3887
+ super(403, "FORBIDDEN", {
3888
+ message,
3889
+ i18nKey: "errors.authorization.forbidden"
3890
+ });
3891
+ this.name = "AuthorizationException";
3892
+ }
3893
+ }
3894
+
3895
+ // src/exceptions/InfrastructureException.ts
3896
+ class InfrastructureException extends GravitoException {
3897
+ retryable;
3898
+ constructor(status, code, options2 = {}) {
3899
+ super(status, code, options2);
3900
+ this.name = "InfrastructureException";
3901
+ this.retryable = options2.retryable ?? false;
3902
+ Object.setPrototypeOf(this, new.target.prototype);
3903
+ }
3904
+ }
3905
+
3906
+ // src/exceptions/CacheException.ts
3907
+ class CacheException extends InfrastructureException {
3908
+ constructor(status, code, options2 = {}) {
3909
+ super(status, code, options2);
3910
+ this.name = "CacheException";
3911
+ Object.setPrototypeOf(this, new.target.prototype);
3912
+ }
3913
+ }
3914
+
3915
+ // src/exceptions/SystemException.ts
3916
+ class SystemException extends GravitoException {
3917
+ constructor(status, code, options2 = {}) {
3918
+ super(status, code, options2);
3919
+ this.name = "SystemException";
3920
+ Object.setPrototypeOf(this, new.target.prototype);
3921
+ }
3922
+ }
3923
+
3924
+ // src/exceptions/CircularDependencyException.ts
3925
+ class CircularDependencyException extends SystemException {
3926
+ constructor(key, stack) {
3927
+ const path2 = [...stack, key].map(String).join(" -> ");
3928
+ super(500, "system.circular_dependency", {
3929
+ message: `Circular dependency detected: ${path2}`
3930
+ });
3931
+ this.name = "CircularDependencyException";
3932
+ }
3933
+ }
3934
+
3935
+ // src/exceptions/ConfigurationException.ts
3936
+ class ConfigurationException extends SystemException {
3937
+ constructor(message, options2 = {}) {
3938
+ super(500, "system.configuration_error", { ...options2, message });
3939
+ this.name = "ConfigurationException";
3940
+ Object.setPrototypeOf(this, new.target.prototype);
3941
+ }
3942
+ }
3943
+
3944
+ // src/exceptions/ContainerBindingCollisionException.ts
3945
+ class ContainerBindingCollisionException extends SystemException {
3946
+ constructor(message, options2 = {}) {
3947
+ super(500, "system.container_binding_collision", { ...options2, message });
3948
+ this.name = "ContainerBindingCollisionException";
3949
+ Object.setPrototypeOf(this, new.target.prototype);
3950
+ }
3951
+ }
3952
+
3953
+ // src/exceptions/DatabaseException.ts
3954
+ class DatabaseException extends InfrastructureException {
3955
+ constructor(status, code, options2 = {}) {
3956
+ super(status, code, options2);
3957
+ this.name = "DatabaseException";
3958
+ Object.setPrototypeOf(this, new.target.prototype);
3959
+ }
3960
+ }
3961
+
3962
+ // src/exceptions/HttpException.ts
3963
+ class HttpException extends GravitoException {
3964
+ constructor(status, options2 = {}) {
3965
+ super(status, "HTTP_ERROR", options2);
3966
+ this.name = "HttpException";
3967
+ }
3968
+ }
3969
+
3970
+ // src/exceptions/MiddlewareDriftException.ts
3971
+ class MiddlewareDriftException extends SystemException {
3972
+ constructor(message, options2 = {}) {
3973
+ super(500, "system.middleware_drift", { ...options2, message });
3974
+ this.name = "MiddlewareDriftException";
3975
+ Object.setPrototypeOf(this, new.target.prototype);
3976
+ }
3977
+ }
3978
+
3979
+ // src/exceptions/ModelNotFoundException.ts
3980
+ class ModelNotFoundException extends GravitoException {
3981
+ model;
3982
+ id;
3983
+ constructor(model, id) {
3984
+ super(404, "NOT_FOUND", {
3985
+ message: `${model} not found.`,
3986
+ i18nKey: "errors.model.not_found",
3987
+ i18nParams: { model, id: String(id ?? "") }
3988
+ });
3989
+ this.name = "ModelNotFoundException";
3990
+ this.model = model;
3991
+ if (id !== undefined) {
3992
+ this.id = id;
3993
+ }
3994
+ }
3995
+ }
3996
+
3997
+ // src/exceptions/QueueException.ts
3998
+ class QueueException extends InfrastructureException {
3999
+ constructor(status, code, options2 = {}) {
4000
+ super(status, code, options2);
4001
+ this.name = "QueueException";
4002
+ Object.setPrototypeOf(this, new.target.prototype);
4003
+ }
4004
+ }
4005
+
4006
+ // src/exceptions/StorageException.ts
4007
+ class StorageException extends InfrastructureException {
4008
+ constructor(status, code, options2 = {}) {
4009
+ super(status, code, options2);
4010
+ this.name = "StorageException";
4011
+ Object.setPrototypeOf(this, new.target.prototype);
4012
+ }
4013
+ }
4014
+
4015
+ // src/exceptions/StreamException.ts
4016
+ class StreamException extends InfrastructureException {
4017
+ constructor(status, code, options2 = {}) {
4018
+ super(status, code, options2);
4019
+ this.name = "StreamException";
4020
+ Object.setPrototypeOf(this, new.target.prototype);
4021
+ }
4022
+ }
4023
+
4024
+ // src/exceptions/ValidationException.ts
4025
+ class ValidationException extends DomainException {
4026
+ errors;
4027
+ redirectTo;
4028
+ input;
4029
+ constructor(errors, message = "Validation failed") {
4030
+ super(422, "VALIDATION_ERROR", {
4031
+ message,
4032
+ i18nKey: "errors.validation.failed"
4033
+ });
4034
+ this.name = "ValidationException";
4035
+ this.errors = errors;
4036
+ }
4037
+ withRedirect(url) {
4038
+ this.redirectTo = url;
4039
+ return this;
4040
+ }
4041
+ withInput(input) {
4042
+ this.input = input;
4043
+ return this;
4044
+ }
4045
+ }
4046
+
3758
4047
  // src/adapters/bun/BunNativeAdapter.ts
3759
4048
  class BunNativeAdapter {
3760
4049
  name = "bun-native";
@@ -3762,7 +4051,9 @@ class BunNativeAdapter {
3762
4051
  get native() {
3763
4052
  return this;
3764
4053
  }
4054
+ isSnapshotLocked = false;
3765
4055
  router = new RadixRouter;
4056
+ fastPathRegistry = new FastPathRegistry;
3766
4057
  middlewares = [];
3767
4058
  errorHandler = null;
3768
4059
  notFoundHandler = null;
@@ -3770,22 +4061,41 @@ class BunNativeAdapter {
3770
4061
  maxPoolSize = 100;
3771
4062
  middlewareChainCache = new Map;
3772
4063
  wsHandler = new BunWebSocketHandler;
4064
+ checkLock() {
4065
+ if (this.isSnapshotLocked && true) {
4066
+ throw new MiddlewareDriftException("FAST_PATH_MIDDLEWARE_DRIFT: Middleware or routes cannot be added after serveConfig() has been called. " + "This ensures the snapshotted configuration remains consistent with the application state.");
4067
+ }
4068
+ }
3773
4069
  route(method, path2, ...handlers) {
3774
- this.router.add(method, path2, handlers);
4070
+ this.checkLock();
4071
+ const last = handlers[handlers.length - 1];
4072
+ let options2;
4073
+ if (last && typeof last === "object" && !Array.isArray(last) && "excludeMiddleware" in last) {
4074
+ options2 = handlers.pop();
4075
+ }
4076
+ this.router.add(method, path2, handlers, options2);
3775
4077
  }
3776
4078
  routes(routes) {
4079
+ this.checkLock();
3777
4080
  for (const route of routes) {
3778
- this.route(route.method, route.path, ...route.handlers);
4081
+ const options2 = {};
4082
+ if (route.excludeMiddleware) {
4083
+ options2.excludeMiddleware = route.excludeMiddleware;
4084
+ }
4085
+ this.router.add(route.method, route.path, route.handlers, Object.keys(options2).length > 0 ? options2 : undefined);
3779
4086
  }
3780
4087
  }
3781
4088
  use(path2, ...middleware) {
4089
+ this.checkLock();
3782
4090
  this.middlewares.push({ path: path2, handlers: middleware });
3783
4091
  this.middlewareChainCache.clear();
3784
4092
  }
3785
4093
  useGlobal(...middleware) {
4094
+ this.checkLock();
3786
4095
  this.use("*", ...middleware);
3787
4096
  }
3788
4097
  useScoped(scope, path2, ...middleware) {
4098
+ this.checkLock();
3789
4099
  if (path2 === "*" || path2 === "*/*") {
3790
4100
  throw new Error(`useScoped(): Cannot use wildcard path '*' in Orbit-scoped middleware. ` + `Use regular use('*') for global middleware, or specify explicit paths like '${scope}/*'`);
3791
4101
  }
@@ -3800,6 +4110,9 @@ class BunNativeAdapter {
3800
4110
  if (pattern === "*") {
3801
4111
  return true;
3802
4112
  }
4113
+ if (pattern === "/") {
4114
+ return true;
4115
+ }
3803
4116
  if (pattern.endsWith("/*")) {
3804
4117
  const basePattern = pattern.slice(0, -2);
3805
4118
  return path2 === basePattern || path2.startsWith(`${basePattern}/`);
@@ -3810,17 +4123,25 @@ class BunNativeAdapter {
3810
4123
  }
3811
4124
  return path2 === pattern || path2.startsWith(`${pattern}/`);
3812
4125
  }
3813
- getCompiledMiddlewareChain(path2) {
3814
- if (this.middlewareChainCache.has(path2)) {
3815
- return this.middlewareChainCache.get(path2);
4126
+ getCompiledMiddlewareChain(path2, options2) {
4127
+ const exclude = options2?.excludeMiddleware || [];
4128
+ const cacheKey = exclude.length > 0 ? `${path2}:exclude:${exclude.sort().join(",")}` : path2;
4129
+ if (this.middlewareChainCache.has(cacheKey)) {
4130
+ return this.middlewareChainCache.get(cacheKey);
3816
4131
  }
3817
4132
  const chain = [];
3818
4133
  for (const mw of this.middlewares) {
3819
4134
  if (this.matchesPath(mw.path, path2)) {
3820
- chain.push(...mw.handlers);
4135
+ for (const handler of mw.handlers) {
4136
+ const name = handler.name || handler.middlewareName;
4137
+ if (name && exclude.includes(name)) {
4138
+ continue;
4139
+ }
4140
+ chain.push(handler);
4141
+ }
3821
4142
  }
3822
4143
  }
3823
- this.middlewareChainCache.set(path2, chain);
4144
+ this.middlewareChainCache.set(cacheKey, chain);
3824
4145
  return chain;
3825
4146
  }
3826
4147
  acquireContext(request) {
@@ -3862,12 +4183,36 @@ class BunNativeAdapter {
3862
4183
  return BunContext.create(request);
3863
4184
  }
3864
4185
  onError(handler) {
4186
+ this.checkLock();
3865
4187
  this.errorHandler = handler;
3866
4188
  }
3867
4189
  onNotFound(handler) {
4190
+ this.checkLock();
3868
4191
  this.notFoundHandler = handler;
3869
4192
  }
4193
+ registerFastPath(method, path2, handler) {
4194
+ this.checkLock();
4195
+ this.fastPathRegistry.register(method, path2, handler);
4196
+ }
4197
+ serveConfig(baseConfig = {}) {
4198
+ this.isSnapshotLocked = true;
4199
+ const routes = {};
4200
+ for (const [method, pathMap] of this.fastPathRegistry.getAll()) {
4201
+ if (method === "GET") {
4202
+ for (const [path2, handler] of pathMap) {
4203
+ routes[path2] = handler;
4204
+ }
4205
+ }
4206
+ }
4207
+ return {
4208
+ ...baseConfig,
4209
+ routes,
4210
+ fetch: this.fetch.bind(this),
4211
+ websocket: this.websocket
4212
+ };
4213
+ }
3870
4214
  registerWebSocketRoute(path2, handlers) {
4215
+ this.checkLock();
3871
4216
  this.wsHandler.register(path2, handlers);
3872
4217
  }
3873
4218
  get websocket() {
@@ -3882,7 +4227,12 @@ class BunNativeAdapter {
3882
4227
  }
3883
4228
  async fetch(request, _server) {
3884
4229
  const url = new URL(request.url);
3885
- if (_server != null && typeof _server.upgrade === "function" && request.headers.get("upgrade")?.toLowerCase() === "websocket" && this.wsHandler.hasRoute(url.pathname)) {
4230
+ const path2 = url.pathname;
4231
+ const fastHandler = this.fastPathRegistry.match(request.method, path2);
4232
+ if (fastHandler) {
4233
+ return fastHandler(request);
4234
+ }
4235
+ if (_server != null && typeof _server.upgrade === "function" && request.headers.get("upgrade")?.toLowerCase() === "websocket" && this.wsHandler.hasRoute(path2)) {
3886
4236
  const upgraded = _server.upgrade(request, {
3887
4237
  data: {
3888
4238
  path: url.pathname,
@@ -3896,11 +4246,10 @@ class BunNativeAdapter {
3896
4246
  }
3897
4247
  const ctx = this.acquireContext(request);
3898
4248
  try {
3899
- const path2 = url.pathname;
3900
4249
  const method = request.method;
3901
4250
  const match = this.router.match(method, path2);
3902
4251
  const handlers = [];
3903
- const middlewareChain = this.getCompiledMiddlewareChain(path2);
4252
+ const middlewareChain = this.getCompiledMiddlewareChain(path2, match?.options);
3904
4253
  handlers.push(...middlewareChain);
3905
4254
  if (match) {
3906
4255
  if (match.params) {
@@ -4608,7 +4957,8 @@ function createNodeAdapter() {
4608
4957
  },
4609
4958
  resourceUsage: async () => {
4610
4959
  try {
4611
- const usage = child.resourceUsage?.();
4960
+ const childWithUsage = child;
4961
+ const usage = childWithUsage.resourceUsage?.();
4612
4962
  if (!usage) {
4613
4963
  return;
4614
4964
  }
@@ -4817,6 +5167,78 @@ function createUnknownAdapter() {
4817
5167
  }
4818
5168
  };
4819
5169
  }
5170
+ // src/runtime/NativeOrbitDetector.ts
5171
+ function probeCryptoHasher(CryptoHasherCtor, algo) {
5172
+ try {
5173
+ const ctor = CryptoHasherCtor;
5174
+ new ctor(algo).update("").digest("hex");
5175
+ return true;
5176
+ } catch {
5177
+ return false;
5178
+ }
5179
+ }
5180
+
5181
+ class NativeOrbitDetector {
5182
+ static cached = null;
5183
+ static detectBunCapabilities() {
5184
+ if (this.cached !== null) {
5185
+ return this.cached;
5186
+ }
5187
+ const kind2 = getRuntimeKind();
5188
+ const B2 = globalThis.Bun;
5189
+ if (kind2 !== "bun" || !B2) {
5190
+ this.cached = Object.freeze({
5191
+ runtime: kind2,
5192
+ bunVersion: null,
5193
+ password: Object.freeze({ available: false, argon2id: false, bcrypt: false }),
5194
+ cryptoHasher: Object.freeze({
5195
+ available: false,
5196
+ sha256: false,
5197
+ sha512: false,
5198
+ blake2b: false
5199
+ }),
5200
+ glob: false
5201
+ });
5202
+ return this.cached;
5203
+ }
5204
+ const hasPassword = typeof B2.password?.hash === "function" && typeof B2.password?.verify === "function";
5205
+ const passwordFeatures = Object.freeze({
5206
+ available: hasPassword,
5207
+ argon2id: hasPassword,
5208
+ bcrypt: hasPassword
5209
+ });
5210
+ const HasherCtor = B2.CryptoHasher;
5211
+ const hasHasher = typeof HasherCtor === "function";
5212
+ const sha256 = hasHasher ? probeCryptoHasher(HasherCtor, "sha256") : false;
5213
+ const sha512 = hasHasher ? probeCryptoHasher(HasherCtor, "sha512") : false;
5214
+ const blake2b = hasHasher ? probeCryptoHasher(HasherCtor, "blake2b256") : false;
5215
+ const cryptoHasherFeatures = Object.freeze({
5216
+ available: hasHasher && sha256,
5217
+ sha256,
5218
+ sha512,
5219
+ blake2b
5220
+ });
5221
+ const hasGlob = typeof B2.Glob === "function";
5222
+ this.cached = Object.freeze({
5223
+ runtime: kind2,
5224
+ bunVersion: B2.version ?? null,
5225
+ password: passwordFeatures,
5226
+ cryptoHasher: cryptoHasherFeatures,
5227
+ glob: hasGlob
5228
+ });
5229
+ return this.cached;
5230
+ }
5231
+ static reset() {
5232
+ this.cached = null;
5233
+ }
5234
+ }
5235
+ function formatCapabilityReport(f) {
5236
+ const passwordPart = f.password.argon2id ? "Bun.password argon2id \u2713" : "Bun.password argon2id \u2717 (fallback: none)";
5237
+ const hasherPart = f.cryptoHasher.available ? "Bun.CryptoHasher \u2713" : "Bun.CryptoHasher \u2717 (fallback: node:crypto)";
5238
+ const globPart = f.glob ? "Bun.Glob \u2713" : "Bun.Glob \u2717 (fallback: node:fs glob)";
5239
+ return `[gravito] native: ${passwordPart}, ${hasherPart}, ${globPart}`;
5240
+ }
5241
+
4820
5242
  // src/runtime/archive.ts
4821
5243
  function createBunArchiveAdapter() {
4822
5244
  return {
@@ -4956,6 +5378,9 @@ async function archiveFromDirectory(dirPath, archivePath, options = {}) {
4956
5378
  let entries = {};
4957
5379
  if (kind === "bun") {
4958
5380
  const B = globalThis.Bun;
5381
+ if (!B?.Glob || !B.file) {
5382
+ throw new Error("[RuntimeArchiveAdapter] Bun global not available for directory scanning");
5383
+ }
4959
5384
  const glob = new B.Glob(options.glob ?? "**/*");
4960
5385
  for await (const file of glob.scan(dirPath)) {
4961
5386
  const pathMod = await eval('import("node:path")');
@@ -5569,6 +5994,9 @@ function getPasswordAdapter() {
5569
5994
  };
5570
5995
  return passwordAdapter;
5571
5996
  }
5997
+ function resetPasswordAdapter() {
5998
+ passwordAdapter = null;
5999
+ }
5572
6000
  async function createSqliteDatabase(path2) {
5573
6001
  const kind2 = getRuntimeKind();
5574
6002
  const B2 = globalThis.Bun;
@@ -5670,15 +6098,6 @@ class ConfigManager {
5670
6098
  }
5671
6099
  }
5672
6100
 
5673
- // src/exceptions/CircularDependencyException.ts
5674
- class CircularDependencyException extends Error {
5675
- constructor(key, stack) {
5676
- const path2 = [...stack, key].map(String).join(" -> ");
5677
- super(`Circular dependency detected: ${path2}`);
5678
- this.name = "CircularDependencyException";
5679
- }
5680
- }
5681
-
5682
6101
  // src/Container.ts
5683
6102
  var scopeStorage = new AsyncLocalStorage;
5684
6103
 
@@ -5703,6 +6122,17 @@ class Container {
5703
6122
  scope: "singleton"
5704
6123
  });
5705
6124
  }
6125
+ singletonInline(namespace, key, factory) {
6126
+ const namespacedKey = `inline:${namespace}:${key}`;
6127
+ if (this.has(namespacedKey)) {
6128
+ if (true) {
6129
+ throw new ContainerBindingCollisionException(`Binding '${namespacedKey}' already registered by plugin '${namespace}'`);
6130
+ }
6131
+ console.warn(`[gravito] Binding '${namespacedKey}' collision detected \u2014 skipping duplicate registration.`);
6132
+ return;
6133
+ }
6134
+ this.singleton(namespacedKey, factory);
6135
+ }
5706
6136
  scoped(key, factory) {
5707
6137
  this.bindings.set(key, {
5708
6138
  factory,
@@ -5840,63 +6270,6 @@ function detectRequestScopeLeaks(context) {
5840
6270
  };
5841
6271
  }
5842
6272
 
5843
- // src/exceptions/GravitoException.ts
5844
- class GravitoException extends Error {
5845
- status;
5846
- code;
5847
- i18nKey;
5848
- i18nParams;
5849
- constructor(status, code, options2 = {}) {
5850
- super(options2.message);
5851
- this.name = "GravitoException";
5852
- this.status = status;
5853
- this.cause = options2.cause;
5854
- this.code = code;
5855
- if (options2.i18nKey) {
5856
- this.i18nKey = options2.i18nKey;
5857
- }
5858
- if (options2.i18nParams) {
5859
- this.i18nParams = options2.i18nParams;
5860
- }
5861
- }
5862
- getLocalizedMessage(t) {
5863
- if (this.i18nKey) {
5864
- return t(this.i18nKey, this.i18nParams);
5865
- }
5866
- return this.message;
5867
- }
5868
- }
5869
-
5870
- // src/exceptions/HttpException.ts
5871
- class HttpException extends GravitoException {
5872
- constructor(status, options2 = {}) {
5873
- super(status, "HTTP_ERROR", options2);
5874
- this.name = "HttpException";
5875
- }
5876
- }
5877
-
5878
- // src/exceptions/ValidationException.ts
5879
- class ValidationException extends GravitoException {
5880
- errors;
5881
- redirectTo;
5882
- input;
5883
- constructor(errors, message = "Validation failed") {
5884
- super(422, "VALIDATION_ERROR", {
5885
- message,
5886
- i18nKey: "errors.validation.failed"
5887
- });
5888
- this.errors = errors;
5889
- }
5890
- withRedirect(url) {
5891
- this.redirectTo = url;
5892
- return this;
5893
- }
5894
- withInput(input) {
5895
- this.input = input;
5896
- return this;
5897
- }
5898
- }
5899
-
5900
6273
  // src/helpers/response.ts
5901
6274
  function ok(data) {
5902
6275
  return { success: true, data };
@@ -9322,59 +9695,60 @@ class EventMetrics {
9322
9695
  circuitBreakerSuccessesCounter;
9323
9696
  circuitBreakerOpenDurationHistogram;
9324
9697
  constructor(registry, prefix = "gravito_event_") {
9325
- this.dispatchLatency = registry.histogram({
9698
+ const reg = registry;
9699
+ this.dispatchLatency = reg.histogram({
9326
9700
  name: `${prefix}dispatch_latency_seconds`,
9327
9701
  help: "Event dispatch latency in seconds",
9328
9702
  labels: ["event_name", "priority"],
9329
9703
  buckets: [0.001, 0.005, 0.01, 0.05, 0.1, 0.5, 1, 2, 5]
9330
9704
  });
9331
- this.listenerExecutionTime = registry.histogram({
9705
+ this.listenerExecutionTime = reg.histogram({
9332
9706
  name: `${prefix}listener_execution_seconds`,
9333
9707
  help: "Listener execution time in seconds",
9334
9708
  labels: ["event_name", "listener_index"],
9335
9709
  buckets: [0.001, 0.005, 0.01, 0.05, 0.1, 0.5, 1, 2, 5]
9336
9710
  });
9337
- this.queueDepthGauge = registry.gauge({
9711
+ this.queueDepthGauge = reg.gauge({
9338
9712
  name: `${prefix}queue_depth`,
9339
9713
  help: "Current queue depth by priority",
9340
9714
  labels: ["priority"]
9341
9715
  });
9342
- this.failureCounter = registry.counter({
9716
+ this.failureCounter = reg.counter({
9343
9717
  name: `${prefix}failures_total`,
9344
9718
  help: "Total number of failed event processing",
9345
9719
  labels: ["event_name", "error_type"]
9346
9720
  });
9347
- this.timeoutCounter = registry.counter({
9721
+ this.timeoutCounter = reg.counter({
9348
9722
  name: `${prefix}timeouts_total`,
9349
9723
  help: "Total number of event processing timeouts",
9350
9724
  labels: ["event_name"]
9351
9725
  });
9352
- this.processedCounter = registry.counter({
9726
+ this.processedCounter = reg.counter({
9353
9727
  name: `${prefix}processed_total`,
9354
9728
  help: "Total number of processed events",
9355
9729
  labels: ["event_name", "status"]
9356
9730
  });
9357
- this.circuitBreakerStateGauge = registry.gauge({
9731
+ this.circuitBreakerStateGauge = reg.gauge({
9358
9732
  name: `${prefix}circuit_breaker_state`,
9359
9733
  help: "Current circuit breaker state (0=CLOSED, 1=HALF_OPEN, 2=OPEN)",
9360
9734
  labels: ["event_name"]
9361
9735
  });
9362
- this.circuitBreakerTransitionsCounter = registry.counter({
9736
+ this.circuitBreakerTransitionsCounter = reg.counter({
9363
9737
  name: `${prefix}circuit_breaker_transitions_total`,
9364
9738
  help: "Total number of circuit breaker state transitions",
9365
9739
  labels: ["event_name", "from_state", "to_state"]
9366
9740
  });
9367
- this.circuitBreakerFailuresCounter = registry.counter({
9741
+ this.circuitBreakerFailuresCounter = reg.counter({
9368
9742
  name: `${prefix}circuit_breaker_failures_total`,
9369
9743
  help: "Total number of failures tracked by circuit breaker",
9370
9744
  labels: ["event_name"]
9371
9745
  });
9372
- this.circuitBreakerSuccessesCounter = registry.counter({
9746
+ this.circuitBreakerSuccessesCounter = reg.counter({
9373
9747
  name: `${prefix}circuit_breaker_successes_total`,
9374
9748
  help: "Total number of successes tracked by circuit breaker",
9375
9749
  labels: ["event_name"]
9376
9750
  });
9377
- this.circuitBreakerOpenDurationHistogram = registry.histogram({
9751
+ this.circuitBreakerOpenDurationHistogram = reg.histogram({
9378
9752
  name: `${prefix}circuit_breaker_open_duration_seconds`,
9379
9753
  help: "Duration of circuit breaker OPEN state in seconds",
9380
9754
  labels: ["event_name"],
@@ -9767,7 +10141,7 @@ class ObservableHookManager extends HookManager {
9767
10141
  let span;
9768
10142
  if (this.eventTracing) {
9769
10143
  span = this.eventTracing.startDispatchSpan(hook, callbacks.length, "normal");
9770
- span.setAttributes({ "event.dispatch_mode": "sync" });
10144
+ span?.setAttributes({ "event.dispatch_mode": "sync" });
9771
10145
  } else if (this.eventTracer) {
9772
10146
  span = this.eventTracer.startDispatchSpan(hook, callbacks.length, "normal");
9773
10147
  }
@@ -9912,18 +10286,18 @@ class OTelEventMetrics {
9912
10286
  });
9913
10287
  }
9914
10288
  });
9915
- this.cbFailuresCounter = meter2.createCounter ? meter2.createCounter(`${prefix}circuit_breaker_failures_total`, {
10289
+ this.cbFailuresCounter = meter2.createCounter(`${prefix}circuit_breaker_failures_total`, {
9916
10290
  description: "Total number of failures recorded by circuit breakers",
9917
10291
  unit: "{failures}"
9918
- }) : { add: () => {} };
9919
- this.cbSuccessesCounter = meter2.createCounter ? meter2.createCounter(`${prefix}circuit_breaker_successes_total`, {
10292
+ });
10293
+ this.cbSuccessesCounter = meter2.createCounter(`${prefix}circuit_breaker_successes_total`, {
9920
10294
  description: "Total number of successes recorded by circuit breakers",
9921
10295
  unit: "{successes}"
9922
- }) : { add: () => {} };
9923
- this.cbTransitionsCounter = meter2.createCounter ? meter2.createCounter(`${prefix}circuit_breaker_transitions_total`, {
10296
+ });
10297
+ this.cbTransitionsCounter = meter2.createCounter(`${prefix}circuit_breaker_transitions_total`, {
9924
10298
  description: "Total number of state transitions in circuit breakers",
9925
10299
  unit: "{transitions}"
9926
- }) : { add: () => {} };
10300
+ });
9927
10301
  this.cbOpenDurationHistogram = meter2.createHistogram(`${prefix}circuit_breaker_open_duration_seconds`, {
9928
10302
  description: "Duration that circuit breakers remain in OPEN state",
9929
10303
  unit: "s",
@@ -9931,10 +10305,10 @@ class OTelEventMetrics {
9931
10305
  explicitBucketBoundaries: this.cbOpenDurationBuckets
9932
10306
  }
9933
10307
  });
9934
- this.backpressureRejectionsCounter = meter2.createCounter ? meter2.createCounter(`${prefix}backpressure_rejections_total`, {
10308
+ this.backpressureRejectionsCounter = meter2.createCounter(`${prefix}backpressure_rejections_total`, {
9935
10309
  description: "Total number of events rejected due to backpressure",
9936
10310
  unit: "{rejections}"
9937
- }) : { add: () => {} };
10311
+ });
9938
10312
  this.backpressureStateGauge = meter2.createObservableGauge(`${prefix}backpressure_state`, {
9939
10313
  description: "Current backpressure state (0=NORMAL, 1=WARNING, 2=CRITICAL, 3=OVERFLOW)",
9940
10314
  unit: "{state}"
@@ -9948,14 +10322,14 @@ class OTelEventMetrics {
9948
10322
  };
9949
10323
  observableResult.observe(stateMap[this.backpressureStateValue] ?? 0);
9950
10324
  });
9951
- this.backpressureDegradationsCounter = meter2.createCounter ? meter2.createCounter(`${prefix}backpressure_degradations_total`, {
10325
+ this.backpressureDegradationsCounter = meter2.createCounter(`${prefix}backpressure_degradations_total`, {
9952
10326
  description: "Total number of priority degradations due to backpressure",
9953
10327
  unit: "{degradations}"
9954
- }) : { add: () => {} };
9955
- this.dlqEntriesCounter = meter2.createCounter ? meter2.createCounter(`${prefix}dlq_entries_total`, {
10328
+ });
10329
+ this.dlqEntriesCounter = meter2.createCounter(`${prefix}dlq_entries_total`, {
9956
10330
  description: "Total number of events added to Dead Letter Queue",
9957
10331
  unit: "{entries}"
9958
- }) : { add: () => {} };
10332
+ });
9959
10333
  this.dlqDepthGauge = meter2.createObservableGauge(`${prefix}dlq_depth`, {
9960
10334
  description: "Current Dead Letter Queue depth",
9961
10335
  unit: "{events}"
@@ -9965,18 +10339,18 @@ class OTelEventMetrics {
9965
10339
  observableResult.observe(this.dlqDepthCallback());
9966
10340
  }
9967
10341
  });
9968
- this.dlqRequeueCounter = meter2.createCounter ? meter2.createCounter(`${prefix}dlq_requeue_total`, {
10342
+ this.dlqRequeueCounter = meter2.createCounter(`${prefix}dlq_requeue_total`, {
9969
10343
  description: "Total number of DLQ requeue attempts",
9970
10344
  unit: "{attempts}"
9971
- }) : { add: () => {} };
9972
- this.retryAttemptsCounter = meter2.createCounter ? meter2.createCounter(`${prefix}retry_attempts_total`, {
10345
+ });
10346
+ this.retryAttemptsCounter = meter2.createCounter(`${prefix}retry_attempts_total`, {
9973
10347
  description: "Total number of event retry attempts",
9974
10348
  unit: "{attempts}"
9975
- }) : { add: () => {} };
9976
- this.priorityEscalationCounter = meter2.createCounter ? meter2.createCounter(`${prefix}priority_escalation_total`, {
10349
+ });
10350
+ this.priorityEscalationCounter = meter2.createCounter(`${prefix}priority_escalation_total`, {
9977
10351
  description: "Total number of priority escalations",
9978
10352
  unit: "{escalations}"
9979
- }) : { add: () => {} };
10353
+ });
9980
10354
  }
9981
10355
  recordDispatchDuration(eventName, priority, durationSeconds) {
9982
10356
  this.dispatchDurationHistogram.record(durationSeconds, {
@@ -10911,23 +11285,6 @@ class CookieJar {
10911
11285
  }
10912
11286
  }
10913
11287
 
10914
- // src/exceptions/ModelNotFoundException.ts
10915
- class ModelNotFoundException extends GravitoException {
10916
- model;
10917
- id;
10918
- constructor(model, id) {
10919
- super(404, "NOT_FOUND", {
10920
- message: `${model} not found.`,
10921
- i18nKey: "errors.model.not_found",
10922
- i18nParams: { model, id: String(id ?? "") }
10923
- });
10924
- this.model = model;
10925
- if (id !== undefined) {
10926
- this.id = id;
10927
- }
10928
- }
10929
- }
10930
-
10931
11288
  // src/Route.ts
10932
11289
  class Route {
10933
11290
  router;
@@ -10944,6 +11301,13 @@ class Route {
10944
11301
  this.router.registerName(name, this.method, this.path, this.options);
10945
11302
  return this;
10946
11303
  }
11304
+ schema(schemas) {
11305
+ this.options.schema = {
11306
+ ...this.options.schema || {},
11307
+ ...schemas
11308
+ };
11309
+ return this;
11310
+ }
10947
11311
  static get(path2, requestOrHandlerOrMiddleware, handler) {
10948
11312
  return router().req("get", path2, requestOrHandlerOrMiddleware, handler);
10949
11313
  }
@@ -11139,18 +11503,20 @@ class Router {
11139
11503
  const compiled = [];
11140
11504
  const nameMap = new Map;
11141
11505
  for (const [name, info] of this.namedRoutes) {
11142
- nameMap.set(`${info.method.toUpperCase()}:${info.path}`, name);
11506
+ nameMap.set(`${info.method.toUpperCase()}:${info.path}`, { name, options: info.options });
11143
11507
  }
11144
11508
  const compiledKeys = new Set;
11145
11509
  for (const route of this.routes) {
11146
11510
  const method = route.method.toUpperCase();
11147
11511
  const key = `${method}:${route.path}`;
11148
11512
  compiledKeys.add(key);
11513
+ const namedInfo = nameMap.get(key);
11149
11514
  compiled.push({
11150
11515
  method,
11151
11516
  path: route.path,
11152
11517
  domain: route.domain,
11153
- name: nameMap.get(key)
11518
+ name: namedInfo?.name,
11519
+ schema: route.options?.schema || namedInfo?.options?.schema
11154
11520
  });
11155
11521
  }
11156
11522
  for (const [name, info] of this.namedRoutes) {
@@ -11160,7 +11526,8 @@ class Router {
11160
11526
  name,
11161
11527
  method: info.method.toUpperCase(),
11162
11528
  path: info.path,
11163
- domain: info.domain
11529
+ domain: info.domain,
11530
+ schema: info.options?.schema
11164
11531
  });
11165
11532
  }
11166
11533
  }
@@ -11171,7 +11538,8 @@ class Router {
11171
11538
  this.namedRoutes.set(name, {
11172
11539
  method: method.toUpperCase(),
11173
11540
  path: fullPath,
11174
- domain: options2.domain
11541
+ domain: options2.domain,
11542
+ options: options2
11175
11543
  });
11176
11544
  }
11177
11545
  url(name, params = {}, query = {}) {
@@ -11211,7 +11579,7 @@ class Router {
11211
11579
  if (modelClass && typeof modelClass === "object" && "find" in modelClass && typeof modelClass.find === "function") {
11212
11580
  const instance = await modelClass.find(id);
11213
11581
  if (!instance) {
11214
- throw new Error("ModelNotFound");
11582
+ throw new ModelNotFoundException(param, String(id));
11215
11583
  }
11216
11584
  return instance;
11217
11585
  }
@@ -11233,17 +11601,9 @@ class Router {
11233
11601
  if (!resolver) {
11234
11602
  continue;
11235
11603
  }
11236
- try {
11237
- const resolved = await resolver(value2);
11238
- routeModels[param] = resolved;
11239
- hasResolvedModels = true;
11240
- } catch (err) {
11241
- const message = err instanceof Error ? err.message : undefined;
11242
- if (message === "ModelNotFound") {
11243
- throw new ModelNotFoundException(param, value2);
11244
- }
11245
- throw err;
11246
- }
11604
+ const resolved = await resolver(value2);
11605
+ routeModels[param] = resolved;
11606
+ hasResolvedModels = true;
11247
11607
  }
11248
11608
  if (hasResolvedModels) {
11249
11609
  c.set("routeModels", routeModels);
@@ -11307,7 +11667,6 @@ class Router {
11307
11667
  }
11308
11668
  req(method, path2, requestOrHandlerOrMiddleware, handler, options2 = {}) {
11309
11669
  const fullPath = (options2.prefix || "") + path2;
11310
- console.log(`[Router] Registering ${method.toUpperCase()} ${fullPath}`);
11311
11670
  let formRequestMiddleware = null;
11312
11671
  let routeMiddleware = [];
11313
11672
  let finalRouteHandler;
@@ -11349,11 +11708,16 @@ class Router {
11349
11708
  if (c.req.header("host") !== options2.domain) {
11350
11709
  return c.text("Not Found", 404);
11351
11710
  }
11352
- await next();
11711
+ return await next();
11353
11712
  };
11354
11713
  handlers.unshift(domainCheck);
11355
11714
  }
11356
- this.routes.push({ method: method.toUpperCase(), path: fullPath, domain: options2.domain });
11715
+ this.routes.push({
11716
+ method: method.toUpperCase(),
11717
+ path: fullPath,
11718
+ domain: options2.domain,
11719
+ options: options2
11720
+ });
11357
11721
  this.core.adapter.route(method, fullPath, ...handlers);
11358
11722
  return new Route(this, method, fullPath, options2);
11359
11723
  }
@@ -11471,14 +11835,16 @@ class PlanetCore {
11471
11835
  services = new Map;
11472
11836
  encrypter;
11473
11837
  hasher;
11838
+ installedOrbits = [];
11474
11839
  observabilityProvider;
11475
11840
  providers = [];
11476
11841
  deferredProviders = new Map;
11477
11842
  bootedProviders = new Set;
11478
11843
  isShuttingDown = false;
11844
+ static GLOBAL_SHUTDOWN_TIMEOUT = 1e4;
11479
11845
  async initializeObservabilityAsync(obsConfig) {
11480
11846
  try {
11481
- if (this.observabilityProvider && this.observabilityProvider !== this.observabilityProvider._isNoOp) {
11847
+ if (this.observabilityProvider && this.observabilityProvider._isNoOp !== true) {
11482
11848
  this.logger.info("[Observability] \u2705 Using observability provider from @gravito/monitor");
11483
11849
  if (obsConfig?.prometheus?.enabled !== false) {
11484
11850
  await this.initializePrometheusAsync(obsConfig);
@@ -11520,10 +11886,11 @@ class PlanetCore {
11520
11886
  this.logger.debug("[Observability] Prometheus setup moved to @gravito/monitor. Use monitor package for metrics initialization.");
11521
11887
  }
11522
11888
  register(provider) {
11523
- if (typeof provider.setCore === "function") {
11524
- provider.setCore(this);
11889
+ const providerRecord = provider;
11890
+ if (typeof providerRecord["setCore"] === "function") {
11891
+ providerRecord["setCore"](this);
11525
11892
  } else {
11526
- provider.core = this;
11893
+ providerRecord["core"] = this;
11527
11894
  }
11528
11895
  if (provider.deferred) {
11529
11896
  const services = provider.provides();
@@ -11577,15 +11944,23 @@ class PlanetCore {
11577
11944
  }
11578
11945
  this.isShuttingDown = true;
11579
11946
  this.logger.debug("\uD83D\uDED1 Application shutdown started");
11580
- for (const provider of [...this.providers].reverse()) {
11581
- if (provider.onShutdown) {
11582
- try {
11583
- this.logger.debug(` onShutdown: ${provider.constructor.name}`);
11584
- await provider.onShutdown(this);
11585
- } catch (error) {
11586
- this.logger.error(`Error during shutdown of ${provider.constructor.name}:`, error);
11947
+ const shutdownSequence = async () => {
11948
+ for (const provider of [...this.providers].reverse()) {
11949
+ if (provider.onShutdown) {
11950
+ try {
11951
+ this.logger.debug(` onShutdown: ${provider.constructor.name}`);
11952
+ await provider.onShutdown(this);
11953
+ } catch (error) {
11954
+ this.logger.error(`Error during shutdown of ${provider.constructor.name}:`, error);
11955
+ }
11587
11956
  }
11588
11957
  }
11958
+ };
11959
+ const globalDeadline = new Promise((_, reject) => setTimeout(() => reject(new Error("[PlanetCore] Global shutdown timeout exceeded (10s)")), PlanetCore.GLOBAL_SHUTDOWN_TIMEOUT));
11960
+ try {
11961
+ await Promise.race([shutdownSequence(), globalDeadline]);
11962
+ } catch (err) {
11963
+ this.logger.warn("[PlanetCore] Forced shutdown after global timeout:", err);
11589
11964
  }
11590
11965
  this.hooks.doAction("app:shutdown", this);
11591
11966
  this.logger.debug("\u2705 Application shutdown complete");
@@ -11686,8 +12061,38 @@ class PlanetCore {
11686
12061
  process.on("SIGTERM", () => handleSignal("SIGTERM"));
11687
12062
  process.on("SIGINT", () => handleSignal("SIGINT"));
11688
12063
  }
12064
+ async plugin(config3) {
12065
+ if (!config3.name) {
12066
+ throw new Error('plugin(): Lite Satellites require a "name" property to enable safe service namespacing. Consider naming it based on the feature (e.g., "ping", "health-check").');
12067
+ }
12068
+ const alreadyRegistered = this.installedOrbits.some((orbit) => orbit.name === config3.name);
12069
+ if (alreadyRegistered) {
12070
+ if (true) {
12071
+ throw new ContainerBindingCollisionException(`Lite Satellite name '${config3.name}' already registered`);
12072
+ }
12073
+ this.logger.warn(`[gravito] Lite Satellite '${config3.name}' already registered \u2014 skipping duplicate installation.`);
12074
+ return this;
12075
+ }
12076
+ this.logger.debug(`\uD83D\uDD0C Installing Lite Satellite: ${config3.name}`);
12077
+ this.installedOrbits.push({
12078
+ name: config3.name,
12079
+ dependencies: config3.dependencies || []
12080
+ });
12081
+ await config3.install(this);
12082
+ return this;
12083
+ }
11689
12084
  async orbit(orbit) {
11690
12085
  const instance = typeof orbit === "function" ? new orbit : orbit;
12086
+ const name = instance.name || instance.constructor.name;
12087
+ if (instance.name) {
12088
+ this.logger.debug(`\uD83D\uDEF0\uFE0F Installing Orbit: ${instance.name}`);
12089
+ } else {
12090
+ this.logger.debug(`\uD83D\uDEF0\uFE0F Installing Orbit: ${instance.constructor.name}`);
12091
+ }
12092
+ this.installedOrbits.push({
12093
+ name,
12094
+ dependencies: instance.dependencies || []
12095
+ });
11691
12096
  await instance.install(this);
11692
12097
  return this;
11693
12098
  }
@@ -11712,17 +12117,24 @@ class PlanetCore {
11712
12117
  ...config3.logger && { logger: config3.logger },
11713
12118
  ...config3.config && { config: config3.config },
11714
12119
  ...config3.adapter && { adapter: config3.adapter },
11715
- ...config3.container && { container: config3.container }
12120
+ ...config3.container && { container: config3.container },
12121
+ ...config3.observabilityProvider && { observabilityProvider: config3.observabilityProvider }
11716
12122
  });
12123
+ const features = NativeOrbitDetector.detectBunCapabilities();
12124
+ core.logger.info(formatCapabilityReport(features));
11717
12125
  if (config3.orbits) {
11718
12126
  for (const OrbitClassOrInstance of config3.orbits) {
11719
- let orbit;
11720
- if (typeof OrbitClassOrInstance === "function") {
11721
- orbit = new OrbitClassOrInstance;
12127
+ if (typeof OrbitClassOrInstance !== "function" && OrbitClassOrInstance.name) {
12128
+ await core.plugin(OrbitClassOrInstance);
11722
12129
  } else {
11723
- orbit = OrbitClassOrInstance;
12130
+ let orbit;
12131
+ if (typeof OrbitClassOrInstance === "function") {
12132
+ orbit = new OrbitClassOrInstance;
12133
+ } else {
12134
+ orbit = OrbitClassOrInstance;
12135
+ }
12136
+ await orbit.install(core);
11724
12137
  }
11725
- await orbit.install(core);
11726
12138
  }
11727
12139
  }
11728
12140
  return core;
@@ -12492,7 +12904,8 @@ class MessageQueueBridge {
12492
12904
  throw new Error(`[MessageQueueBridge] No listeners registered for event: ${eventName}`);
12493
12905
  }
12494
12906
  if (this.config.enableCircuitBreaker) {
12495
- const breaker = this.config.hookManager.getCircuitBreaker?.(eventName);
12907
+ const hm = this.config.hookManager;
12908
+ const breaker = hm.getCircuitBreaker?.(eventName);
12496
12909
  if (breaker?.getState?.() === "OPEN") {
12497
12910
  throw new Error(`[MessageQueueBridge] Circuit breaker is OPEN for event: ${eventName}`);
12498
12911
  }
@@ -12618,9 +13031,9 @@ class RetryScheduler {
12618
13031
  try {
12619
13032
  const queue = this.getOrCreateQueue(eventName);
12620
13033
  const delay = this.calculateDelay(retryCount);
12621
- const addMethod = queue.add;
12622
- if (typeof addMethod === "function") {
12623
- await addMethod.call(queue, "retry", { payload, error: error.message, retryCount }, { delay });
13034
+ const queueObj = queue;
13035
+ if (typeof queueObj.add === "function") {
13036
+ await queueObj.add.call(queue, "retry", { payload, error: error.message, retryCount }, { delay });
12624
13037
  }
12625
13038
  } catch (schedulerError) {
12626
13039
  const err = schedulerError instanceof Error ? schedulerError : new Error(String(schedulerError));
@@ -13189,25 +13602,6 @@ class QueueDashboard {
13189
13602
  return value2.replace(/\\/g, "\\\\").replace(/"/g, "\\\"").replace(/\n/g, "\\n");
13190
13603
  }
13191
13604
  }
13192
- // src/exceptions/AuthenticationException.ts
13193
- class AuthenticationException extends GravitoException {
13194
- constructor(message = "Unauthenticated.") {
13195
- super(401, "UNAUTHENTICATED", {
13196
- message,
13197
- i18nKey: "errors.authentication.unauthenticated"
13198
- });
13199
- }
13200
- }
13201
-
13202
- // src/exceptions/AuthorizationException.ts
13203
- class AuthorizationException extends GravitoException {
13204
- constructor(message = "This action is unauthorized.") {
13205
- super(403, "FORBIDDEN", {
13206
- message,
13207
- i18nKey: "errors.authorization.forbidden"
13208
- });
13209
- }
13210
- }
13211
13605
  // src/ServiceProvider.ts
13212
13606
  class ServiceProvider {
13213
13607
  core;
@@ -13431,15 +13825,19 @@ class TestResponse {
13431
13825
  async assertJsonStructure(structure) {
13432
13826
  const json = await this.getJson();
13433
13827
  const checkKeys = (data2, struct) => {
13434
- for (const key in struct) {
13435
- if (Array.isArray(struct[key])) {
13436
- expect(Array.isArray(data2[key])).toBe(true);
13437
- if (data2[key].length > 0) {
13438
- checkKeys(data2[key][0], struct[key][0]);
13828
+ const structObj = struct;
13829
+ const dataObj = data2;
13830
+ for (const key in structObj) {
13831
+ if (Array.isArray(structObj[key])) {
13832
+ expect(Array.isArray(dataObj[key])).toBe(true);
13833
+ const dataArr = dataObj[key];
13834
+ const structArr = structObj[key];
13835
+ if (dataArr.length > 0) {
13836
+ checkKeys(dataArr[0], structArr[0]);
13439
13837
  }
13440
- } else if (typeof struct[key] === "object") {
13441
- expect(typeof data2[key]).toBe("object");
13442
- checkKeys(data2[key], struct[key]);
13838
+ } else if (typeof structObj[key] === "object") {
13839
+ expect(typeof dataObj[key]).toBe("object");
13840
+ checkKeys(dataObj[key], structObj[key]);
13443
13841
  } else {
13444
13842
  expect(data2).toHaveProperty(key);
13445
13843
  }
@@ -13888,6 +14286,7 @@ export {
13888
14286
  runtimeAppendFile,
13889
14287
  router,
13890
14288
  resetRuntimeAdapter,
14289
+ resetPasswordAdapter,
13891
14290
  registerQueueCommands,
13892
14291
  registerGlobalErrorHandlers,
13893
14292
  old,
@@ -13912,6 +14311,7 @@ export {
13912
14311
  getCookie,
13913
14312
  getCompressionAdapter,
13914
14313
  getArchiveAdapter,
14314
+ formatCapabilityReport,
13915
14315
  filled,
13916
14316
  fail,
13917
14317
  extractRequestScopeErrorContext,
@@ -13945,7 +14345,10 @@ export {
13945
14345
  ValidationException,
13946
14346
  VERSION,
13947
14347
  TestResponse,
14348
+ SystemException,
14349
+ StreamException,
13948
14350
  Str,
14351
+ StorageException,
13949
14352
  StarvationProtectionStrategy,
13950
14353
  ServiceProvider,
13951
14354
  Router,
@@ -13961,6 +14364,7 @@ export {
13961
14364
  RateLimitStrategy,
13962
14365
  RadixRouter,
13963
14366
  RadixNode,
14367
+ QueueException,
13964
14368
  QueueDepthStrategy,
13965
14369
  QueueDashboard,
13966
14370
  PriorityRebalanceStrategy,
@@ -13969,7 +14373,9 @@ export {
13969
14373
  ObservableHookManager,
13970
14374
  OTelEventMetrics,
13971
14375
  NodeType,
14376
+ NativeOrbitDetector,
13972
14377
  ModelNotFoundException,
14378
+ InfrastructureException,
13973
14379
  IdempotencyCache,
13974
14380
  HttpTester,
13975
14381
  HttpException,
@@ -13988,18 +14394,22 @@ export {
13988
14394
  ErrorHandler,
13989
14395
  Encrypter,
13990
14396
  DumpDieError,
14397
+ DomainException,
13991
14398
  DeadLetterQueueManager,
13992
14399
  DeadLetterQueue,
14400
+ DatabaseException,
13993
14401
  DEFAULT_EVENT_OPTIONS,
13994
14402
  CookieJar,
13995
14403
  Container,
13996
14404
  ConsoleLogger,
14405
+ ConfigurationException,
13997
14406
  ConfigManager,
13998
14407
  CompositeStrategy,
13999
14408
  CommandKernel,
14000
14409
  CircularDependencyException,
14001
14410
  CircuitBreakerState,
14002
14411
  CircuitBreaker,
14412
+ CacheException,
14003
14413
  BunWebSocketHandler,
14004
14414
  BunRequest,
14005
14415
  BunNativeAdapter,
@@ -14009,8 +14419,9 @@ export {
14009
14419
  BackpressureManager,
14010
14420
  AuthorizationException,
14011
14421
  AuthenticationException,
14422
+ AuthException,
14012
14423
  Arr,
14013
14424
  Application
14014
14425
  };
14015
14426
 
14016
- //# debugId=B420456F9068F67364756E2164756E21
14427
+ //# debugId=AFB01087B997521264756E2164756E21