@rebasepro/server-core 0.0.1-canary.eae7889 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (132) hide show
  1. package/app/frontend/node_modules/esbuild/LICENSE.md +21 -0
  2. package/app/frontend/node_modules/esbuild/README.md +3 -0
  3. package/app/frontend/node_modules/esbuild/bin/esbuild +220 -0
  4. package/app/frontend/node_modules/esbuild/install.js +285 -0
  5. package/app/frontend/node_modules/esbuild/lib/main.d.ts +705 -0
  6. package/app/frontend/node_modules/esbuild/lib/main.js +2239 -0
  7. package/app/frontend/node_modules/esbuild/package.json +46 -0
  8. package/dist/index.es.js +1186 -1673
  9. package/dist/index.es.js.map +1 -1
  10. package/dist/index.umd.js +1185 -1672
  11. package/dist/index.umd.js.map +1 -1
  12. package/dist/server-core/src/api/rest/api-generator.d.ts +15 -3
  13. package/dist/server-core/src/auth/admin-routes.d.ts +5 -0
  14. package/dist/server-core/src/auth/google-oauth.d.ts +36 -3
  15. package/dist/server-core/src/auth/index.d.ts +1 -0
  16. package/dist/server-core/src/cron/cron-scheduler.d.ts +45 -0
  17. package/dist/server-core/src/cron/index.d.ts +1 -1
  18. package/dist/server-core/src/init.d.ts +11 -1
  19. package/dist/types/src/controllers/auth.d.ts +8 -2
  20. package/dist/types/src/controllers/client.d.ts +13 -0
  21. package/dist/types/src/controllers/collection_registry.d.ts +2 -1
  22. package/dist/types/src/controllers/data_driver.d.ts +36 -1
  23. package/dist/types/src/controllers/navigation.d.ts +18 -6
  24. package/dist/types/src/controllers/registry.d.ts +9 -1
  25. package/dist/types/src/controllers/side_entity_controller.d.ts +7 -0
  26. package/dist/types/src/rebase_context.d.ts +17 -0
  27. package/dist/types/src/types/backend_hooks.d.ts +187 -0
  28. package/dist/types/src/types/collections.d.ts +31 -11
  29. package/dist/types/src/types/component_ref.d.ts +47 -0
  30. package/dist/types/src/types/cron.d.ts +1 -1
  31. package/dist/types/src/types/entity_views.d.ts +6 -7
  32. package/dist/types/src/types/formex.d.ts +40 -0
  33. package/dist/types/src/types/index.d.ts +3 -0
  34. package/dist/types/src/types/plugins.d.ts +6 -3
  35. package/dist/types/src/types/properties.d.ts +72 -88
  36. package/dist/types/src/types/slots.d.ts +20 -10
  37. package/dist/types/src/types/translations.d.ts +6 -0
  38. package/examples/firebase/node_modules/esbuild/LICENSE.md +21 -0
  39. package/examples/firebase/node_modules/esbuild/README.md +3 -0
  40. package/examples/firebase/node_modules/esbuild/bin/esbuild +220 -0
  41. package/examples/firebase/node_modules/esbuild/install.js +285 -0
  42. package/examples/firebase/node_modules/esbuild/lib/main.d.ts +705 -0
  43. package/examples/firebase/node_modules/esbuild/lib/main.js +2239 -0
  44. package/examples/firebase/node_modules/esbuild/package.json +46 -0
  45. package/examples/medmot-staging/frontend/node_modules/esbuild/LICENSE.md +21 -0
  46. package/examples/medmot-staging/frontend/node_modules/esbuild/README.md +3 -0
  47. package/examples/medmot-staging/frontend/node_modules/esbuild/bin/esbuild +220 -0
  48. package/examples/medmot-staging/frontend/node_modules/esbuild/install.js +285 -0
  49. package/examples/medmot-staging/frontend/node_modules/esbuild/lib/main.d.ts +705 -0
  50. package/examples/medmot-staging/frontend/node_modules/esbuild/lib/main.js +2239 -0
  51. package/examples/medmot-staging/frontend/node_modules/esbuild/package.json +46 -0
  52. package/examples/sdk-demo/node_modules/esbuild/LICENSE.md +21 -0
  53. package/examples/sdk-demo/node_modules/esbuild/README.md +3 -0
  54. package/examples/sdk-demo/node_modules/esbuild/bin/esbuild +223 -0
  55. package/examples/sdk-demo/node_modules/esbuild/install.js +289 -0
  56. package/examples/sdk-demo/node_modules/esbuild/lib/main.d.ts +716 -0
  57. package/examples/sdk-demo/node_modules/esbuild/lib/main.js +2242 -0
  58. package/examples/sdk-demo/node_modules/esbuild/package.json +49 -0
  59. package/package.json +9 -9
  60. package/packages/client/node_modules/esbuild/LICENSE.md +21 -0
  61. package/packages/client/node_modules/esbuild/README.md +3 -0
  62. package/packages/client/node_modules/esbuild/bin/esbuild +220 -0
  63. package/packages/client/node_modules/esbuild/install.js +285 -0
  64. package/packages/client/node_modules/esbuild/lib/main.d.ts +705 -0
  65. package/packages/client/node_modules/esbuild/lib/main.js +2239 -0
  66. package/packages/client/node_modules/esbuild/package.json +46 -0
  67. package/packages/client-postgresql/node_modules/esbuild/LICENSE.md +21 -0
  68. package/packages/client-postgresql/node_modules/esbuild/README.md +3 -0
  69. package/packages/client-postgresql/node_modules/esbuild/bin/esbuild +220 -0
  70. package/packages/client-postgresql/node_modules/esbuild/install.js +285 -0
  71. package/packages/client-postgresql/node_modules/esbuild/lib/main.d.ts +705 -0
  72. package/packages/client-postgresql/node_modules/esbuild/lib/main.js +2239 -0
  73. package/packages/client-postgresql/node_modules/esbuild/package.json +46 -0
  74. package/packages/common/node_modules/esbuild/LICENSE.md +21 -0
  75. package/packages/common/node_modules/esbuild/README.md +3 -0
  76. package/packages/common/node_modules/esbuild/bin/esbuild +220 -0
  77. package/packages/common/node_modules/esbuild/install.js +285 -0
  78. package/packages/common/node_modules/esbuild/lib/main.d.ts +705 -0
  79. package/packages/common/node_modules/esbuild/lib/main.js +2239 -0
  80. package/packages/common/node_modules/esbuild/package.json +46 -0
  81. package/packages/server-mongodb/node_modules/esbuild/LICENSE.md +21 -0
  82. package/packages/server-mongodb/node_modules/esbuild/README.md +3 -0
  83. package/packages/server-mongodb/node_modules/esbuild/bin/esbuild +220 -0
  84. package/packages/server-mongodb/node_modules/esbuild/install.js +285 -0
  85. package/packages/server-mongodb/node_modules/esbuild/lib/main.d.ts +705 -0
  86. package/packages/server-mongodb/node_modules/esbuild/lib/main.js +2239 -0
  87. package/packages/server-mongodb/node_modules/esbuild/package.json +46 -0
  88. package/packages/server-postgresql/node_modules/esbuild/LICENSE.md +21 -0
  89. package/packages/server-postgresql/node_modules/esbuild/README.md +3 -0
  90. package/packages/server-postgresql/node_modules/esbuild/bin/esbuild +220 -0
  91. package/packages/server-postgresql/node_modules/esbuild/install.js +285 -0
  92. package/packages/server-postgresql/node_modules/esbuild/lib/main.d.ts +705 -0
  93. package/packages/server-postgresql/node_modules/esbuild/lib/main.js +2239 -0
  94. package/packages/server-postgresql/node_modules/esbuild/package.json +46 -0
  95. package/packages/types/node_modules/esbuild/LICENSE.md +21 -0
  96. package/packages/types/node_modules/esbuild/README.md +3 -0
  97. package/packages/types/node_modules/esbuild/bin/esbuild +220 -0
  98. package/packages/types/node_modules/esbuild/install.js +285 -0
  99. package/packages/types/node_modules/esbuild/lib/main.d.ts +705 -0
  100. package/packages/types/node_modules/esbuild/lib/main.js +2239 -0
  101. package/packages/types/node_modules/esbuild/package.json +46 -0
  102. package/packages/utils/node_modules/esbuild/LICENSE.md +21 -0
  103. package/packages/utils/node_modules/esbuild/README.md +3 -0
  104. package/packages/utils/node_modules/esbuild/bin/esbuild +220 -0
  105. package/packages/utils/node_modules/esbuild/install.js +285 -0
  106. package/packages/utils/node_modules/esbuild/lib/main.d.ts +705 -0
  107. package/packages/utils/node_modules/esbuild/lib/main.js +2239 -0
  108. package/packages/utils/node_modules/esbuild/package.json +46 -0
  109. package/src/api/errors.ts +3 -2
  110. package/src/api/rest/api-generator-count.test.ts +113 -0
  111. package/src/api/rest/api-generator.ts +123 -22
  112. package/src/api/server.ts +8 -4
  113. package/src/auth/admin-routes.ts +133 -57
  114. package/src/auth/apple-oauth.ts +8 -18
  115. package/src/auth/google-oauth.ts +192 -22
  116. package/src/auth/index.ts +1 -0
  117. package/src/auth/rate-limiter.ts +9 -5
  118. package/src/auth/routes.ts +25 -5
  119. package/src/collections/loader.ts +3 -3
  120. package/src/cron/cron-scheduler.test.ts +301 -175
  121. package/src/cron/cron-scheduler.ts +220 -57
  122. package/src/cron/index.ts +1 -1
  123. package/src/init.ts +27 -5
  124. package/src/storage/LocalStorageController.ts +37 -13
  125. package/src/storage/S3StorageController.ts +4 -1
  126. package/src/storage/routes.ts +51 -5
  127. package/test/backend-hooks-admin.test.ts +394 -0
  128. package/test/backend-hooks-data.test.ts +408 -0
  129. package/history_diff.log +0 -385
  130. package/scratch.ts +0 -9
  131. package/test-ast.ts +0 -28
  132. package/test_output.txt +0 -1133
package/dist/index.es.js CHANGED
@@ -7,7 +7,7 @@ import { Hono } from "hono";
7
7
  import require$$0$2 from "buffer";
8
8
  import require$$0$3 from "stream";
9
9
  import require$$5, { promisify } from "util";
10
- import require$$0$4, { randomBytes, createHash, timingSafeEqual as timingSafeEqual$1, scrypt, createPrivateKey as createPrivateKey$1 } from "crypto";
10
+ import require$$0$4, { randomBytes, createHash, timingSafeEqual as timingSafeEqual$1, scrypt } from "crypto";
11
11
  import { bodyLimit } from "hono/body-limit";
12
12
  import { csrf } from "hono/csrf";
13
13
  import require$$0$a from "child_process";
@@ -1020,13 +1020,14 @@ var object_hash = { exports: {} };
1020
1020
  }, { buffer: 3, lYpoI2: 11 }] }, {}, [1])(1);
1021
1021
  });
1022
1022
  })(object_hash);
1023
- const snakeCaseRegex = /[A-Z]{2,}(?=[A-Z][a-z]+[0-9]*|\b)|[A-Z]?[a-z]+[0-9]*|[A-Z]|[0-9]+/g;
1023
+ const tokenizeRegex = /[A-Z]{2,}(?=[A-Z][a-z]|\b)|[A-Z]?[a-z]+|[0-9]+(?:[a-z](?![a-z]))?|[A-Z]/g;
1024
+ const snakeCaseRegex = tokenizeRegex;
1024
1025
  const toSnakeCase = (str) => {
1025
1026
  const regExpMatchArray = str.match(snakeCaseRegex);
1026
1027
  if (!regExpMatchArray) return "";
1027
1028
  return regExpMatchArray.map((x) => x.toLowerCase()).join("_");
1028
1029
  };
1029
- function isObject$b(item) {
1030
+ function isObject$a(item) {
1030
1031
  return !!item && typeof item === "object" && !Array.isArray(item);
1031
1032
  }
1032
1033
  function isPlainObject$3(obj) {
@@ -1037,13 +1038,13 @@ function isPlainObject$3(obj) {
1037
1038
  return proto === Object.prototype;
1038
1039
  }
1039
1040
  function mergeDeep(target, source, ignoreUndefined = false) {
1040
- if (!isObject$b(target)) {
1041
+ if (!isObject$a(target)) {
1041
1042
  return target;
1042
1043
  }
1043
1044
  const output = {
1044
1045
  ...target
1045
1046
  };
1046
- if (!isObject$b(source)) {
1047
+ if (!isObject$a(source)) {
1047
1048
  return output;
1048
1049
  }
1049
1050
  for (const key in source) {
@@ -1084,7 +1085,7 @@ function mergeDeep(target, source, ignoreUndefined = false) {
1084
1085
  } else {
1085
1086
  output[key] = sourceValue;
1086
1087
  }
1087
- } else if (isObject$b(sourceValue)) {
1088
+ } else if (isObject$a(sourceValue)) {
1088
1089
  output[key] = sourceValue;
1089
1090
  } else {
1090
1091
  output[key] = sourceValue;
@@ -1721,8 +1722,8 @@ var logic = { exports: {} };
1721
1722
  return jsonLogic;
1722
1723
  });
1723
1724
  })(logic);
1724
- var getOwnPropertyNames = Object.getOwnPropertyNames, getOwnPropertySymbols = Object.getOwnPropertySymbols;
1725
- var hasOwnProperty$d = Object.prototype.hasOwnProperty;
1725
+ const { getOwnPropertyNames, getOwnPropertySymbols } = Object;
1726
+ const { hasOwnProperty: hasOwnProperty$d } = Object.prototype;
1726
1727
  function combineComparators(comparatorA, comparatorB) {
1727
1728
  return function isEqual(a2, b, state) {
1728
1729
  return comparatorA(a2, b, state) && comparatorB(a2, b, state);
@@ -1733,38 +1734,45 @@ function createIsCircular(areItemsEqual) {
1733
1734
  if (!a2 || !b || typeof a2 !== "object" || typeof b !== "object") {
1734
1735
  return areItemsEqual(a2, b, state);
1735
1736
  }
1736
- var cache2 = state.cache;
1737
- var cachedA = cache2.get(a2);
1738
- var cachedB = cache2.get(b);
1737
+ const { cache } = state;
1738
+ const cachedA = cache.get(a2);
1739
+ const cachedB = cache.get(b);
1739
1740
  if (cachedA && cachedB) {
1740
1741
  return cachedA === b && cachedB === a2;
1741
1742
  }
1742
- cache2.set(a2, b);
1743
- cache2.set(b, a2);
1744
- var result = areItemsEqual(a2, b, state);
1745
- cache2.delete(a2);
1746
- cache2.delete(b);
1743
+ cache.set(a2, b);
1744
+ cache.set(b, a2);
1745
+ const result = areItemsEqual(a2, b, state);
1746
+ cache.delete(a2);
1747
+ cache.delete(b);
1747
1748
  return result;
1748
1749
  };
1749
1750
  }
1750
- function getShortTag(value) {
1751
- return value != null ? value[Symbol.toStringTag] : void 0;
1752
- }
1753
1751
  function getStrictProperties(object) {
1754
1752
  return getOwnPropertyNames(object).concat(getOwnPropertySymbols(object));
1755
1753
  }
1756
- var hasOwn$1 = Object.hasOwn || function(object, property) {
1757
- return hasOwnProperty$d.call(object, property);
1758
- };
1759
- function sameValueZeroEqual(a2, b) {
1760
- return a2 === b || !a2 && !b && a2 !== a2 && b !== b;
1754
+ const hasOwn$1 = (
1755
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
1756
+ Object.hasOwn || ((object, property) => hasOwnProperty$d.call(object, property))
1757
+ );
1758
+ const PREACT_VNODE = "__v";
1759
+ const PREACT_OWNER = "__o";
1760
+ const REACT_OWNER = "_owner";
1761
+ const { getOwnPropertyDescriptor, keys: keys$5 } = Object;
1762
+ const sameValueEqual = (
1763
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
1764
+ Object.is || function sameValueEqual2(a2, b) {
1765
+ return a2 === b ? a2 !== 0 || 1 / a2 === 1 / b : a2 !== a2 && b !== b;
1766
+ }
1767
+ );
1768
+ function strictEqual(a2, b) {
1769
+ return a2 === b;
1770
+ }
1771
+ function areArrayBuffersEqual(a2, b) {
1772
+ return a2.byteLength === b.byteLength && areTypedArraysEqual(new Uint8Array(a2), new Uint8Array(b));
1761
1773
  }
1762
- var PREACT_VNODE = "__v";
1763
- var PREACT_OWNER = "__o";
1764
- var REACT_OWNER = "_owner";
1765
- var getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor, keys$5 = Object.keys;
1766
1774
  function areArraysEqual(a2, b, state) {
1767
- var index = a2.length;
1775
+ let index = a2.length;
1768
1776
  if (b.length !== index) {
1769
1777
  return false;
1770
1778
  }
@@ -1775,35 +1783,35 @@ function areArraysEqual(a2, b, state) {
1775
1783
  }
1776
1784
  return true;
1777
1785
  }
1786
+ function areDataViewsEqual(a2, b) {
1787
+ return a2.byteLength === b.byteLength && areTypedArraysEqual(new Uint8Array(a2.buffer, a2.byteOffset, a2.byteLength), new Uint8Array(b.buffer, b.byteOffset, b.byteLength));
1788
+ }
1778
1789
  function areDatesEqual(a2, b) {
1779
- return sameValueZeroEqual(a2.getTime(), b.getTime());
1790
+ return sameValueEqual(a2.getTime(), b.getTime());
1780
1791
  }
1781
1792
  function areErrorsEqual(a2, b) {
1782
1793
  return a2.name === b.name && a2.message === b.message && a2.cause === b.cause && a2.stack === b.stack;
1783
1794
  }
1784
- function areFunctionsEqual(a2, b) {
1785
- return a2 === b;
1786
- }
1787
1795
  function areMapsEqual(a2, b, state) {
1788
- var size = a2.size;
1796
+ const size = a2.size;
1789
1797
  if (size !== b.size) {
1790
1798
  return false;
1791
1799
  }
1792
1800
  if (!size) {
1793
1801
  return true;
1794
1802
  }
1795
- var matchedIndices = new Array(size);
1796
- var aIterable = a2.entries();
1797
- var aResult;
1798
- var bResult;
1799
- var index = 0;
1803
+ const matchedIndices = new Array(size);
1804
+ const aIterable = a2.entries();
1805
+ let aResult;
1806
+ let bResult;
1807
+ let index = 0;
1800
1808
  while (aResult = aIterable.next()) {
1801
1809
  if (aResult.done) {
1802
1810
  break;
1803
1811
  }
1804
- var bIterable = b.entries();
1805
- var hasMatch = false;
1806
- var matchIndex = 0;
1812
+ const bIterable = b.entries();
1813
+ let hasMatch = false;
1814
+ let matchIndex = 0;
1807
1815
  while (bResult = bIterable.next()) {
1808
1816
  if (bResult.done) {
1809
1817
  break;
@@ -1812,8 +1820,8 @@ function areMapsEqual(a2, b, state) {
1812
1820
  matchIndex++;
1813
1821
  continue;
1814
1822
  }
1815
- var aEntry = aResult.value;
1816
- var bEntry = bResult.value;
1823
+ const aEntry = aResult.value;
1824
+ const bEntry = bResult.value;
1817
1825
  if (state.equals(aEntry[0], bEntry[0], index, matchIndex, a2, b, state) && state.equals(aEntry[1], bEntry[1], aEntry[0], bEntry[0], a2, b, state)) {
1818
1826
  hasMatch = matchedIndices[matchIndex] = true;
1819
1827
  break;
@@ -1827,10 +1835,9 @@ function areMapsEqual(a2, b, state) {
1827
1835
  }
1828
1836
  return true;
1829
1837
  }
1830
- var areNumbersEqual = sameValueZeroEqual;
1831
1838
  function areObjectsEqual(a2, b, state) {
1832
- var properties = keys$5(a2);
1833
- var index = properties.length;
1839
+ const properties = keys$5(a2);
1840
+ let index = properties.length;
1834
1841
  if (keys$5(b).length !== index) {
1835
1842
  return false;
1836
1843
  }
@@ -1842,14 +1849,14 @@ function areObjectsEqual(a2, b, state) {
1842
1849
  return true;
1843
1850
  }
1844
1851
  function areObjectsEqualStrict(a2, b, state) {
1845
- var properties = getStrictProperties(a2);
1846
- var index = properties.length;
1852
+ const properties = getStrictProperties(a2);
1853
+ let index = properties.length;
1847
1854
  if (getStrictProperties(b).length !== index) {
1848
1855
  return false;
1849
1856
  }
1850
- var property;
1851
- var descriptorA;
1852
- var descriptorB;
1857
+ let property;
1858
+ let descriptorA;
1859
+ let descriptorB;
1853
1860
  while (index-- > 0) {
1854
1861
  property = properties[index];
1855
1862
  if (!isPropertyEqual(a2, b, state, property)) {
@@ -1864,30 +1871,30 @@ function areObjectsEqualStrict(a2, b, state) {
1864
1871
  return true;
1865
1872
  }
1866
1873
  function arePrimitiveWrappersEqual(a2, b) {
1867
- return sameValueZeroEqual(a2.valueOf(), b.valueOf());
1874
+ return sameValueEqual(a2.valueOf(), b.valueOf());
1868
1875
  }
1869
1876
  function areRegExpsEqual(a2, b) {
1870
1877
  return a2.source === b.source && a2.flags === b.flags;
1871
1878
  }
1872
1879
  function areSetsEqual(a2, b, state) {
1873
- var size = a2.size;
1880
+ const size = a2.size;
1874
1881
  if (size !== b.size) {
1875
1882
  return false;
1876
1883
  }
1877
1884
  if (!size) {
1878
1885
  return true;
1879
1886
  }
1880
- var matchedIndices = new Array(size);
1881
- var aIterable = a2.values();
1882
- var aResult;
1883
- var bResult;
1887
+ const matchedIndices = new Array(size);
1888
+ const aIterable = a2.values();
1889
+ let aResult;
1890
+ let bResult;
1884
1891
  while (aResult = aIterable.next()) {
1885
1892
  if (aResult.done) {
1886
1893
  break;
1887
1894
  }
1888
- var bIterable = b.values();
1889
- var hasMatch = false;
1890
- var matchIndex = 0;
1895
+ const bIterable = b.values();
1896
+ let hasMatch = false;
1897
+ let matchIndex = 0;
1891
1898
  while (bResult = bIterable.next()) {
1892
1899
  if (bResult.done) {
1893
1900
  break;
@@ -1905,8 +1912,8 @@ function areSetsEqual(a2, b, state) {
1905
1912
  return true;
1906
1913
  }
1907
1914
  function areTypedArraysEqual(a2, b) {
1908
- var index = a2.length;
1909
- if (b.length !== index) {
1915
+ let index = a2.byteLength;
1916
+ if (b.byteLength !== index || a2.byteOffset !== b.byteOffset) {
1910
1917
  return false;
1911
1918
  }
1912
1919
  while (index-- > 0) {
@@ -1925,23 +1932,10 @@ function isPropertyEqual(a2, b, state, property) {
1925
1932
  }
1926
1933
  return hasOwn$1(b, property) && state.equals(a2[property], b[property], property, property, a2, b, state);
1927
1934
  }
1928
- var ARGUMENTS_TAG = "[object Arguments]";
1929
- var BOOLEAN_TAG = "[object Boolean]";
1930
- var DATE_TAG = "[object Date]";
1931
- var ERROR_TAG = "[object Error]";
1932
- var MAP_TAG = "[object Map]";
1933
- var NUMBER_TAG = "[object Number]";
1934
- var OBJECT_TAG = "[object Object]";
1935
- var REG_EXP_TAG = "[object RegExp]";
1936
- var SET_TAG = "[object Set]";
1937
- var STRING_TAG = "[object String]";
1938
- var URL_TAG = "[object URL]";
1939
- var isArray$7 = Array.isArray;
1940
- var isTypedArray$2 = typeof ArrayBuffer === "function" && ArrayBuffer.isView ? ArrayBuffer.isView : null;
1941
- var assign$1 = Object.assign;
1942
- var getTag$4 = Object.prototype.toString.call.bind(Object.prototype.toString);
1943
- function createEqualityComparator(_a2) {
1944
- var areArraysEqual2 = _a2.areArraysEqual, areDatesEqual2 = _a2.areDatesEqual, areErrorsEqual2 = _a2.areErrorsEqual, areFunctionsEqual2 = _a2.areFunctionsEqual, areMapsEqual2 = _a2.areMapsEqual, areNumbersEqual2 = _a2.areNumbersEqual, areObjectsEqual2 = _a2.areObjectsEqual, arePrimitiveWrappersEqual2 = _a2.arePrimitiveWrappersEqual, areRegExpsEqual2 = _a2.areRegExpsEqual, areSetsEqual2 = _a2.areSetsEqual, areTypedArraysEqual2 = _a2.areTypedArraysEqual, areUrlsEqual2 = _a2.areUrlsEqual, unknownTagComparators = _a2.unknownTagComparators;
1935
+ const toString$2 = Object.prototype.toString;
1936
+ function createEqualityComparator(config) {
1937
+ const supportedComparatorMap = createSupportedComparatorMap(config);
1938
+ const { areArraysEqual: areArraysEqual2, areDatesEqual: areDatesEqual2, areFunctionsEqual, areMapsEqual: areMapsEqual2, areNumbersEqual, areObjectsEqual: areObjectsEqual2, areRegExpsEqual: areRegExpsEqual2, areSetsEqual: areSetsEqual2, getUnsupportedCustomComparator } = config;
1945
1939
  return function comparator2(a2, b, state) {
1946
1940
  if (a2 === b) {
1947
1941
  return true;
@@ -1949,32 +1943,29 @@ function createEqualityComparator(_a2) {
1949
1943
  if (a2 == null || b == null) {
1950
1944
  return false;
1951
1945
  }
1952
- var type = typeof a2;
1946
+ const type = typeof a2;
1953
1947
  if (type !== typeof b) {
1954
1948
  return false;
1955
1949
  }
1956
1950
  if (type !== "object") {
1957
- if (type === "number") {
1958
- return areNumbersEqual2(a2, b, state);
1951
+ if (type === "number" || type === "bigint") {
1952
+ return areNumbersEqual(a2, b, state);
1959
1953
  }
1960
1954
  if (type === "function") {
1961
- return areFunctionsEqual2(a2, b, state);
1955
+ return areFunctionsEqual(a2, b, state);
1962
1956
  }
1963
1957
  return false;
1964
1958
  }
1965
- var constructor = a2.constructor;
1959
+ const constructor = a2.constructor;
1966
1960
  if (constructor !== b.constructor) {
1967
1961
  return false;
1968
1962
  }
1969
1963
  if (constructor === Object) {
1970
1964
  return areObjectsEqual2(a2, b, state);
1971
1965
  }
1972
- if (isArray$7(a2)) {
1966
+ if (constructor === Array) {
1973
1967
  return areArraysEqual2(a2, b, state);
1974
1968
  }
1975
- if (isTypedArray$2 != null && isTypedArray$2(a2)) {
1976
- return areTypedArraysEqual2(a2, b, state);
1977
- }
1978
1969
  if (constructor === Date) {
1979
1970
  return areDatesEqual2(a2, b, state);
1980
1971
  }
@@ -1987,79 +1978,55 @@ function createEqualityComparator(_a2) {
1987
1978
  if (constructor === Set) {
1988
1979
  return areSetsEqual2(a2, b, state);
1989
1980
  }
1990
- var tag2 = getTag$4(a2);
1991
- if (tag2 === DATE_TAG) {
1992
- return areDatesEqual2(a2, b, state);
1993
- }
1994
- if (tag2 === REG_EXP_TAG) {
1995
- return areRegExpsEqual2(a2, b, state);
1996
- }
1997
- if (tag2 === MAP_TAG) {
1998
- return areMapsEqual2(a2, b, state);
1999
- }
2000
- if (tag2 === SET_TAG) {
2001
- return areSetsEqual2(a2, b, state);
2002
- }
2003
- if (tag2 === OBJECT_TAG) {
2004
- return typeof a2.then !== "function" && typeof b.then !== "function" && areObjectsEqual2(a2, b, state);
2005
- }
2006
- if (tag2 === URL_TAG) {
2007
- return areUrlsEqual2(a2, b, state);
2008
- }
2009
- if (tag2 === ERROR_TAG) {
2010
- return areErrorsEqual2(a2, b, state);
1981
+ if (constructor === Promise) {
1982
+ return false;
2011
1983
  }
2012
- if (tag2 === ARGUMENTS_TAG) {
2013
- return areObjectsEqual2(a2, b, state);
1984
+ if (Array.isArray(a2)) {
1985
+ return areArraysEqual2(a2, b, state);
2014
1986
  }
2015
- if (tag2 === BOOLEAN_TAG || tag2 === NUMBER_TAG || tag2 === STRING_TAG) {
2016
- return arePrimitiveWrappersEqual2(a2, b, state);
1987
+ const tag = toString$2.call(a2);
1988
+ const supportedComparator = supportedComparatorMap[tag];
1989
+ if (supportedComparator) {
1990
+ return supportedComparator(a2, b, state);
2017
1991
  }
2018
- if (unknownTagComparators) {
2019
- var unknownTagComparator = unknownTagComparators[tag2];
2020
- if (!unknownTagComparator) {
2021
- var shortTag = getShortTag(a2);
2022
- if (shortTag) {
2023
- unknownTagComparator = unknownTagComparators[shortTag];
2024
- }
2025
- }
2026
- if (unknownTagComparator) {
2027
- return unknownTagComparator(a2, b, state);
2028
- }
1992
+ const unsupportedCustomComparator = getUnsupportedCustomComparator && getUnsupportedCustomComparator(a2, b, state, tag);
1993
+ if (unsupportedCustomComparator) {
1994
+ return unsupportedCustomComparator(a2, b, state);
2029
1995
  }
2030
1996
  return false;
2031
1997
  };
2032
1998
  }
2033
- function createEqualityComparatorConfig(_a2) {
2034
- var circular = _a2.circular, createCustomConfig = _a2.createCustomConfig, strict = _a2.strict;
2035
- var config = {
1999
+ function createEqualityComparatorConfig({ circular, createCustomConfig, strict }) {
2000
+ let config = {
2001
+ areArrayBuffersEqual,
2036
2002
  areArraysEqual: strict ? areObjectsEqualStrict : areArraysEqual,
2003
+ areDataViewsEqual,
2037
2004
  areDatesEqual,
2038
2005
  areErrorsEqual,
2039
- areFunctionsEqual,
2006
+ areFunctionsEqual: strictEqual,
2040
2007
  areMapsEqual: strict ? combineComparators(areMapsEqual, areObjectsEqualStrict) : areMapsEqual,
2041
- areNumbersEqual,
2008
+ areNumbersEqual: sameValueEqual,
2042
2009
  areObjectsEqual: strict ? areObjectsEqualStrict : areObjectsEqual,
2043
2010
  arePrimitiveWrappersEqual,
2044
2011
  areRegExpsEqual,
2045
2012
  areSetsEqual: strict ? combineComparators(areSetsEqual, areObjectsEqualStrict) : areSetsEqual,
2046
- areTypedArraysEqual: strict ? areObjectsEqualStrict : areTypedArraysEqual,
2013
+ areTypedArraysEqual: strict ? combineComparators(areTypedArraysEqual, areObjectsEqualStrict) : areTypedArraysEqual,
2047
2014
  areUrlsEqual,
2048
- unknownTagComparators: void 0
2015
+ getUnsupportedCustomComparator: void 0
2049
2016
  };
2050
2017
  if (createCustomConfig) {
2051
- config = assign$1({}, config, createCustomConfig(config));
2018
+ config = Object.assign({}, config, createCustomConfig(config));
2052
2019
  }
2053
2020
  if (circular) {
2054
- var areArraysEqual$1 = createIsCircular(config.areArraysEqual);
2055
- var areMapsEqual$1 = createIsCircular(config.areMapsEqual);
2056
- var areObjectsEqual$1 = createIsCircular(config.areObjectsEqual);
2057
- var areSetsEqual$1 = createIsCircular(config.areSetsEqual);
2058
- config = assign$1({}, config, {
2059
- areArraysEqual: areArraysEqual$1,
2060
- areMapsEqual: areMapsEqual$1,
2061
- areObjectsEqual: areObjectsEqual$1,
2062
- areSetsEqual: areSetsEqual$1
2021
+ const areArraysEqual2 = createIsCircular(config.areArraysEqual);
2022
+ const areMapsEqual2 = createIsCircular(config.areMapsEqual);
2023
+ const areObjectsEqual2 = createIsCircular(config.areObjectsEqual);
2024
+ const areSetsEqual2 = createIsCircular(config.areSetsEqual);
2025
+ config = Object.assign({}, config, {
2026
+ areArraysEqual: areArraysEqual2,
2027
+ areMapsEqual: areMapsEqual2,
2028
+ areObjectsEqual: areObjectsEqual2,
2029
+ areSetsEqual: areSetsEqual2
2063
2030
  });
2064
2031
  }
2065
2032
  return config;
@@ -2069,13 +2036,12 @@ function createInternalEqualityComparator(compare2) {
2069
2036
  return compare2(a2, b, state);
2070
2037
  };
2071
2038
  }
2072
- function createIsEqual(_a2) {
2073
- var circular = _a2.circular, comparator2 = _a2.comparator, createState = _a2.createState, equals = _a2.equals, strict = _a2.strict;
2039
+ function createIsEqual({ circular, comparator: comparator2, createState, equals, strict }) {
2074
2040
  if (createState) {
2075
2041
  return function isEqual(a2, b) {
2076
- var _a3 = createState(), _b2 = _a3.cache, cache2 = _b2 === void 0 ? circular ? /* @__PURE__ */ new WeakMap() : void 0 : _b2, meta = _a3.meta;
2042
+ const { cache = circular ? /* @__PURE__ */ new WeakMap() : void 0, meta } = createState();
2077
2043
  return comparator2(a2, b, {
2078
- cache: cache2,
2044
+ cache,
2079
2045
  equals,
2080
2046
  meta,
2081
2047
  strict
@@ -2092,7 +2058,7 @@ function createIsEqual(_a2) {
2092
2058
  });
2093
2059
  };
2094
2060
  }
2095
- var state = {
2061
+ const state = {
2096
2062
  cache: void 0,
2097
2063
  equals,
2098
2064
  meta: void 0,
@@ -2102,7 +2068,50 @@ function createIsEqual(_a2) {
2102
2068
  return comparator2(a2, b, state);
2103
2069
  };
2104
2070
  }
2105
- var deepEqual = createCustomEqual();
2071
+ function createSupportedComparatorMap({ areArrayBuffersEqual: areArrayBuffersEqual2, areArraysEqual: areArraysEqual2, areDataViewsEqual: areDataViewsEqual2, areDatesEqual: areDatesEqual2, areErrorsEqual: areErrorsEqual2, areFunctionsEqual, areMapsEqual: areMapsEqual2, areNumbersEqual, areObjectsEqual: areObjectsEqual2, arePrimitiveWrappersEqual: arePrimitiveWrappersEqual2, areRegExpsEqual: areRegExpsEqual2, areSetsEqual: areSetsEqual2, areTypedArraysEqual: areTypedArraysEqual2, areUrlsEqual: areUrlsEqual2 }) {
2072
+ return {
2073
+ "[object Arguments]": areObjectsEqual2,
2074
+ "[object Array]": areArraysEqual2,
2075
+ "[object ArrayBuffer]": areArrayBuffersEqual2,
2076
+ "[object AsyncGeneratorFunction]": areFunctionsEqual,
2077
+ "[object BigInt]": areNumbersEqual,
2078
+ "[object BigInt64Array]": areTypedArraysEqual2,
2079
+ "[object BigUint64Array]": areTypedArraysEqual2,
2080
+ "[object Boolean]": arePrimitiveWrappersEqual2,
2081
+ "[object DataView]": areDataViewsEqual2,
2082
+ "[object Date]": areDatesEqual2,
2083
+ // If an error tag, it should be tested explicitly. Like RegExp, the properties are not
2084
+ // enumerable, and therefore will give false positives if tested like a standard object.
2085
+ "[object Error]": areErrorsEqual2,
2086
+ "[object Float16Array]": areTypedArraysEqual2,
2087
+ "[object Float32Array]": areTypedArraysEqual2,
2088
+ "[object Float64Array]": areTypedArraysEqual2,
2089
+ "[object Function]": areFunctionsEqual,
2090
+ "[object GeneratorFunction]": areFunctionsEqual,
2091
+ "[object Int8Array]": areTypedArraysEqual2,
2092
+ "[object Int16Array]": areTypedArraysEqual2,
2093
+ "[object Int32Array]": areTypedArraysEqual2,
2094
+ "[object Map]": areMapsEqual2,
2095
+ "[object Number]": arePrimitiveWrappersEqual2,
2096
+ "[object Object]": (a2, b, state) => (
2097
+ // The exception for value comparison is custom `Promise`-like class instances. These should
2098
+ // be treated the same as standard `Promise` objects, which means strict equality, and if
2099
+ // it reaches this point then that strict equality comparison has already failed.
2100
+ typeof a2.then !== "function" && typeof b.then !== "function" && areObjectsEqual2(a2, b, state)
2101
+ ),
2102
+ // For RegExp, the properties are not enumerable, and therefore will give false positives if
2103
+ // tested like a standard object.
2104
+ "[object RegExp]": areRegExpsEqual2,
2105
+ "[object Set]": areSetsEqual2,
2106
+ "[object String]": arePrimitiveWrappersEqual2,
2107
+ "[object URL]": areUrlsEqual2,
2108
+ "[object Uint8Array]": areTypedArraysEqual2,
2109
+ "[object Uint8ClampedArray]": areTypedArraysEqual2,
2110
+ "[object Uint16Array]": areTypedArraysEqual2,
2111
+ "[object Uint32Array]": areTypedArraysEqual2
2112
+ };
2113
+ }
2114
+ const deepEqual = createCustomEqual();
2106
2115
  createCustomEqual({ strict: true });
2107
2116
  createCustomEqual({ circular: true });
2108
2117
  createCustomEqual({
@@ -2110,37 +2119,26 @@ createCustomEqual({
2110
2119
  strict: true
2111
2120
  });
2112
2121
  createCustomEqual({
2113
- createInternalComparator: function() {
2114
- return sameValueZeroEqual;
2115
- }
2122
+ createInternalComparator: () => sameValueEqual
2116
2123
  });
2117
2124
  createCustomEqual({
2118
2125
  strict: true,
2119
- createInternalComparator: function() {
2120
- return sameValueZeroEqual;
2121
- }
2126
+ createInternalComparator: () => sameValueEqual
2122
2127
  });
2123
2128
  createCustomEqual({
2124
2129
  circular: true,
2125
- createInternalComparator: function() {
2126
- return sameValueZeroEqual;
2127
- }
2130
+ createInternalComparator: () => sameValueEqual
2128
2131
  });
2129
2132
  createCustomEqual({
2130
2133
  circular: true,
2131
- createInternalComparator: function() {
2132
- return sameValueZeroEqual;
2133
- },
2134
+ createInternalComparator: () => sameValueEqual,
2134
2135
  strict: true
2135
2136
  });
2136
- function createCustomEqual(options2) {
2137
- if (options2 === void 0) {
2138
- options2 = {};
2139
- }
2140
- var _a2 = options2.circular, circular = _a2 === void 0 ? false : _a2, createCustomInternalComparator = options2.createInternalComparator, createState = options2.createState, _b2 = options2.strict, strict = _b2 === void 0 ? false : _b2;
2141
- var config = createEqualityComparatorConfig(options2);
2142
- var comparator2 = createEqualityComparator(config);
2143
- var equals = createCustomInternalComparator ? createCustomInternalComparator(comparator2) : createInternalEqualityComparator(comparator2);
2137
+ function createCustomEqual(options2 = {}) {
2138
+ const { circular = false, createInternalComparator: createCustomInternalComparator, createState, strict = false } = options2;
2139
+ const config = createEqualityComparatorConfig(options2);
2140
+ const comparator2 = createEqualityComparator(config);
2141
+ const equals = createCustomInternalComparator ? createCustomInternalComparator(comparator2) : createInternalEqualityComparator(comparator2);
2144
2142
  return createIsEqual({ circular, comparator: comparator2, createState, equals, strict });
2145
2143
  }
2146
2144
  function listCacheClear$1() {
@@ -2254,7 +2252,7 @@ var hasOwnProperty$c = objectProto$j.hasOwnProperty;
2254
2252
  var nativeObjectToString$1 = objectProto$j.toString;
2255
2253
  var symToStringTag$1 = Symbol$3 ? Symbol$3.toStringTag : void 0;
2256
2254
  function getRawTag$1(value) {
2257
- var isOwn = hasOwnProperty$c.call(value, symToStringTag$1), tag2 = value[symToStringTag$1];
2255
+ var isOwn = hasOwnProperty$c.call(value, symToStringTag$1), tag = value[symToStringTag$1];
2258
2256
  try {
2259
2257
  value[symToStringTag$1] = void 0;
2260
2258
  var unmasked = true;
@@ -2263,7 +2261,7 @@ function getRawTag$1(value) {
2263
2261
  var result = nativeObjectToString$1.call(value);
2264
2262
  if (unmasked) {
2265
2263
  if (isOwn) {
2266
- value[symToStringTag$1] = tag2;
2264
+ value[symToStringTag$1] = tag;
2267
2265
  } else {
2268
2266
  delete value[symToStringTag$1];
2269
2267
  }
@@ -2287,19 +2285,19 @@ function baseGetTag$4(value) {
2287
2285
  return symToStringTag && symToStringTag in Object(value) ? getRawTag(value) : objectToString$7(value);
2288
2286
  }
2289
2287
  var _baseGetTag = baseGetTag$4;
2290
- function isObject$a(value) {
2288
+ function isObject$9(value) {
2291
2289
  var type = typeof value;
2292
2290
  return value != null && (type == "object" || type == "function");
2293
2291
  }
2294
- var isObject_1 = isObject$a;
2295
- var baseGetTag$3 = _baseGetTag, isObject$9 = isObject_1;
2292
+ var isObject_1 = isObject$9;
2293
+ var baseGetTag$3 = _baseGetTag, isObject$8 = isObject_1;
2296
2294
  var asyncTag = "[object AsyncFunction]", funcTag$3 = "[object Function]", genTag$2 = "[object GeneratorFunction]", proxyTag = "[object Proxy]";
2297
2295
  function isFunction$3(value) {
2298
- if (!isObject$9(value)) {
2296
+ if (!isObject$8(value)) {
2299
2297
  return false;
2300
2298
  }
2301
- var tag2 = baseGetTag$3(value);
2302
- return tag2 == funcTag$3 || tag2 == genTag$2 || tag2 == asyncTag || tag2 == proxyTag;
2299
+ var tag = baseGetTag$3(value);
2300
+ return tag == funcTag$3 || tag == genTag$2 || tag == asyncTag || tag == proxyTag;
2303
2301
  }
2304
2302
  var isFunction_1 = isFunction$3;
2305
2303
  var root$6 = _root;
@@ -2330,7 +2328,7 @@ function toSource$2(func) {
2330
2328
  return "";
2331
2329
  }
2332
2330
  var _toSource = toSource$2;
2333
- var isFunction$2 = isFunction_1, isMasked = _isMasked, isObject$8 = isObject_1, toSource$1 = _toSource;
2331
+ var isFunction$2 = isFunction_1, isMasked = _isMasked, isObject$7 = isObject_1, toSource$1 = _toSource;
2334
2332
  var reRegExpChar = /[\\^$.*+?()[\]{}|]/g;
2335
2333
  var reIsHostCtor = /^\[object .+?Constructor\]$/;
2336
2334
  var funcProto$1 = Function.prototype, objectProto$h = Object.prototype;
@@ -2340,7 +2338,7 @@ var reIsNative = RegExp(
2340
2338
  "^" + funcToString$1.call(hasOwnProperty$b).replace(reRegExpChar, "\\$&").replace(/hasOwnProperty|(function).*?(?=\\\()| for .+?(?=\\\])/g, "$1.*?") + "$"
2341
2339
  );
2342
2340
  function baseIsNative$1(value) {
2343
- if (!isObject$8(value) || isMasked(value)) {
2341
+ if (!isObject$7(value) || isMasked(value)) {
2344
2342
  return false;
2345
2343
  }
2346
2344
  var pattern = isFunction$2(value) ? reIsNative : reIsHostCtor;
@@ -2582,24 +2580,24 @@ function baseTimes$2(n, iteratee) {
2582
2580
  return result;
2583
2581
  }
2584
2582
  var _baseTimes = baseTimes$2;
2585
- function isObjectLike$e(value) {
2583
+ function isObjectLike$d(value) {
2586
2584
  return value != null && typeof value == "object";
2587
2585
  }
2588
- var isObjectLike_1 = isObjectLike$e;
2589
- var baseGetTag$2 = _baseGetTag, isObjectLike$d = isObjectLike_1;
2586
+ var isObjectLike_1 = isObjectLike$d;
2587
+ var baseGetTag$2 = _baseGetTag, isObjectLike$c = isObjectLike_1;
2590
2588
  var argsTag$3 = "[object Arguments]";
2591
2589
  function baseIsArguments$1(value) {
2592
- return isObjectLike$d(value) && baseGetTag$2(value) == argsTag$3;
2590
+ return isObjectLike$c(value) && baseGetTag$2(value) == argsTag$3;
2593
2591
  }
2594
2592
  var _baseIsArguments = baseIsArguments$1;
2595
- var baseIsArguments = _baseIsArguments, isObjectLike$c = isObjectLike_1;
2593
+ var baseIsArguments = _baseIsArguments, isObjectLike$b = isObjectLike_1;
2596
2594
  var objectProto$d = Object.prototype;
2597
2595
  var hasOwnProperty$7 = objectProto$d.hasOwnProperty;
2598
2596
  var propertyIsEnumerable$2 = objectProto$d.propertyIsEnumerable;
2599
2597
  var isArguments$2 = baseIsArguments(/* @__PURE__ */ function() {
2600
2598
  return arguments;
2601
2599
  }()) ? baseIsArguments : function(value) {
2602
- return isObjectLike$c(value) && hasOwnProperty$7.call(value, "callee") && !propertyIsEnumerable$2.call(value, "callee");
2600
+ return isObjectLike$b(value) && hasOwnProperty$7.call(value, "callee") && !propertyIsEnumerable$2.call(value, "callee");
2603
2601
  };
2604
2602
  var isArguments_1 = isArguments$2;
2605
2603
  var isArray$6 = Array.isArray;
@@ -2634,14 +2632,14 @@ function isLength$3(value) {
2634
2632
  return typeof value == "number" && value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER$3;
2635
2633
  }
2636
2634
  var isLength_1 = isLength$3;
2637
- var baseGetTag$1 = _baseGetTag, isLength$2 = isLength_1, isObjectLike$b = isObjectLike_1;
2635
+ var baseGetTag$1 = _baseGetTag, isLength$2 = isLength_1, isObjectLike$a = isObjectLike_1;
2638
2636
  var argsTag$2 = "[object Arguments]", arrayTag$1 = "[object Array]", boolTag$3 = "[object Boolean]", dateTag$2 = "[object Date]", errorTag$1 = "[object Error]", funcTag$2 = "[object Function]", mapTag$4 = "[object Map]", numberTag$3 = "[object Number]", objectTag$3 = "[object Object]", regexpTag$2 = "[object RegExp]", setTag$4 = "[object Set]", stringTag$4 = "[object String]", weakMapTag$2 = "[object WeakMap]";
2639
2637
  var arrayBufferTag$2 = "[object ArrayBuffer]", dataViewTag$3 = "[object DataView]", float32Tag$2 = "[object Float32Array]", float64Tag$2 = "[object Float64Array]", int8Tag$2 = "[object Int8Array]", int16Tag$2 = "[object Int16Array]", int32Tag$2 = "[object Int32Array]", uint8Tag$2 = "[object Uint8Array]", uint8ClampedTag$2 = "[object Uint8ClampedArray]", uint16Tag$2 = "[object Uint16Array]", uint32Tag$2 = "[object Uint32Array]";
2640
2638
  var typedArrayTags = {};
2641
2639
  typedArrayTags[float32Tag$2] = typedArrayTags[float64Tag$2] = typedArrayTags[int8Tag$2] = typedArrayTags[int16Tag$2] = typedArrayTags[int32Tag$2] = typedArrayTags[uint8Tag$2] = typedArrayTags[uint8ClampedTag$2] = typedArrayTags[uint16Tag$2] = typedArrayTags[uint32Tag$2] = true;
2642
2640
  typedArrayTags[argsTag$2] = typedArrayTags[arrayTag$1] = typedArrayTags[arrayBufferTag$2] = typedArrayTags[boolTag$3] = typedArrayTags[dataViewTag$3] = typedArrayTags[dateTag$2] = typedArrayTags[errorTag$1] = typedArrayTags[funcTag$2] = typedArrayTags[mapTag$4] = typedArrayTags[numberTag$3] = typedArrayTags[objectTag$3] = typedArrayTags[regexpTag$2] = typedArrayTags[setTag$4] = typedArrayTags[stringTag$4] = typedArrayTags[weakMapTag$2] = false;
2643
2641
  function baseIsTypedArray$1(value) {
2644
- return isObjectLike$b(value) && isLength$2(value.length) && !!typedArrayTags[baseGetTag$1(value)];
2642
+ return isObjectLike$a(value) && isLength$2(value.length) && !!typedArrayTags[baseGetTag$1(value)];
2645
2643
  }
2646
2644
  var _baseIsTypedArray = baseIsTypedArray$1;
2647
2645
  function baseUnary$3(func) {
@@ -2748,11 +2746,11 @@ function nativeKeysIn$1(object) {
2748
2746
  return result;
2749
2747
  }
2750
2748
  var _nativeKeysIn = nativeKeysIn$1;
2751
- var isObject$7 = isObject_1, isPrototype$2 = _isPrototype, nativeKeysIn = _nativeKeysIn;
2749
+ var isObject$6 = isObject_1, isPrototype$2 = _isPrototype, nativeKeysIn = _nativeKeysIn;
2752
2750
  var objectProto$9 = Object.prototype;
2753
2751
  var hasOwnProperty$4 = objectProto$9.hasOwnProperty;
2754
2752
  function baseKeysIn$1(object) {
2755
- if (!isObject$7(object)) {
2753
+ if (!isObject$6(object)) {
2756
2754
  return nativeKeysIn(object);
2757
2755
  }
2758
2756
  var isProto = isPrototype$2(object), result = [];
@@ -2966,9 +2964,9 @@ var _cloneTypedArray = cloneTypedArray$1;
2966
2964
  var cloneArrayBuffer = _cloneArrayBuffer, cloneDataView = _cloneDataView, cloneRegExp = _cloneRegExp, cloneSymbol = _cloneSymbol, cloneTypedArray = _cloneTypedArray;
2967
2965
  var boolTag$2 = "[object Boolean]", dateTag$1 = "[object Date]", mapTag$2 = "[object Map]", numberTag$2 = "[object Number]", regexpTag$1 = "[object RegExp]", setTag$2 = "[object Set]", stringTag$3 = "[object String]", symbolTag$4 = "[object Symbol]";
2968
2966
  var arrayBufferTag$1 = "[object ArrayBuffer]", dataViewTag$1 = "[object DataView]", float32Tag$1 = "[object Float32Array]", float64Tag$1 = "[object Float64Array]", int8Tag$1 = "[object Int8Array]", int16Tag$1 = "[object Int16Array]", int32Tag$1 = "[object Int32Array]", uint8Tag$1 = "[object Uint8Array]", uint8ClampedTag$1 = "[object Uint8ClampedArray]", uint16Tag$1 = "[object Uint16Array]", uint32Tag$1 = "[object Uint32Array]";
2969
- function initCloneByTag$1(object, tag2, isDeep) {
2967
+ function initCloneByTag$1(object, tag, isDeep) {
2970
2968
  var Ctor = object.constructor;
2971
- switch (tag2) {
2969
+ switch (tag) {
2972
2970
  case arrayBufferTag$1:
2973
2971
  return cloneArrayBuffer(object);
2974
2972
  case boolTag$2:
@@ -3000,13 +2998,13 @@ function initCloneByTag$1(object, tag2, isDeep) {
3000
2998
  }
3001
2999
  }
3002
3000
  var _initCloneByTag = initCloneByTag$1;
3003
- var isObject$6 = isObject_1;
3001
+ var isObject$5 = isObject_1;
3004
3002
  var objectCreate = Object.create;
3005
3003
  var baseCreate$1 = /* @__PURE__ */ function() {
3006
3004
  function object() {
3007
3005
  }
3008
3006
  return function(proto) {
3009
- if (!isObject$6(proto)) {
3007
+ if (!isObject$5(proto)) {
3010
3008
  return {};
3011
3009
  }
3012
3010
  if (objectCreate) {
@@ -3024,27 +3022,27 @@ function initCloneObject$1(object) {
3024
3022
  return typeof object.constructor == "function" && !isPrototype$1(object) ? baseCreate(getPrototype$1(object)) : {};
3025
3023
  }
3026
3024
  var _initCloneObject = initCloneObject$1;
3027
- var getTag$2 = _getTag, isObjectLike$a = isObjectLike_1;
3025
+ var getTag$2 = _getTag, isObjectLike$9 = isObjectLike_1;
3028
3026
  var mapTag$1 = "[object Map]";
3029
3027
  function baseIsMap$1(value) {
3030
- return isObjectLike$a(value) && getTag$2(value) == mapTag$1;
3028
+ return isObjectLike$9(value) && getTag$2(value) == mapTag$1;
3031
3029
  }
3032
3030
  var _baseIsMap = baseIsMap$1;
3033
3031
  var baseIsMap = _baseIsMap, baseUnary$1 = _baseUnary, nodeUtil$1 = _nodeUtilExports;
3034
3032
  var nodeIsMap = nodeUtil$1 && nodeUtil$1.isMap;
3035
3033
  var isMap$1 = nodeIsMap ? baseUnary$1(nodeIsMap) : baseIsMap;
3036
3034
  var isMap_1 = isMap$1;
3037
- var getTag$1 = _getTag, isObjectLike$9 = isObjectLike_1;
3035
+ var getTag$1 = _getTag, isObjectLike$8 = isObjectLike_1;
3038
3036
  var setTag$1 = "[object Set]";
3039
3037
  function baseIsSet$1(value) {
3040
- return isObjectLike$9(value) && getTag$1(value) == setTag$1;
3038
+ return isObjectLike$8(value) && getTag$1(value) == setTag$1;
3041
3039
  }
3042
3040
  var _baseIsSet = baseIsSet$1;
3043
3041
  var baseIsSet = _baseIsSet, baseUnary = _baseUnary, nodeUtil = _nodeUtilExports;
3044
3042
  var nodeIsSet = nodeUtil && nodeUtil.isSet;
3045
3043
  var isSet$1 = nodeIsSet ? baseUnary(nodeIsSet) : baseIsSet;
3046
3044
  var isSet_1 = isSet$1;
3047
- var Stack = _Stack, arrayEach = _arrayEach, assignValue = _assignValue, baseAssign = _baseAssign, baseAssignIn = _baseAssignIn, cloneBuffer = _cloneBufferExports, copyArray = _copyArray, copySymbols = _copySymbols, copySymbolsIn = _copySymbolsIn, getAllKeys = _getAllKeys, getAllKeysIn = _getAllKeysIn, getTag = _getTag, initCloneArray = _initCloneArray, initCloneByTag = _initCloneByTag, initCloneObject = _initCloneObject, isArray$3 = isArray_1, isBuffer = isBufferExports, isMap = isMap_1, isObject$5 = isObject_1, isSet = isSet_1, keys$1 = keys_1, keysIn = keysIn_1;
3045
+ var Stack = _Stack, arrayEach = _arrayEach, assignValue = _assignValue, baseAssign = _baseAssign, baseAssignIn = _baseAssignIn, cloneBuffer = _cloneBufferExports, copyArray = _copyArray, copySymbols = _copySymbols, copySymbolsIn = _copySymbolsIn, getAllKeys = _getAllKeys, getAllKeysIn = _getAllKeysIn, getTag = _getTag, initCloneArray = _initCloneArray, initCloneByTag = _initCloneByTag, initCloneObject = _initCloneObject, isArray$3 = isArray_1, isBuffer = isBufferExports, isMap = isMap_1, isObject$4 = isObject_1, isSet = isSet_1, keys$1 = keys_1, keysIn = keysIn_1;
3048
3046
  var CLONE_DEEP_FLAG$1 = 1, CLONE_FLAT_FLAG = 2, CLONE_SYMBOLS_FLAG$1 = 4;
3049
3047
  var argsTag$1 = "[object Arguments]", arrayTag = "[object Array]", boolTag$1 = "[object Boolean]", dateTag = "[object Date]", errorTag = "[object Error]", funcTag$1 = "[object Function]", genTag$1 = "[object GeneratorFunction]", mapTag = "[object Map]", numberTag$1 = "[object Number]", objectTag$1 = "[object Object]", regexpTag = "[object RegExp]", setTag = "[object Set]", stringTag$2 = "[object String]", symbolTag$3 = "[object Symbol]", weakMapTag = "[object WeakMap]";
3050
3048
  var arrayBufferTag = "[object ArrayBuffer]", dataViewTag = "[object DataView]", float32Tag = "[object Float32Array]", float64Tag = "[object Float64Array]", int8Tag = "[object Int8Array]", int16Tag = "[object Int16Array]", int32Tag = "[object Int32Array]", uint8Tag = "[object Uint8Array]", uint8ClampedTag = "[object Uint8ClampedArray]", uint16Tag = "[object Uint16Array]", uint32Tag = "[object Uint32Array]";
@@ -3059,7 +3057,7 @@ function baseClone$1(value, bitmask, customizer, key, object, stack) {
3059
3057
  if (result !== void 0) {
3060
3058
  return result;
3061
3059
  }
3062
- if (!isObject$5(value)) {
3060
+ if (!isObject$4(value)) {
3063
3061
  return value;
3064
3062
  }
3065
3063
  var isArr = isArray$3(value);
@@ -3069,20 +3067,20 @@ function baseClone$1(value, bitmask, customizer, key, object, stack) {
3069
3067
  return copyArray(value, result);
3070
3068
  }
3071
3069
  } else {
3072
- var tag2 = getTag(value), isFunc = tag2 == funcTag$1 || tag2 == genTag$1;
3070
+ var tag = getTag(value), isFunc = tag == funcTag$1 || tag == genTag$1;
3073
3071
  if (isBuffer(value)) {
3074
3072
  return cloneBuffer(value, isDeep);
3075
3073
  }
3076
- if (tag2 == objectTag$1 || tag2 == argsTag$1 || isFunc && !object) {
3074
+ if (tag == objectTag$1 || tag == argsTag$1 || isFunc && !object) {
3077
3075
  result = isFlat || isFunc ? {} : initCloneObject(value);
3078
3076
  if (!isDeep) {
3079
3077
  return isFlat ? copySymbolsIn(value, baseAssignIn(result, value)) : copySymbols(value, baseAssign(result, value));
3080
3078
  }
3081
3079
  } else {
3082
- if (!cloneableTags[tag2]) {
3080
+ if (!cloneableTags[tag]) {
3083
3081
  return object ? value : {};
3084
3082
  }
3085
- result = initCloneByTag(value, tag2, isDeep);
3083
+ result = initCloneByTag(value, tag, isDeep);
3086
3084
  }
3087
3085
  }
3088
3086
  stack || (stack = new Stack());
@@ -3390,7 +3388,10 @@ class CollectionRegistry {
3390
3388
  if (!relation) {
3391
3389
  throw new Error(`Relation '${relationKey}' not found in collection '${currentCollection.slug}'`);
3392
3390
  }
3393
- currentCollection = relation.target();
3391
+ const target = relation.target();
3392
+ const targetRelationKey = relation.relationName || target.slug;
3393
+ const targetSlug = relation.overrides?.slug ?? targetRelationKey;
3394
+ currentCollection = this.get(targetSlug) || this.normalizeCollection(target);
3394
3395
  if (i + 1 < pathSegments.length) ;
3395
3396
  }
3396
3397
  return currentCollection;
@@ -3439,7 +3440,7 @@ class CollectionRegistry {
3439
3440
  if (!subcollection) {
3440
3441
  throw new Error(`Subcollection '${subcollectionSlug}' not found in ${currentCollection.slug}`);
3441
3442
  }
3442
- currentCollection = subcollection;
3443
+ currentCollection = this.get(subcollection.slug) || this.normalizeCollection(subcollection);
3443
3444
  collections.push(currentCollection);
3444
3445
  }
3445
3446
  }
@@ -3474,16 +3475,15 @@ async function loadCollectionsFromDirectory(directory) {
3474
3475
  const filePath = path$3.join(directory, file);
3475
3476
  try {
3476
3477
  const fileUrl = pathToFileURL(filePath).href;
3477
- const dynamicImport = new Function("url", "return import(url)");
3478
- const module = await dynamicImport(fileUrl);
3478
+ const module = await import(fileUrl);
3479
3479
  if (module && module.default) {
3480
3480
  collections.push(module.default);
3481
3481
  } else {
3482
3482
  console.warn(`[loadCollectionsFromDirectory] File ${file} does not have a default export. Skipping.`);
3483
3483
  }
3484
3484
  } catch (err) {
3485
- const message2 = err instanceof Error ? err.message : String(err);
3486
- console.error(`[loadCollectionsFromDirectory] Failed to load collection from ${file}: ${message2}`);
3485
+ const message = err instanceof Error ? err.message : String(err);
3486
+ console.error(`[loadCollectionsFromDirectory] Failed to load collection from ${file}: ${message}`);
3487
3487
  }
3488
3488
  }
3489
3489
  }
@@ -3566,34 +3566,34 @@ class ApiError extends Error {
3566
3566
  statusCode;
3567
3567
  code;
3568
3568
  details;
3569
- constructor(statusCode, code2, message2, details) {
3570
- super(message2);
3569
+ constructor(statusCode, code2, message, details) {
3570
+ super(message);
3571
3571
  this.name = "ApiError";
3572
3572
  this.statusCode = statusCode;
3573
3573
  this.code = code2;
3574
3574
  this.details = details;
3575
3575
  }
3576
3576
  // ── Factory methods ──────────────────────────────────────────────
3577
- static badRequest(message2, code2 = "BAD_REQUEST", details) {
3578
- return new ApiError(400, code2, message2, details);
3577
+ static badRequest(message, code2 = "BAD_REQUEST", details) {
3578
+ return new ApiError(400, code2, message, details);
3579
3579
  }
3580
- static unauthorized(message2, code2 = "UNAUTHORIZED") {
3581
- return new ApiError(401, code2, message2);
3580
+ static unauthorized(message, code2 = "UNAUTHORIZED") {
3581
+ return new ApiError(401, code2, message);
3582
3582
  }
3583
- static forbidden(message2, code2 = "FORBIDDEN") {
3584
- return new ApiError(403, code2, message2);
3583
+ static forbidden(message, code2 = "FORBIDDEN") {
3584
+ return new ApiError(403, code2, message);
3585
3585
  }
3586
- static notFound(message2, code2 = "NOT_FOUND") {
3587
- return new ApiError(404, code2, message2);
3586
+ static notFound(message, code2 = "NOT_FOUND") {
3587
+ return new ApiError(404, code2, message);
3588
3588
  }
3589
- static conflict(message2, code2 = "CONFLICT") {
3590
- return new ApiError(409, code2, message2);
3589
+ static conflict(message, code2 = "CONFLICT") {
3590
+ return new ApiError(409, code2, message);
3591
3591
  }
3592
- static internal(message2, code2 = "INTERNAL_ERROR") {
3593
- return new ApiError(500, code2, message2);
3592
+ static internal(message, code2 = "INTERNAL_ERROR") {
3593
+ return new ApiError(500, code2, message);
3594
3594
  }
3595
- static serviceUnavailable(message2, code2 = "SERVICE_UNAVAILABLE") {
3596
- return new ApiError(503, code2, message2);
3595
+ static serviceUnavailable(message, code2 = "SERVICE_UNAVAILABLE") {
3596
+ return new ApiError(503, code2, message);
3597
3597
  }
3598
3598
  }
3599
3599
  const errorHandler = (err, c) => {
@@ -3633,7 +3633,8 @@ const errorHandler = (err, c) => {
3633
3633
  console.error(`❌ [API] ${c.req.method} ${c.req.path} → ${statusCode} ${code2}: ${logMessage}`);
3634
3634
  const causePg = error2.cause && typeof error2.cause === "object" ? error2.cause : void 0;
3635
3635
  const pgErrorCode = causePg?.code || error2.code;
3636
- if (pgErrorCode !== "42703" && pgErrorCode !== "42P01") {
3636
+ const suppressStack = pgErrorCode === "42703" || pgErrorCode === "42P01" || statusCode < 500 && code2 === "BAD_REQUEST";
3637
+ if (!suppressStack) {
3637
3638
  console.error(error2.stack || error2);
3638
3639
  }
3639
3640
  let clientMessage = "An unexpected error occurred";
@@ -3721,8 +3722,8 @@ function parseQueryOptions(query) {
3721
3722
  }
3722
3723
  Object.assign(options2.where, parsedWhere);
3723
3724
  } catch (e) {
3724
- const message2 = e instanceof Error ? e.message : "malformed JSON";
3725
- const err = new Error(`Invalid 'where' filter: ${message2}`);
3725
+ const message = e instanceof Error ? e.message : "malformed JSON";
3726
+ const err = new Error(`Invalid 'where' filter: ${message}`);
3726
3727
  err.code = "BAD_REQUEST";
3727
3728
  err.statusCode = 400;
3728
3729
  throw err;
@@ -3806,11 +3807,24 @@ class RestApiGenerator {
3806
3807
  collections;
3807
3808
  router;
3808
3809
  driver;
3809
- constructor(collections, driver) {
3810
+ dataHooks;
3811
+ constructor(collections, driver, dataHooks) {
3810
3812
  this.collections = collections;
3811
3813
  this.driver = driver;
3814
+ this.dataHooks = dataHooks;
3812
3815
  this.router = new Hono();
3813
3816
  }
3817
+ /** Build a BackendHookContext from a Hono context */
3818
+ buildHookContext(c, method) {
3819
+ const user = c.get("user");
3820
+ return {
3821
+ requestUser: user ? {
3822
+ userId: user.userId,
3823
+ roles: user.roles ?? []
3824
+ } : void 0,
3825
+ method
3826
+ };
3827
+ }
3814
3828
  /**
3815
3829
  * Generate REST routes using existing DataDriver
3816
3830
  */
@@ -3822,16 +3836,10 @@ class RestApiGenerator {
3822
3836
  return this.router;
3823
3837
  }
3824
3838
  /**
3825
- * Get the EntityFetchService from a driver if it exposes one (for include support)
3839
+ * Get the typed RestFetchService from a driver if it exposes one (for include support).
3826
3840
  */
3827
3841
  getFetchService(driver) {
3828
- if ("entityService" in driver && typeof driver.entityService === "object" && driver.entityService) {
3829
- const es = driver.entityService;
3830
- if (typeof es.getFetchService === "function") {
3831
- return es.getFetchService();
3832
- }
3833
- }
3834
- return null;
3842
+ return driver.restFetchService;
3835
3843
  }
3836
3844
  /**
3837
3845
  * Create REST routes for a collection using existing Rebase patterns
@@ -3839,15 +3847,26 @@ class RestApiGenerator {
3839
3847
  createCollectionRoutes(collection) {
3840
3848
  const basePath = `/${collection.slug}`;
3841
3849
  const resolvedCollection = collection;
3850
+ this.router.get(`${basePath}/count`, async (c) => {
3851
+ const queryDict = c.req.query();
3852
+ const queryOptions = parseQueryOptions(queryDict);
3853
+ const searchString = queryDict.searchString;
3854
+ const driver = c.get("driver") || this.driver;
3855
+ const total = await this.countRawEntities(driver, resolvedCollection, queryOptions, searchString);
3856
+ return c.json({
3857
+ count: total
3858
+ });
3859
+ });
3842
3860
  this.router.get(basePath, async (c) => {
3843
3861
  const queryDict = c.req.query();
3844
3862
  const queryOptions = parseQueryOptions(queryDict);
3845
3863
  const searchString = queryDict.searchString;
3846
3864
  const driver = c.get("driver") || this.driver;
3847
3865
  const fetchService = this.getFetchService(driver);
3866
+ const hookCtx = this.buildHookContext(c, "GET");
3848
3867
  if (fetchService) {
3849
3868
  const collectionPath = collection.slug;
3850
- const entities2 = await fetchService.fetchCollectionForRest(collectionPath, {
3869
+ let entities2 = await fetchService.fetchCollectionForRest(collectionPath, {
3851
3870
  filter: queryOptions.where,
3852
3871
  limit: queryOptions.limit,
3853
3872
  offset: queryOptions.offset,
@@ -3855,6 +3874,7 @@ class RestApiGenerator {
3855
3874
  order: queryOptions.orderBy?.[0]?.direction === "desc" ? "desc" : "asc",
3856
3875
  searchString
3857
3876
  }, queryOptions.include);
3877
+ entities2 = await this.applyAfterReadBatch(collection.slug, entities2, hookCtx);
3858
3878
  const total2 = await this.countRawEntities(driver, resolvedCollection, queryOptions, searchString);
3859
3879
  return c.json({
3860
3880
  data: entities2,
@@ -3866,7 +3886,8 @@ class RestApiGenerator {
3866
3886
  }
3867
3887
  });
3868
3888
  }
3869
- const entities = await this.fetchRawCollection(driver, resolvedCollection, queryOptions, searchString);
3889
+ let entities = await this.fetchRawCollection(driver, resolvedCollection, queryOptions, searchString);
3890
+ entities = await this.applyAfterReadBatch(collection.slug, entities, hookCtx);
3870
3891
  const total = await this.countRawEntities(driver, resolvedCollection, queryOptions, searchString);
3871
3892
  return c.json({
3872
3893
  data: entities,
@@ -3884,15 +3905,24 @@ class RestApiGenerator {
3884
3905
  const queryOptions = parseQueryOptions(queryDict);
3885
3906
  const driver = c.get("driver") || this.driver;
3886
3907
  const fetchService = this.getFetchService(driver);
3908
+ const hookCtx = this.buildHookContext(c, "GET");
3887
3909
  if (fetchService) {
3888
3910
  const collectionPath = collection.slug;
3889
- const entity2 = await fetchService.fetchEntityForRest(collectionPath, String(id), queryOptions.include);
3911
+ let entity2 = await fetchService.fetchEntityForRest(collectionPath, String(id), queryOptions.include);
3912
+ if (!entity2) {
3913
+ throw ApiError.notFound("Entity not found");
3914
+ }
3915
+ entity2 = await this.applyAfterRead(collection.slug, entity2, hookCtx);
3890
3916
  if (!entity2) {
3891
3917
  throw ApiError.notFound("Entity not found");
3892
3918
  }
3893
3919
  return c.json(entity2);
3894
3920
  }
3895
- const entity = await this.fetchRawEntity(driver, resolvedCollection, String(id));
3921
+ let entity = await this.fetchRawEntity(driver, resolvedCollection, String(id));
3922
+ if (!entity) {
3923
+ throw ApiError.notFound("Entity not found");
3924
+ }
3925
+ entity = await this.applyAfterRead(collection.slug, entity, hookCtx);
3896
3926
  if (!entity) {
3897
3927
  throw ApiError.notFound("Entity not found");
3898
3928
  }
@@ -3902,14 +3932,24 @@ class RestApiGenerator {
3902
3932
  try {
3903
3933
  const driver = c.get("driver") || this.driver;
3904
3934
  const path2 = collection.slug;
3905
- const body = await c.req.json().catch(() => ({}));
3935
+ const hookCtx = this.buildHookContext(c, "POST");
3936
+ let body = await c.req.json().catch(() => ({}));
3937
+ if (this.dataHooks?.beforeSave) {
3938
+ body = await this.dataHooks.beforeSave(path2, body, void 0, hookCtx);
3939
+ }
3906
3940
  const entity = await driver.saveEntity({
3907
3941
  path: path2,
3908
3942
  values: body,
3909
3943
  collection: resolvedCollection,
3910
3944
  status: "new"
3911
3945
  });
3912
- return c.json(this.formatResponse(entity), 201);
3946
+ const response = this.formatResponse(entity);
3947
+ if (this.dataHooks?.afterSave) {
3948
+ Promise.resolve(this.dataHooks.afterSave(path2, response, hookCtx)).catch((err) => {
3949
+ console.error("[BackendHooks] data.afterSave error:", err instanceof Error ? err.message : err);
3950
+ });
3951
+ }
3952
+ return c.json(response, 201);
3913
3953
  } catch (error2) {
3914
3954
  const err = error2;
3915
3955
  err.code = err.code || "BAD_REQUEST";
@@ -3920,6 +3960,7 @@ class RestApiGenerator {
3920
3960
  try {
3921
3961
  const id = c.req.param("id");
3922
3962
  const driver = c.get("driver") || this.driver;
3963
+ const hookCtx = this.buildHookContext(c, "PUT");
3923
3964
  const existingEntity = await driver.fetchEntity({
3924
3965
  path: collection.slug,
3925
3966
  entityId: String(id),
@@ -3928,7 +3969,10 @@ class RestApiGenerator {
3928
3969
  if (!existingEntity) {
3929
3970
  throw ApiError.notFound("Entity not found");
3930
3971
  }
3931
- const body = await c.req.json().catch(() => ({}));
3972
+ let body = await c.req.json().catch(() => ({}));
3973
+ if (this.dataHooks?.beforeSave) {
3974
+ body = await this.dataHooks.beforeSave(collection.slug, body, String(id), hookCtx);
3975
+ }
3932
3976
  const entity = await driver.saveEntity({
3933
3977
  path: collection.slug,
3934
3978
  entityId: String(id),
@@ -3936,7 +3980,13 @@ class RestApiGenerator {
3936
3980
  collection: resolvedCollection,
3937
3981
  status: "existing"
3938
3982
  });
3939
- return c.json(this.formatResponse(entity));
3983
+ const response = this.formatResponse(entity);
3984
+ if (this.dataHooks?.afterSave) {
3985
+ Promise.resolve(this.dataHooks.afterSave(collection.slug, response, hookCtx)).catch((err) => {
3986
+ console.error("[BackendHooks] data.afterSave error:", err instanceof Error ? err.message : err);
3987
+ });
3988
+ }
3989
+ return c.json(response);
3940
3990
  } catch (error2) {
3941
3991
  const err = error2;
3942
3992
  err.code = err.code || "BAD_REQUEST";
@@ -3946,6 +3996,7 @@ class RestApiGenerator {
3946
3996
  this.router.delete(`${basePath}/:id`, async (c) => {
3947
3997
  const id = c.req.param("id");
3948
3998
  const driver = c.get("driver") || this.driver;
3999
+ const hookCtx = this.buildHookContext(c, "DELETE");
3949
4000
  const existingEntity = await driver.fetchEntity({
3950
4001
  path: collection.slug,
3951
4002
  entityId: String(id),
@@ -3954,10 +4005,18 @@ class RestApiGenerator {
3954
4005
  if (!existingEntity) {
3955
4006
  throw ApiError.notFound("Entity not found");
3956
4007
  }
4008
+ if (this.dataHooks?.beforeDelete) {
4009
+ await this.dataHooks.beforeDelete(collection.slug, String(id), hookCtx);
4010
+ }
3957
4011
  await driver.deleteEntity({
3958
4012
  entity: existingEntity,
3959
4013
  collection: resolvedCollection
3960
4014
  });
4015
+ if (this.dataHooks?.afterDelete) {
4016
+ Promise.resolve(this.dataHooks.afterDelete(collection.slug, String(id), hookCtx)).catch((err) => {
4017
+ console.error("[BackendHooks] data.afterDelete error:", err instanceof Error ? err.message : err);
4018
+ });
4019
+ }
3961
4020
  return new Response(null, {
3962
4021
  status: 204
3963
4022
  });
@@ -4006,7 +4065,18 @@ class RestApiGenerator {
4006
4065
  const parsed = parseSubPath(rawPath);
4007
4066
  if (!parsed) return next();
4008
4067
  const driver = c.get("driver") || this.driver;
4009
- if (parsed.entityId) {
4068
+ if (parsed.entityId === "count") {
4069
+ const queryDict = c.req.query();
4070
+ const queryOptions = parseQueryOptions(queryDict);
4071
+ const total = driver.countEntities ? await driver.countEntities({
4072
+ path: parsed.collectionPath,
4073
+ filter: queryOptions.where,
4074
+ searchString: queryDict.searchString
4075
+ }) : 0;
4076
+ return c.json({
4077
+ count: total
4078
+ });
4079
+ } else if (parsed.entityId) {
4010
4080
  const entity = await driver.fetchEntity({
4011
4081
  path: parsed.collectionPath,
4012
4082
  entityId: parsed.entityId
@@ -4164,6 +4234,22 @@ class RestApiGenerator {
4164
4234
  });
4165
4235
  return entity ? this.flattenEntity(entity) : null;
4166
4236
  }
4237
+ /**
4238
+ * Apply data.afterRead hook to a single entity.
4239
+ * Returns the transformed entity, or null to filter it out.
4240
+ */
4241
+ async applyAfterRead(slug, entity, ctx) {
4242
+ if (!this.dataHooks?.afterRead) return entity;
4243
+ return this.dataHooks.afterRead(slug, entity, ctx);
4244
+ }
4245
+ /**
4246
+ * Apply data.afterRead hook to an array of entities, filtering out nulls.
4247
+ */
4248
+ async applyAfterReadBatch(slug, entities, ctx) {
4249
+ if (!this.dataHooks?.afterRead) return entities;
4250
+ const results = await Promise.all(entities.map((e) => this.applyAfterRead(slug, e, ctx)));
4251
+ return results.filter((e) => e !== null);
4252
+ }
4167
4253
  }
4168
4254
  var jws$5 = {};
4169
4255
  var safeBuffer = { exports: {} };
@@ -4745,11 +4831,11 @@ var Stream$1 = require$$0$3;
4745
4831
  var toString2 = tostring;
4746
4832
  var util$4 = require$$5;
4747
4833
  var JWS_REGEX = /^[a-zA-Z0-9\-_]+?\.[a-zA-Z0-9\-_]+?\.([a-zA-Z0-9\-_]+)?$/;
4748
- function isObject$4(thing) {
4834
+ function isObject$3(thing) {
4749
4835
  return Object.prototype.toString.call(thing) === "[object Object]";
4750
4836
  }
4751
4837
  function safeJsonParse(thing) {
4752
- if (isObject$4(thing))
4838
+ if (isObject$3(thing))
4753
4839
  return thing;
4754
4840
  try {
4755
4841
  return JSON.parse(thing);
@@ -4875,7 +4961,7 @@ jws$5.createVerify = function createVerify(opts) {
4875
4961
  return new VerifyStream(opts);
4876
4962
  };
4877
4963
  var jws$4 = jws$5;
4878
- var decode$3 = function(jwt2, options2) {
4964
+ var decode$2 = function(jwt2, options2) {
4879
4965
  options2 = options2 || {};
4880
4966
  var decoded = jws$4.decode(jwt2, options2);
4881
4967
  if (!decoded) {
@@ -4900,21 +4986,21 @@ var decode$3 = function(jwt2, options2) {
4900
4986
  }
4901
4987
  return payload;
4902
4988
  };
4903
- var JsonWebTokenError$3 = function(message2, error2) {
4904
- Error.call(this, message2);
4989
+ var JsonWebTokenError$3 = function(message, error2) {
4990
+ Error.call(this, message);
4905
4991
  if (Error.captureStackTrace) {
4906
4992
  Error.captureStackTrace(this, this.constructor);
4907
4993
  }
4908
4994
  this.name = "JsonWebTokenError";
4909
- this.message = message2;
4995
+ this.message = message;
4910
4996
  if (error2) this.inner = error2;
4911
4997
  };
4912
4998
  JsonWebTokenError$3.prototype = Object.create(Error.prototype);
4913
4999
  JsonWebTokenError$3.prototype.constructor = JsonWebTokenError$3;
4914
5000
  var JsonWebTokenError_1 = JsonWebTokenError$3;
4915
5001
  var JsonWebTokenError$2 = JsonWebTokenError_1;
4916
- var NotBeforeError$1 = function(message2, date) {
4917
- JsonWebTokenError$2.call(this, message2);
5002
+ var NotBeforeError$1 = function(message, date) {
5003
+ JsonWebTokenError$2.call(this, message);
4918
5004
  this.name = "NotBeforeError";
4919
5005
  this.date = date;
4920
5006
  };
@@ -4922,8 +5008,8 @@ NotBeforeError$1.prototype = Object.create(JsonWebTokenError$2.prototype);
4922
5008
  NotBeforeError$1.prototype.constructor = NotBeforeError$1;
4923
5009
  var NotBeforeError_1 = NotBeforeError$1;
4924
5010
  var JsonWebTokenError$1 = JsonWebTokenError_1;
4925
- var TokenExpiredError$1 = function(message2, expiredAt) {
4926
- JsonWebTokenError$1.call(this, message2);
5011
+ var TokenExpiredError$1 = function(message, expiredAt) {
5012
+ JsonWebTokenError$1.call(this, message);
4927
5013
  this.name = "TokenExpiredError";
4928
5014
  this.expiredAt = expiredAt;
4929
5015
  };
@@ -5788,7 +5874,7 @@ function requireRange() {
5788
5874
  parseRange(range2) {
5789
5875
  const memoOpts = (this.options.includePrerelease && FLAG_INCLUDE_PRERELEASE) | (this.options.loose && FLAG_LOOSE);
5790
5876
  const memoKey = memoOpts + ":" + range2;
5791
- const cached = cache2.get(memoKey);
5877
+ const cached = cache.get(memoKey);
5792
5878
  if (cached) {
5793
5879
  return cached;
5794
5880
  }
@@ -5822,7 +5908,7 @@ function requireRange() {
5822
5908
  rangeMap.delete("");
5823
5909
  }
5824
5910
  const result = [...rangeMap.values()];
5825
- cache2.set(memoKey, result);
5911
+ cache.set(memoKey, result);
5826
5912
  return result;
5827
5913
  }
5828
5914
  intersects(range2, options2) {
@@ -5861,7 +5947,7 @@ function requireRange() {
5861
5947
  }
5862
5948
  range = Range2;
5863
5949
  const LRU = lrucache;
5864
- const cache2 = new LRU();
5950
+ const cache = new LRU();
5865
5951
  const parseOptions2 = parseOptions_1;
5866
5952
  const Comparator2 = requireComparator();
5867
5953
  const debug2 = debug_1;
@@ -6738,7 +6824,7 @@ var psSupported = semver.satisfies(process.version, "^6.12.0 || >=8.0.0");
6738
6824
  const JsonWebTokenError = JsonWebTokenError_1;
6739
6825
  const NotBeforeError = NotBeforeError_1;
6740
6826
  const TokenExpiredError = TokenExpiredError_1;
6741
- const decode$2 = decode$3;
6827
+ const decode$1 = decode$2;
6742
6828
  const timespan$1 = timespan$2;
6743
6829
  const validateAsymmetricKey$1 = validateAsymmetricKey$2;
6744
6830
  const PS_SUPPORTED$1 = psSupported;
@@ -6792,7 +6878,7 @@ var verify2 = function(jwtString, secretOrPublicKey, options2, callback) {
6792
6878
  }
6793
6879
  let decodedToken;
6794
6880
  try {
6795
- decodedToken = decode$2(jwtString, { complete: true });
6881
+ decodedToken = decode$1(jwtString, { complete: true });
6796
6882
  } catch (err) {
6797
6883
  return done(err);
6798
6884
  }
@@ -7052,27 +7138,27 @@ function isArrayLike(value) {
7052
7138
  return value != null && isLength(value.length) && !isFunction(value);
7053
7139
  }
7054
7140
  function isArrayLikeObject(value) {
7055
- return isObjectLike$8(value) && isArrayLike(value);
7141
+ return isObjectLike$7(value) && isArrayLike(value);
7056
7142
  }
7057
7143
  function isFunction(value) {
7058
- var tag2 = isObject$3(value) ? objectToString$6.call(value) : "";
7059
- return tag2 == funcTag || tag2 == genTag;
7144
+ var tag = isObject$2(value) ? objectToString$6.call(value) : "";
7145
+ return tag == funcTag || tag == genTag;
7060
7146
  }
7061
7147
  function isLength(value) {
7062
7148
  return typeof value == "number" && value > -1 && value % 1 == 0 && value <= MAX_SAFE_INTEGER;
7063
7149
  }
7064
- function isObject$3(value) {
7150
+ function isObject$2(value) {
7065
7151
  var type = typeof value;
7066
7152
  return !!value && (type == "object" || type == "function");
7067
7153
  }
7068
- function isObjectLike$8(value) {
7154
+ function isObjectLike$7(value) {
7069
7155
  return !!value && typeof value == "object";
7070
7156
  }
7071
7157
  function isString$2(value) {
7072
- return typeof value == "string" || !isArray$2(value) && isObjectLike$8(value) && objectToString$6.call(value) == stringTag$1;
7158
+ return typeof value == "string" || !isArray$2(value) && isObjectLike$7(value) && objectToString$6.call(value) == stringTag$1;
7073
7159
  }
7074
7160
  function isSymbol$2(value) {
7075
- return typeof value == "symbol" || isObjectLike$8(value) && objectToString$6.call(value) == symbolTag$2;
7161
+ return typeof value == "symbol" || isObjectLike$7(value) && objectToString$6.call(value) == symbolTag$2;
7076
7162
  }
7077
7163
  function toFinite$2(value) {
7078
7164
  if (!value) {
@@ -7096,9 +7182,9 @@ function toNumber$2(value) {
7096
7182
  if (isSymbol$2(value)) {
7097
7183
  return NAN$2;
7098
7184
  }
7099
- if (isObject$3(value)) {
7185
+ if (isObject$2(value)) {
7100
7186
  var other = typeof value.valueOf == "function" ? value.valueOf() : value;
7101
- value = isObject$3(other) ? other + "" : other;
7187
+ value = isObject$2(other) ? other + "" : other;
7102
7188
  }
7103
7189
  if (typeof value != "string") {
7104
7190
  return value === 0 ? value : +value;
@@ -7118,9 +7204,9 @@ var boolTag = "[object Boolean]";
7118
7204
  var objectProto$5 = Object.prototype;
7119
7205
  var objectToString$5 = objectProto$5.toString;
7120
7206
  function isBoolean$1(value) {
7121
- return value === true || value === false || isObjectLike$7(value) && objectToString$5.call(value) == boolTag;
7207
+ return value === true || value === false || isObjectLike$6(value) && objectToString$5.call(value) == boolTag;
7122
7208
  }
7123
- function isObjectLike$7(value) {
7209
+ function isObjectLike$6(value) {
7124
7210
  return !!value && typeof value == "object";
7125
7211
  }
7126
7212
  var lodash_isboolean = isBoolean$1;
@@ -7136,15 +7222,15 @@ var objectToString$4 = objectProto$4.toString;
7136
7222
  function isInteger$1(value) {
7137
7223
  return typeof value == "number" && value == toInteger$1(value);
7138
7224
  }
7139
- function isObject$2(value) {
7225
+ function isObject$1(value) {
7140
7226
  var type = typeof value;
7141
7227
  return !!value && (type == "object" || type == "function");
7142
7228
  }
7143
- function isObjectLike$6(value) {
7229
+ function isObjectLike$5(value) {
7144
7230
  return !!value && typeof value == "object";
7145
7231
  }
7146
7232
  function isSymbol$1(value) {
7147
- return typeof value == "symbol" || isObjectLike$6(value) && objectToString$4.call(value) == symbolTag$1;
7233
+ return typeof value == "symbol" || isObjectLike$5(value) && objectToString$4.call(value) == symbolTag$1;
7148
7234
  }
7149
7235
  function toFinite$1(value) {
7150
7236
  if (!value) {
@@ -7168,9 +7254,9 @@ function toNumber$1(value) {
7168
7254
  if (isSymbol$1(value)) {
7169
7255
  return NAN$1;
7170
7256
  }
7171
- if (isObject$2(value)) {
7257
+ if (isObject$1(value)) {
7172
7258
  var other = typeof value.valueOf == "function" ? value.valueOf() : value;
7173
- value = isObject$2(other) ? other + "" : other;
7259
+ value = isObject$1(other) ? other + "" : other;
7174
7260
  }
7175
7261
  if (typeof value != "string") {
7176
7262
  return value === 0 ? value : +value;
@@ -7183,11 +7269,11 @@ var lodash_isinteger = isInteger$1;
7183
7269
  var numberTag = "[object Number]";
7184
7270
  var objectProto$3 = Object.prototype;
7185
7271
  var objectToString$3 = objectProto$3.toString;
7186
- function isObjectLike$5(value) {
7272
+ function isObjectLike$4(value) {
7187
7273
  return !!value && typeof value == "object";
7188
7274
  }
7189
7275
  function isNumber$1(value) {
7190
- return typeof value == "number" || isObjectLike$5(value) && objectToString$3.call(value) == numberTag;
7276
+ return typeof value == "number" || isObjectLike$4(value) && objectToString$3.call(value) == numberTag;
7191
7277
  }
7192
7278
  var lodash_isnumber = isNumber$1;
7193
7279
  var objectTag = "[object Object]";
@@ -7212,11 +7298,11 @@ var hasOwnProperty$1 = objectProto$2.hasOwnProperty;
7212
7298
  var objectCtorString = funcToString.call(Object);
7213
7299
  var objectToString$2 = objectProto$2.toString;
7214
7300
  var getPrototype = overArg(Object.getPrototypeOf, Object);
7215
- function isObjectLike$4(value) {
7301
+ function isObjectLike$3(value) {
7216
7302
  return !!value && typeof value == "object";
7217
7303
  }
7218
7304
  function isPlainObject$2(value) {
7219
- if (!isObjectLike$4(value) || objectToString$2.call(value) != objectTag || isHostObject(value)) {
7305
+ if (!isObjectLike$3(value) || objectToString$2.call(value) != objectTag || isHostObject(value)) {
7220
7306
  return false;
7221
7307
  }
7222
7308
  var proto = getPrototype(value);
@@ -7231,11 +7317,11 @@ var stringTag = "[object String]";
7231
7317
  var objectProto$1 = Object.prototype;
7232
7318
  var objectToString$1 = objectProto$1.toString;
7233
7319
  var isArray$1 = Array.isArray;
7234
- function isObjectLike$3(value) {
7320
+ function isObjectLike$2(value) {
7235
7321
  return !!value && typeof value == "object";
7236
7322
  }
7237
7323
  function isString$1(value) {
7238
- return typeof value == "string" || !isArray$1(value) && isObjectLike$3(value) && objectToString$1.call(value) == stringTag;
7324
+ return typeof value == "string" || !isArray$1(value) && isObjectLike$2(value) && objectToString$1.call(value) == stringTag;
7239
7325
  }
7240
7326
  var lodash_isstring = isString$1;
7241
7327
  var FUNC_ERROR_TEXT = "Expected a function";
@@ -7267,15 +7353,15 @@ function before(n, func) {
7267
7353
  function once$1(func) {
7268
7354
  return before(2, func);
7269
7355
  }
7270
- function isObject$1(value) {
7356
+ function isObject(value) {
7271
7357
  var type = typeof value;
7272
7358
  return !!value && (type == "object" || type == "function");
7273
7359
  }
7274
- function isObjectLike$2(value) {
7360
+ function isObjectLike$1(value) {
7275
7361
  return !!value && typeof value == "object";
7276
7362
  }
7277
7363
  function isSymbol(value) {
7278
- return typeof value == "symbol" || isObjectLike$2(value) && objectToString.call(value) == symbolTag;
7364
+ return typeof value == "symbol" || isObjectLike$1(value) && objectToString.call(value) == symbolTag;
7279
7365
  }
7280
7366
  function toFinite(value) {
7281
7367
  if (!value) {
@@ -7299,9 +7385,9 @@ function toNumber(value) {
7299
7385
  if (isSymbol(value)) {
7300
7386
  return NAN;
7301
7387
  }
7302
- if (isObject$1(value)) {
7388
+ if (isObject(value)) {
7303
7389
  var other = typeof value.valueOf == "function" ? value.valueOf() : value;
7304
- value = isObject$1(other) ? other + "" : other;
7390
+ value = isObject(other) ? other + "" : other;
7305
7391
  }
7306
7392
  if (typeof value != "string") {
7307
7393
  return value === 0 ? value : +value;
@@ -7392,7 +7478,7 @@ const options_for_objects = [
7392
7478
  "subject",
7393
7479
  "jwtid"
7394
7480
  ];
7395
- var sign$4 = function(payload, secretOrPrivateKey, options2, callback) {
7481
+ var sign$3 = function(payload, secretOrPrivateKey, options2, callback) {
7396
7482
  if (typeof options2 === "function") {
7397
7483
  callback = options2;
7398
7484
  options2 = {};
@@ -7531,9 +7617,9 @@ var sign$4 = function(payload, secretOrPrivateKey, options2, callback) {
7531
7617
  }
7532
7618
  };
7533
7619
  var jsonwebtoken = {
7534
- decode: decode$3,
7620
+ decode: decode$2,
7535
7621
  verify: verify2,
7536
- sign: sign$4,
7622
+ sign: sign$3,
7537
7623
  JsonWebTokenError: JsonWebTokenError_1,
7538
7624
  NotBeforeError: NotBeforeError_1,
7539
7625
  TokenExpiredError: TokenExpiredError_1
@@ -7984,7 +8070,7 @@ function formatData(data) {
7984
8070
  }
7985
8071
  function createLogger(defaultFields = {}) {
7986
8072
  const minLevel = getMinLevel();
7987
- function emit(level, message2, data) {
8073
+ function emit(level, message, data) {
7988
8074
  if (LOG_PRIORITY[level] < LOG_PRIORITY[minLevel]) return;
7989
8075
  const merged = {
7990
8076
  ...defaultFields,
@@ -7993,7 +8079,7 @@ function createLogger(defaultFields = {}) {
7993
8079
  if (isProduction$1()) {
7994
8080
  const entry = {
7995
8081
  severity: GCP_SEVERITY[level],
7996
- message: message2,
8082
+ message,
7997
8083
  timestamp: (/* @__PURE__ */ new Date()).toISOString(),
7998
8084
  ...merged
7999
8085
  };
@@ -8006,7 +8092,7 @@ function createLogger(defaultFields = {}) {
8006
8092
  } else {
8007
8093
  const prefix = level === "error" ? "❌" : level === "warn" ? "⚠️" : level === "info" ? "ℹ️" : "🐛";
8008
8094
  const extra = Object.keys(merged).length > 0 ? ` ${JSON.stringify(merged)}` : "";
8009
- const out = `${prefix} [${level.toUpperCase()}] ${message2}${extra}`;
8095
+ const out = `${prefix} [${level.toUpperCase()}] ${message}${extra}`;
8010
8096
  if (level === "error") {
8011
8097
  console.error(out);
8012
8098
  } else if (level === "warn") {
@@ -8367,9 +8453,9 @@ util$3.pkg = require$$0$1;
8367
8453
  }
8368
8454
  return Function.prototype[Symbol.hasInstance].call(GaxiosError, instance);
8369
8455
  }
8370
- constructor(message2, config, response, error2) {
8456
+ constructor(message, config, response, error2) {
8371
8457
  var _b2;
8372
- super(message2);
8458
+ super(message);
8373
8459
  this.config = config;
8374
8460
  this.response = response;
8375
8461
  this.error = error2;
@@ -14265,8 +14351,8 @@ const readFile$2 = fs$3.readFile ? (0, util_1$5.promisify)(fs$3.readFile) : asyn
14265
14351
  const GOOGLE_TOKEN_URL = "https://www.googleapis.com/oauth2/v4/token";
14266
14352
  const GOOGLE_REVOKE_TOKEN_URL = "https://accounts.google.com/o/oauth2/revoke?token=";
14267
14353
  class ErrorWithCode extends Error {
14268
- constructor(message2, code2) {
14269
- super(message2);
14354
+ constructor(message, code2) {
14355
+ super(message);
14270
14356
  this.code = code2;
14271
14357
  }
14272
14358
  }
@@ -15122,13 +15208,13 @@ class Impersonated extends oauth2client_1.OAuth2Client {
15122
15208
  if (!(error2 instanceof Error))
15123
15209
  throw error2;
15124
15210
  let status = 0;
15125
- let message2 = "";
15211
+ let message = "";
15126
15212
  if (error2 instanceof gaxios_1$2.GaxiosError) {
15127
15213
  status = (_c2 = (_b2 = (_a2 = error2 === null || error2 === void 0 ? void 0 : error2.response) === null || _a2 === void 0 ? void 0 : _a2.data) === null || _b2 === void 0 ? void 0 : _b2.error) === null || _c2 === void 0 ? void 0 : _c2.status;
15128
- message2 = (_f = (_e = (_d = error2 === null || error2 === void 0 ? void 0 : error2.response) === null || _d === void 0 ? void 0 : _d.data) === null || _e === void 0 ? void 0 : _e.error) === null || _f === void 0 ? void 0 : _f.message;
15214
+ message = (_f = (_e = (_d = error2 === null || error2 === void 0 ? void 0 : error2.response) === null || _d === void 0 ? void 0 : _d.data) === null || _e === void 0 ? void 0 : _e.error) === null || _f === void 0 ? void 0 : _f.message;
15129
15215
  }
15130
- if (status && message2) {
15131
- error2.message = `${status}: unable to impersonate: ${message2}`;
15216
+ if (status && message) {
15217
+ error2.message = `${status}: unable to impersonate: ${message}`;
15132
15218
  throw error2;
15133
15219
  } else {
15134
15220
  error2.message = `unable to impersonate: ${error2}`;
@@ -15290,14 +15376,14 @@ function getErrorFromOAuthErrorResponse(resp, err) {
15290
15376
  const errorCode = resp.error;
15291
15377
  const errorDescription = resp.error_description;
15292
15378
  const errorUri = resp.error_uri;
15293
- let message2 = `Error code ${errorCode}`;
15379
+ let message = `Error code ${errorCode}`;
15294
15380
  if (typeof errorDescription !== "undefined") {
15295
- message2 += `: ${errorDescription}`;
15381
+ message += `: ${errorDescription}`;
15296
15382
  }
15297
15383
  if (typeof errorUri !== "undefined") {
15298
- message2 += ` - ${errorUri}`;
15384
+ message += ` - ${errorUri}`;
15299
15385
  }
15300
- const newError = new Error(message2);
15386
+ const newError = new Error(message);
15301
15387
  if (err) {
15302
15388
  const keys2 = Object.keys(err);
15303
15389
  if (err.stack) {
@@ -16025,14 +16111,14 @@ class AwsRequestSigner {
16025
16111
  }
16026
16112
  }
16027
16113
  awsrequestsigner.AwsRequestSigner = AwsRequestSigner;
16028
- async function sign$3(crypto2, key, msg) {
16114
+ async function sign$2(crypto2, key, msg) {
16029
16115
  return await crypto2.signWithHmacSha256(key, msg);
16030
16116
  }
16031
16117
  async function getSigningKey(crypto2, key, dateStamp, region, serviceName) {
16032
- const kDate = await sign$3(crypto2, `AWS4${key}`, dateStamp);
16033
- const kRegion = await sign$3(crypto2, kDate, region);
16034
- const kService = await sign$3(crypto2, kRegion, serviceName);
16035
- const kSigning = await sign$3(crypto2, kService, "aws4_request");
16118
+ const kDate = await sign$2(crypto2, `AWS4${key}`, dateStamp);
16119
+ const kRegion = await sign$2(crypto2, kDate, region);
16120
+ const kService = await sign$2(crypto2, kRegion, serviceName);
16121
+ const kSigning = await sign$2(crypto2, kService, "aws4_request");
16036
16122
  return kSigning;
16037
16123
  }
16038
16124
  async function generateAuthenticationHeaderMap(options2) {
@@ -16078,7 +16164,7 @@ ${amzDate}
16078
16164
  ${credentialScope}
16079
16165
  ` + await options2.crypto.sha256DigestHex(canonicalRequest);
16080
16166
  const signingKey = await getSigningKey(options2.crypto, options2.securityCredentials.secretAccessKey, dateStamp, options2.region, serviceName);
16081
- const signature = await sign$3(options2.crypto, signingKey, stringToSign);
16167
+ const signature = await sign$2(options2.crypto, signingKey, stringToSign);
16082
16168
  const authorizationHeader = `${AWS_ALGORITHM} Credential=${options2.securityCredentials.accessKeyId}/${credentialScope}, SignedHeaders=${signedHeaders}, Signature=${(0, crypto_1.fromArrayBufferToHex)(signature)}`;
16083
16169
  return {
16084
16170
  // Do not return x-amz-date if date is available.
@@ -16409,8 +16495,8 @@ class ExecutableResponse {
16409
16495
  }
16410
16496
  executableResponse.ExecutableResponse = ExecutableResponse;
16411
16497
  class ExecutableResponseError extends Error {
16412
- constructor(message2) {
16413
- super(message2);
16498
+ constructor(message) {
16499
+ super(message);
16414
16500
  Object.setPrototypeOf(this, new.target.prototype);
16415
16501
  }
16416
16502
  }
@@ -16573,8 +16659,8 @@ function requirePluggableAuthClient() {
16573
16659
  const executable_response_1 = executableResponse;
16574
16660
  const pluggable_auth_handler_1 = requirePluggableAuthHandler();
16575
16661
  class ExecutableError extends Error {
16576
- constructor(message2, code2) {
16577
- super(`The executable failed with exit code: ${code2} and error message: ${message2}.`);
16662
+ constructor(message, code2) {
16663
+ super(`The executable failed with exit code: ${code2} and error message: ${message}.`);
16578
16664
  this.code = code2;
16579
16665
  Object.setPrototypeOf(this, new.target.prototype);
16580
16666
  }
@@ -18222,104 +18308,104 @@ ZodError.create = (issues) => {
18222
18308
  return error2;
18223
18309
  };
18224
18310
  const errorMap = (issue, _ctx) => {
18225
- let message2;
18311
+ let message;
18226
18312
  switch (issue.code) {
18227
18313
  case ZodIssueCode.invalid_type:
18228
18314
  if (issue.received === ZodParsedType.undefined) {
18229
- message2 = "Required";
18315
+ message = "Required";
18230
18316
  } else {
18231
- message2 = `Expected ${issue.expected}, received ${issue.received}`;
18317
+ message = `Expected ${issue.expected}, received ${issue.received}`;
18232
18318
  }
18233
18319
  break;
18234
18320
  case ZodIssueCode.invalid_literal:
18235
- message2 = `Invalid literal value, expected ${JSON.stringify(issue.expected, util$1.jsonStringifyReplacer)}`;
18321
+ message = `Invalid literal value, expected ${JSON.stringify(issue.expected, util$1.jsonStringifyReplacer)}`;
18236
18322
  break;
18237
18323
  case ZodIssueCode.unrecognized_keys:
18238
- message2 = `Unrecognized key(s) in object: ${util$1.joinValues(issue.keys, ", ")}`;
18324
+ message = `Unrecognized key(s) in object: ${util$1.joinValues(issue.keys, ", ")}`;
18239
18325
  break;
18240
18326
  case ZodIssueCode.invalid_union:
18241
- message2 = `Invalid input`;
18327
+ message = `Invalid input`;
18242
18328
  break;
18243
18329
  case ZodIssueCode.invalid_union_discriminator:
18244
- message2 = `Invalid discriminator value. Expected ${util$1.joinValues(issue.options)}`;
18330
+ message = `Invalid discriminator value. Expected ${util$1.joinValues(issue.options)}`;
18245
18331
  break;
18246
18332
  case ZodIssueCode.invalid_enum_value:
18247
- message2 = `Invalid enum value. Expected ${util$1.joinValues(issue.options)}, received '${issue.received}'`;
18333
+ message = `Invalid enum value. Expected ${util$1.joinValues(issue.options)}, received '${issue.received}'`;
18248
18334
  break;
18249
18335
  case ZodIssueCode.invalid_arguments:
18250
- message2 = `Invalid function arguments`;
18336
+ message = `Invalid function arguments`;
18251
18337
  break;
18252
18338
  case ZodIssueCode.invalid_return_type:
18253
- message2 = `Invalid function return type`;
18339
+ message = `Invalid function return type`;
18254
18340
  break;
18255
18341
  case ZodIssueCode.invalid_date:
18256
- message2 = `Invalid date`;
18342
+ message = `Invalid date`;
18257
18343
  break;
18258
18344
  case ZodIssueCode.invalid_string:
18259
18345
  if (typeof issue.validation === "object") {
18260
18346
  if ("includes" in issue.validation) {
18261
- message2 = `Invalid input: must include "${issue.validation.includes}"`;
18347
+ message = `Invalid input: must include "${issue.validation.includes}"`;
18262
18348
  if (typeof issue.validation.position === "number") {
18263
- message2 = `${message2} at one or more positions greater than or equal to ${issue.validation.position}`;
18349
+ message = `${message} at one or more positions greater than or equal to ${issue.validation.position}`;
18264
18350
  }
18265
18351
  } else if ("startsWith" in issue.validation) {
18266
- message2 = `Invalid input: must start with "${issue.validation.startsWith}"`;
18352
+ message = `Invalid input: must start with "${issue.validation.startsWith}"`;
18267
18353
  } else if ("endsWith" in issue.validation) {
18268
- message2 = `Invalid input: must end with "${issue.validation.endsWith}"`;
18354
+ message = `Invalid input: must end with "${issue.validation.endsWith}"`;
18269
18355
  } else {
18270
18356
  util$1.assertNever(issue.validation);
18271
18357
  }
18272
18358
  } else if (issue.validation !== "regex") {
18273
- message2 = `Invalid ${issue.validation}`;
18359
+ message = `Invalid ${issue.validation}`;
18274
18360
  } else {
18275
- message2 = "Invalid";
18361
+ message = "Invalid";
18276
18362
  }
18277
18363
  break;
18278
18364
  case ZodIssueCode.too_small:
18279
18365
  if (issue.type === "array")
18280
- message2 = `Array must contain ${issue.exact ? "exactly" : issue.inclusive ? `at least` : `more than`} ${issue.minimum} element(s)`;
18366
+ message = `Array must contain ${issue.exact ? "exactly" : issue.inclusive ? `at least` : `more than`} ${issue.minimum} element(s)`;
18281
18367
  else if (issue.type === "string")
18282
- message2 = `String must contain ${issue.exact ? "exactly" : issue.inclusive ? `at least` : `over`} ${issue.minimum} character(s)`;
18368
+ message = `String must contain ${issue.exact ? "exactly" : issue.inclusive ? `at least` : `over`} ${issue.minimum} character(s)`;
18283
18369
  else if (issue.type === "number")
18284
- message2 = `Number must be ${issue.exact ? `exactly equal to ` : issue.inclusive ? `greater than or equal to ` : `greater than `}${issue.minimum}`;
18370
+ message = `Number must be ${issue.exact ? `exactly equal to ` : issue.inclusive ? `greater than or equal to ` : `greater than `}${issue.minimum}`;
18285
18371
  else if (issue.type === "bigint")
18286
- message2 = `Number must be ${issue.exact ? `exactly equal to ` : issue.inclusive ? `greater than or equal to ` : `greater than `}${issue.minimum}`;
18372
+ message = `Number must be ${issue.exact ? `exactly equal to ` : issue.inclusive ? `greater than or equal to ` : `greater than `}${issue.minimum}`;
18287
18373
  else if (issue.type === "date")
18288
- message2 = `Date must be ${issue.exact ? `exactly equal to ` : issue.inclusive ? `greater than or equal to ` : `greater than `}${new Date(Number(issue.minimum))}`;
18374
+ message = `Date must be ${issue.exact ? `exactly equal to ` : issue.inclusive ? `greater than or equal to ` : `greater than `}${new Date(Number(issue.minimum))}`;
18289
18375
  else
18290
- message2 = "Invalid input";
18376
+ message = "Invalid input";
18291
18377
  break;
18292
18378
  case ZodIssueCode.too_big:
18293
18379
  if (issue.type === "array")
18294
- message2 = `Array must contain ${issue.exact ? `exactly` : issue.inclusive ? `at most` : `less than`} ${issue.maximum} element(s)`;
18380
+ message = `Array must contain ${issue.exact ? `exactly` : issue.inclusive ? `at most` : `less than`} ${issue.maximum} element(s)`;
18295
18381
  else if (issue.type === "string")
18296
- message2 = `String must contain ${issue.exact ? `exactly` : issue.inclusive ? `at most` : `under`} ${issue.maximum} character(s)`;
18382
+ message = `String must contain ${issue.exact ? `exactly` : issue.inclusive ? `at most` : `under`} ${issue.maximum} character(s)`;
18297
18383
  else if (issue.type === "number")
18298
- message2 = `Number must be ${issue.exact ? `exactly` : issue.inclusive ? `less than or equal to` : `less than`} ${issue.maximum}`;
18384
+ message = `Number must be ${issue.exact ? `exactly` : issue.inclusive ? `less than or equal to` : `less than`} ${issue.maximum}`;
18299
18385
  else if (issue.type === "bigint")
18300
- message2 = `BigInt must be ${issue.exact ? `exactly` : issue.inclusive ? `less than or equal to` : `less than`} ${issue.maximum}`;
18386
+ message = `BigInt must be ${issue.exact ? `exactly` : issue.inclusive ? `less than or equal to` : `less than`} ${issue.maximum}`;
18301
18387
  else if (issue.type === "date")
18302
- message2 = `Date must be ${issue.exact ? `exactly` : issue.inclusive ? `smaller than or equal to` : `smaller than`} ${new Date(Number(issue.maximum))}`;
18388
+ message = `Date must be ${issue.exact ? `exactly` : issue.inclusive ? `smaller than or equal to` : `smaller than`} ${new Date(Number(issue.maximum))}`;
18303
18389
  else
18304
- message2 = "Invalid input";
18390
+ message = "Invalid input";
18305
18391
  break;
18306
18392
  case ZodIssueCode.custom:
18307
- message2 = `Invalid input`;
18393
+ message = `Invalid input`;
18308
18394
  break;
18309
18395
  case ZodIssueCode.invalid_intersection_types:
18310
- message2 = `Intersection results could not be merged`;
18396
+ message = `Intersection results could not be merged`;
18311
18397
  break;
18312
18398
  case ZodIssueCode.not_multiple_of:
18313
- message2 = `Number must be a multiple of ${issue.multipleOf}`;
18399
+ message = `Number must be a multiple of ${issue.multipleOf}`;
18314
18400
  break;
18315
18401
  case ZodIssueCode.not_finite:
18316
- message2 = "Number must be finite";
18402
+ message = "Number must be finite";
18317
18403
  break;
18318
18404
  default:
18319
- message2 = _ctx.defaultError;
18405
+ message = _ctx.defaultError;
18320
18406
  util$1.assertNever(issue);
18321
18407
  }
18322
- return { message: message2 };
18408
+ return { message };
18323
18409
  };
18324
18410
  let overrideErrorMap = errorMap;
18325
18411
  function getErrorMap() {
@@ -18434,8 +18520,8 @@ const isValid = (x) => x.status === "valid";
18434
18520
  const isAsync = (x) => typeof Promise !== "undefined" && x instanceof Promise;
18435
18521
  var errorUtil;
18436
18522
  (function(errorUtil2) {
18437
- errorUtil2.errToObj = (message2) => typeof message2 === "string" ? { message: message2 } : message2 || {};
18438
- errorUtil2.toString = (message2) => typeof message2 === "string" ? message2 : message2?.message;
18523
+ errorUtil2.errToObj = (message) => typeof message === "string" ? { message } : message || {};
18524
+ errorUtil2.toString = (message) => typeof message === "string" ? message : message?.message;
18439
18525
  })(errorUtil || (errorUtil = {}));
18440
18526
  class ParseInputLazyPath {
18441
18527
  constructor(parent, value, path2, key) {
@@ -18485,16 +18571,16 @@ function processCreateParams(params) {
18485
18571
  if (errorMap2)
18486
18572
  return { errorMap: errorMap2, description: description2 };
18487
18573
  const customMap = (iss, ctx) => {
18488
- const { message: message2 } = params;
18574
+ const { message } = params;
18489
18575
  if (iss.code === "invalid_enum_value") {
18490
- return { message: message2 ?? ctx.defaultError };
18576
+ return { message: message ?? ctx.defaultError };
18491
18577
  }
18492
18578
  if (typeof ctx.data === "undefined") {
18493
- return { message: message2 ?? required_error ?? ctx.defaultError };
18579
+ return { message: message ?? required_error ?? ctx.defaultError };
18494
18580
  }
18495
18581
  if (iss.code !== "invalid_type")
18496
18582
  return { message: ctx.defaultError };
18497
- return { message: message2 ?? invalid_type_error ?? ctx.defaultError };
18583
+ return { message: message ?? invalid_type_error ?? ctx.defaultError };
18498
18584
  };
18499
18585
  return { errorMap: customMap, description: description2 };
18500
18586
  }
@@ -18620,14 +18706,14 @@ class ZodType {
18620
18706
  const result = await (isAsync(maybeAsyncResult) ? maybeAsyncResult : Promise.resolve(maybeAsyncResult));
18621
18707
  return handleResult(ctx, result);
18622
18708
  }
18623
- refine(check, message2) {
18709
+ refine(check, message) {
18624
18710
  const getIssueProperties = (val) => {
18625
- if (typeof message2 === "string" || typeof message2 === "undefined") {
18626
- return { message: message2 };
18627
- } else if (typeof message2 === "function") {
18628
- return message2(val);
18711
+ if (typeof message === "string" || typeof message === "undefined") {
18712
+ return { message };
18713
+ } else if (typeof message === "function") {
18714
+ return message(val);
18629
18715
  } else {
18630
- return message2;
18716
+ return message;
18631
18717
  }
18632
18718
  };
18633
18719
  return this._refinement((val, ctx) => {
@@ -19163,11 +19249,11 @@ class ZodString extends ZodType {
19163
19249
  }
19164
19250
  return { status: status.value, value: input.data };
19165
19251
  }
19166
- _regex(regex2, validation, message2) {
19252
+ _regex(regex2, validation, message) {
19167
19253
  return this.refinement((data) => regex2.test(data), {
19168
19254
  validation,
19169
19255
  code: ZodIssueCode.invalid_string,
19170
- ...errorUtil.errToObj(message2)
19256
+ ...errorUtil.errToObj(message)
19171
19257
  });
19172
19258
  }
19173
19259
  _addCheck(check) {
@@ -19176,37 +19262,37 @@ class ZodString extends ZodType {
19176
19262
  checks: [...this._def.checks, check]
19177
19263
  });
19178
19264
  }
19179
- email(message2) {
19180
- return this._addCheck({ kind: "email", ...errorUtil.errToObj(message2) });
19265
+ email(message) {
19266
+ return this._addCheck({ kind: "email", ...errorUtil.errToObj(message) });
19181
19267
  }
19182
- url(message2) {
19183
- return this._addCheck({ kind: "url", ...errorUtil.errToObj(message2) });
19268
+ url(message) {
19269
+ return this._addCheck({ kind: "url", ...errorUtil.errToObj(message) });
19184
19270
  }
19185
- emoji(message2) {
19186
- return this._addCheck({ kind: "emoji", ...errorUtil.errToObj(message2) });
19271
+ emoji(message) {
19272
+ return this._addCheck({ kind: "emoji", ...errorUtil.errToObj(message) });
19187
19273
  }
19188
- uuid(message2) {
19189
- return this._addCheck({ kind: "uuid", ...errorUtil.errToObj(message2) });
19274
+ uuid(message) {
19275
+ return this._addCheck({ kind: "uuid", ...errorUtil.errToObj(message) });
19190
19276
  }
19191
- nanoid(message2) {
19192
- return this._addCheck({ kind: "nanoid", ...errorUtil.errToObj(message2) });
19277
+ nanoid(message) {
19278
+ return this._addCheck({ kind: "nanoid", ...errorUtil.errToObj(message) });
19193
19279
  }
19194
- cuid(message2) {
19195
- return this._addCheck({ kind: "cuid", ...errorUtil.errToObj(message2) });
19280
+ cuid(message) {
19281
+ return this._addCheck({ kind: "cuid", ...errorUtil.errToObj(message) });
19196
19282
  }
19197
- cuid2(message2) {
19198
- return this._addCheck({ kind: "cuid2", ...errorUtil.errToObj(message2) });
19283
+ cuid2(message) {
19284
+ return this._addCheck({ kind: "cuid2", ...errorUtil.errToObj(message) });
19199
19285
  }
19200
- ulid(message2) {
19201
- return this._addCheck({ kind: "ulid", ...errorUtil.errToObj(message2) });
19286
+ ulid(message) {
19287
+ return this._addCheck({ kind: "ulid", ...errorUtil.errToObj(message) });
19202
19288
  }
19203
- base64(message2) {
19204
- return this._addCheck({ kind: "base64", ...errorUtil.errToObj(message2) });
19289
+ base64(message) {
19290
+ return this._addCheck({ kind: "base64", ...errorUtil.errToObj(message) });
19205
19291
  }
19206
- base64url(message2) {
19292
+ base64url(message) {
19207
19293
  return this._addCheck({
19208
19294
  kind: "base64url",
19209
- ...errorUtil.errToObj(message2)
19295
+ ...errorUtil.errToObj(message)
19210
19296
  });
19211
19297
  }
19212
19298
  jwt(options2) {
@@ -19236,8 +19322,8 @@ class ZodString extends ZodType {
19236
19322
  ...errorUtil.errToObj(options2?.message)
19237
19323
  });
19238
19324
  }
19239
- date(message2) {
19240
- return this._addCheck({ kind: "date", message: message2 });
19325
+ date(message) {
19326
+ return this._addCheck({ kind: "date", message });
19241
19327
  }
19242
19328
  time(options2) {
19243
19329
  if (typeof options2 === "string") {
@@ -19253,14 +19339,14 @@ class ZodString extends ZodType {
19253
19339
  ...errorUtil.errToObj(options2?.message)
19254
19340
  });
19255
19341
  }
19256
- duration(message2) {
19257
- return this._addCheck({ kind: "duration", ...errorUtil.errToObj(message2) });
19342
+ duration(message) {
19343
+ return this._addCheck({ kind: "duration", ...errorUtil.errToObj(message) });
19258
19344
  }
19259
- regex(regex2, message2) {
19345
+ regex(regex2, message) {
19260
19346
  return this._addCheck({
19261
19347
  kind: "regex",
19262
19348
  regex: regex2,
19263
- ...errorUtil.errToObj(message2)
19349
+ ...errorUtil.errToObj(message)
19264
19350
  });
19265
19351
  }
19266
19352
  includes(value, options2) {
@@ -19271,46 +19357,46 @@ class ZodString extends ZodType {
19271
19357
  ...errorUtil.errToObj(options2?.message)
19272
19358
  });
19273
19359
  }
19274
- startsWith(value, message2) {
19360
+ startsWith(value, message) {
19275
19361
  return this._addCheck({
19276
19362
  kind: "startsWith",
19277
19363
  value,
19278
- ...errorUtil.errToObj(message2)
19364
+ ...errorUtil.errToObj(message)
19279
19365
  });
19280
19366
  }
19281
- endsWith(value, message2) {
19367
+ endsWith(value, message) {
19282
19368
  return this._addCheck({
19283
19369
  kind: "endsWith",
19284
19370
  value,
19285
- ...errorUtil.errToObj(message2)
19371
+ ...errorUtil.errToObj(message)
19286
19372
  });
19287
19373
  }
19288
- min(minLength, message2) {
19374
+ min(minLength, message) {
19289
19375
  return this._addCheck({
19290
19376
  kind: "min",
19291
19377
  value: minLength,
19292
- ...errorUtil.errToObj(message2)
19378
+ ...errorUtil.errToObj(message)
19293
19379
  });
19294
19380
  }
19295
- max(maxLength, message2) {
19381
+ max(maxLength, message) {
19296
19382
  return this._addCheck({
19297
19383
  kind: "max",
19298
19384
  value: maxLength,
19299
- ...errorUtil.errToObj(message2)
19385
+ ...errorUtil.errToObj(message)
19300
19386
  });
19301
19387
  }
19302
- length(len, message2) {
19388
+ length(len, message) {
19303
19389
  return this._addCheck({
19304
19390
  kind: "length",
19305
19391
  value: len,
19306
- ...errorUtil.errToObj(message2)
19392
+ ...errorUtil.errToObj(message)
19307
19393
  });
19308
19394
  }
19309
19395
  /**
19310
19396
  * Equivalent to `.min(1)`
19311
19397
  */
19312
- nonempty(message2) {
19313
- return this.min(1, errorUtil.errToObj(message2));
19398
+ nonempty(message) {
19399
+ return this.min(1, errorUtil.errToObj(message));
19314
19400
  }
19315
19401
  trim() {
19316
19402
  return new ZodString({
@@ -19503,19 +19589,19 @@ class ZodNumber extends ZodType {
19503
19589
  }
19504
19590
  return { status: status.value, value: input.data };
19505
19591
  }
19506
- gte(value, message2) {
19507
- return this.setLimit("min", value, true, errorUtil.toString(message2));
19592
+ gte(value, message) {
19593
+ return this.setLimit("min", value, true, errorUtil.toString(message));
19508
19594
  }
19509
- gt(value, message2) {
19510
- return this.setLimit("min", value, false, errorUtil.toString(message2));
19595
+ gt(value, message) {
19596
+ return this.setLimit("min", value, false, errorUtil.toString(message));
19511
19597
  }
19512
- lte(value, message2) {
19513
- return this.setLimit("max", value, true, errorUtil.toString(message2));
19598
+ lte(value, message) {
19599
+ return this.setLimit("max", value, true, errorUtil.toString(message));
19514
19600
  }
19515
- lt(value, message2) {
19516
- return this.setLimit("max", value, false, errorUtil.toString(message2));
19601
+ lt(value, message) {
19602
+ return this.setLimit("max", value, false, errorUtil.toString(message));
19517
19603
  }
19518
- setLimit(kind, value, inclusive, message2) {
19604
+ setLimit(kind, value, inclusive, message) {
19519
19605
  return new ZodNumber({
19520
19606
  ...this._def,
19521
19607
  checks: [
@@ -19524,7 +19610,7 @@ class ZodNumber extends ZodType {
19524
19610
  kind,
19525
19611
  value,
19526
19612
  inclusive,
19527
- message: errorUtil.toString(message2)
19613
+ message: errorUtil.toString(message)
19528
19614
  }
19529
19615
  ]
19530
19616
  });
@@ -19535,68 +19621,68 @@ class ZodNumber extends ZodType {
19535
19621
  checks: [...this._def.checks, check]
19536
19622
  });
19537
19623
  }
19538
- int(message2) {
19624
+ int(message) {
19539
19625
  return this._addCheck({
19540
19626
  kind: "int",
19541
- message: errorUtil.toString(message2)
19627
+ message: errorUtil.toString(message)
19542
19628
  });
19543
19629
  }
19544
- positive(message2) {
19630
+ positive(message) {
19545
19631
  return this._addCheck({
19546
19632
  kind: "min",
19547
19633
  value: 0,
19548
19634
  inclusive: false,
19549
- message: errorUtil.toString(message2)
19635
+ message: errorUtil.toString(message)
19550
19636
  });
19551
19637
  }
19552
- negative(message2) {
19638
+ negative(message) {
19553
19639
  return this._addCheck({
19554
19640
  kind: "max",
19555
19641
  value: 0,
19556
19642
  inclusive: false,
19557
- message: errorUtil.toString(message2)
19643
+ message: errorUtil.toString(message)
19558
19644
  });
19559
19645
  }
19560
- nonpositive(message2) {
19646
+ nonpositive(message) {
19561
19647
  return this._addCheck({
19562
19648
  kind: "max",
19563
19649
  value: 0,
19564
19650
  inclusive: true,
19565
- message: errorUtil.toString(message2)
19651
+ message: errorUtil.toString(message)
19566
19652
  });
19567
19653
  }
19568
- nonnegative(message2) {
19654
+ nonnegative(message) {
19569
19655
  return this._addCheck({
19570
19656
  kind: "min",
19571
19657
  value: 0,
19572
19658
  inclusive: true,
19573
- message: errorUtil.toString(message2)
19659
+ message: errorUtil.toString(message)
19574
19660
  });
19575
19661
  }
19576
- multipleOf(value, message2) {
19662
+ multipleOf(value, message) {
19577
19663
  return this._addCheck({
19578
19664
  kind: "multipleOf",
19579
19665
  value,
19580
- message: errorUtil.toString(message2)
19666
+ message: errorUtil.toString(message)
19581
19667
  });
19582
19668
  }
19583
- finite(message2) {
19669
+ finite(message) {
19584
19670
  return this._addCheck({
19585
19671
  kind: "finite",
19586
- message: errorUtil.toString(message2)
19672
+ message: errorUtil.toString(message)
19587
19673
  });
19588
19674
  }
19589
- safe(message2) {
19675
+ safe(message) {
19590
19676
  return this._addCheck({
19591
19677
  kind: "min",
19592
19678
  inclusive: true,
19593
19679
  value: Number.MIN_SAFE_INTEGER,
19594
- message: errorUtil.toString(message2)
19680
+ message: errorUtil.toString(message)
19595
19681
  })._addCheck({
19596
19682
  kind: "max",
19597
19683
  inclusive: true,
19598
19684
  value: Number.MAX_SAFE_INTEGER,
19599
- message: errorUtil.toString(message2)
19685
+ message: errorUtil.toString(message)
19600
19686
  });
19601
19687
  }
19602
19688
  get minValue() {
@@ -19719,19 +19805,19 @@ class ZodBigInt extends ZodType {
19719
19805
  });
19720
19806
  return INVALID;
19721
19807
  }
19722
- gte(value, message2) {
19723
- return this.setLimit("min", value, true, errorUtil.toString(message2));
19808
+ gte(value, message) {
19809
+ return this.setLimit("min", value, true, errorUtil.toString(message));
19724
19810
  }
19725
- gt(value, message2) {
19726
- return this.setLimit("min", value, false, errorUtil.toString(message2));
19811
+ gt(value, message) {
19812
+ return this.setLimit("min", value, false, errorUtil.toString(message));
19727
19813
  }
19728
- lte(value, message2) {
19729
- return this.setLimit("max", value, true, errorUtil.toString(message2));
19814
+ lte(value, message) {
19815
+ return this.setLimit("max", value, true, errorUtil.toString(message));
19730
19816
  }
19731
- lt(value, message2) {
19732
- return this.setLimit("max", value, false, errorUtil.toString(message2));
19817
+ lt(value, message) {
19818
+ return this.setLimit("max", value, false, errorUtil.toString(message));
19733
19819
  }
19734
- setLimit(kind, value, inclusive, message2) {
19820
+ setLimit(kind, value, inclusive, message) {
19735
19821
  return new ZodBigInt({
19736
19822
  ...this._def,
19737
19823
  checks: [
@@ -19740,7 +19826,7 @@ class ZodBigInt extends ZodType {
19740
19826
  kind,
19741
19827
  value,
19742
19828
  inclusive,
19743
- message: errorUtil.toString(message2)
19829
+ message: errorUtil.toString(message)
19744
19830
  }
19745
19831
  ]
19746
19832
  });
@@ -19751,43 +19837,43 @@ class ZodBigInt extends ZodType {
19751
19837
  checks: [...this._def.checks, check]
19752
19838
  });
19753
19839
  }
19754
- positive(message2) {
19840
+ positive(message) {
19755
19841
  return this._addCheck({
19756
19842
  kind: "min",
19757
19843
  value: BigInt(0),
19758
19844
  inclusive: false,
19759
- message: errorUtil.toString(message2)
19845
+ message: errorUtil.toString(message)
19760
19846
  });
19761
19847
  }
19762
- negative(message2) {
19848
+ negative(message) {
19763
19849
  return this._addCheck({
19764
19850
  kind: "max",
19765
19851
  value: BigInt(0),
19766
19852
  inclusive: false,
19767
- message: errorUtil.toString(message2)
19853
+ message: errorUtil.toString(message)
19768
19854
  });
19769
19855
  }
19770
- nonpositive(message2) {
19856
+ nonpositive(message) {
19771
19857
  return this._addCheck({
19772
19858
  kind: "max",
19773
19859
  value: BigInt(0),
19774
19860
  inclusive: true,
19775
- message: errorUtil.toString(message2)
19861
+ message: errorUtil.toString(message)
19776
19862
  });
19777
19863
  }
19778
- nonnegative(message2) {
19864
+ nonnegative(message) {
19779
19865
  return this._addCheck({
19780
19866
  kind: "min",
19781
19867
  value: BigInt(0),
19782
19868
  inclusive: true,
19783
- message: errorUtil.toString(message2)
19869
+ message: errorUtil.toString(message)
19784
19870
  });
19785
19871
  }
19786
- multipleOf(value, message2) {
19872
+ multipleOf(value, message) {
19787
19873
  return this._addCheck({
19788
19874
  kind: "multipleOf",
19789
19875
  value,
19790
- message: errorUtil.toString(message2)
19876
+ message: errorUtil.toString(message)
19791
19877
  });
19792
19878
  }
19793
19879
  get minValue() {
@@ -19910,18 +19996,18 @@ class ZodDate extends ZodType {
19910
19996
  checks: [...this._def.checks, check]
19911
19997
  });
19912
19998
  }
19913
- min(minDate, message2) {
19999
+ min(minDate, message) {
19914
20000
  return this._addCheck({
19915
20001
  kind: "min",
19916
20002
  value: minDate.getTime(),
19917
- message: errorUtil.toString(message2)
20003
+ message: errorUtil.toString(message)
19918
20004
  });
19919
20005
  }
19920
- max(maxDate, message2) {
20006
+ max(maxDate, message) {
19921
20007
  return this._addCheck({
19922
20008
  kind: "max",
19923
20009
  value: maxDate.getTime(),
19924
- message: errorUtil.toString(message2)
20010
+ message: errorUtil.toString(message)
19925
20011
  });
19926
20012
  }
19927
20013
  get minDate() {
@@ -20153,26 +20239,26 @@ class ZodArray extends ZodType {
20153
20239
  get element() {
20154
20240
  return this._def.type;
20155
20241
  }
20156
- min(minLength, message2) {
20242
+ min(minLength, message) {
20157
20243
  return new ZodArray({
20158
20244
  ...this._def,
20159
- minLength: { value: minLength, message: errorUtil.toString(message2) }
20245
+ minLength: { value: minLength, message: errorUtil.toString(message) }
20160
20246
  });
20161
20247
  }
20162
- max(maxLength, message2) {
20248
+ max(maxLength, message) {
20163
20249
  return new ZodArray({
20164
20250
  ...this._def,
20165
- maxLength: { value: maxLength, message: errorUtil.toString(message2) }
20251
+ maxLength: { value: maxLength, message: errorUtil.toString(message) }
20166
20252
  });
20167
20253
  }
20168
- length(len, message2) {
20254
+ length(len, message) {
20169
20255
  return new ZodArray({
20170
20256
  ...this._def,
20171
- exactLength: { value: len, message: errorUtil.toString(message2) }
20257
+ exactLength: { value: len, message: errorUtil.toString(message) }
20172
20258
  });
20173
20259
  }
20174
- nonempty(message2) {
20175
- return this.min(1, message2);
20260
+ nonempty(message) {
20261
+ return this.min(1, message);
20176
20262
  }
20177
20263
  }
20178
20264
  ZodArray.create = (schema, params) => {
@@ -20315,17 +20401,17 @@ class ZodObject extends ZodType {
20315
20401
  get shape() {
20316
20402
  return this._def.shape();
20317
20403
  }
20318
- strict(message2) {
20404
+ strict(message) {
20319
20405
  errorUtil.errToObj;
20320
20406
  return new ZodObject({
20321
20407
  ...this._def,
20322
20408
  unknownKeys: "strict",
20323
- ...message2 !== void 0 ? {
20409
+ ...message !== void 0 ? {
20324
20410
  errorMap: (issue, ctx) => {
20325
20411
  const defaultError = this._def.errorMap?.(issue, ctx).message ?? ctx.defaultError;
20326
20412
  if (issue.code === "unrecognized_keys")
20327
20413
  return {
20328
- message: errorUtil.errToObj(message2).message ?? defaultError
20414
+ message: errorUtil.errToObj(message).message ?? defaultError
20329
20415
  };
20330
20416
  return {
20331
20417
  message: defaultError
@@ -20921,23 +21007,23 @@ class ZodSet extends ZodType {
20921
21007
  return finalizeSet(elements);
20922
21008
  }
20923
21009
  }
20924
- min(minSize, message2) {
21010
+ min(minSize, message) {
20925
21011
  return new ZodSet({
20926
21012
  ...this._def,
20927
- minSize: { value: minSize, message: errorUtil.toString(message2) }
21013
+ minSize: { value: minSize, message: errorUtil.toString(message) }
20928
21014
  });
20929
21015
  }
20930
- max(maxSize, message2) {
21016
+ max(maxSize, message) {
20931
21017
  return new ZodSet({
20932
21018
  ...this._def,
20933
- maxSize: { value: maxSize, message: errorUtil.toString(message2) }
21019
+ maxSize: { value: maxSize, message: errorUtil.toString(message) }
20934
21020
  });
20935
21021
  }
20936
- size(size, message2) {
20937
- return this.min(size, message2).max(size, message2);
21022
+ size(size, message) {
21023
+ return this.min(size, message).max(size, message);
20938
21024
  }
20939
- nonempty(message2) {
20940
- return this.min(1, message2);
21025
+ nonempty(message) {
21026
+ return this.min(1, message);
20941
21027
  }
20942
21028
  }
20943
21029
  ZodSet.create = (valueType, params) => {
@@ -21547,32 +21633,125 @@ ZodEnum.create;
21547
21633
  ZodPromise.create;
21548
21634
  ZodOptional.create;
21549
21635
  ZodNullable.create;
21550
- function createGoogleProvider(clientId) {
21551
- const googleClient = new src$4.OAuth2Client(clientId);
21636
+ function createGoogleProvider(config) {
21637
+ const clientId = typeof config === "string" ? config : config.clientId;
21638
+ const clientSecret = typeof config === "string" ? void 0 : config.clientSecret;
21639
+ const googleClient = new src$4.OAuth2Client(clientId, clientSecret);
21552
21640
  return {
21553
21641
  id: "google",
21554
21642
  schema: objectType({
21555
- idToken: stringType().min(1, "ID token is required")
21643
+ idToken: stringType().min(1).optional(),
21644
+ accessToken: stringType().min(1).optional(),
21645
+ code: stringType().min(1).optional(),
21646
+ redirectUri: stringType().min(1).optional()
21647
+ }).refine((data) => data.idToken || data.accessToken || data.code && data.redirectUri, {
21648
+ message: "One of idToken, accessToken, or code+redirectUri is required"
21556
21649
  }),
21557
21650
  verify: async (payload) => {
21558
21651
  try {
21559
- const ticket = await googleClient.verifyIdToken({
21560
- idToken: payload.idToken,
21561
- audience: clientId
21562
- });
21563
- const content = ticket.getPayload();
21564
- if (!content) {
21565
- return null;
21652
+ if (payload.idToken) {
21653
+ const ticket = await googleClient.verifyIdToken({
21654
+ idToken: payload.idToken,
21655
+ audience: clientId
21656
+ });
21657
+ const content = ticket.getPayload();
21658
+ if (!content) {
21659
+ throw new Error("Google ID token payload was empty");
21660
+ }
21661
+ return {
21662
+ providerId: content.sub,
21663
+ email: content.email || "",
21664
+ displayName: content.name || null,
21665
+ photoUrl: content.picture || null
21666
+ };
21566
21667
  }
21567
- return {
21568
- providerId: content.sub,
21569
- email: content.email || "",
21570
- displayName: content.name || null,
21571
- photoUrl: content.picture || null
21572
- };
21668
+ if (payload.accessToken) {
21669
+ const res = await fetch("https://www.googleapis.com/oauth2/v3/userinfo", {
21670
+ headers: {
21671
+ Authorization: `Bearer ${payload.accessToken}`
21672
+ }
21673
+ });
21674
+ if (!res.ok) {
21675
+ throw new Error(`Google userinfo request failed with status ${res.status}`);
21676
+ }
21677
+ const info = await res.json();
21678
+ if (!info.sub || !info.email) {
21679
+ throw new Error("Google userinfo response missing sub or email");
21680
+ }
21681
+ return {
21682
+ providerId: info.sub,
21683
+ email: info.email,
21684
+ displayName: info.name || null,
21685
+ photoUrl: info.picture || null
21686
+ };
21687
+ }
21688
+ if (payload.code && payload.redirectUri) {
21689
+ if (!clientSecret) {
21690
+ throw new Error("Google authorization code flow requires clientSecret. Configure GOOGLE_CLIENT_SECRET in your environment.");
21691
+ }
21692
+ const tokenResponse = await fetch("https://oauth2.googleapis.com/token", {
21693
+ method: "POST",
21694
+ headers: {
21695
+ "Content-Type": "application/x-www-form-urlencoded"
21696
+ },
21697
+ body: new URLSearchParams({
21698
+ code: payload.code,
21699
+ client_id: clientId,
21700
+ client_secret: clientSecret,
21701
+ redirect_uri: payload.redirectUri,
21702
+ grant_type: "authorization_code"
21703
+ })
21704
+ });
21705
+ if (!tokenResponse.ok) {
21706
+ const errorBody = await tokenResponse.text();
21707
+ throw new Error(`Google token exchange failed (${tokenResponse.status}): ${errorBody}`);
21708
+ }
21709
+ const tokenData = await tokenResponse.json();
21710
+ if (tokenData.error) {
21711
+ throw new Error(`Google token exchange error: ${tokenData.error} – ${tokenData.error_description || "no details"}`);
21712
+ }
21713
+ if (tokenData.id_token) {
21714
+ const ticket = await googleClient.verifyIdToken({
21715
+ idToken: tokenData.id_token,
21716
+ audience: clientId
21717
+ });
21718
+ const content = ticket.getPayload();
21719
+ if (!content) {
21720
+ throw new Error("Google ID token payload was empty after code exchange");
21721
+ }
21722
+ return {
21723
+ providerId: content.sub,
21724
+ email: content.email || "",
21725
+ displayName: content.name || null,
21726
+ photoUrl: content.picture || null
21727
+ };
21728
+ }
21729
+ if (tokenData.access_token) {
21730
+ const userInfoRes = await fetch("https://www.googleapis.com/oauth2/v3/userinfo", {
21731
+ headers: {
21732
+ Authorization: `Bearer ${tokenData.access_token}`
21733
+ }
21734
+ });
21735
+ if (!userInfoRes.ok) {
21736
+ throw new Error(`Google userinfo request failed after code exchange (${userInfoRes.status})`);
21737
+ }
21738
+ const info = await userInfoRes.json();
21739
+ if (!info.sub || !info.email) {
21740
+ return null;
21741
+ }
21742
+ return {
21743
+ providerId: info.sub,
21744
+ email: info.email,
21745
+ displayName: info.name || null,
21746
+ photoUrl: info.picture || null
21747
+ };
21748
+ }
21749
+ throw new Error("Google token exchange returned neither id_token nor access_token");
21750
+ }
21751
+ throw new Error("No valid Google credential provided (expected idToken, accessToken, or code+redirectUri)");
21573
21752
  } catch (error2) {
21574
- console.error("Failed to verify Google ID token:", error2);
21575
- return null;
21753
+ console.error("Google OAuth verification failed:", error2);
21754
+ throw error2;
21576
21755
  }
21577
21756
  }
21578
21757
  };
@@ -21764,1002 +21943,16 @@ function createMicrosoftProvider(config) {
21764
21943
  }
21765
21944
  };
21766
21945
  }
21767
- const encoder = new TextEncoder();
21768
- const decoder = new TextDecoder();
21769
- function concat(...buffers) {
21770
- const size = buffers.reduce((acc, { length }) => acc + length, 0);
21771
- const buf = new Uint8Array(size);
21772
- let i = 0;
21773
- for (const buffer of buffers) {
21774
- buf.set(buffer, i);
21775
- i += buffer.length;
21776
- }
21777
- return buf;
21778
- }
21779
- function encode$4(string) {
21780
- const bytes = new Uint8Array(string.length);
21781
- for (let i = 0; i < string.length; i++) {
21782
- const code2 = string.charCodeAt(i);
21783
- if (code2 > 127) {
21784
- throw new TypeError("non-ASCII string encountered in encode()");
21785
- }
21786
- bytes[i] = code2;
21787
- }
21788
- return bytes;
21789
- }
21790
- function encodeBase64(input) {
21791
- if (Uint8Array.prototype.toBase64) {
21792
- return input.toBase64();
21793
- }
21794
- const CHUNK_SIZE = 32768;
21795
- const arr = [];
21796
- for (let i = 0; i < input.length; i += CHUNK_SIZE) {
21797
- arr.push(String.fromCharCode.apply(null, input.subarray(i, i + CHUNK_SIZE)));
21798
- }
21799
- return btoa(arr.join(""));
21800
- }
21801
- function decodeBase64(encoded) {
21802
- if (Uint8Array.fromBase64) {
21803
- return Uint8Array.fromBase64(encoded);
21804
- }
21805
- const binary = atob(encoded);
21806
- const bytes = new Uint8Array(binary.length);
21807
- for (let i = 0; i < binary.length; i++) {
21808
- bytes[i] = binary.charCodeAt(i);
21809
- }
21810
- return bytes;
21811
- }
21812
- function decode$1(input) {
21813
- if (Uint8Array.fromBase64) {
21814
- return Uint8Array.fromBase64(typeof input === "string" ? input : decoder.decode(input), {
21815
- alphabet: "base64url"
21816
- });
21817
- }
21818
- let encoded = input;
21819
- if (encoded instanceof Uint8Array) {
21820
- encoded = decoder.decode(encoded);
21821
- }
21822
- encoded = encoded.replace(/-/g, "+").replace(/_/g, "/");
21823
- try {
21824
- return decodeBase64(encoded);
21825
- } catch {
21826
- throw new TypeError("The input to be decoded is not correctly encoded.");
21827
- }
21828
- }
21829
- function encode$3(input) {
21830
- let unencoded = input;
21831
- if (typeof unencoded === "string") {
21832
- unencoded = encoder.encode(unencoded);
21833
- }
21834
- if (Uint8Array.prototype.toBase64) {
21835
- return unencoded.toBase64({ alphabet: "base64url", omitPadding: true });
21836
- }
21837
- return encodeBase64(unencoded).replace(/=/g, "").replace(/\+/g, "-").replace(/\//g, "_");
21838
- }
21839
- const unusable = (name2, prop = "algorithm.name") => new TypeError(`CryptoKey does not support this operation, its ${prop} must be ${name2}`);
21840
- const isAlgorithm = (algorithm, name2) => algorithm.name === name2;
21841
- function getHashLength(hash) {
21842
- return parseInt(hash.name.slice(4), 10);
21843
- }
21844
- function checkHashLength(algorithm, expected) {
21845
- const actual = getHashLength(algorithm.hash);
21846
- if (actual !== expected)
21847
- throw unusable(`SHA-${expected}`, "algorithm.hash");
21848
- }
21849
- function getNamedCurve(alg) {
21850
- switch (alg) {
21851
- case "ES256":
21852
- return "P-256";
21853
- case "ES384":
21854
- return "P-384";
21855
- case "ES512":
21856
- return "P-521";
21857
- default:
21858
- throw new Error("unreachable");
21859
- }
21860
- }
21861
- function checkUsage(key, usage) {
21862
- if (!key.usages.includes(usage)) {
21863
- throw new TypeError(`CryptoKey does not support this operation, its usages must include ${usage}.`);
21864
- }
21865
- }
21866
- function checkSigCryptoKey(key, alg, usage) {
21867
- switch (alg) {
21868
- case "HS256":
21869
- case "HS384":
21870
- case "HS512": {
21871
- if (!isAlgorithm(key.algorithm, "HMAC"))
21872
- throw unusable("HMAC");
21873
- checkHashLength(key.algorithm, parseInt(alg.slice(2), 10));
21874
- break;
21875
- }
21876
- case "RS256":
21877
- case "RS384":
21878
- case "RS512": {
21879
- if (!isAlgorithm(key.algorithm, "RSASSA-PKCS1-v1_5"))
21880
- throw unusable("RSASSA-PKCS1-v1_5");
21881
- checkHashLength(key.algorithm, parseInt(alg.slice(2), 10));
21882
- break;
21883
- }
21884
- case "PS256":
21885
- case "PS384":
21886
- case "PS512": {
21887
- if (!isAlgorithm(key.algorithm, "RSA-PSS"))
21888
- throw unusable("RSA-PSS");
21889
- checkHashLength(key.algorithm, parseInt(alg.slice(2), 10));
21890
- break;
21891
- }
21892
- case "Ed25519":
21893
- case "EdDSA": {
21894
- if (!isAlgorithm(key.algorithm, "Ed25519"))
21895
- throw unusable("Ed25519");
21896
- break;
21897
- }
21898
- case "ML-DSA-44":
21899
- case "ML-DSA-65":
21900
- case "ML-DSA-87": {
21901
- if (!isAlgorithm(key.algorithm, alg))
21902
- throw unusable(alg);
21903
- break;
21904
- }
21905
- case "ES256":
21906
- case "ES384":
21907
- case "ES512": {
21908
- if (!isAlgorithm(key.algorithm, "ECDSA"))
21909
- throw unusable("ECDSA");
21910
- const expected = getNamedCurve(alg);
21911
- const actual = key.algorithm.namedCurve;
21912
- if (actual !== expected)
21913
- throw unusable(expected, "algorithm.namedCurve");
21914
- break;
21915
- }
21916
- default:
21917
- throw new TypeError("CryptoKey does not support this operation");
21918
- }
21919
- checkUsage(key, usage);
21920
- }
21921
- function message(msg, actual, ...types2) {
21922
- types2 = types2.filter(Boolean);
21923
- if (types2.length > 2) {
21924
- const last = types2.pop();
21925
- msg += `one of type ${types2.join(", ")}, or ${last}.`;
21926
- } else if (types2.length === 2) {
21927
- msg += `one of type ${types2[0]} or ${types2[1]}.`;
21928
- } else {
21929
- msg += `of type ${types2[0]}.`;
21930
- }
21931
- if (actual == null) {
21932
- msg += ` Received ${actual}`;
21933
- } else if (typeof actual === "function" && actual.name) {
21934
- msg += ` Received function ${actual.name}`;
21935
- } else if (typeof actual === "object" && actual != null) {
21936
- if (actual.constructor?.name) {
21937
- msg += ` Received an instance of ${actual.constructor.name}`;
21938
- }
21939
- }
21940
- return msg;
21941
- }
21942
- const invalidKeyInput = (actual, ...types2) => message("Key must be ", actual, ...types2);
21943
- const withAlg = (alg, actual, ...types2) => message(`Key for the ${alg} algorithm must be `, actual, ...types2);
21944
- class JOSEError extends Error {
21945
- static code = "ERR_JOSE_GENERIC";
21946
- code = "ERR_JOSE_GENERIC";
21947
- constructor(message2, options2) {
21948
- super(message2, options2);
21949
- this.name = this.constructor.name;
21950
- Error.captureStackTrace?.(this, this.constructor);
21951
- }
21952
- }
21953
- class JOSENotSupported extends JOSEError {
21954
- static code = "ERR_JOSE_NOT_SUPPORTED";
21955
- code = "ERR_JOSE_NOT_SUPPORTED";
21956
- }
21957
- class JWSInvalid extends JOSEError {
21958
- static code = "ERR_JWS_INVALID";
21959
- code = "ERR_JWS_INVALID";
21960
- }
21961
- class JWTInvalid extends JOSEError {
21962
- static code = "ERR_JWT_INVALID";
21963
- code = "ERR_JWT_INVALID";
21964
- }
21965
- const isCryptoKey = (key) => {
21966
- if (key?.[Symbol.toStringTag] === "CryptoKey")
21967
- return true;
21968
- try {
21969
- return key instanceof CryptoKey;
21970
- } catch {
21971
- return false;
21972
- }
21973
- };
21974
- const isKeyObject = (key) => key?.[Symbol.toStringTag] === "KeyObject";
21975
- const isKeyLike = (key) => isCryptoKey(key) || isKeyObject(key);
21976
- function assertNotSet(value, name2) {
21977
- if (value) {
21978
- throw new TypeError(`${name2} can only be called once`);
21979
- }
21980
- }
21981
- const isObjectLike$1 = (value) => typeof value === "object" && value !== null;
21982
- function isObject(input) {
21983
- if (!isObjectLike$1(input) || Object.prototype.toString.call(input) !== "[object Object]") {
21984
- return false;
21985
- }
21986
- if (Object.getPrototypeOf(input) === null) {
21987
- return true;
21988
- }
21989
- let proto = input;
21990
- while (Object.getPrototypeOf(proto) !== null) {
21991
- proto = Object.getPrototypeOf(proto);
21992
- }
21993
- return Object.getPrototypeOf(input) === proto;
21994
- }
21995
- function isDisjoint(...headers) {
21996
- const sources = headers.filter(Boolean);
21997
- if (sources.length === 0 || sources.length === 1) {
21998
- return true;
21999
- }
22000
- let acc;
22001
- for (const header of sources) {
22002
- const parameters = Object.keys(header);
22003
- if (!acc || acc.size === 0) {
22004
- acc = new Set(parameters);
22005
- continue;
22006
- }
22007
- for (const parameter of parameters) {
22008
- if (acc.has(parameter)) {
22009
- return false;
22010
- }
22011
- acc.add(parameter);
22012
- }
22013
- }
22014
- return true;
22015
- }
22016
- const isJWK = (key) => isObject(key) && typeof key.kty === "string";
22017
- const isPrivateJWK = (key) => key.kty !== "oct" && (key.kty === "AKP" && typeof key.priv === "string" || typeof key.d === "string");
22018
- const isPublicJWK = (key) => key.kty !== "oct" && key.d === void 0 && key.priv === void 0;
22019
- const isSecretJWK = (key) => key.kty === "oct" && typeof key.k === "string";
22020
- function checkKeyLength(alg, key) {
22021
- if (alg.startsWith("RS") || alg.startsWith("PS")) {
22022
- const { modulusLength } = key.algorithm;
22023
- if (typeof modulusLength !== "number" || modulusLength < 2048) {
22024
- throw new TypeError(`${alg} requires key modulusLength to be 2048 bits or larger`);
22025
- }
22026
- }
22027
- }
22028
- function subtleAlgorithm(alg, algorithm) {
22029
- const hash = `SHA-${alg.slice(-3)}`;
22030
- switch (alg) {
22031
- case "HS256":
22032
- case "HS384":
22033
- case "HS512":
22034
- return { hash, name: "HMAC" };
22035
- case "PS256":
22036
- case "PS384":
22037
- case "PS512":
22038
- return { hash, name: "RSA-PSS", saltLength: parseInt(alg.slice(-3), 10) >> 3 };
22039
- case "RS256":
22040
- case "RS384":
22041
- case "RS512":
22042
- return { hash, name: "RSASSA-PKCS1-v1_5" };
22043
- case "ES256":
22044
- case "ES384":
22045
- case "ES512":
22046
- return { hash, name: "ECDSA", namedCurve: algorithm.namedCurve };
22047
- case "Ed25519":
22048
- case "EdDSA":
22049
- return { name: "Ed25519" };
22050
- case "ML-DSA-44":
22051
- case "ML-DSA-65":
22052
- case "ML-DSA-87":
22053
- return { name: alg };
22054
- default:
22055
- throw new JOSENotSupported(`alg ${alg} is not supported either by JOSE or your javascript runtime`);
22056
- }
22057
- }
22058
- async function getSigKey(alg, key, usage) {
22059
- if (key instanceof Uint8Array) {
22060
- if (!alg.startsWith("HS")) {
22061
- throw new TypeError(invalidKeyInput(key, "CryptoKey", "KeyObject", "JSON Web Key"));
22062
- }
22063
- return crypto.subtle.importKey("raw", key, { hash: `SHA-${alg.slice(-3)}`, name: "HMAC" }, false, [usage]);
22064
- }
22065
- checkSigCryptoKey(key, alg, usage);
22066
- return key;
22067
- }
22068
- async function sign$2(alg, key, data) {
22069
- const cryptoKey = await getSigKey(alg, key, "sign");
22070
- checkKeyLength(alg, cryptoKey);
22071
- const signature = await crypto.subtle.sign(subtleAlgorithm(alg, cryptoKey.algorithm), cryptoKey, data);
22072
- return new Uint8Array(signature);
22073
- }
22074
- const unsupportedAlg = 'Invalid or unsupported JWK "alg" (Algorithm) Parameter value';
22075
- function subtleMapping(jwk) {
22076
- let algorithm;
22077
- let keyUsages;
22078
- switch (jwk.kty) {
22079
- case "AKP": {
22080
- switch (jwk.alg) {
22081
- case "ML-DSA-44":
22082
- case "ML-DSA-65":
22083
- case "ML-DSA-87":
22084
- algorithm = { name: jwk.alg };
22085
- keyUsages = jwk.priv ? ["sign"] : ["verify"];
22086
- break;
22087
- default:
22088
- throw new JOSENotSupported(unsupportedAlg);
22089
- }
22090
- break;
22091
- }
22092
- case "RSA": {
22093
- switch (jwk.alg) {
22094
- case "PS256":
22095
- case "PS384":
22096
- case "PS512":
22097
- algorithm = { name: "RSA-PSS", hash: `SHA-${jwk.alg.slice(-3)}` };
22098
- keyUsages = jwk.d ? ["sign"] : ["verify"];
22099
- break;
22100
- case "RS256":
22101
- case "RS384":
22102
- case "RS512":
22103
- algorithm = { name: "RSASSA-PKCS1-v1_5", hash: `SHA-${jwk.alg.slice(-3)}` };
22104
- keyUsages = jwk.d ? ["sign"] : ["verify"];
22105
- break;
22106
- case "RSA-OAEP":
22107
- case "RSA-OAEP-256":
22108
- case "RSA-OAEP-384":
22109
- case "RSA-OAEP-512":
22110
- algorithm = {
22111
- name: "RSA-OAEP",
22112
- hash: `SHA-${parseInt(jwk.alg.slice(-3), 10) || 1}`
22113
- };
22114
- keyUsages = jwk.d ? ["decrypt", "unwrapKey"] : ["encrypt", "wrapKey"];
22115
- break;
22116
- default:
22117
- throw new JOSENotSupported(unsupportedAlg);
22118
- }
22119
- break;
22120
- }
22121
- case "EC": {
22122
- switch (jwk.alg) {
22123
- case "ES256":
22124
- case "ES384":
22125
- case "ES512":
22126
- algorithm = {
22127
- name: "ECDSA",
22128
- namedCurve: { ES256: "P-256", ES384: "P-384", ES512: "P-521" }[jwk.alg]
22129
- };
22130
- keyUsages = jwk.d ? ["sign"] : ["verify"];
22131
- break;
22132
- case "ECDH-ES":
22133
- case "ECDH-ES+A128KW":
22134
- case "ECDH-ES+A192KW":
22135
- case "ECDH-ES+A256KW":
22136
- algorithm = { name: "ECDH", namedCurve: jwk.crv };
22137
- keyUsages = jwk.d ? ["deriveBits"] : [];
22138
- break;
22139
- default:
22140
- throw new JOSENotSupported(unsupportedAlg);
22141
- }
22142
- break;
22143
- }
22144
- case "OKP": {
22145
- switch (jwk.alg) {
22146
- case "Ed25519":
22147
- case "EdDSA":
22148
- algorithm = { name: "Ed25519" };
22149
- keyUsages = jwk.d ? ["sign"] : ["verify"];
22150
- break;
22151
- case "ECDH-ES":
22152
- case "ECDH-ES+A128KW":
22153
- case "ECDH-ES+A192KW":
22154
- case "ECDH-ES+A256KW":
22155
- algorithm = { name: jwk.crv };
22156
- keyUsages = jwk.d ? ["deriveBits"] : [];
22157
- break;
22158
- default:
22159
- throw new JOSENotSupported(unsupportedAlg);
22160
- }
22161
- break;
22162
- }
22163
- default:
22164
- throw new JOSENotSupported('Invalid or unsupported JWK "kty" (Key Type) Parameter value');
22165
- }
22166
- return { algorithm, keyUsages };
22167
- }
22168
- async function jwkToKey(jwk) {
22169
- if (!jwk.alg) {
22170
- throw new TypeError('"alg" argument is required when "jwk.alg" is not present');
22171
- }
22172
- const { algorithm, keyUsages } = subtleMapping(jwk);
22173
- const keyData = { ...jwk };
22174
- if (keyData.kty !== "AKP") {
22175
- delete keyData.alg;
22176
- }
22177
- delete keyData.use;
22178
- return crypto.subtle.importKey("jwk", keyData, algorithm, jwk.ext ?? (jwk.d || jwk.priv ? false : true), jwk.key_ops ?? keyUsages);
22179
- }
22180
- const unusableForAlg = "given KeyObject instance cannot be used for this algorithm";
22181
- let cache;
22182
- const handleJWK = async (key, jwk, alg, freeze = false) => {
22183
- cache ||= /* @__PURE__ */ new WeakMap();
22184
- let cached = cache.get(key);
22185
- if (cached?.[alg]) {
22186
- return cached[alg];
22187
- }
22188
- const cryptoKey = await jwkToKey({ ...jwk, alg });
22189
- if (freeze)
22190
- Object.freeze(key);
22191
- if (!cached) {
22192
- cache.set(key, { [alg]: cryptoKey });
22193
- } else {
22194
- cached[alg] = cryptoKey;
22195
- }
22196
- return cryptoKey;
22197
- };
22198
- const handleKeyObject = (keyObject, alg) => {
22199
- cache ||= /* @__PURE__ */ new WeakMap();
22200
- let cached = cache.get(keyObject);
22201
- if (cached?.[alg]) {
22202
- return cached[alg];
22203
- }
22204
- const isPublic = keyObject.type === "public";
22205
- const extractable = isPublic ? true : false;
22206
- let cryptoKey;
22207
- if (keyObject.asymmetricKeyType === "x25519") {
22208
- switch (alg) {
22209
- case "ECDH-ES":
22210
- case "ECDH-ES+A128KW":
22211
- case "ECDH-ES+A192KW":
22212
- case "ECDH-ES+A256KW":
22213
- break;
22214
- default:
22215
- throw new TypeError(unusableForAlg);
22216
- }
22217
- cryptoKey = keyObject.toCryptoKey(keyObject.asymmetricKeyType, extractable, isPublic ? [] : ["deriveBits"]);
22218
- }
22219
- if (keyObject.asymmetricKeyType === "ed25519") {
22220
- if (alg !== "EdDSA" && alg !== "Ed25519") {
22221
- throw new TypeError(unusableForAlg);
22222
- }
22223
- cryptoKey = keyObject.toCryptoKey(keyObject.asymmetricKeyType, extractable, [
22224
- isPublic ? "verify" : "sign"
22225
- ]);
22226
- }
22227
- switch (keyObject.asymmetricKeyType) {
22228
- case "ml-dsa-44":
22229
- case "ml-dsa-65":
22230
- case "ml-dsa-87": {
22231
- if (alg !== keyObject.asymmetricKeyType.toUpperCase()) {
22232
- throw new TypeError(unusableForAlg);
22233
- }
22234
- cryptoKey = keyObject.toCryptoKey(keyObject.asymmetricKeyType, extractable, [
22235
- isPublic ? "verify" : "sign"
22236
- ]);
22237
- }
22238
- }
22239
- if (keyObject.asymmetricKeyType === "rsa") {
22240
- let hash;
22241
- switch (alg) {
22242
- case "RSA-OAEP":
22243
- hash = "SHA-1";
22244
- break;
22245
- case "RS256":
22246
- case "PS256":
22247
- case "RSA-OAEP-256":
22248
- hash = "SHA-256";
22249
- break;
22250
- case "RS384":
22251
- case "PS384":
22252
- case "RSA-OAEP-384":
22253
- hash = "SHA-384";
22254
- break;
22255
- case "RS512":
22256
- case "PS512":
22257
- case "RSA-OAEP-512":
22258
- hash = "SHA-512";
22259
- break;
22260
- default:
22261
- throw new TypeError(unusableForAlg);
22262
- }
22263
- if (alg.startsWith("RSA-OAEP")) {
22264
- return keyObject.toCryptoKey({
22265
- name: "RSA-OAEP",
22266
- hash
22267
- }, extractable, isPublic ? ["encrypt"] : ["decrypt"]);
22268
- }
22269
- cryptoKey = keyObject.toCryptoKey({
22270
- name: alg.startsWith("PS") ? "RSA-PSS" : "RSASSA-PKCS1-v1_5",
22271
- hash
22272
- }, extractable, [isPublic ? "verify" : "sign"]);
22273
- }
22274
- if (keyObject.asymmetricKeyType === "ec") {
22275
- const nist = /* @__PURE__ */ new Map([
22276
- ["prime256v1", "P-256"],
22277
- ["secp384r1", "P-384"],
22278
- ["secp521r1", "P-521"]
22279
- ]);
22280
- const namedCurve = nist.get(keyObject.asymmetricKeyDetails?.namedCurve);
22281
- if (!namedCurve) {
22282
- throw new TypeError(unusableForAlg);
22283
- }
22284
- const expectedCurve = { ES256: "P-256", ES384: "P-384", ES512: "P-521" };
22285
- if (expectedCurve[alg] && namedCurve === expectedCurve[alg]) {
22286
- cryptoKey = keyObject.toCryptoKey({
22287
- name: "ECDSA",
22288
- namedCurve
22289
- }, extractable, [isPublic ? "verify" : "sign"]);
22290
- }
22291
- if (alg.startsWith("ECDH-ES")) {
22292
- cryptoKey = keyObject.toCryptoKey({
22293
- name: "ECDH",
22294
- namedCurve
22295
- }, extractable, isPublic ? [] : ["deriveBits"]);
22296
- }
22297
- }
22298
- if (!cryptoKey) {
22299
- throw new TypeError(unusableForAlg);
22300
- }
22301
- if (!cached) {
22302
- cache.set(keyObject, { [alg]: cryptoKey });
22303
- } else {
22304
- cached[alg] = cryptoKey;
22305
- }
22306
- return cryptoKey;
22307
- };
22308
- async function normalizeKey$1(key, alg) {
22309
- if (key instanceof Uint8Array) {
22310
- return key;
22311
- }
22312
- if (isCryptoKey(key)) {
22313
- return key;
22314
- }
22315
- if (isKeyObject(key)) {
22316
- if (key.type === "secret") {
22317
- return key.export();
22318
- }
22319
- if ("toCryptoKey" in key && typeof key.toCryptoKey === "function") {
22320
- try {
22321
- return handleKeyObject(key, alg);
22322
- } catch (err) {
22323
- if (err instanceof TypeError) {
22324
- throw err;
22325
- }
22326
- }
22327
- }
22328
- let jwk = key.export({ format: "jwk" });
22329
- return handleJWK(key, jwk, alg);
22330
- }
22331
- if (isJWK(key)) {
22332
- if (key.k) {
22333
- return decode$1(key.k);
22334
- }
22335
- return handleJWK(key, key, alg, true);
22336
- }
22337
- throw new Error("unreachable");
22338
- }
22339
- function validateCrit(Err, recognizedDefault, recognizedOption, protectedHeader, joseHeader) {
22340
- if (joseHeader.crit !== void 0 && protectedHeader?.crit === void 0) {
22341
- throw new Err('"crit" (Critical) Header Parameter MUST be integrity protected');
22342
- }
22343
- if (!protectedHeader || protectedHeader.crit === void 0) {
22344
- return /* @__PURE__ */ new Set();
22345
- }
22346
- if (!Array.isArray(protectedHeader.crit) || protectedHeader.crit.length === 0 || protectedHeader.crit.some((input) => typeof input !== "string" || input.length === 0)) {
22347
- throw new Err('"crit" (Critical) Header Parameter MUST be an array of non-empty strings when present');
22348
- }
22349
- let recognized;
22350
- if (recognizedOption !== void 0) {
22351
- recognized = new Map([...Object.entries(recognizedOption), ...recognizedDefault.entries()]);
22352
- } else {
22353
- recognized = recognizedDefault;
22354
- }
22355
- for (const parameter of protectedHeader.crit) {
22356
- if (!recognized.has(parameter)) {
22357
- throw new JOSENotSupported(`Extension Header Parameter "${parameter}" is not recognized`);
22358
- }
22359
- if (joseHeader[parameter] === void 0) {
22360
- throw new Err(`Extension Header Parameter "${parameter}" is missing`);
22361
- }
22362
- if (recognized.get(parameter) && protectedHeader[parameter] === void 0) {
22363
- throw new Err(`Extension Header Parameter "${parameter}" MUST be integrity protected`);
22364
- }
22365
- }
22366
- return new Set(protectedHeader.crit);
22367
- }
22368
- const tag = (key) => key?.[Symbol.toStringTag];
22369
- const jwkMatchesOp = (alg, key, usage) => {
22370
- if (key.use !== void 0) {
22371
- let expected;
22372
- switch (usage) {
22373
- case "sign":
22374
- case "verify":
22375
- expected = "sig";
22376
- break;
22377
- case "encrypt":
22378
- case "decrypt":
22379
- expected = "enc";
22380
- break;
22381
- }
22382
- if (key.use !== expected) {
22383
- throw new TypeError(`Invalid key for this operation, its "use" must be "${expected}" when present`);
22384
- }
22385
- }
22386
- if (key.alg !== void 0 && key.alg !== alg) {
22387
- throw new TypeError(`Invalid key for this operation, its "alg" must be "${alg}" when present`);
22388
- }
22389
- if (Array.isArray(key.key_ops)) {
22390
- let expectedKeyOp;
22391
- switch (true) {
22392
- case usage === "sign":
22393
- case alg === "dir":
22394
- case alg.includes("CBC-HS"):
22395
- expectedKeyOp = usage;
22396
- break;
22397
- case alg.startsWith("PBES2"):
22398
- expectedKeyOp = "deriveBits";
22399
- break;
22400
- case /^A\d{3}(?:GCM)?(?:KW)?$/.test(alg):
22401
- if (!alg.includes("GCM") && alg.endsWith("KW")) {
22402
- expectedKeyOp = "unwrapKey";
22403
- } else {
22404
- expectedKeyOp = usage;
22405
- }
22406
- break;
22407
- case usage === "encrypt":
22408
- expectedKeyOp = "wrapKey";
22409
- break;
22410
- case usage === "decrypt":
22411
- expectedKeyOp = alg.startsWith("RSA") ? "unwrapKey" : "deriveBits";
22412
- break;
22413
- }
22414
- if (expectedKeyOp && key.key_ops?.includes?.(expectedKeyOp) === false) {
22415
- throw new TypeError(`Invalid key for this operation, its "key_ops" must include "${expectedKeyOp}" when present`);
22416
- }
22417
- }
22418
- return true;
22419
- };
22420
- const symmetricTypeCheck = (alg, key, usage) => {
22421
- if (key instanceof Uint8Array)
22422
- return;
22423
- if (isJWK(key)) {
22424
- if (isSecretJWK(key) && jwkMatchesOp(alg, key, usage))
22425
- return;
22426
- throw new TypeError(`JSON Web Key for symmetric algorithms must have JWK "kty" (Key Type) equal to "oct" and the JWK "k" (Key Value) present`);
22427
- }
22428
- if (!isKeyLike(key)) {
22429
- throw new TypeError(withAlg(alg, key, "CryptoKey", "KeyObject", "JSON Web Key", "Uint8Array"));
22430
- }
22431
- if (key.type !== "secret") {
22432
- throw new TypeError(`${tag(key)} instances for symmetric algorithms must be of type "secret"`);
22433
- }
22434
- };
22435
- const asymmetricTypeCheck = (alg, key, usage) => {
22436
- if (isJWK(key)) {
22437
- switch (usage) {
22438
- case "decrypt":
22439
- case "sign":
22440
- if (isPrivateJWK(key) && jwkMatchesOp(alg, key, usage))
22441
- return;
22442
- throw new TypeError(`JSON Web Key for this operation must be a private JWK`);
22443
- case "encrypt":
22444
- case "verify":
22445
- if (isPublicJWK(key) && jwkMatchesOp(alg, key, usage))
22446
- return;
22447
- throw new TypeError(`JSON Web Key for this operation must be a public JWK`);
22448
- }
22449
- }
22450
- if (!isKeyLike(key)) {
22451
- throw new TypeError(withAlg(alg, key, "CryptoKey", "KeyObject", "JSON Web Key"));
22452
- }
22453
- if (key.type === "secret") {
22454
- throw new TypeError(`${tag(key)} instances for asymmetric algorithms must not be of type "secret"`);
22455
- }
22456
- if (key.type === "public") {
22457
- switch (usage) {
22458
- case "sign":
22459
- throw new TypeError(`${tag(key)} instances for asymmetric algorithm signing must be of type "private"`);
22460
- case "decrypt":
22461
- throw new TypeError(`${tag(key)} instances for asymmetric algorithm decryption must be of type "private"`);
22462
- }
22463
- }
22464
- if (key.type === "private") {
22465
- switch (usage) {
22466
- case "verify":
22467
- throw new TypeError(`${tag(key)} instances for asymmetric algorithm verifying must be of type "public"`);
22468
- case "encrypt":
22469
- throw new TypeError(`${tag(key)} instances for asymmetric algorithm encryption must be of type "public"`);
22470
- }
22471
- }
22472
- };
22473
- function checkKeyType(alg, key, usage) {
22474
- switch (alg.substring(0, 2)) {
22475
- case "A1":
22476
- case "A2":
22477
- case "di":
22478
- case "HS":
22479
- case "PB":
22480
- symmetricTypeCheck(alg, key, usage);
22481
- break;
22482
- default:
22483
- asymmetricTypeCheck(alg, key, usage);
22484
- }
22485
- }
22486
- const epoch = (date) => Math.floor(date.getTime() / 1e3);
22487
- const minute = 60;
22488
- const hour = minute * 60;
22489
- const day = hour * 24;
22490
- const week = day * 7;
22491
- const year = day * 365.25;
22492
- const REGEX = /^(\+|\-)? ?(\d+|\d+\.\d+) ?(seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|weeks?|w|years?|yrs?|y)(?: (ago|from now))?$/i;
22493
- function secs(str) {
22494
- const matched = REGEX.exec(str);
22495
- if (!matched || matched[4] && matched[1]) {
22496
- throw new TypeError("Invalid time period format");
22497
- }
22498
- const value = parseFloat(matched[2]);
22499
- const unit = matched[3].toLowerCase();
22500
- let numericDate;
22501
- switch (unit) {
22502
- case "sec":
22503
- case "secs":
22504
- case "second":
22505
- case "seconds":
22506
- case "s":
22507
- numericDate = Math.round(value);
22508
- break;
22509
- case "minute":
22510
- case "minutes":
22511
- case "min":
22512
- case "mins":
22513
- case "m":
22514
- numericDate = Math.round(value * minute);
22515
- break;
22516
- case "hour":
22517
- case "hours":
22518
- case "hr":
22519
- case "hrs":
22520
- case "h":
22521
- numericDate = Math.round(value * hour);
22522
- break;
22523
- case "day":
22524
- case "days":
22525
- case "d":
22526
- numericDate = Math.round(value * day);
22527
- break;
22528
- case "week":
22529
- case "weeks":
22530
- case "w":
22531
- numericDate = Math.round(value * week);
22532
- break;
22533
- default:
22534
- numericDate = Math.round(value * year);
22535
- break;
22536
- }
22537
- if (matched[1] === "-" || matched[4] === "ago") {
22538
- return -numericDate;
22539
- }
22540
- return numericDate;
22541
- }
22542
- function validateInput(label, input) {
22543
- if (!Number.isFinite(input)) {
22544
- throw new TypeError(`Invalid ${label} input`);
22545
- }
22546
- return input;
22547
- }
22548
- class JWTClaimsBuilder {
22549
- #payload;
22550
- constructor(payload) {
22551
- if (!isObject(payload)) {
22552
- throw new TypeError("JWT Claims Set MUST be an object");
22553
- }
22554
- this.#payload = structuredClone(payload);
22555
- }
22556
- data() {
22557
- return encoder.encode(JSON.stringify(this.#payload));
22558
- }
22559
- get iss() {
22560
- return this.#payload.iss;
22561
- }
22562
- set iss(value) {
22563
- this.#payload.iss = value;
22564
- }
22565
- get sub() {
22566
- return this.#payload.sub;
22567
- }
22568
- set sub(value) {
22569
- this.#payload.sub = value;
22570
- }
22571
- get aud() {
22572
- return this.#payload.aud;
22573
- }
22574
- set aud(value) {
22575
- this.#payload.aud = value;
22576
- }
22577
- set jti(value) {
22578
- this.#payload.jti = value;
22579
- }
22580
- set nbf(value) {
22581
- if (typeof value === "number") {
22582
- this.#payload.nbf = validateInput("setNotBefore", value);
22583
- } else if (value instanceof Date) {
22584
- this.#payload.nbf = validateInput("setNotBefore", epoch(value));
22585
- } else {
22586
- this.#payload.nbf = epoch(/* @__PURE__ */ new Date()) + secs(value);
22587
- }
22588
- }
22589
- set exp(value) {
22590
- if (typeof value === "number") {
22591
- this.#payload.exp = validateInput("setExpirationTime", value);
22592
- } else if (value instanceof Date) {
22593
- this.#payload.exp = validateInput("setExpirationTime", epoch(value));
22594
- } else {
22595
- this.#payload.exp = epoch(/* @__PURE__ */ new Date()) + secs(value);
22596
- }
22597
- }
22598
- set iat(value) {
22599
- if (value === void 0) {
22600
- this.#payload.iat = epoch(/* @__PURE__ */ new Date());
22601
- } else if (value instanceof Date) {
22602
- this.#payload.iat = validateInput("setIssuedAt", epoch(value));
22603
- } else if (typeof value === "string") {
22604
- this.#payload.iat = validateInput("setIssuedAt", epoch(/* @__PURE__ */ new Date()) + secs(value));
22605
- } else {
22606
- this.#payload.iat = validateInput("setIssuedAt", value);
22607
- }
22608
- }
22609
- }
22610
- class FlattenedSign {
22611
- #payload;
22612
- #protectedHeader;
22613
- #unprotectedHeader;
22614
- constructor(payload) {
22615
- if (!(payload instanceof Uint8Array)) {
22616
- throw new TypeError("payload must be an instance of Uint8Array");
22617
- }
22618
- this.#payload = payload;
22619
- }
22620
- setProtectedHeader(protectedHeader) {
22621
- assertNotSet(this.#protectedHeader, "setProtectedHeader");
22622
- this.#protectedHeader = protectedHeader;
22623
- return this;
22624
- }
22625
- setUnprotectedHeader(unprotectedHeader) {
22626
- assertNotSet(this.#unprotectedHeader, "setUnprotectedHeader");
22627
- this.#unprotectedHeader = unprotectedHeader;
22628
- return this;
22629
- }
22630
- async sign(key, options2) {
22631
- if (!this.#protectedHeader && !this.#unprotectedHeader) {
22632
- throw new JWSInvalid("either setProtectedHeader or setUnprotectedHeader must be called before #sign()");
22633
- }
22634
- if (!isDisjoint(this.#protectedHeader, this.#unprotectedHeader)) {
22635
- throw new JWSInvalid("JWS Protected and JWS Unprotected Header Parameter names must be disjoint");
22636
- }
22637
- const joseHeader = {
22638
- ...this.#protectedHeader,
22639
- ...this.#unprotectedHeader
22640
- };
22641
- const extensions2 = validateCrit(JWSInvalid, /* @__PURE__ */ new Map([["b64", true]]), options2?.crit, this.#protectedHeader, joseHeader);
22642
- let b64 = true;
22643
- if (extensions2.has("b64")) {
22644
- b64 = this.#protectedHeader.b64;
22645
- if (typeof b64 !== "boolean") {
22646
- throw new JWSInvalid('The "b64" (base64url-encode payload) Header Parameter must be a boolean');
22647
- }
22648
- }
22649
- const { alg } = joseHeader;
22650
- if (typeof alg !== "string" || !alg) {
22651
- throw new JWSInvalid('JWS "alg" (Algorithm) Header Parameter missing or invalid');
22652
- }
22653
- checkKeyType(alg, key, "sign");
22654
- let payloadS;
22655
- let payloadB;
22656
- if (b64) {
22657
- payloadS = encode$3(this.#payload);
22658
- payloadB = encode$4(payloadS);
22659
- } else {
22660
- payloadB = this.#payload;
22661
- payloadS = "";
22662
- }
22663
- let protectedHeaderString;
22664
- let protectedHeaderBytes;
22665
- if (this.#protectedHeader) {
22666
- protectedHeaderString = encode$3(JSON.stringify(this.#protectedHeader));
22667
- protectedHeaderBytes = encode$4(protectedHeaderString);
22668
- } else {
22669
- protectedHeaderString = "";
22670
- protectedHeaderBytes = new Uint8Array();
22671
- }
22672
- const data = concat(protectedHeaderBytes, encode$4("."), payloadB);
22673
- const k = await normalizeKey$1(key, alg);
22674
- const signature = await sign$2(alg, k, data);
22675
- const jws2 = {
22676
- signature: encode$3(signature),
22677
- payload: payloadS
22678
- };
22679
- if (this.#unprotectedHeader) {
22680
- jws2.header = this.#unprotectedHeader;
22681
- }
22682
- if (this.#protectedHeader) {
22683
- jws2.protected = protectedHeaderString;
22684
- }
22685
- return jws2;
22686
- }
22687
- }
22688
- class CompactSign {
22689
- #flattened;
22690
- constructor(payload) {
22691
- this.#flattened = new FlattenedSign(payload);
22692
- }
22693
- setProtectedHeader(protectedHeader) {
22694
- this.#flattened.setProtectedHeader(protectedHeader);
22695
- return this;
22696
- }
22697
- async sign(key, options2) {
22698
- const jws2 = await this.#flattened.sign(key, options2);
22699
- if (jws2.payload === void 0) {
22700
- throw new TypeError("use the flattened module for creating JWS with b64: false");
22701
- }
22702
- return `${jws2.protected}.${jws2.payload}.${jws2.signature}`;
22703
- }
22704
- }
22705
- class SignJWT {
22706
- #protectedHeader;
22707
- #jwt;
22708
- constructor(payload = {}) {
22709
- this.#jwt = new JWTClaimsBuilder(payload);
22710
- }
22711
- setIssuer(issuer) {
22712
- this.#jwt.iss = issuer;
22713
- return this;
22714
- }
22715
- setSubject(subject) {
22716
- this.#jwt.sub = subject;
22717
- return this;
22718
- }
22719
- setAudience(audience) {
22720
- this.#jwt.aud = audience;
22721
- return this;
22722
- }
22723
- setJti(jwtId) {
22724
- this.#jwt.jti = jwtId;
22725
- return this;
22726
- }
22727
- setNotBefore(input) {
22728
- this.#jwt.nbf = input;
22729
- return this;
22730
- }
22731
- setExpirationTime(input) {
22732
- this.#jwt.exp = input;
22733
- return this;
22734
- }
22735
- setIssuedAt(input) {
22736
- this.#jwt.iat = input;
22737
- return this;
22738
- }
22739
- setProtectedHeader(protectedHeader) {
22740
- this.#protectedHeader = protectedHeader;
22741
- return this;
22742
- }
22743
- async sign(key, options2) {
22744
- const sig = new CompactSign(this.#jwt.data());
22745
- sig.setProtectedHeader(this.#protectedHeader);
22746
- if (Array.isArray(this.#protectedHeader?.crit) && this.#protectedHeader.crit.includes("b64") && this.#protectedHeader.b64 === false) {
22747
- throw new JWTInvalid("JWTs MUST NOT use unencoded payload");
22748
- }
22749
- return sig.sign(key, options2);
22750
- }
22751
- }
22752
21946
  function createAppleProvider(config) {
22753
21947
  async function generateClientSecret() {
22754
- const key = createPrivateKey$1({
22755
- key: config.privateKey,
22756
- format: "pem"
21948
+ return jwt.sign({}, config.privateKey, {
21949
+ algorithm: "ES256",
21950
+ keyid: config.keyId,
21951
+ issuer: config.teamId,
21952
+ expiresIn: "180d",
21953
+ audience: "https://appleid.apple.com",
21954
+ subject: config.clientId
22757
21955
  });
22758
- const now = Math.floor(Date.now() / 1e3);
22759
- return new SignJWT({}).setProtectedHeader({
22760
- alg: "ES256",
22761
- kid: config.keyId
22762
- }).setIssuer(config.teamId).setIssuedAt(now).setExpirationTime(now + 86400 * 180).setAudience("https://appleid.apple.com").setSubject(config.clientId).sign(key);
22763
21956
  }
22764
21957
  return {
22765
21958
  id: "apple",
@@ -23567,7 +22760,7 @@ function createRateLimiter(options2 = {}) {
23567
22760
  windowMs = 15 * 60 * 1e3,
23568
22761
  limit = 100,
23569
22762
  keyGenerator = defaultKeyGenerator,
23570
- message: message2 = "Too many requests, please try again later."
22763
+ message = "Too many requests, please try again later."
23571
22764
  } = options2;
23572
22765
  const store = /* @__PURE__ */ new Map();
23573
22766
  const cleanupInterval = setInterval(() => {
@@ -23602,7 +22795,7 @@ function createRateLimiter(options2 = {}) {
23602
22795
  c.header("X-RateLimit-Reset", String(Math.ceil((now + retryAfterMs) / 1e3)));
23603
22796
  return c.json({
23604
22797
  error: {
23605
- message: message2,
22798
+ message,
23606
22799
  code: "RATE_LIMITED"
23607
22800
  }
23608
22801
  }, 429);
@@ -23614,7 +22807,12 @@ function createRateLimiter(options2 = {}) {
23614
22807
  };
23615
22808
  }
23616
22809
  function defaultKeyGenerator(c) {
23617
- return c.req.header("x-forwarded-for")?.split(",")[0]?.trim() || c.req.header("x-real-ip") || "unknown";
22810
+ const forwardedFor = c.req.header("x-forwarded-for");
22811
+ if (forwardedFor) {
22812
+ const ips = forwardedFor.split(",");
22813
+ return ips[ips.length - 1].trim();
22814
+ }
22815
+ return c.req.header("x-real-ip") || "unknown";
23618
22816
  }
23619
22817
  const defaultAuthLimiter = createRateLimiter({
23620
22818
  windowMs: 15 * 60 * 1e3,
@@ -23761,7 +22959,11 @@ function createAuthRoutes(config) {
23761
22959
  passwordHash,
23762
22960
  displayName: displayName || void 0
23763
22961
  });
23764
- if (config.defaultRole) {
22962
+ const existingUsers = await authRepo.listUsers();
22963
+ const isFirstUser = existingUsers.length === 1 && existingUsers[0].id === user.id;
22964
+ if (isFirstUser) {
22965
+ await authRepo.setUserRoles(user.id, ["admin"]);
22966
+ } else if (config.defaultRole) {
23765
22967
  await authRepo.assignDefaultRole(user.id, config.defaultRole);
23766
22968
  }
23767
22969
  const {
@@ -23802,7 +23004,13 @@ function createAuthRoutes(config) {
23802
23004
  for (const provider of config.oauthProviders) {
23803
23005
  router.post(`/${provider.id}`, defaultAuthLimiter, async (c) => {
23804
23006
  const payload = parseBody2(provider.schema, await c.req.json());
23805
- const externalUser = await provider.verify(payload);
23007
+ let externalUser;
23008
+ try {
23009
+ externalUser = await provider.verify(payload);
23010
+ } catch (err) {
23011
+ const msg = err instanceof Error ? err.message : String(err);
23012
+ throw ApiError.unauthorized(`${provider.id} login failed: ${msg}`, "OAUTH_ERROR");
23013
+ }
23806
23014
  if (!externalUser) {
23807
23015
  throw ApiError.unauthorized(`Invalid ${provider.id} credentials`, "INVALID_TOKEN");
23808
23016
  }
@@ -23826,7 +23034,11 @@ function createAuthRoutes(config) {
23826
23034
  await authRepo.linkUserIdentity(user.id, provider.id, externalUser.providerId, {
23827
23035
  email: externalUser.email
23828
23036
  });
23829
- if (config.defaultRole) {
23037
+ const allUsers = await authRepo.listUsers();
23038
+ const isFirstUser = allUsers.length === 1 && allUsers[0].id === user.id;
23039
+ if (isFirstUser) {
23040
+ await authRepo.setUserRoles(user.id, ["admin"]);
23041
+ } else if (config.defaultRole) {
23830
23042
  await authRepo.assignDefaultRole(user.id, config.defaultRole);
23831
23043
  }
23832
23044
  sendWelcomeEmail({
@@ -24182,8 +23394,45 @@ function createAdminRoutes(config) {
24182
23394
  const authRepo = config.authRepo;
24183
23395
  const {
24184
23396
  emailService,
24185
- emailConfig
23397
+ emailConfig,
23398
+ hooks
24186
23399
  } = config;
23400
+ function buildHookContext(c, method) {
23401
+ const user = c.get("user");
23402
+ return {
23403
+ requestUser: user ? {
23404
+ userId: user.userId,
23405
+ roles: user.roles ?? []
23406
+ } : void 0,
23407
+ method
23408
+ };
23409
+ }
23410
+ async function applyUserAfterRead(user, ctx) {
23411
+ if (!hooks?.users?.afterRead) return user;
23412
+ return hooks.users.afterRead(user, ctx);
23413
+ }
23414
+ async function applyUserAfterReadBatch(users, ctx) {
23415
+ if (!hooks?.users?.afterRead) return users;
23416
+ const results = await Promise.all(users.map((u) => applyUserAfterRead(u, ctx)));
23417
+ return results.filter((u) => u !== null);
23418
+ }
23419
+ async function applyRoleAfterReadBatch(roles, ctx) {
23420
+ if (!hooks?.roles?.afterRead) return roles;
23421
+ const results = await Promise.all(roles.map((r) => hooks.roles.afterRead(r, ctx)));
23422
+ return results.filter((r) => r !== null);
23423
+ }
23424
+ function toAdminUser(u, roles) {
23425
+ return {
23426
+ uid: u.id,
23427
+ email: u.email,
23428
+ displayName: u.displayName ?? null,
23429
+ photoURL: u.photoUrl ?? null,
23430
+ provider: "custom",
23431
+ roles,
23432
+ createdAt: u.createdAt instanceof Date ? u.createdAt.toISOString() : u.createdAt ?? (/* @__PURE__ */ new Date()).toISOString(),
23433
+ updatedAt: u.updatedAt instanceof Date ? u.updatedAt.toISOString() : u.updatedAt ?? (/* @__PURE__ */ new Date()).toISOString()
23434
+ };
23435
+ }
24187
23436
  router.onError(errorHandler);
24188
23437
  router.use("/*", createRequireAuth({
24189
23438
  serviceKey: config.serviceKey
@@ -24234,6 +23483,7 @@ function createAdminRoutes(config) {
24234
23483
  const search = c.req.query("search");
24235
23484
  const orderBy = c.req.query("orderBy");
24236
23485
  const orderDir = c.req.query("orderDir");
23486
+ const hookCtx = buildHookContext(c, "GET");
24237
23487
  if (limitParam !== void 0 || search) {
24238
23488
  const limit = limitParam ? parseInt(limitParam, 10) : 25;
24239
23489
  const offset = offsetParam ? parseInt(offsetParam, 10) : 0;
@@ -24245,18 +23495,11 @@ function createAdminRoutes(config) {
24245
23495
  orderDir: orderDir || void 0,
24246
23496
  roleId: c.req.query("role") || void 0
24247
23497
  });
24248
- const usersWithRoles2 = await Promise.all(result.users.map(async (u) => {
23498
+ let usersWithRoles2 = await Promise.all(result.users.map(async (u) => {
24249
23499
  const roles = await authRepo.getUserRoleIds(u.id);
24250
- return {
24251
- uid: u.id,
24252
- email: u.email,
24253
- displayName: u.displayName,
24254
- photoURL: u.photoUrl,
24255
- roles,
24256
- createdAt: u.createdAt,
24257
- updatedAt: u.updatedAt
24258
- };
23500
+ return toAdminUser(u, roles);
24259
23501
  }));
23502
+ usersWithRoles2 = await applyUserAfterReadBatch(usersWithRoles2, hookCtx);
24260
23503
  return c.json({
24261
23504
  users: usersWithRoles2,
24262
23505
  total: result.total,
@@ -24265,18 +23508,11 @@ function createAdminRoutes(config) {
24265
23508
  });
24266
23509
  }
24267
23510
  const users = await authRepo.listUsers();
24268
- const usersWithRoles = await Promise.all(users.map(async (u) => {
23511
+ let usersWithRoles = await Promise.all(users.map(async (u) => {
24269
23512
  const roles = await authRepo.getUserRoleIds(u.id);
24270
- return {
24271
- uid: u.id,
24272
- email: u.email,
24273
- displayName: u.displayName,
24274
- photoURL: u.photoUrl,
24275
- roles,
24276
- createdAt: u.createdAt,
24277
- updatedAt: u.updatedAt
24278
- };
23513
+ return toAdminUser(u, roles);
24279
23514
  }));
23515
+ usersWithRoles = await applyUserAfterReadBatch(usersWithRoles, hookCtx);
24280
23516
  return c.json({
24281
23517
  users: usersWithRoles
24282
23518
  });
@@ -24287,21 +23523,19 @@ function createAdminRoutes(config) {
24287
23523
  if (!result) {
24288
23524
  throw ApiError.notFound("User not found");
24289
23525
  }
23526
+ const hookCtx = buildHookContext(c, "GET");
23527
+ let adminUser = toAdminUser(result.user, result.roles.map((r) => r.id));
23528
+ adminUser = await applyUserAfterRead(adminUser, hookCtx);
23529
+ if (!adminUser) {
23530
+ throw ApiError.notFound("User not found");
23531
+ }
24290
23532
  return c.json({
24291
- user: {
24292
- uid: result.user.id,
24293
- email: result.user.email,
24294
- displayName: result.user.displayName,
24295
- photoURL: result.user.photoUrl,
24296
- roles: result.roles.map((r) => r.id),
24297
- createdAt: result.user.createdAt,
24298
- updatedAt: result.user.updatedAt
24299
- }
23533
+ user: adminUser
24300
23534
  });
24301
23535
  });
24302
23536
  router.post("/users", requireAdmin, async (c) => {
24303
23537
  const body = await c.req.json();
24304
- const {
23538
+ let {
24305
23539
  email,
24306
23540
  displayName,
24307
23541
  password,
@@ -24310,6 +23544,17 @@ function createAdminRoutes(config) {
24310
23544
  if (!email) {
24311
23545
  throw ApiError.badRequest("Email is required", "INVALID_INPUT");
24312
23546
  }
23547
+ const hookCtx = buildHookContext(c, "POST");
23548
+ if (hooks?.users?.beforeSave) {
23549
+ const hooked = await hooks.users.beforeSave({
23550
+ email,
23551
+ displayName,
23552
+ roles
23553
+ }, hookCtx);
23554
+ email = hooked.email ?? email;
23555
+ displayName = hooked.displayName ?? displayName;
23556
+ roles = hooked.roles ?? roles;
23557
+ }
24313
23558
  const existing = await authRepo.getUserByEmail(email);
24314
23559
  if (existing) {
24315
23560
  throw ApiError.conflict("Email already exists", "EMAIL_EXISTS");
@@ -24365,13 +23610,14 @@ function createAdminRoutes(config) {
24365
23610
  } else if (!password) {
24366
23611
  temporaryPassword = clearPassword;
24367
23612
  }
23613
+ const createdAdminUser = toAdminUser(user, userRoles);
23614
+ if (hooks?.users?.afterSave) {
23615
+ Promise.resolve(hooks.users.afterSave(createdAdminUser, hookCtx)).catch((err) => {
23616
+ console.error("[BackendHooks] users.afterSave error:", err instanceof Error ? err.message : err);
23617
+ });
23618
+ }
24368
23619
  return c.json({
24369
- user: {
24370
- uid: user.id,
24371
- email: user.email,
24372
- displayName: user.displayName,
24373
- roles: userRoles
24374
- },
23620
+ user: createdAdminUser,
24375
23621
  invitationSent,
24376
23622
  ...temporaryPassword ? {
24377
23623
  temporaryPassword
@@ -24441,7 +23687,7 @@ function createAdminRoutes(config) {
24441
23687
  router.put("/users/:userId", requireAdmin, async (c) => {
24442
23688
  const userId = c.req.param("userId");
24443
23689
  const body = await c.req.json();
24444
- const {
23690
+ let {
24445
23691
  email,
24446
23692
  displayName,
24447
23693
  password,
@@ -24451,6 +23697,17 @@ function createAdminRoutes(config) {
24451
23697
  if (!existing) {
24452
23698
  throw ApiError.notFound("User not found");
24453
23699
  }
23700
+ const hookCtx = buildHookContext(c, "PUT");
23701
+ if (hooks?.users?.beforeSave) {
23702
+ const hooked = await hooks.users.beforeSave({
23703
+ email,
23704
+ displayName,
23705
+ roles
23706
+ }, hookCtx);
23707
+ email = hooked.email ?? email;
23708
+ displayName = hooked.displayName ?? displayName;
23709
+ roles = hooked.roles ?? roles;
23710
+ }
24454
23711
  const updates = {};
24455
23712
  if (email !== void 0) updates.email = email.toLowerCase();
24456
23713
  if (displayName !== void 0) updates.displayName = displayName;
@@ -24468,13 +23725,14 @@ function createAdminRoutes(config) {
24468
23725
  await authRepo.setUserRoles(userId, roles);
24469
23726
  }
24470
23727
  const result = await authRepo.getUserWithRoles(userId);
23728
+ const updatedAdminUser = toAdminUser(result.user, result.roles.map((r) => r.id));
23729
+ if (hooks?.users?.afterSave) {
23730
+ Promise.resolve(hooks.users.afterSave(updatedAdminUser, hookCtx)).catch((err) => {
23731
+ console.error("[BackendHooks] users.afterSave error:", err instanceof Error ? err.message : err);
23732
+ });
23733
+ }
24471
23734
  return c.json({
24472
- user: {
24473
- uid: result.user.id,
24474
- email: result.user.email,
24475
- displayName: result.user.displayName,
24476
- roles: result.roles.map((r) => r.id)
24477
- }
23735
+ user: updatedAdminUser
24478
23736
  });
24479
23737
  });
24480
23738
  router.delete("/users/:userId", requireAdmin, async (c) => {
@@ -24488,21 +23746,33 @@ function createAdminRoutes(config) {
24488
23746
  if (!existing) {
24489
23747
  throw ApiError.notFound("User not found");
24490
23748
  }
23749
+ const hookCtx = buildHookContext(c, "DELETE");
23750
+ if (hooks?.users?.beforeDelete) {
23751
+ await hooks.users.beforeDelete(userId, hookCtx);
23752
+ }
24491
23753
  await authRepo.deleteUser(userId);
23754
+ if (hooks?.users?.afterDelete) {
23755
+ Promise.resolve(hooks.users.afterDelete(userId, hookCtx)).catch((err) => {
23756
+ console.error("[BackendHooks] users.afterDelete error:", err instanceof Error ? err.message : err);
23757
+ });
23758
+ }
24492
23759
  return c.json({
24493
23760
  success: true
24494
23761
  });
24495
23762
  });
24496
23763
  router.get("/roles", requireAdmin, async (c) => {
24497
23764
  const roles = await authRepo.listRoles();
23765
+ const hookCtx = buildHookContext(c, "GET");
23766
+ let adminRoles = roles.map((r) => ({
23767
+ id: r.id,
23768
+ name: r.name,
23769
+ isAdmin: r.isAdmin,
23770
+ defaultPermissions: r.defaultPermissions,
23771
+ config: r.config
23772
+ }));
23773
+ adminRoles = await applyRoleAfterReadBatch(adminRoles, hookCtx);
24498
23774
  return c.json({
24499
- roles: roles.map((r) => ({
24500
- id: r.id,
24501
- name: r.name,
24502
- isAdmin: r.isAdmin,
24503
- defaultPermissions: r.defaultPermissions,
24504
- config: r.config
24505
- }))
23775
+ roles: adminRoles
24506
23776
  });
24507
23777
  });
24508
23778
  router.get("/roles/:roleId", requireAdmin, async (c) => {
@@ -24630,10 +23900,10 @@ class LocalStorageController {
24630
23900
  * Includes a path traversal guard to prevent escaping the base directory.
24631
23901
  */
24632
23902
  getFullPath(storagePath, bucket) {
24633
- const parts = bucket ? [this.basePath, bucket, storagePath] : [this.basePath, storagePath];
24634
- const resolved = path$3.resolve(path$3.join(...parts));
24635
- if (!resolved.startsWith(this.basePath + path$3.sep) && resolved !== this.basePath) {
24636
- throw new Error("Path traversal detected: resolved storage path is outside the base directory.");
23903
+ const bucketPath = bucket ? path$3.join(this.basePath, bucket) : this.basePath;
23904
+ const resolved = path$3.resolve(path$3.join(bucketPath, storagePath));
23905
+ if (!resolved.startsWith(bucketPath + path$3.sep) && resolved !== bucketPath) {
23906
+ throw new Error("Path traversal detected: resolved storage path is outside the bucket directory.");
24637
23907
  }
24638
23908
  return resolved;
24639
23909
  }
@@ -24780,17 +24050,34 @@ class LocalStorageController {
24780
24050
  }
24781
24051
  }
24782
24052
  resolvedPath = normalizeStoragePath(resolvedPath);
24053
+ if (!resolvedPath) {
24054
+ return;
24055
+ }
24783
24056
  const fullPath = this.getFullPath(resolvedPath, resolvedBucket);
24784
24057
  try {
24785
- await unlink(fullPath);
24786
- try {
24787
- await unlink(`${fullPath}.metadata.json`);
24788
- } catch {
24058
+ await access(fullPath, fs$4.constants.F_OK);
24059
+ } catch {
24060
+ return;
24061
+ }
24062
+ try {
24063
+ const stats = await stat(fullPath);
24064
+ if (stats.isDirectory()) {
24065
+ await fs$4.promises.rmdir(fullPath);
24066
+ } else {
24067
+ await unlink(fullPath);
24068
+ try {
24069
+ await unlink(`${fullPath}.metadata.json`);
24070
+ } catch {
24071
+ }
24789
24072
  }
24790
24073
  } catch (error2) {
24791
- if (error2 instanceof Error && error2.code !== "ENOENT") {
24792
- throw error2;
24074
+ if (error2 instanceof Error) {
24075
+ const code2 = error2.code;
24076
+ if (code2 === "ENOENT" || code2 === "ENOTEMPTY") {
24077
+ return;
24078
+ }
24793
24079
  }
24080
+ throw error2;
24794
24081
  }
24795
24082
  }
24796
24083
  async listObjects(prefix, options2) {
@@ -24897,7 +24184,8 @@ class S3StorageController {
24897
24184
  * Get the bucket name - either from parameter or config
24898
24185
  */
24899
24186
  getBucket(bucket) {
24900
- return bucket ?? this.config.bucket;
24187
+ if (!bucket || bucket === "default") return this.config.bucket;
24188
+ return bucket;
24901
24189
  }
24902
24190
  async putObject({
24903
24191
  file,
@@ -25185,11 +24473,18 @@ function createStorageRoutes(config) {
25185
24473
  const fileContent = fs$4.readFileSync(absolutePath);
25186
24474
  return c.body(new Uint8Array(fileContent));
25187
24475
  }
25188
- const downloadConfig = await controller.getSignedUrl(filePath);
25189
- if (downloadConfig.fileNotFound || !downloadConfig.url) {
24476
+ const {
24477
+ bucket: parsedBucket,
24478
+ resolvedPath: parsedPath
24479
+ } = parseBucketAndPath(filePath);
24480
+ const fileObject = await controller.getObject(parsedPath, parsedBucket);
24481
+ if (!fileObject) {
25190
24482
  throw ApiError.notFound("File not found");
25191
24483
  }
25192
- return c.redirect(downloadConfig.url);
24484
+ c.header("Content-Type", fileObject.type || "application/octet-stream");
24485
+ c.header("Cache-Control", "public, max-age=3600, immutable");
24486
+ const buf = await fileObject.arrayBuffer();
24487
+ return c.body(new Uint8Array(buf));
25193
24488
  });
25194
24489
  router.get("/metadata/*", readAuthMiddleware, async (c) => {
25195
24490
  const rawPath = extractWildcardPath(c);
@@ -25239,7 +24534,7 @@ function createStorageRoutes(config) {
25239
24534
  const maxResults = c.req.query("maxResults");
25240
24535
  const pageToken = c.req.query("pageToken");
25241
24536
  const result = await controller.listObjects(storagePrefix, {
25242
- bucket,
24537
+ bucket: bucket ?? (controller.getType() === "local" ? "default" : void 0),
25243
24538
  maxResults: maxResults ? parseInt(maxResults, 10) : void 0,
25244
24539
  pageToken
25245
24540
  });
@@ -25248,6 +24543,40 @@ function createStorageRoutes(config) {
25248
24543
  data: result
25249
24544
  });
25250
24545
  });
24546
+ router.post("/folder", writeAuthMiddleware, async (c) => {
24547
+ const body = await c.req.json();
24548
+ const folderPath = body.path;
24549
+ if (!folderPath || typeof folderPath !== "string") {
24550
+ throw ApiError.badRequest("Folder path is required");
24551
+ }
24552
+ const {
24553
+ bucket,
24554
+ resolvedPath
24555
+ } = parseBucketAndPath(folderPath);
24556
+ if (!resolvedPath || resolvedPath.trim() === "") {
24557
+ throw ApiError.badRequest("Invalid folder path");
24558
+ }
24559
+ if (controller.getType() === "local") {
24560
+ const localController = controller;
24561
+ const absolutePath = localController.getAbsolutePath(resolvedPath, bucket);
24562
+ fs$4.mkdirSync(absolutePath, {
24563
+ recursive: true
24564
+ });
24565
+ } else {
24566
+ const key = resolvedPath.endsWith("/") ? resolvedPath : resolvedPath + "/";
24567
+ const emptyFile = new File([], key, {
24568
+ type: "application/x-directory"
24569
+ });
24570
+ await controller.putObject({
24571
+ file: emptyFile,
24572
+ key
24573
+ });
24574
+ }
24575
+ return c.json({
24576
+ success: true,
24577
+ message: "Folder created"
24578
+ }, 201);
24579
+ });
25251
24580
  return router;
25252
24581
  }
25253
24582
  const DEFAULT_STORAGE_ID = "(default)";
@@ -25371,8 +24700,8 @@ class RebaseApiError extends Error {
25371
24700
  status;
25372
24701
  code;
25373
24702
  details;
25374
- constructor(status, message2, code2, details) {
25375
- super(message2);
24703
+ constructor(status, message, code2, details) {
24704
+ super(message);
25376
24705
  this.name = "RebaseApiError";
25377
24706
  this.status = status;
25378
24707
  this.code = code2;
@@ -25702,20 +25031,21 @@ function createAuth(transport, options2) {
25702
25031
  refreshToken: session.refreshToken
25703
25032
  };
25704
25033
  }
25705
- async function signInWithGoogle(idToken) {
25034
+ async function signInWithGoogle(tokenOrPayload) {
25706
25035
  const fetchFn = getFetch();
25036
+ const body = typeof tokenOrPayload === "string" ? {
25037
+ idToken: tokenOrPayload
25038
+ } : tokenOrPayload;
25707
25039
  const res = await fetchFn(authUrl("/google"), {
25708
25040
  method: "POST",
25709
25041
  headers: {
25710
25042
  "Content-Type": "application/json"
25711
25043
  },
25712
- body: JSON.stringify({
25713
- idToken
25714
- })
25044
+ body: JSON.stringify(body)
25715
25045
  });
25716
- const body = await res.json().catch(() => ({}));
25717
- if (!res.ok) throwApiError(res.status, body, res.statusText);
25718
- const session = handleAuthResponse(body, "SIGNED_IN");
25046
+ const responseBody = await res.json().catch(() => ({}));
25047
+ if (!res.ok) throwApiError(res.status, responseBody, res.statusText);
25048
+ const session = handleAuthResponse(responseBody, "SIGNED_IN");
25719
25049
  return {
25720
25050
  user: session.user,
25721
25051
  accessToken: session.accessToken,
@@ -26343,6 +25673,18 @@ function createCollectionClient(transport, slug, ws) {
26343
25673
  method: "DELETE"
26344
25674
  });
26345
25675
  },
25676
+ async count(params) {
25677
+ const countParams = {
25678
+ ...params,
25679
+ limit: void 0,
25680
+ offset: void 0
25681
+ };
25682
+ const qs = buildQueryString(countParams);
25683
+ const raw = await transport.request(basePath + "/count" + qs, {
25684
+ method: "GET"
25685
+ });
25686
+ return raw.count ?? 0;
25687
+ },
26346
25688
  // Fluent builder instantiation
26347
25689
  where(column, operator, value) {
26348
25690
  return new QueryBuilder(client).where(column, operator, value);
@@ -26365,6 +25707,25 @@ function createCollectionClient(transport, slug, ws) {
26365
25707
  };
26366
25708
  return client;
26367
25709
  }
25710
+ function createFunctionsClient(transport) {
25711
+ return {
25712
+ async invoke(name2, payload, options2) {
25713
+ const method = options2?.method ?? "POST";
25714
+ const subPath = options2?.path ? `/${options2.path.replace(/^\//, "")}` : "";
25715
+ const routePath = `/functions/${encodeURIComponent(name2)}${subPath}`;
25716
+ const init = {
25717
+ method
25718
+ };
25719
+ if (payload !== void 0 && method !== "GET") {
25720
+ init.body = JSON.stringify(payload);
25721
+ }
25722
+ if (options2?.headers) {
25723
+ init.headers = options2.headers;
25724
+ }
25725
+ return transport.request(routePath, init);
25726
+ }
25727
+ };
25728
+ }
26368
25729
  function createStorage(transport) {
26369
25730
  const urlsCache = /* @__PURE__ */ new Map();
26370
25731
  async function putObject({
@@ -26498,6 +25859,7 @@ function createRebaseClient(options2) {
26498
25859
  const admin = createAdmin(transport, options2.admin);
26499
25860
  const cron = createCron(transport, options2.cron);
26500
25861
  const storage = createStorage(transport);
25862
+ const functions = createFunctionsClient(transport);
26501
25863
  let ws;
26502
25864
  if (!options2.onUnauthorized) {
26503
25865
  transport.setOnUnauthorized(async () => {
@@ -26536,6 +25898,7 @@ function createRebaseClient(options2) {
26536
25898
  auth,
26537
25899
  admin,
26538
25900
  cron,
25901
+ functions,
26539
25902
  storage,
26540
25903
  ws,
26541
25904
  setToken: transport.setToken,
@@ -27349,7 +26712,7 @@ var fetchExports = fetch$1.exports;
27349
26712
  });
27350
26713
  return options2;
27351
26714
  };
27352
- module.exports._logFunc = (logger2, level, defaults, data, message2, ...args) => {
26715
+ module.exports._logFunc = (logger2, level, defaults, data, message, ...args) => {
27353
26716
  let entry = {};
27354
26717
  Object.keys(defaults || {}).forEach((key) => {
27355
26718
  if (key !== "level") {
@@ -27361,7 +26724,7 @@ var fetchExports = fetch$1.exports;
27361
26724
  entry[key] = data[key];
27362
26725
  }
27363
26726
  });
27364
- logger2[level](entry, message2, ...args);
26727
+ logger2[level](entry, message, ...args);
27365
26728
  };
27366
26729
  module.exports.getLogger = (options2, defaults) => {
27367
26730
  options2 = options2 || {};
@@ -27378,8 +26741,8 @@ var fetchExports = fetch$1.exports;
27378
26741
  logger2 = createDefaultLogger(levels);
27379
26742
  }
27380
26743
  levels.forEach((level) => {
27381
- response[level] = (data, message2, ...args) => {
27382
- module.exports._logFunc(logger2, level, defaults, data, message2, ...args);
26744
+ response[level] = (data, message, ...args) => {
26745
+ module.exports._logFunc(logger2, level, defaults, data, message, ...args);
27383
26746
  };
27384
26747
  });
27385
26748
  return response;
@@ -27562,7 +26925,7 @@ var fetchExports = fetch$1.exports;
27562
26925
  }
27563
26926
  levelNames.set(level, levelName);
27564
26927
  });
27565
- let print2 = (level, entry, message2, ...args) => {
26928
+ let print2 = (level, entry, message, ...args) => {
27566
26929
  let prefix = "";
27567
26930
  if (entry) {
27568
26931
  if (entry.tnx === "server") {
@@ -27577,8 +26940,8 @@ var fetchExports = fetch$1.exports;
27577
26940
  prefix = "[#" + entry.cid + "] " + prefix;
27578
26941
  }
27579
26942
  }
27580
- message2 = util2.format(message2, ...args);
27581
- message2.split(/\r?\n/).forEach((line) => {
26943
+ message = util2.format(message, ...args);
26944
+ message.split(/\r?\n/).forEach((line) => {
27582
26945
  console.log("[%s] %s %s", (/* @__PURE__ */ new Date()).toISOString().substr(0, 19).replace(/T/, " "), levelNames.get(level), prefix + line);
27583
26946
  });
27584
26947
  };
@@ -34074,8 +33437,8 @@ let SMTPConnection$3 = class SMTPConnection extends EventEmitter$4 {
34074
33437
  * @param {Object} message String, Buffer or a Stream
34075
33438
  * @param {Function} callback Callback to return once sending is completed
34076
33439
  */
34077
- send(envelope, message2, done) {
34078
- if (!message2) {
33440
+ send(envelope, message, done) {
33441
+ if (!message) {
34079
33442
  return done(this._formatError("Empty message", "EMESSAGE", false, "API"));
34080
33443
  }
34081
33444
  const isDestroyedMessage = this._isDestroyedMessage("send message");
@@ -34095,17 +33458,17 @@ let SMTPConnection$3 = class SMTPConnection extends EventEmitter$4 {
34095
33458
  returned = true;
34096
33459
  done(...arguments);
34097
33460
  };
34098
- if (typeof message2.on === "function") {
34099
- message2.on("error", (err) => callback(this._formatError(err, "ESTREAM", false, "API")));
33461
+ if (typeof message.on === "function") {
33462
+ message.on("error", (err) => callback(this._formatError(err, "ESTREAM", false, "API")));
34100
33463
  }
34101
33464
  let startTime = Date.now();
34102
33465
  this._setEnvelope(envelope, (err, info) => {
34103
33466
  if (err) {
34104
33467
  let stream3 = new PassThrough();
34105
- if (typeof message2.pipe === "function") {
34106
- message2.pipe(stream3);
33468
+ if (typeof message.pipe === "function") {
33469
+ message.pipe(stream3);
34107
33470
  } else {
34108
- stream3.write(message2);
33471
+ stream3.write(message);
34109
33472
  stream3.end();
34110
33473
  }
34111
33474
  return callback(err);
@@ -34121,10 +33484,10 @@ let SMTPConnection$3 = class SMTPConnection extends EventEmitter$4 {
34121
33484
  info.response = str;
34122
33485
  return callback(null, info);
34123
33486
  });
34124
- if (typeof message2.pipe === "function") {
34125
- message2.pipe(stream2);
33487
+ if (typeof message.pipe === "function") {
33488
+ message.pipe(stream2);
34126
33489
  } else {
34127
- stream2.write(message2);
33490
+ stream2.write(message);
34128
33491
  stream2.end();
34129
33492
  }
34130
33493
  });
@@ -34237,12 +33600,12 @@ let SMTPConnection$3 = class SMTPConnection extends EventEmitter$4 {
34237
33600
  this.emit("error", err);
34238
33601
  this.close();
34239
33602
  }
34240
- _formatError(message2, type, response, command) {
33603
+ _formatError(message, type, response, command) {
34241
33604
  let err;
34242
- if (/Error\]$/i.test(Object.prototype.toString.call(message2))) {
34243
- err = message2;
33605
+ if (/Error\]$/i.test(Object.prototype.toString.call(message))) {
33606
+ err = message;
34244
33607
  } else {
34245
- err = new Error(message2);
33608
+ err = new Error(message);
34246
33609
  }
34247
33610
  if (type && type !== "Error") {
34248
33611
  err.code = type;
@@ -34885,14 +34248,14 @@ let SMTPConnection$3 = class SMTPConnection extends EventEmitter$4 {
34885
34248
  * @param {String} str Message from the server
34886
34249
  */
34887
34250
  _actionMAIL(str, callback) {
34888
- let message2, curRecipient;
34251
+ let message, curRecipient;
34889
34252
  if (Number(str.charAt(0)) !== 2) {
34890
34253
  if (this._usingSmtpUtf8 && /^550 /.test(str) && /[\x80-\uFFFF]/.test(this._envelope.from)) {
34891
- message2 = "Internationalized mailbox name not allowed";
34254
+ message = "Internationalized mailbox name not allowed";
34892
34255
  } else {
34893
- message2 = "Mail command failed";
34256
+ message = "Mail command failed";
34894
34257
  }
34895
- return callback(this._formatError(message2, "EENVELOPE", str, "MAIL FROM"));
34258
+ return callback(this._formatError(message, "EENVELOPE", str, "MAIL FROM"));
34896
34259
  }
34897
34260
  if (!this._envelope.rcptQueue.length) {
34898
34261
  return callback(this._formatError("Can't send mail - no recipients defined", "EENVELOPE", false, "API"));
@@ -34923,15 +34286,15 @@ let SMTPConnection$3 = class SMTPConnection extends EventEmitter$4 {
34923
34286
  * @param {String} str Message from the server
34924
34287
  */
34925
34288
  _actionRCPT(str, callback) {
34926
- let message2, err, curRecipient = this._recipientQueue.shift();
34289
+ let message, err, curRecipient = this._recipientQueue.shift();
34927
34290
  if (Number(str.charAt(0)) !== 2) {
34928
34291
  if (this._usingSmtpUtf8 && /^553 /.test(str) && /[\x80-\uFFFF]/.test(curRecipient)) {
34929
- message2 = "Internationalized mailbox name not allowed";
34292
+ message = "Internationalized mailbox name not allowed";
34930
34293
  } else {
34931
- message2 = "Recipient command failed";
34294
+ message = "Recipient command failed";
34932
34295
  }
34933
34296
  this._envelope.rejected.push(curRecipient);
34934
- err = this._formatError(message2, "EENVELOPE", str, "RCPT TO");
34297
+ err = this._formatError(message, "EENVELOPE", str, "RCPT TO");
34935
34298
  err.recipient = curRecipient;
34936
34299
  this._envelope.rejectedErrors.push(err);
34937
34300
  } else {
@@ -37647,9 +37010,9 @@ class SMTPEmailService {
37647
37010
  replyTo: options2.replyTo
37648
37011
  });
37649
37012
  } catch (error2) {
37650
- const message2 = error2 instanceof Error ? error2.message : String(error2);
37651
- console.error("Failed to send email:", message2);
37652
- throw new Error(`Failed to send email: ${message2}`);
37013
+ const message = error2 instanceof Error ? error2.message : String(error2);
37014
+ console.error("Failed to send email:", message);
37015
+ throw new Error(`Failed to send email: ${message}`);
37653
37016
  }
37654
37017
  }
37655
37018
  /**
@@ -37663,8 +37026,8 @@ class SMTPEmailService {
37663
37026
  await this.transporter.verify();
37664
37027
  return true;
37665
37028
  } catch (error2) {
37666
- const message2 = error2 instanceof Error ? error2.message : String(error2);
37667
- console.error("SMTP connection verification failed:", message2);
37029
+ const message = error2 instanceof Error ? error2.message : String(error2);
37030
+ console.error("SMTP connection verification failed:", message);
37668
37031
  return false;
37669
37032
  }
37670
37033
  }
@@ -37863,7 +37226,7 @@ async function _initializeRebaseBackend(config) {
37863
37226
  const {
37864
37227
  createGoogleProvider: createGoogleProvider2
37865
37228
  } = await import("./index-DXVBFp5V.js");
37866
- oauthProviders.push(createGoogleProvider2(config.auth.google.clientId));
37229
+ oauthProviders.push(createGoogleProvider2(config.auth.google));
37867
37230
  }
37868
37231
  if (config.auth.linkedin?.clientId && config.auth.linkedin?.clientSecret) {
37869
37232
  const {
@@ -37944,7 +37307,8 @@ async function _initializeRebaseBackend(config) {
37944
37307
  authRepo: authConfigResult.authRepository ?? authConfigResult.userService,
37945
37308
  emailService: authConfigResult.emailService,
37946
37309
  emailConfig: config.auth.email,
37947
- serviceKey
37310
+ serviceKey,
37311
+ hooks: config.hooks
37948
37312
  });
37949
37313
  config.app.route(`${basePath}/admin`, adminRoutes);
37950
37314
  }
@@ -38002,7 +37366,7 @@ async function _initializeRebaseBackend(config) {
38002
37366
  });
38003
37367
  dataRouter.route("/", historyRoutes);
38004
37368
  }
38005
- const restGenerator = new RestApiGenerator(activeCollections, defaultDriver);
37369
+ const restGenerator = new RestApiGenerator(activeCollections, defaultDriver, config.hooks?.data);
38006
37370
  dataRouter.route("/", restGenerator.generateRoutes());
38007
37371
  config.app.route(`${basePath}/data`, dataRouter);
38008
37372
  }
@@ -38063,6 +37427,13 @@ async function _initializeRebaseBackend(config) {
38063
37427
  }
38064
37428
  _initRebase(serverClient);
38065
37429
  logger.info("Rebase singleton initialized");
37430
+ if (defaultDriverResult.internals) {
37431
+ const internals = defaultDriverResult.internals;
37432
+ const driver = internals.driver;
37433
+ if (driver && "client" in driver) {
37434
+ driver.client = serverClient;
37435
+ }
37436
+ }
38066
37437
  if (config.functionsDir) {
38067
37438
  const {
38068
37439
  loadFunctionsFromDirectory: loadFunctionsFromDirectory2
@@ -38196,10 +37567,10 @@ async function _initializeRebaseBackend(config) {
38196
37567
  shutdown
38197
37568
  };
38198
37569
  }
38199
- function devAssert(condition, message2) {
37570
+ function devAssert(condition, message) {
38200
37571
  const booleanCondition = Boolean(condition);
38201
37572
  if (!booleanCondition) {
38202
- throw new Error(message2);
37573
+ throw new Error(message);
38203
37574
  }
38204
37575
  }
38205
37576
  function isPromise(value) {
@@ -38208,11 +37579,11 @@ function isPromise(value) {
38208
37579
  function isObjectLike(value) {
38209
37580
  return typeof value == "object" && value !== null;
38210
37581
  }
38211
- function invariant(condition, message2) {
37582
+ function invariant(condition, message) {
38212
37583
  const booleanCondition = Boolean(condition);
38213
37584
  if (!booleanCondition) {
38214
37585
  throw new Error(
38215
- message2 != null ? message2 : "Unexpected invariant triggered."
37586
+ message != null ? message : "Unexpected invariant triggered."
38216
37587
  );
38217
37588
  }
38218
37589
  }
@@ -38331,10 +37702,10 @@ class GraphQLError extends Error {
38331
37702
  /**
38332
37703
  * @deprecated Please use the `GraphQLErrorOptions` constructor overload instead.
38333
37704
  */
38334
- constructor(message2, ...rawArgs) {
37705
+ constructor(message, ...rawArgs) {
38335
37706
  var _this$nodes, _nodeLocations$, _ref;
38336
37707
  const { nodes, source, positions, path: path2, originalError, extensions: extensions2 } = toNormalizedOptions(rawArgs);
38337
- super(message2);
37708
+ super(message);
38338
37709
  this.name = "GraphQLError";
38339
37710
  this.path = path2 !== null && path2 !== void 0 ? path2 : void 0;
38340
37711
  this.originalError = originalError !== null && originalError !== void 0 ? originalError : void 0;
@@ -39352,14 +38723,14 @@ function formatArray(array, seenValues) {
39352
38723
  return "[" + items.join(", ") + "]";
39353
38724
  }
39354
38725
  function getObjectTag(object) {
39355
- const tag2 = Object.prototype.toString.call(object).replace(/^\[object /, "").replace(/]$/, "");
39356
- if (tag2 === "Object" && typeof object.constructor === "function") {
38726
+ const tag = Object.prototype.toString.call(object).replace(/^\[object /, "").replace(/]$/, "");
38727
+ if (tag === "Object" && typeof object.constructor === "function") {
39357
38728
  const name2 = object.constructor.name;
39358
38729
  if (typeof name2 === "string" && name2 !== "") {
39359
38730
  return name2;
39360
38731
  }
39361
38732
  }
39362
- return tag2;
38733
+ return tag;
39363
38734
  }
39364
38735
  const isProduction = globalThis.process && // eslint-disable-next-line no-undef
39365
38736
  process.env.NODE_ENV === "production";
@@ -40757,22 +40128,22 @@ function getTokenKindDesc(kind) {
40757
40128
  const MAX_SUGGESTIONS = 5;
40758
40129
  function didYouMean(firstArg, secondArg) {
40759
40130
  const [subMessage, suggestionsArg] = secondArg ? [firstArg, secondArg] : [void 0, firstArg];
40760
- let message2 = " Did you mean ";
40131
+ let message = " Did you mean ";
40761
40132
  if (subMessage) {
40762
- message2 += subMessage + " ";
40133
+ message += subMessage + " ";
40763
40134
  }
40764
40135
  const suggestions = suggestionsArg.map((x) => `"${x}"`);
40765
40136
  switch (suggestions.length) {
40766
40137
  case 0:
40767
40138
  return "";
40768
40139
  case 1:
40769
- return message2 + suggestions[0] + "?";
40140
+ return message + suggestions[0] + "?";
40770
40141
  case 2:
40771
- return message2 + suggestions[0] + " or " + suggestions[1] + "?";
40142
+ return message + suggestions[0] + " or " + suggestions[1] + "?";
40772
40143
  }
40773
40144
  const selected = suggestions.slice(0, MAX_SUGGESTIONS);
40774
40145
  const lastItem = selected.pop();
40775
- return message2 + selected.join(", ") + ", or " + lastItem + "?";
40146
+ return message + selected.join(", ") + ", or " + lastItem + "?";
40776
40147
  }
40777
40148
  function identityFunc(x) {
40778
40149
  return x;
@@ -43416,10 +42787,10 @@ class SchemaValidationContext {
43416
42787
  this._errors = [];
43417
42788
  this.schema = schema;
43418
42789
  }
43419
- reportError(message2, nodes) {
42790
+ reportError(message, nodes) {
43420
42791
  const _nodes = Array.isArray(nodes) ? nodes.filter(Boolean) : nodes;
43421
42792
  this._errors.push(
43422
- new GraphQLError(message2, {
42793
+ new GraphQLError(message, {
43423
42794
  nodes: _nodes
43424
42795
  })
43425
42796
  );
@@ -47794,9 +47165,9 @@ var errorMessages = (messages, graphqlErrors) => {
47794
47165
  };
47795
47166
  }
47796
47167
  return {
47797
- errors: messages.map((message2) => {
47168
+ errors: messages.map((message) => {
47798
47169
  return {
47799
- message: message2
47170
+ message
47800
47171
  };
47801
47172
  })
47802
47173
  };
@@ -48933,7 +48304,9 @@ class RebaseApiServer {
48933
48304
  * Setup Hono middleware
48934
48305
  */
48935
48306
  setupMiddleware() {
48936
- this.router.use("/*", secureHeaders());
48307
+ this.router.use("/*", secureHeaders({
48308
+ crossOriginOpenerPolicy: "same-origin-allow-popups"
48309
+ }));
48937
48310
  if (this.config.cors) {
48938
48311
  const origin = this.config.cors.origin;
48939
48312
  this.router.use("/*", cors({
@@ -49020,9 +48393,9 @@ class RebaseApiServer {
49020
48393
  if (process.env.NODE_ENV === "production") {
49021
48394
  console.warn("[RebaseApiServer] Schema Editor is disabled in production environments for security.");
49022
48395
  } else {
48396
+ this.router.use(`${basePath}/schema-editor/*`, requireAuth, requireAdmin);
49023
48397
  const schemaEditorRoutes2 = createSchemaEditorRoutes(this.config.collectionsDir);
49024
48398
  this.router.route(`${basePath}/schema-editor`, schemaEditorRoutes2);
49025
- this.router.use(`${basePath}/schema-editor/*`, requireAuth, requireAdmin);
49026
48399
  }
49027
48400
  }
49028
48401
  this.router.get(`${basePath}/docs`, (c) => {
@@ -49136,8 +48509,8 @@ async function loadFunctionsFromDirectory(directory) {
49136
48509
  Hint: ensure the function exports a Hono app created with the same hono version as the server.
49137
48510
  The loader checks for .fetch() and .routes — any Hono-compatible app will work.`);
49138
48511
  } catch (err) {
49139
- const message2 = err instanceof Error ? err.message : String(err);
49140
- console.error(`[functions] Failed to load ${file}: ${message2}`);
48512
+ const message = err instanceof Error ? err.message : String(err);
48513
+ console.error(`[functions] Failed to load ${file}: ${message}`);
49141
48514
  }
49142
48515
  }
49143
48516
  }
@@ -49209,8 +48582,8 @@ async function loadCronJobsFromDirectory(directory) {
49209
48582
  });
49210
48583
  console.log(`⏰ Loaded cron job: ${id} (${definition.schedule})`);
49211
48584
  } catch (err) {
49212
- const message2 = err instanceof Error ? err.message : String(err);
49213
- console.error(`[cron] Failed to load ${file}: ${message2}`);
48585
+ const message = err instanceof Error ? err.message : String(err);
48586
+ console.error(`[cron] Failed to load ${file}: ${message}`);
49214
48587
  }
49215
48588
  }
49216
48589
  }
@@ -49220,46 +48593,98 @@ const cronLoader = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.definePr
49220
48593
  __proto__: null,
49221
48594
  loadCronJobsFromDirectory
49222
48595
  }, Symbol.toStringTag, { value: "Module" }));
48596
+ function expandCronField(field, min, max) {
48597
+ const results = /* @__PURE__ */ new Set();
48598
+ for (const segment of field.split(",")) {
48599
+ const trimmed = segment.trim();
48600
+ if (trimmed === "*") {
48601
+ for (let i = min; i <= max; i++) results.add(i);
48602
+ } else if (trimmed.includes("/")) {
48603
+ const [rangeStr, stepStr] = trimmed.split("/");
48604
+ const step = parseInt(stepStr, 10);
48605
+ if (isNaN(step) || step <= 0) {
48606
+ throw new Error(`Invalid step value "${stepStr}" in cron field "${field}"`);
48607
+ }
48608
+ let start = min;
48609
+ let end2 = max;
48610
+ if (rangeStr !== "*") {
48611
+ if (rangeStr.includes("-")) {
48612
+ const [a2, b] = rangeStr.split("-").map(Number);
48613
+ start = a2;
48614
+ end2 = b;
48615
+ } else {
48616
+ start = parseInt(rangeStr, 10);
48617
+ }
48618
+ }
48619
+ for (let i = start; i <= end2; i += step) results.add(i);
48620
+ } else if (trimmed.includes("-")) {
48621
+ const [a2, b] = trimmed.split("-").map(Number);
48622
+ for (let i = a2; i <= b; i++) results.add(i);
48623
+ } else {
48624
+ const val = parseInt(trimmed, 10);
48625
+ if (isNaN(val)) {
48626
+ throw new Error(`Invalid value "${trimmed}" in cron field "${field}"`);
48627
+ }
48628
+ results.add(val);
48629
+ }
48630
+ }
48631
+ return [...results].sort((a2, b) => a2 - b);
48632
+ }
48633
+ function validateCronExpression(schedule) {
48634
+ if (!schedule || typeof schedule !== "string") {
48635
+ return {
48636
+ valid: false,
48637
+ reason: "Schedule must be a non-empty string"
48638
+ };
48639
+ }
48640
+ const parts = schedule.trim().split(/\s+/);
48641
+ if (parts.length !== 5) {
48642
+ return {
48643
+ valid: false,
48644
+ reason: `Expected 5 fields, got ${parts.length}`
48645
+ };
48646
+ }
48647
+ const fieldRanges = [["minute", 0, 59], ["hour", 0, 23], ["day of month", 1, 31], ["month", 1, 12], ["day of week", 0, 6]];
48648
+ for (let i = 0; i < 5; i++) {
48649
+ const [name2, min, max] = fieldRanges[i];
48650
+ try {
48651
+ const values2 = expandCronField(parts[i], min, max);
48652
+ if (values2.length === 0) {
48653
+ return {
48654
+ valid: false,
48655
+ reason: `${name2} field "${parts[i]}" produces no values`
48656
+ };
48657
+ }
48658
+ for (const v of values2) {
48659
+ if (v < min || v > max) {
48660
+ return {
48661
+ valid: false,
48662
+ reason: `${name2} field value ${v} out of range [${min}–${max}]`
48663
+ };
48664
+ }
48665
+ }
48666
+ } catch (err) {
48667
+ return {
48668
+ valid: false,
48669
+ reason: `${name2} field: ${err instanceof Error ? err.message : String(err)}`
48670
+ };
48671
+ }
48672
+ }
48673
+ return {
48674
+ valid: true
48675
+ };
48676
+ }
49223
48677
  function parseCronExpression(expression, after) {
49224
48678
  const parts = expression.trim().split(/\s+/);
49225
48679
  if (parts.length < 5) {
49226
48680
  throw new Error(`Invalid cron expression: "${expression}". Expected 5 fields.`);
49227
48681
  }
49228
48682
  const [minField, hourField, domField, monField, dowField] = parts;
49229
- const expand = (field, min, max) => {
49230
- const results = /* @__PURE__ */ new Set();
49231
- for (const segment of field.split(",")) {
49232
- if (segment === "*") {
49233
- for (let i = min; i <= max; i++) results.add(i);
49234
- } else if (segment.includes("/")) {
49235
- const [rangeStr, stepStr] = segment.split("/");
49236
- const step = parseInt(stepStr, 10);
49237
- let start = min;
49238
- let end2 = max;
49239
- if (rangeStr !== "*") {
49240
- if (rangeStr.includes("-")) {
49241
- const [a2, b] = rangeStr.split("-").map(Number);
49242
- start = a2;
49243
- end2 = b;
49244
- } else {
49245
- start = parseInt(rangeStr, 10);
49246
- }
49247
- }
49248
- for (let i = start; i <= end2; i += step) results.add(i);
49249
- } else if (segment.includes("-")) {
49250
- const [a2, b] = segment.split("-").map(Number);
49251
- for (let i = a2; i <= b; i++) results.add(i);
49252
- } else {
49253
- results.add(parseInt(segment, 10));
49254
- }
49255
- }
49256
- return [...results].sort((a2, b) => a2 - b);
49257
- };
49258
- const minutes = expand(minField, 0, 59);
49259
- const hours = expand(hourField, 0, 23);
49260
- const doms = expand(domField, 1, 31);
49261
- const months = expand(monField, 1, 12);
49262
- const dows = expand(dowField, 0, 6);
48683
+ const minutes = expandCronField(minField, 0, 59);
48684
+ const hours = expandCronField(hourField, 0, 23);
48685
+ const doms = expandCronField(domField, 1, 31);
48686
+ const months = expandCronField(monField, 1, 12);
48687
+ const dows = expandCronField(dowField, 0, 6);
49263
48688
  const candidate = new Date(after);
49264
48689
  candidate.setSeconds(0, 0);
49265
48690
  candidate.setMinutes(candidate.getMinutes() + 1);
@@ -49268,9 +48693,9 @@ function parseCronExpression(expression, after) {
49268
48693
  const month = candidate.getMonth() + 1;
49269
48694
  const dom = candidate.getDate();
49270
48695
  const dow = candidate.getDay();
49271
- const hour2 = candidate.getHours();
49272
- const minute2 = candidate.getMinutes();
49273
- if (months.includes(month) && doms.includes(dom) && dows.includes(dow) && hours.includes(hour2) && minutes.includes(minute2)) {
48696
+ const hour = candidate.getHours();
48697
+ const minute = candidate.getMinutes();
48698
+ if (months.includes(month) && doms.includes(dom) && dows.includes(dow) && hours.includes(hour) && minutes.includes(minute)) {
49274
48699
  return candidate;
49275
48700
  }
49276
48701
  candidate.setMinutes(candidate.getMinutes() + 1);
@@ -49280,6 +48705,7 @@ function parseCronExpression(expression, after) {
49280
48705
  return fallback;
49281
48706
  }
49282
48707
  const MAX_LOGS_PER_JOB = 50;
48708
+ const MIN_SCHEDULE_INTERVAL_MS = 5e3;
49283
48709
  class CronScheduler {
49284
48710
  jobs = /* @__PURE__ */ new Map();
49285
48711
  started = false;
@@ -49301,23 +48727,39 @@ class CronScheduler {
49301
48727
  }
49302
48728
  /**
49303
48729
  * Register a batch of loaded cron jobs.
48730
+ *
48731
+ * If the scheduler is already started, newly registered jobs are
48732
+ * automatically scheduled (so late-registered jobs don't sit idle).
48733
+ *
48734
+ * Validates the cron schedule on registration — invalid schedules
48735
+ * are rejected with a warning and the job is NOT registered.
49304
48736
  */
49305
48737
  registerJobs(loadedJobs) {
49306
48738
  for (const loaded of loadedJobs) {
48739
+ const validation = validateCronExpression(loaded.definition.schedule);
48740
+ if (!validation.valid) {
48741
+ console.error(`[cron] Rejecting job "${loaded.id}": invalid schedule "${loaded.definition.schedule}" — ${validation.reason}`);
48742
+ continue;
48743
+ }
49307
48744
  const existing = this.jobs.get(loaded.id);
49308
48745
  if (existing) {
49309
48746
  console.warn(`[cron] Duplicate cron job id: "${loaded.id}". Overwriting.`);
49310
48747
  this.stopJob(loaded.id);
49311
48748
  }
48749
+ const enabled = loaded.definition.enabled !== false;
49312
48750
  this.jobs.set(loaded.id, {
49313
48751
  id: loaded.id,
49314
48752
  definition: loaded.definition,
49315
- enabled: loaded.definition.enabled !== false,
49316
- state: loaded.definition.enabled !== false ? "idle" : "disabled",
48753
+ enabled,
48754
+ state: enabled ? "idle" : "disabled",
49317
48755
  totalRuns: 0,
49318
48756
  totalFailures: 0,
49319
- logs: []
48757
+ logs: [],
48758
+ executing: false
49320
48759
  });
48760
+ if (this.started && enabled) {
48761
+ this.scheduleNext(loaded.id);
48762
+ }
49321
48763
  }
49322
48764
  }
49323
48765
  /**
@@ -49351,6 +48793,9 @@ class CronScheduler {
49351
48793
  }
49352
48794
  /**
49353
48795
  * Stop the scheduler and clear all timers.
48796
+ *
48797
+ * Currently-executing handlers run to completion (they are async),
48798
+ * but no further scheduling occurs after stop.
49354
48799
  */
49355
48800
  stop() {
49356
48801
  this.started = false;
@@ -49409,32 +48854,81 @@ class CronScheduler {
49409
48854
  }
49410
48855
  /**
49411
48856
  * Manually trigger a job execution immediately.
48857
+ *
48858
+ * Returns `undefined` if the job doesn't exist.
48859
+ * If the job is currently executing, returns the log entry with
48860
+ * a `skipped: true` result rather than running concurrently.
49412
48861
  */
49413
48862
  async triggerJob(id) {
49414
48863
  const job = this.jobs.get(id);
49415
48864
  if (!job) return void 0;
48865
+ if (job.executing) {
48866
+ console.warn(`[cron] Skipping manual trigger of "${id}" — already executing`);
48867
+ const logEntry = {
48868
+ jobId: id,
48869
+ startedAt: (/* @__PURE__ */ new Date()).toISOString(),
48870
+ finishedAt: (/* @__PURE__ */ new Date()).toISOString(),
48871
+ durationMs: 0,
48872
+ success: true,
48873
+ result: {
48874
+ skipped: true,
48875
+ reason: "already_executing"
48876
+ },
48877
+ logs: ["Skipped: job is already running"],
48878
+ manual: true
48879
+ };
48880
+ job.logs.push(logEntry);
48881
+ if (job.logs.length > MAX_LOGS_PER_JOB) job.logs.shift();
48882
+ return logEntry;
48883
+ }
49416
48884
  return this.executeJob(job, true);
49417
48885
  }
49418
48886
  // ─── Internal ────────────────────────────────────────────────────
48887
+ /**
48888
+ * Schedule the next execution for a job.
48889
+ *
48890
+ * Safety guarantees:
48891
+ * 1. Clears any existing timer first (prevents leaked/duplicate timers)
48892
+ * 2. Enforces a minimum delay to prevent tight loops from jitter
48893
+ * 3. Unref's the timer so it doesn't prevent process exit
48894
+ * 4. Re-checks enabled & started state before executing
48895
+ * 5. Concurrency guard prevents overlapping handler executions
48896
+ */
49419
48897
  scheduleNext(id) {
49420
48898
  const job = this.jobs.get(id);
49421
48899
  if (!job || !job.enabled || !this.started) return;
48900
+ this.stopJob(id);
49422
48901
  try {
49423
48902
  const now = /* @__PURE__ */ new Date();
49424
48903
  const nextRun = parseCronExpression(job.definition.schedule, now);
49425
48904
  job.nextRunAt = nextRun;
49426
- const delay = Math.max(nextRun.getTime() - now.getTime(), 0);
49427
- job.timerId = setTimeout(async () => {
48905
+ const rawDelay = nextRun.getTime() - now.getTime();
48906
+ const delay = Math.max(rawDelay, MIN_SCHEDULE_INTERVAL_MS);
48907
+ const timer = setTimeout(async () => {
49428
48908
  if (!job.enabled || !this.started) return;
48909
+ if (job.executing) {
48910
+ console.warn(`[cron] Skipping scheduled run of "${id}" — still executing from previous run`);
48911
+ this.scheduleNext(id);
48912
+ return;
48913
+ }
49429
48914
  await this.executeJob(job, false);
49430
- this.scheduleNext(id);
48915
+ if (this.started && job.enabled) {
48916
+ this.scheduleNext(id);
48917
+ }
49431
48918
  }, delay);
48919
+ if (timer && typeof timer === "object" && "unref" in timer) {
48920
+ timer.unref();
48921
+ }
48922
+ job.timerId = timer;
49432
48923
  } catch (err) {
49433
48924
  console.error(`[cron] Failed to schedule "${id}":`, err);
49434
48925
  job.state = "error";
49435
48926
  job.lastError = err instanceof Error ? err.message : String(err);
49436
48927
  }
49437
48928
  }
48929
+ /**
48930
+ * Stop a single job's timer and clear its next run state.
48931
+ */
49438
48932
  stopJob(id) {
49439
48933
  const job = this.jobs.get(id);
49440
48934
  if (job?.timerId) {
@@ -49443,9 +48937,19 @@ class CronScheduler {
49443
48937
  job.nextRunAt = void 0;
49444
48938
  }
49445
48939
  }
48940
+ /**
48941
+ * Execute a job's handler with full isolation and safety.
48942
+ *
48943
+ * - Sets a concurrency flag to prevent overlapping runs
48944
+ * - Wraps handler in a timeout race
48945
+ * - Captures all logs, errors, and results
48946
+ * - Persists to store (non-blocking) if available
48947
+ * - Always restores state even on catastrophic errors
48948
+ */
49446
48949
  async executeJob(job, manual) {
49447
48950
  const startedAt = /* @__PURE__ */ new Date();
49448
48951
  const capturedLogs = [];
48952
+ job.executing = true;
49449
48953
  const ctx = {
49450
48954
  jobId: job.id,
49451
48955
  scheduledAt: startedAt,
@@ -49464,14 +48968,21 @@ class CronScheduler {
49464
48968
  try {
49465
48969
  const timeout = (job.definition.timeoutSeconds ?? 300) * 1e3;
49466
48970
  const handlerPromise = Promise.resolve(job.definition.handler(ctx));
48971
+ let timeoutHandle;
49467
48972
  const timeoutPromise = new Promise((_, reject) => {
49468
- setTimeout(() => reject(new Error(`Cron job "${job.id}" timed out after ${timeout}ms`)), timeout);
48973
+ timeoutHandle = setTimeout(() => reject(new Error(`Cron job "${job.id}" timed out after ${timeout}ms`)), timeout);
49469
48974
  });
49470
- result = await Promise.race([handlerPromise, timeoutPromise]);
48975
+ try {
48976
+ result = await Promise.race([handlerPromise, timeoutPromise]);
48977
+ } finally {
48978
+ clearTimeout(timeoutHandle);
48979
+ }
49471
48980
  } catch (err) {
49472
48981
  success = false;
49473
48982
  error2 = err instanceof Error ? err.message : String(err);
49474
48983
  job.totalFailures++;
48984
+ } finally {
48985
+ job.executing = false;
49475
48986
  }
49476
48987
  const finishedAt = /* @__PURE__ */ new Date();
49477
48988
  const durationMs = finishedAt.getTime() - startedAt.getTime();
@@ -49494,8 +49005,8 @@ class CronScheduler {
49494
49005
  job.logs.shift();
49495
49006
  }
49496
49007
  if (this.store) {
49497
- this.store.insertLog(logEntry).catch((err) => {
49498
- console.error(`[cron] Failed to persist log for "${job.id}":`, err);
49008
+ this.store.insertLog(logEntry).catch((persistErr) => {
49009
+ console.error(`[cron] Failed to persist log for "${job.id}":`, persistErr);
49499
49010
  });
49500
49011
  }
49501
49012
  if (success) {
@@ -49524,7 +49035,8 @@ class CronScheduler {
49524
49035
  }
49525
49036
  const cronScheduler = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProperty({
49526
49037
  __proto__: null,
49527
- CronScheduler
49038
+ CronScheduler,
49039
+ validateCronExpression
49528
49040
  }, Symbol.toStringTag, { value: "Module" }));
49529
49041
  function createCronRoutes(scheduler) {
49530
49042
  const router = new Hono();
@@ -49927,6 +49439,7 @@ export {
49927
49439
  resetConsole,
49928
49440
  serveSPA,
49929
49441
  strictAuthLimiter,
49442
+ validateCronExpression,
49930
49443
  validatePasswordStrength,
49931
49444
  verifyAccessToken,
49932
49445
  verifyPassword