@gravito/core 3.0.0 → 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 (59) 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 +48 -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/MessageQueueBridge.d.ts +2 -1
  27. package/dist/events/observability/EventMetrics.d.ts +1 -2
  28. package/dist/events/observability/ObservableHookManager.d.ts +1 -1
  29. package/dist/exceptions/AuthException.d.ts +11 -2
  30. package/dist/exceptions/AuthenticationException.d.ts +7 -1
  31. package/dist/exceptions/ContainerBindingCollisionException.d.ts +10 -0
  32. package/dist/exceptions/MiddlewareDriftException.d.ts +10 -0
  33. package/dist/exceptions/index.d.ts +3 -1
  34. package/dist/ffi/NativeAccelerator.js.map +3 -3
  35. package/dist/ffi/NativeHasher.d.ts +14 -0
  36. package/dist/ffi/NativeHasher.js +24 -1
  37. package/dist/ffi/NativeHasher.js.map +4 -4
  38. package/dist/ffi/cbor-fallback.js.map +1 -1
  39. package/dist/ffi/hash-fallback.d.ts +15 -0
  40. package/dist/ffi/hash-fallback.js +12 -1
  41. package/dist/ffi/hash-fallback.js.map +3 -3
  42. package/dist/ffi/types.d.ts +13 -0
  43. package/dist/ffi/types.js.map +1 -1
  44. package/dist/hooks/types.d.ts +7 -3
  45. package/dist/http/types.d.ts +2 -2
  46. package/dist/index.browser.d.ts +5 -5
  47. package/dist/index.browser.js +138 -17
  48. package/dist/index.browser.js.map +44 -42
  49. package/dist/index.d.ts +17 -7
  50. package/dist/index.js +588 -295
  51. package/dist/index.js.map +81 -77
  52. package/dist/runtime/NativeOrbitDetector.d.ts +59 -0
  53. package/dist/runtime/index.browser.d.ts +1 -1
  54. package/dist/runtime/index.d.ts +7 -0
  55. package/dist/runtime.d.ts +1 -1
  56. package/dist/testing/HttpTester.d.ts +4 -4
  57. package/dist/testing/TestResponse.d.ts +4 -4
  58. package/dist/types.d.ts +3 -3
  59. 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: "3.0.0",
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
  }
@@ -4815,8 +5165,80 @@ function createUnknownAdapter() {
4815
5165
  serve() {
4816
5166
  throw new Error("[RuntimeAdapter] Unsupported runtime for serve()");
4817
5167
  }
4818
- };
5168
+ };
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
+ }
4819
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,54 +6098,6 @@ class ConfigManager {
5670
6098
  }
5671
6099
  }
5672
6100
 
5673
- // src/exceptions/GravitoException.ts
5674
- class GravitoException extends Error {
5675
- status;
5676
- code;
5677
- i18nKey;
5678
- i18nParams;
5679
- constructor(status, code, options2 = {}) {
5680
- super(options2.message);
5681
- this.name = "GravitoException";
5682
- this.status = status;
5683
- this.cause = options2.cause;
5684
- this.code = code;
5685
- if (options2.i18nKey) {
5686
- this.i18nKey = options2.i18nKey;
5687
- }
5688
- if (options2.i18nParams) {
5689
- this.i18nParams = options2.i18nParams;
5690
- }
5691
- Object.setPrototypeOf(this, new.target.prototype);
5692
- }
5693
- getLocalizedMessage(t) {
5694
- if (this.i18nKey) {
5695
- return t(this.i18nKey, this.i18nParams);
5696
- }
5697
- return this.message;
5698
- }
5699
- }
5700
-
5701
- // src/exceptions/SystemException.ts
5702
- class SystemException extends GravitoException {
5703
- constructor(status, code, options2 = {}) {
5704
- super(status, code, options2);
5705
- this.name = "SystemException";
5706
- Object.setPrototypeOf(this, new.target.prototype);
5707
- }
5708
- }
5709
-
5710
- // src/exceptions/CircularDependencyException.ts
5711
- class CircularDependencyException extends SystemException {
5712
- constructor(key, stack) {
5713
- const path2 = [...stack, key].map(String).join(" -> ");
5714
- super(500, "system.circular_dependency", {
5715
- message: `Circular dependency detected: ${path2}`
5716
- });
5717
- this.name = "CircularDependencyException";
5718
- }
5719
- }
5720
-
5721
6101
  // src/Container.ts
5722
6102
  var scopeStorage = new AsyncLocalStorage;
5723
6103
 
@@ -5742,6 +6122,17 @@ class Container {
5742
6122
  scope: "singleton"
5743
6123
  });
5744
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
+ }
5745
6136
  scoped(key, factory) {
5746
6137
  this.bindings.set(key, {
5747
6138
  factory,
@@ -5879,46 +6270,6 @@ function detectRequestScopeLeaks(context) {
5879
6270
  };
5880
6271
  }
5881
6272
 
5882
- // src/exceptions/HttpException.ts
5883
- class HttpException extends GravitoException {
5884
- constructor(status, options2 = {}) {
5885
- super(status, "HTTP_ERROR", options2);
5886
- this.name = "HttpException";
5887
- }
5888
- }
5889
-
5890
- // src/exceptions/DomainException.ts
5891
- class DomainException extends GravitoException {
5892
- constructor(status, code, options2 = {}) {
5893
- super(status, code, options2);
5894
- this.name = "DomainException";
5895
- Object.setPrototypeOf(this, new.target.prototype);
5896
- }
5897
- }
5898
-
5899
- // src/exceptions/ValidationException.ts
5900
- class ValidationException extends DomainException {
5901
- errors;
5902
- redirectTo;
5903
- input;
5904
- constructor(errors, message = "Validation failed") {
5905
- super(422, "VALIDATION_ERROR", {
5906
- message,
5907
- i18nKey: "errors.validation.failed"
5908
- });
5909
- this.name = "ValidationException";
5910
- this.errors = errors;
5911
- }
5912
- withRedirect(url) {
5913
- this.redirectTo = url;
5914
- return this;
5915
- }
5916
- withInput(input) {
5917
- this.input = input;
5918
- return this;
5919
- }
5920
- }
5921
-
5922
6273
  // src/helpers/response.ts
5923
6274
  function ok(data) {
5924
6275
  return { success: true, data };
@@ -9344,59 +9695,60 @@ class EventMetrics {
9344
9695
  circuitBreakerSuccessesCounter;
9345
9696
  circuitBreakerOpenDurationHistogram;
9346
9697
  constructor(registry, prefix = "gravito_event_") {
9347
- this.dispatchLatency = registry.histogram({
9698
+ const reg = registry;
9699
+ this.dispatchLatency = reg.histogram({
9348
9700
  name: `${prefix}dispatch_latency_seconds`,
9349
9701
  help: "Event dispatch latency in seconds",
9350
9702
  labels: ["event_name", "priority"],
9351
9703
  buckets: [0.001, 0.005, 0.01, 0.05, 0.1, 0.5, 1, 2, 5]
9352
9704
  });
9353
- this.listenerExecutionTime = registry.histogram({
9705
+ this.listenerExecutionTime = reg.histogram({
9354
9706
  name: `${prefix}listener_execution_seconds`,
9355
9707
  help: "Listener execution time in seconds",
9356
9708
  labels: ["event_name", "listener_index"],
9357
9709
  buckets: [0.001, 0.005, 0.01, 0.05, 0.1, 0.5, 1, 2, 5]
9358
9710
  });
9359
- this.queueDepthGauge = registry.gauge({
9711
+ this.queueDepthGauge = reg.gauge({
9360
9712
  name: `${prefix}queue_depth`,
9361
9713
  help: "Current queue depth by priority",
9362
9714
  labels: ["priority"]
9363
9715
  });
9364
- this.failureCounter = registry.counter({
9716
+ this.failureCounter = reg.counter({
9365
9717
  name: `${prefix}failures_total`,
9366
9718
  help: "Total number of failed event processing",
9367
9719
  labels: ["event_name", "error_type"]
9368
9720
  });
9369
- this.timeoutCounter = registry.counter({
9721
+ this.timeoutCounter = reg.counter({
9370
9722
  name: `${prefix}timeouts_total`,
9371
9723
  help: "Total number of event processing timeouts",
9372
9724
  labels: ["event_name"]
9373
9725
  });
9374
- this.processedCounter = registry.counter({
9726
+ this.processedCounter = reg.counter({
9375
9727
  name: `${prefix}processed_total`,
9376
9728
  help: "Total number of processed events",
9377
9729
  labels: ["event_name", "status"]
9378
9730
  });
9379
- this.circuitBreakerStateGauge = registry.gauge({
9731
+ this.circuitBreakerStateGauge = reg.gauge({
9380
9732
  name: `${prefix}circuit_breaker_state`,
9381
9733
  help: "Current circuit breaker state (0=CLOSED, 1=HALF_OPEN, 2=OPEN)",
9382
9734
  labels: ["event_name"]
9383
9735
  });
9384
- this.circuitBreakerTransitionsCounter = registry.counter({
9736
+ this.circuitBreakerTransitionsCounter = reg.counter({
9385
9737
  name: `${prefix}circuit_breaker_transitions_total`,
9386
9738
  help: "Total number of circuit breaker state transitions",
9387
9739
  labels: ["event_name", "from_state", "to_state"]
9388
9740
  });
9389
- this.circuitBreakerFailuresCounter = registry.counter({
9741
+ this.circuitBreakerFailuresCounter = reg.counter({
9390
9742
  name: `${prefix}circuit_breaker_failures_total`,
9391
9743
  help: "Total number of failures tracked by circuit breaker",
9392
9744
  labels: ["event_name"]
9393
9745
  });
9394
- this.circuitBreakerSuccessesCounter = registry.counter({
9746
+ this.circuitBreakerSuccessesCounter = reg.counter({
9395
9747
  name: `${prefix}circuit_breaker_successes_total`,
9396
9748
  help: "Total number of successes tracked by circuit breaker",
9397
9749
  labels: ["event_name"]
9398
9750
  });
9399
- this.circuitBreakerOpenDurationHistogram = registry.histogram({
9751
+ this.circuitBreakerOpenDurationHistogram = reg.histogram({
9400
9752
  name: `${prefix}circuit_breaker_open_duration_seconds`,
9401
9753
  help: "Duration of circuit breaker OPEN state in seconds",
9402
9754
  labels: ["event_name"],
@@ -9789,7 +10141,7 @@ class ObservableHookManager extends HookManager {
9789
10141
  let span;
9790
10142
  if (this.eventTracing) {
9791
10143
  span = this.eventTracing.startDispatchSpan(hook, callbacks.length, "normal");
9792
- span.setAttributes({ "event.dispatch_mode": "sync" });
10144
+ span?.setAttributes({ "event.dispatch_mode": "sync" });
9793
10145
  } else if (this.eventTracer) {
9794
10146
  span = this.eventTracer.startDispatchSpan(hook, callbacks.length, "normal");
9795
10147
  }
@@ -9934,18 +10286,18 @@ class OTelEventMetrics {
9934
10286
  });
9935
10287
  }
9936
10288
  });
9937
- this.cbFailuresCounter = meter2.createCounter ? meter2.createCounter(`${prefix}circuit_breaker_failures_total`, {
10289
+ this.cbFailuresCounter = meter2.createCounter(`${prefix}circuit_breaker_failures_total`, {
9938
10290
  description: "Total number of failures recorded by circuit breakers",
9939
10291
  unit: "{failures}"
9940
- }) : { add: () => {} };
9941
- this.cbSuccessesCounter = meter2.createCounter ? meter2.createCounter(`${prefix}circuit_breaker_successes_total`, {
10292
+ });
10293
+ this.cbSuccessesCounter = meter2.createCounter(`${prefix}circuit_breaker_successes_total`, {
9942
10294
  description: "Total number of successes recorded by circuit breakers",
9943
10295
  unit: "{successes}"
9944
- }) : { add: () => {} };
9945
- this.cbTransitionsCounter = meter2.createCounter ? meter2.createCounter(`${prefix}circuit_breaker_transitions_total`, {
10296
+ });
10297
+ this.cbTransitionsCounter = meter2.createCounter(`${prefix}circuit_breaker_transitions_total`, {
9946
10298
  description: "Total number of state transitions in circuit breakers",
9947
10299
  unit: "{transitions}"
9948
- }) : { add: () => {} };
10300
+ });
9949
10301
  this.cbOpenDurationHistogram = meter2.createHistogram(`${prefix}circuit_breaker_open_duration_seconds`, {
9950
10302
  description: "Duration that circuit breakers remain in OPEN state",
9951
10303
  unit: "s",
@@ -9953,10 +10305,10 @@ class OTelEventMetrics {
9953
10305
  explicitBucketBoundaries: this.cbOpenDurationBuckets
9954
10306
  }
9955
10307
  });
9956
- this.backpressureRejectionsCounter = meter2.createCounter ? meter2.createCounter(`${prefix}backpressure_rejections_total`, {
10308
+ this.backpressureRejectionsCounter = meter2.createCounter(`${prefix}backpressure_rejections_total`, {
9957
10309
  description: "Total number of events rejected due to backpressure",
9958
10310
  unit: "{rejections}"
9959
- }) : { add: () => {} };
10311
+ });
9960
10312
  this.backpressureStateGauge = meter2.createObservableGauge(`${prefix}backpressure_state`, {
9961
10313
  description: "Current backpressure state (0=NORMAL, 1=WARNING, 2=CRITICAL, 3=OVERFLOW)",
9962
10314
  unit: "{state}"
@@ -9970,14 +10322,14 @@ class OTelEventMetrics {
9970
10322
  };
9971
10323
  observableResult.observe(stateMap[this.backpressureStateValue] ?? 0);
9972
10324
  });
9973
- this.backpressureDegradationsCounter = meter2.createCounter ? meter2.createCounter(`${prefix}backpressure_degradations_total`, {
10325
+ this.backpressureDegradationsCounter = meter2.createCounter(`${prefix}backpressure_degradations_total`, {
9974
10326
  description: "Total number of priority degradations due to backpressure",
9975
10327
  unit: "{degradations}"
9976
- }) : { add: () => {} };
9977
- this.dlqEntriesCounter = meter2.createCounter ? meter2.createCounter(`${prefix}dlq_entries_total`, {
10328
+ });
10329
+ this.dlqEntriesCounter = meter2.createCounter(`${prefix}dlq_entries_total`, {
9978
10330
  description: "Total number of events added to Dead Letter Queue",
9979
10331
  unit: "{entries}"
9980
- }) : { add: () => {} };
10332
+ });
9981
10333
  this.dlqDepthGauge = meter2.createObservableGauge(`${prefix}dlq_depth`, {
9982
10334
  description: "Current Dead Letter Queue depth",
9983
10335
  unit: "{events}"
@@ -9987,18 +10339,18 @@ class OTelEventMetrics {
9987
10339
  observableResult.observe(this.dlqDepthCallback());
9988
10340
  }
9989
10341
  });
9990
- this.dlqRequeueCounter = meter2.createCounter ? meter2.createCounter(`${prefix}dlq_requeue_total`, {
10342
+ this.dlqRequeueCounter = meter2.createCounter(`${prefix}dlq_requeue_total`, {
9991
10343
  description: "Total number of DLQ requeue attempts",
9992
10344
  unit: "{attempts}"
9993
- }) : { add: () => {} };
9994
- this.retryAttemptsCounter = meter2.createCounter ? meter2.createCounter(`${prefix}retry_attempts_total`, {
10345
+ });
10346
+ this.retryAttemptsCounter = meter2.createCounter(`${prefix}retry_attempts_total`, {
9995
10347
  description: "Total number of event retry attempts",
9996
10348
  unit: "{attempts}"
9997
- }) : { add: () => {} };
9998
- this.priorityEscalationCounter = meter2.createCounter ? meter2.createCounter(`${prefix}priority_escalation_total`, {
10349
+ });
10350
+ this.priorityEscalationCounter = meter2.createCounter(`${prefix}priority_escalation_total`, {
9999
10351
  description: "Total number of priority escalations",
10000
10352
  unit: "{escalations}"
10001
- }) : { add: () => {} };
10353
+ });
10002
10354
  }
10003
10355
  recordDispatchDuration(eventName, priority, durationSeconds) {
10004
10356
  this.dispatchDurationHistogram.record(durationSeconds, {
@@ -10933,24 +11285,6 @@ class CookieJar {
10933
11285
  }
10934
11286
  }
10935
11287
 
10936
- // src/exceptions/ModelNotFoundException.ts
10937
- class ModelNotFoundException extends GravitoException {
10938
- model;
10939
- id;
10940
- constructor(model, id) {
10941
- super(404, "NOT_FOUND", {
10942
- message: `${model} not found.`,
10943
- i18nKey: "errors.model.not_found",
10944
- i18nParams: { model, id: String(id ?? "") }
10945
- });
10946
- this.name = "ModelNotFoundException";
10947
- this.model = model;
10948
- if (id !== undefined) {
10949
- this.id = id;
10950
- }
10951
- }
10952
- }
10953
-
10954
11288
  // src/Route.ts
10955
11289
  class Route {
10956
11290
  router;
@@ -10967,6 +11301,13 @@ class Route {
10967
11301
  this.router.registerName(name, this.method, this.path, this.options);
10968
11302
  return this;
10969
11303
  }
11304
+ schema(schemas) {
11305
+ this.options.schema = {
11306
+ ...this.options.schema || {},
11307
+ ...schemas
11308
+ };
11309
+ return this;
11310
+ }
10970
11311
  static get(path2, requestOrHandlerOrMiddleware, handler) {
10971
11312
  return router().req("get", path2, requestOrHandlerOrMiddleware, handler);
10972
11313
  }
@@ -11162,18 +11503,20 @@ class Router {
11162
11503
  const compiled = [];
11163
11504
  const nameMap = new Map;
11164
11505
  for (const [name, info] of this.namedRoutes) {
11165
- nameMap.set(`${info.method.toUpperCase()}:${info.path}`, name);
11506
+ nameMap.set(`${info.method.toUpperCase()}:${info.path}`, { name, options: info.options });
11166
11507
  }
11167
11508
  const compiledKeys = new Set;
11168
11509
  for (const route of this.routes) {
11169
11510
  const method = route.method.toUpperCase();
11170
11511
  const key = `${method}:${route.path}`;
11171
11512
  compiledKeys.add(key);
11513
+ const namedInfo = nameMap.get(key);
11172
11514
  compiled.push({
11173
11515
  method,
11174
11516
  path: route.path,
11175
11517
  domain: route.domain,
11176
- name: nameMap.get(key)
11518
+ name: namedInfo?.name,
11519
+ schema: route.options?.schema || namedInfo?.options?.schema
11177
11520
  });
11178
11521
  }
11179
11522
  for (const [name, info] of this.namedRoutes) {
@@ -11183,7 +11526,8 @@ class Router {
11183
11526
  name,
11184
11527
  method: info.method.toUpperCase(),
11185
11528
  path: info.path,
11186
- domain: info.domain
11529
+ domain: info.domain,
11530
+ schema: info.options?.schema
11187
11531
  });
11188
11532
  }
11189
11533
  }
@@ -11194,7 +11538,8 @@ class Router {
11194
11538
  this.namedRoutes.set(name, {
11195
11539
  method: method.toUpperCase(),
11196
11540
  path: fullPath,
11197
- domain: options2.domain
11541
+ domain: options2.domain,
11542
+ options: options2
11198
11543
  });
11199
11544
  }
11200
11545
  url(name, params = {}, query = {}) {
@@ -11234,7 +11579,7 @@ class Router {
11234
11579
  if (modelClass && typeof modelClass === "object" && "find" in modelClass && typeof modelClass.find === "function") {
11235
11580
  const instance = await modelClass.find(id);
11236
11581
  if (!instance) {
11237
- throw new Error("ModelNotFound");
11582
+ throw new ModelNotFoundException(param, String(id));
11238
11583
  }
11239
11584
  return instance;
11240
11585
  }
@@ -11256,17 +11601,9 @@ class Router {
11256
11601
  if (!resolver) {
11257
11602
  continue;
11258
11603
  }
11259
- try {
11260
- const resolved = await resolver(value2);
11261
- routeModels[param] = resolved;
11262
- hasResolvedModels = true;
11263
- } catch (err) {
11264
- const message = err instanceof Error ? err.message : undefined;
11265
- if (message === "ModelNotFound") {
11266
- throw new ModelNotFoundException(param, value2);
11267
- }
11268
- throw err;
11269
- }
11604
+ const resolved = await resolver(value2);
11605
+ routeModels[param] = resolved;
11606
+ hasResolvedModels = true;
11270
11607
  }
11271
11608
  if (hasResolvedModels) {
11272
11609
  c.set("routeModels", routeModels);
@@ -11330,7 +11667,6 @@ class Router {
11330
11667
  }
11331
11668
  req(method, path2, requestOrHandlerOrMiddleware, handler, options2 = {}) {
11332
11669
  const fullPath = (options2.prefix || "") + path2;
11333
- console.log(`[Router] Registering ${method.toUpperCase()} ${fullPath}`);
11334
11670
  let formRequestMiddleware = null;
11335
11671
  let routeMiddleware = [];
11336
11672
  let finalRouteHandler;
@@ -11372,11 +11708,16 @@ class Router {
11372
11708
  if (c.req.header("host") !== options2.domain) {
11373
11709
  return c.text("Not Found", 404);
11374
11710
  }
11375
- await next();
11711
+ return await next();
11376
11712
  };
11377
11713
  handlers.unshift(domainCheck);
11378
11714
  }
11379
- 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
+ });
11380
11721
  this.core.adapter.route(method, fullPath, ...handlers);
11381
11722
  return new Route(this, method, fullPath, options2);
11382
11723
  }
@@ -11494,6 +11835,7 @@ class PlanetCore {
11494
11835
  services = new Map;
11495
11836
  encrypter;
11496
11837
  hasher;
11838
+ installedOrbits = [];
11497
11839
  observabilityProvider;
11498
11840
  providers = [];
11499
11841
  deferredProviders = new Map;
@@ -11502,7 +11844,7 @@ class PlanetCore {
11502
11844
  static GLOBAL_SHUTDOWN_TIMEOUT = 1e4;
11503
11845
  async initializeObservabilityAsync(obsConfig) {
11504
11846
  try {
11505
- if (this.observabilityProvider && this.observabilityProvider !== this.observabilityProvider._isNoOp) {
11847
+ if (this.observabilityProvider && this.observabilityProvider._isNoOp !== true) {
11506
11848
  this.logger.info("[Observability] \u2705 Using observability provider from @gravito/monitor");
11507
11849
  if (obsConfig?.prometheus?.enabled !== false) {
11508
11850
  await this.initializePrometheusAsync(obsConfig);
@@ -11544,10 +11886,11 @@ class PlanetCore {
11544
11886
  this.logger.debug("[Observability] Prometheus setup moved to @gravito/monitor. Use monitor package for metrics initialization.");
11545
11887
  }
11546
11888
  register(provider) {
11547
- if (typeof provider.setCore === "function") {
11548
- provider.setCore(this);
11889
+ const providerRecord = provider;
11890
+ if (typeof providerRecord["setCore"] === "function") {
11891
+ providerRecord["setCore"](this);
11549
11892
  } else {
11550
- provider.core = this;
11893
+ providerRecord["core"] = this;
11551
11894
  }
11552
11895
  if (provider.deferred) {
11553
11896
  const services = provider.provides();
@@ -11718,8 +12061,38 @@ class PlanetCore {
11718
12061
  process.on("SIGTERM", () => handleSignal("SIGTERM"));
11719
12062
  process.on("SIGINT", () => handleSignal("SIGINT"));
11720
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
+ }
11721
12084
  async orbit(orbit) {
11722
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
+ });
11723
12096
  await instance.install(this);
11724
12097
  return this;
11725
12098
  }
@@ -11744,17 +12117,24 @@ class PlanetCore {
11744
12117
  ...config3.logger && { logger: config3.logger },
11745
12118
  ...config3.config && { config: config3.config },
11746
12119
  ...config3.adapter && { adapter: config3.adapter },
11747
- ...config3.container && { container: config3.container }
12120
+ ...config3.container && { container: config3.container },
12121
+ ...config3.observabilityProvider && { observabilityProvider: config3.observabilityProvider }
11748
12122
  });
12123
+ const features = NativeOrbitDetector.detectBunCapabilities();
12124
+ core.logger.info(formatCapabilityReport(features));
11749
12125
  if (config3.orbits) {
11750
12126
  for (const OrbitClassOrInstance of config3.orbits) {
11751
- let orbit;
11752
- if (typeof OrbitClassOrInstance === "function") {
11753
- orbit = new OrbitClassOrInstance;
12127
+ if (typeof OrbitClassOrInstance !== "function" && OrbitClassOrInstance.name) {
12128
+ await core.plugin(OrbitClassOrInstance);
11754
12129
  } else {
11755
- 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);
11756
12137
  }
11757
- await orbit.install(core);
11758
12138
  }
11759
12139
  }
11760
12140
  return core;
@@ -12524,7 +12904,8 @@ class MessageQueueBridge {
12524
12904
  throw new Error(`[MessageQueueBridge] No listeners registered for event: ${eventName}`);
12525
12905
  }
12526
12906
  if (this.config.enableCircuitBreaker) {
12527
- const breaker = this.config.hookManager.getCircuitBreaker?.(eventName);
12907
+ const hm = this.config.hookManager;
12908
+ const breaker = hm.getCircuitBreaker?.(eventName);
12528
12909
  if (breaker?.getState?.() === "OPEN") {
12529
12910
  throw new Error(`[MessageQueueBridge] Circuit breaker is OPEN for event: ${eventName}`);
12530
12911
  }
@@ -12650,9 +13031,9 @@ class RetryScheduler {
12650
13031
  try {
12651
13032
  const queue = this.getOrCreateQueue(eventName);
12652
13033
  const delay = this.calculateDelay(retryCount);
12653
- const addMethod = queue.add;
12654
- if (typeof addMethod === "function") {
12655
- 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 });
12656
13037
  }
12657
13038
  } catch (schedulerError) {
12658
13039
  const err = schedulerError instanceof Error ? schedulerError : new Error(String(schedulerError));
@@ -13221,101 +13602,6 @@ class QueueDashboard {
13221
13602
  return value2.replace(/\\/g, "\\\\").replace(/"/g, "\\\"").replace(/\n/g, "\\n");
13222
13603
  }
13223
13604
  }
13224
- // src/exceptions/AuthenticationException.ts
13225
- class AuthenticationException extends DomainException {
13226
- constructor(message = "Unauthenticated.") {
13227
- super(401, "UNAUTHENTICATED", {
13228
- message,
13229
- i18nKey: "errors.authentication.unauthenticated"
13230
- });
13231
- this.name = "AuthenticationException";
13232
- }
13233
- }
13234
-
13235
- // src/exceptions/AuthException.ts
13236
- class AuthException extends DomainException {
13237
- constructor(status, code, options2 = {}) {
13238
- super(status, code, options2);
13239
- this.name = "AuthException";
13240
- Object.setPrototypeOf(this, new.target.prototype);
13241
- }
13242
- }
13243
-
13244
- // src/exceptions/AuthorizationException.ts
13245
- class AuthorizationException extends DomainException {
13246
- constructor(message = "This action is unauthorized.") {
13247
- super(403, "FORBIDDEN", {
13248
- message,
13249
- i18nKey: "errors.authorization.forbidden"
13250
- });
13251
- this.name = "AuthorizationException";
13252
- }
13253
- }
13254
-
13255
- // src/exceptions/InfrastructureException.ts
13256
- class InfrastructureException extends GravitoException {
13257
- retryable;
13258
- constructor(status, code, options2 = {}) {
13259
- super(status, code, options2);
13260
- this.name = "InfrastructureException";
13261
- this.retryable = options2.retryable ?? false;
13262
- Object.setPrototypeOf(this, new.target.prototype);
13263
- }
13264
- }
13265
-
13266
- // src/exceptions/CacheException.ts
13267
- class CacheException extends InfrastructureException {
13268
- constructor(status, code, options2 = {}) {
13269
- super(status, code, options2);
13270
- this.name = "CacheException";
13271
- Object.setPrototypeOf(this, new.target.prototype);
13272
- }
13273
- }
13274
-
13275
- // src/exceptions/ConfigurationException.ts
13276
- class ConfigurationException extends SystemException {
13277
- constructor(message, options2 = {}) {
13278
- super(500, "system.configuration_error", { ...options2, message });
13279
- this.name = "ConfigurationException";
13280
- Object.setPrototypeOf(this, new.target.prototype);
13281
- }
13282
- }
13283
-
13284
- // src/exceptions/DatabaseException.ts
13285
- class DatabaseException extends InfrastructureException {
13286
- constructor(status, code, options2 = {}) {
13287
- super(status, code, options2);
13288
- this.name = "DatabaseException";
13289
- Object.setPrototypeOf(this, new.target.prototype);
13290
- }
13291
- }
13292
-
13293
- // src/exceptions/QueueException.ts
13294
- class QueueException extends InfrastructureException {
13295
- constructor(status, code, options2 = {}) {
13296
- super(status, code, options2);
13297
- this.name = "QueueException";
13298
- Object.setPrototypeOf(this, new.target.prototype);
13299
- }
13300
- }
13301
-
13302
- // src/exceptions/StorageException.ts
13303
- class StorageException extends InfrastructureException {
13304
- constructor(status, code, options2 = {}) {
13305
- super(status, code, options2);
13306
- this.name = "StorageException";
13307
- Object.setPrototypeOf(this, new.target.prototype);
13308
- }
13309
- }
13310
-
13311
- // src/exceptions/StreamException.ts
13312
- class StreamException extends InfrastructureException {
13313
- constructor(status, code, options2 = {}) {
13314
- super(status, code, options2);
13315
- this.name = "StreamException";
13316
- Object.setPrototypeOf(this, new.target.prototype);
13317
- }
13318
- }
13319
13605
  // src/ServiceProvider.ts
13320
13606
  class ServiceProvider {
13321
13607
  core;
@@ -13539,15 +13825,19 @@ class TestResponse {
13539
13825
  async assertJsonStructure(structure) {
13540
13826
  const json = await this.getJson();
13541
13827
  const checkKeys = (data2, struct) => {
13542
- for (const key in struct) {
13543
- if (Array.isArray(struct[key])) {
13544
- expect(Array.isArray(data2[key])).toBe(true);
13545
- if (data2[key].length > 0) {
13546
- 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]);
13547
13837
  }
13548
- } else if (typeof struct[key] === "object") {
13549
- expect(typeof data2[key]).toBe("object");
13550
- 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]);
13551
13841
  } else {
13552
13842
  expect(data2).toHaveProperty(key);
13553
13843
  }
@@ -13996,6 +14286,7 @@ export {
13996
14286
  runtimeAppendFile,
13997
14287
  router,
13998
14288
  resetRuntimeAdapter,
14289
+ resetPasswordAdapter,
13999
14290
  registerQueueCommands,
14000
14291
  registerGlobalErrorHandlers,
14001
14292
  old,
@@ -14020,6 +14311,7 @@ export {
14020
14311
  getCookie,
14021
14312
  getCompressionAdapter,
14022
14313
  getArchiveAdapter,
14314
+ formatCapabilityReport,
14023
14315
  filled,
14024
14316
  fail,
14025
14317
  extractRequestScopeErrorContext,
@@ -14081,6 +14373,7 @@ export {
14081
14373
  ObservableHookManager,
14082
14374
  OTelEventMetrics,
14083
14375
  NodeType,
14376
+ NativeOrbitDetector,
14084
14377
  ModelNotFoundException,
14085
14378
  InfrastructureException,
14086
14379
  IdempotencyCache,
@@ -14131,4 +14424,4 @@ export {
14131
14424
  Application
14132
14425
  };
14133
14426
 
14134
- //# debugId=182898C607162D4164756E2164756E21
14427
+ //# debugId=AFB01087B997521264756E2164756E21