@rebasepro/server-core 0.0.1-canary.bbcb8b4 → 0.0.1-canary.c53f5db
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.es.js +397 -236
- package/dist/index.es.js.map +1 -1
- package/dist/index.umd.js +397 -236
- package/dist/index.umd.js.map +1 -1
- package/dist/server-core/src/api/rest/api-generator.d.ts +15 -3
- package/dist/server-core/src/auth/admin-routes.d.ts +5 -0
- package/dist/server-core/src/init.d.ts +10 -1
- package/dist/types/src/controllers/collection_registry.d.ts +2 -1
- package/dist/types/src/controllers/data_driver.d.ts +36 -1
- package/dist/types/src/types/backend_hooks.d.ts +187 -0
- package/dist/types/src/types/collections.d.ts +10 -10
- package/dist/types/src/types/entity_views.d.ts +4 -6
- package/dist/types/src/types/formex.d.ts +40 -0
- package/dist/types/src/types/index.d.ts +2 -0
- package/dist/types/src/types/plugins.d.ts +6 -3
- package/dist/types/src/types/properties.d.ts +4 -4
- package/dist/types/src/types/slots.d.ts +20 -10
- package/dist/types/src/types/translations.d.ts +4 -0
- package/package.json +7 -7
- package/src/api/rest/api-generator-count.test.ts +113 -0
- package/src/api/rest/api-generator.ts +123 -22
- package/src/api/server.ts +3 -2
- package/src/auth/admin-routes.ts +133 -57
- package/src/auth/rate-limiter.ts +9 -5
- package/src/init.ts +13 -3
- package/src/storage/LocalStorageController.ts +4 -4
- package/test/backend-hooks-admin.test.ts +394 -0
- package/test/backend-hooks-data.test.ts +408 -0
package/dist/index.es.js
CHANGED
|
@@ -1721,8 +1721,8 @@ var logic = { exports: {} };
|
|
|
1721
1721
|
return jsonLogic;
|
|
1722
1722
|
});
|
|
1723
1723
|
})(logic);
|
|
1724
|
-
|
|
1725
|
-
|
|
1724
|
+
const { getOwnPropertyNames, getOwnPropertySymbols } = Object;
|
|
1725
|
+
const { hasOwnProperty: hasOwnProperty$d } = Object.prototype;
|
|
1726
1726
|
function combineComparators(comparatorA, comparatorB) {
|
|
1727
1727
|
return function isEqual(a2, b, state) {
|
|
1728
1728
|
return comparatorA(a2, b, state) && comparatorB(a2, b, state);
|
|
@@ -1733,38 +1733,45 @@ function createIsCircular(areItemsEqual) {
|
|
|
1733
1733
|
if (!a2 || !b || typeof a2 !== "object" || typeof b !== "object") {
|
|
1734
1734
|
return areItemsEqual(a2, b, state);
|
|
1735
1735
|
}
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
|
|
1736
|
+
const { cache: cache2 } = state;
|
|
1737
|
+
const cachedA = cache2.get(a2);
|
|
1738
|
+
const cachedB = cache2.get(b);
|
|
1739
1739
|
if (cachedA && cachedB) {
|
|
1740
1740
|
return cachedA === b && cachedB === a2;
|
|
1741
1741
|
}
|
|
1742
1742
|
cache2.set(a2, b);
|
|
1743
1743
|
cache2.set(b, a2);
|
|
1744
|
-
|
|
1744
|
+
const result = areItemsEqual(a2, b, state);
|
|
1745
1745
|
cache2.delete(a2);
|
|
1746
1746
|
cache2.delete(b);
|
|
1747
1747
|
return result;
|
|
1748
1748
|
};
|
|
1749
1749
|
}
|
|
1750
|
-
function getShortTag(value) {
|
|
1751
|
-
return value != null ? value[Symbol.toStringTag] : void 0;
|
|
1752
|
-
}
|
|
1753
1750
|
function getStrictProperties(object) {
|
|
1754
1751
|
return getOwnPropertyNames(object).concat(getOwnPropertySymbols(object));
|
|
1755
1752
|
}
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
1753
|
+
const hasOwn$1 = (
|
|
1754
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
1755
|
+
Object.hasOwn || ((object, property) => hasOwnProperty$d.call(object, property))
|
|
1756
|
+
);
|
|
1757
|
+
const PREACT_VNODE = "__v";
|
|
1758
|
+
const PREACT_OWNER = "__o";
|
|
1759
|
+
const REACT_OWNER = "_owner";
|
|
1760
|
+
const { getOwnPropertyDescriptor, keys: keys$5 } = Object;
|
|
1761
|
+
const sameValueEqual = (
|
|
1762
|
+
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
|
1763
|
+
Object.is || function sameValueEqual2(a2, b) {
|
|
1764
|
+
return a2 === b ? a2 !== 0 || 1 / a2 === 1 / b : a2 !== a2 && b !== b;
|
|
1765
|
+
}
|
|
1766
|
+
);
|
|
1767
|
+
function strictEqual(a2, b) {
|
|
1768
|
+
return a2 === b;
|
|
1769
|
+
}
|
|
1770
|
+
function areArrayBuffersEqual(a2, b) {
|
|
1771
|
+
return a2.byteLength === b.byteLength && areTypedArraysEqual(new Uint8Array(a2), new Uint8Array(b));
|
|
1761
1772
|
}
|
|
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
1773
|
function areArraysEqual(a2, b, state) {
|
|
1767
|
-
|
|
1774
|
+
let index = a2.length;
|
|
1768
1775
|
if (b.length !== index) {
|
|
1769
1776
|
return false;
|
|
1770
1777
|
}
|
|
@@ -1775,35 +1782,35 @@ function areArraysEqual(a2, b, state) {
|
|
|
1775
1782
|
}
|
|
1776
1783
|
return true;
|
|
1777
1784
|
}
|
|
1785
|
+
function areDataViewsEqual(a2, b) {
|
|
1786
|
+
return a2.byteLength === b.byteLength && areTypedArraysEqual(new Uint8Array(a2.buffer, a2.byteOffset, a2.byteLength), new Uint8Array(b.buffer, b.byteOffset, b.byteLength));
|
|
1787
|
+
}
|
|
1778
1788
|
function areDatesEqual(a2, b) {
|
|
1779
|
-
return
|
|
1789
|
+
return sameValueEqual(a2.getTime(), b.getTime());
|
|
1780
1790
|
}
|
|
1781
1791
|
function areErrorsEqual(a2, b) {
|
|
1782
1792
|
return a2.name === b.name && a2.message === b.message && a2.cause === b.cause && a2.stack === b.stack;
|
|
1783
1793
|
}
|
|
1784
|
-
function areFunctionsEqual(a2, b) {
|
|
1785
|
-
return a2 === b;
|
|
1786
|
-
}
|
|
1787
1794
|
function areMapsEqual(a2, b, state) {
|
|
1788
|
-
|
|
1795
|
+
const size = a2.size;
|
|
1789
1796
|
if (size !== b.size) {
|
|
1790
1797
|
return false;
|
|
1791
1798
|
}
|
|
1792
1799
|
if (!size) {
|
|
1793
1800
|
return true;
|
|
1794
1801
|
}
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1802
|
+
const matchedIndices = new Array(size);
|
|
1803
|
+
const aIterable = a2.entries();
|
|
1804
|
+
let aResult;
|
|
1805
|
+
let bResult;
|
|
1806
|
+
let index = 0;
|
|
1800
1807
|
while (aResult = aIterable.next()) {
|
|
1801
1808
|
if (aResult.done) {
|
|
1802
1809
|
break;
|
|
1803
1810
|
}
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1811
|
+
const bIterable = b.entries();
|
|
1812
|
+
let hasMatch = false;
|
|
1813
|
+
let matchIndex = 0;
|
|
1807
1814
|
while (bResult = bIterable.next()) {
|
|
1808
1815
|
if (bResult.done) {
|
|
1809
1816
|
break;
|
|
@@ -1812,8 +1819,8 @@ function areMapsEqual(a2, b, state) {
|
|
|
1812
1819
|
matchIndex++;
|
|
1813
1820
|
continue;
|
|
1814
1821
|
}
|
|
1815
|
-
|
|
1816
|
-
|
|
1822
|
+
const aEntry = aResult.value;
|
|
1823
|
+
const bEntry = bResult.value;
|
|
1817
1824
|
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
1825
|
hasMatch = matchedIndices[matchIndex] = true;
|
|
1819
1826
|
break;
|
|
@@ -1827,10 +1834,9 @@ function areMapsEqual(a2, b, state) {
|
|
|
1827
1834
|
}
|
|
1828
1835
|
return true;
|
|
1829
1836
|
}
|
|
1830
|
-
var areNumbersEqual = sameValueZeroEqual;
|
|
1831
1837
|
function areObjectsEqual(a2, b, state) {
|
|
1832
|
-
|
|
1833
|
-
|
|
1838
|
+
const properties = keys$5(a2);
|
|
1839
|
+
let index = properties.length;
|
|
1834
1840
|
if (keys$5(b).length !== index) {
|
|
1835
1841
|
return false;
|
|
1836
1842
|
}
|
|
@@ -1842,14 +1848,14 @@ function areObjectsEqual(a2, b, state) {
|
|
|
1842
1848
|
return true;
|
|
1843
1849
|
}
|
|
1844
1850
|
function areObjectsEqualStrict(a2, b, state) {
|
|
1845
|
-
|
|
1846
|
-
|
|
1851
|
+
const properties = getStrictProperties(a2);
|
|
1852
|
+
let index = properties.length;
|
|
1847
1853
|
if (getStrictProperties(b).length !== index) {
|
|
1848
1854
|
return false;
|
|
1849
1855
|
}
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1856
|
+
let property;
|
|
1857
|
+
let descriptorA;
|
|
1858
|
+
let descriptorB;
|
|
1853
1859
|
while (index-- > 0) {
|
|
1854
1860
|
property = properties[index];
|
|
1855
1861
|
if (!isPropertyEqual(a2, b, state, property)) {
|
|
@@ -1864,30 +1870,30 @@ function areObjectsEqualStrict(a2, b, state) {
|
|
|
1864
1870
|
return true;
|
|
1865
1871
|
}
|
|
1866
1872
|
function arePrimitiveWrappersEqual(a2, b) {
|
|
1867
|
-
return
|
|
1873
|
+
return sameValueEqual(a2.valueOf(), b.valueOf());
|
|
1868
1874
|
}
|
|
1869
1875
|
function areRegExpsEqual(a2, b) {
|
|
1870
1876
|
return a2.source === b.source && a2.flags === b.flags;
|
|
1871
1877
|
}
|
|
1872
1878
|
function areSetsEqual(a2, b, state) {
|
|
1873
|
-
|
|
1879
|
+
const size = a2.size;
|
|
1874
1880
|
if (size !== b.size) {
|
|
1875
1881
|
return false;
|
|
1876
1882
|
}
|
|
1877
1883
|
if (!size) {
|
|
1878
1884
|
return true;
|
|
1879
1885
|
}
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1886
|
+
const matchedIndices = new Array(size);
|
|
1887
|
+
const aIterable = a2.values();
|
|
1888
|
+
let aResult;
|
|
1889
|
+
let bResult;
|
|
1884
1890
|
while (aResult = aIterable.next()) {
|
|
1885
1891
|
if (aResult.done) {
|
|
1886
1892
|
break;
|
|
1887
1893
|
}
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1894
|
+
const bIterable = b.values();
|
|
1895
|
+
let hasMatch = false;
|
|
1896
|
+
let matchIndex = 0;
|
|
1891
1897
|
while (bResult = bIterable.next()) {
|
|
1892
1898
|
if (bResult.done) {
|
|
1893
1899
|
break;
|
|
@@ -1905,8 +1911,8 @@ function areSetsEqual(a2, b, state) {
|
|
|
1905
1911
|
return true;
|
|
1906
1912
|
}
|
|
1907
1913
|
function areTypedArraysEqual(a2, b) {
|
|
1908
|
-
|
|
1909
|
-
if (b.
|
|
1914
|
+
let index = a2.byteLength;
|
|
1915
|
+
if (b.byteLength !== index || a2.byteOffset !== b.byteOffset) {
|
|
1910
1916
|
return false;
|
|
1911
1917
|
}
|
|
1912
1918
|
while (index-- > 0) {
|
|
@@ -1925,23 +1931,10 @@ function isPropertyEqual(a2, b, state, property) {
|
|
|
1925
1931
|
}
|
|
1926
1932
|
return hasOwn$1(b, property) && state.equals(a2[property], b[property], property, property, a2, b, state);
|
|
1927
1933
|
}
|
|
1928
|
-
|
|
1929
|
-
|
|
1930
|
-
|
|
1931
|
-
|
|
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;
|
|
1934
|
+
const toString$2 = Object.prototype.toString;
|
|
1935
|
+
function createEqualityComparator(config) {
|
|
1936
|
+
const supportedComparatorMap = createSupportedComparatorMap(config);
|
|
1937
|
+
const { areArraysEqual: areArraysEqual2, areDatesEqual: areDatesEqual2, areFunctionsEqual, areMapsEqual: areMapsEqual2, areNumbersEqual, areObjectsEqual: areObjectsEqual2, areRegExpsEqual: areRegExpsEqual2, areSetsEqual: areSetsEqual2, getUnsupportedCustomComparator } = config;
|
|
1945
1938
|
return function comparator2(a2, b, state) {
|
|
1946
1939
|
if (a2 === b) {
|
|
1947
1940
|
return true;
|
|
@@ -1949,32 +1942,29 @@ function createEqualityComparator(_a2) {
|
|
|
1949
1942
|
if (a2 == null || b == null) {
|
|
1950
1943
|
return false;
|
|
1951
1944
|
}
|
|
1952
|
-
|
|
1945
|
+
const type = typeof a2;
|
|
1953
1946
|
if (type !== typeof b) {
|
|
1954
1947
|
return false;
|
|
1955
1948
|
}
|
|
1956
1949
|
if (type !== "object") {
|
|
1957
|
-
if (type === "number") {
|
|
1958
|
-
return
|
|
1950
|
+
if (type === "number" || type === "bigint") {
|
|
1951
|
+
return areNumbersEqual(a2, b, state);
|
|
1959
1952
|
}
|
|
1960
1953
|
if (type === "function") {
|
|
1961
|
-
return
|
|
1954
|
+
return areFunctionsEqual(a2, b, state);
|
|
1962
1955
|
}
|
|
1963
1956
|
return false;
|
|
1964
1957
|
}
|
|
1965
|
-
|
|
1958
|
+
const constructor = a2.constructor;
|
|
1966
1959
|
if (constructor !== b.constructor) {
|
|
1967
1960
|
return false;
|
|
1968
1961
|
}
|
|
1969
1962
|
if (constructor === Object) {
|
|
1970
1963
|
return areObjectsEqual2(a2, b, state);
|
|
1971
1964
|
}
|
|
1972
|
-
if (
|
|
1965
|
+
if (constructor === Array) {
|
|
1973
1966
|
return areArraysEqual2(a2, b, state);
|
|
1974
1967
|
}
|
|
1975
|
-
if (isTypedArray$2 != null && isTypedArray$2(a2)) {
|
|
1976
|
-
return areTypedArraysEqual2(a2, b, state);
|
|
1977
|
-
}
|
|
1978
1968
|
if (constructor === Date) {
|
|
1979
1969
|
return areDatesEqual2(a2, b, state);
|
|
1980
1970
|
}
|
|
@@ -1987,79 +1977,55 @@ function createEqualityComparator(_a2) {
|
|
|
1987
1977
|
if (constructor === Set) {
|
|
1988
1978
|
return areSetsEqual2(a2, b, state);
|
|
1989
1979
|
}
|
|
1990
|
-
|
|
1991
|
-
|
|
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);
|
|
1980
|
+
if (constructor === Promise) {
|
|
1981
|
+
return false;
|
|
2005
1982
|
}
|
|
2006
|
-
if (
|
|
2007
|
-
return
|
|
1983
|
+
if (Array.isArray(a2)) {
|
|
1984
|
+
return areArraysEqual2(a2, b, state);
|
|
2008
1985
|
}
|
|
2009
|
-
|
|
2010
|
-
|
|
1986
|
+
const tag2 = toString$2.call(a2);
|
|
1987
|
+
const supportedComparator = supportedComparatorMap[tag2];
|
|
1988
|
+
if (supportedComparator) {
|
|
1989
|
+
return supportedComparator(a2, b, state);
|
|
2011
1990
|
}
|
|
2012
|
-
|
|
2013
|
-
|
|
2014
|
-
|
|
2015
|
-
if (tag2 === BOOLEAN_TAG || tag2 === NUMBER_TAG || tag2 === STRING_TAG) {
|
|
2016
|
-
return arePrimitiveWrappersEqual2(a2, b, state);
|
|
2017
|
-
}
|
|
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
|
-
}
|
|
1991
|
+
const unsupportedCustomComparator = getUnsupportedCustomComparator && getUnsupportedCustomComparator(a2, b, state, tag2);
|
|
1992
|
+
if (unsupportedCustomComparator) {
|
|
1993
|
+
return unsupportedCustomComparator(a2, b, state);
|
|
2029
1994
|
}
|
|
2030
1995
|
return false;
|
|
2031
1996
|
};
|
|
2032
1997
|
}
|
|
2033
|
-
function createEqualityComparatorConfig(
|
|
2034
|
-
|
|
2035
|
-
|
|
1998
|
+
function createEqualityComparatorConfig({ circular, createCustomConfig, strict }) {
|
|
1999
|
+
let config = {
|
|
2000
|
+
areArrayBuffersEqual,
|
|
2036
2001
|
areArraysEqual: strict ? areObjectsEqualStrict : areArraysEqual,
|
|
2002
|
+
areDataViewsEqual,
|
|
2037
2003
|
areDatesEqual,
|
|
2038
2004
|
areErrorsEqual,
|
|
2039
|
-
areFunctionsEqual,
|
|
2005
|
+
areFunctionsEqual: strictEqual,
|
|
2040
2006
|
areMapsEqual: strict ? combineComparators(areMapsEqual, areObjectsEqualStrict) : areMapsEqual,
|
|
2041
|
-
areNumbersEqual,
|
|
2007
|
+
areNumbersEqual: sameValueEqual,
|
|
2042
2008
|
areObjectsEqual: strict ? areObjectsEqualStrict : areObjectsEqual,
|
|
2043
2009
|
arePrimitiveWrappersEqual,
|
|
2044
2010
|
areRegExpsEqual,
|
|
2045
2011
|
areSetsEqual: strict ? combineComparators(areSetsEqual, areObjectsEqualStrict) : areSetsEqual,
|
|
2046
|
-
areTypedArraysEqual: strict ? areObjectsEqualStrict : areTypedArraysEqual,
|
|
2012
|
+
areTypedArraysEqual: strict ? combineComparators(areTypedArraysEqual, areObjectsEqualStrict) : areTypedArraysEqual,
|
|
2047
2013
|
areUrlsEqual,
|
|
2048
|
-
|
|
2014
|
+
getUnsupportedCustomComparator: void 0
|
|
2049
2015
|
};
|
|
2050
2016
|
if (createCustomConfig) {
|
|
2051
|
-
config = assign
|
|
2017
|
+
config = Object.assign({}, config, createCustomConfig(config));
|
|
2052
2018
|
}
|
|
2053
2019
|
if (circular) {
|
|
2054
|
-
|
|
2055
|
-
|
|
2056
|
-
|
|
2057
|
-
|
|
2058
|
-
config = assign
|
|
2059
|
-
areArraysEqual:
|
|
2060
|
-
areMapsEqual:
|
|
2061
|
-
areObjectsEqual:
|
|
2062
|
-
areSetsEqual:
|
|
2020
|
+
const areArraysEqual2 = createIsCircular(config.areArraysEqual);
|
|
2021
|
+
const areMapsEqual2 = createIsCircular(config.areMapsEqual);
|
|
2022
|
+
const areObjectsEqual2 = createIsCircular(config.areObjectsEqual);
|
|
2023
|
+
const areSetsEqual2 = createIsCircular(config.areSetsEqual);
|
|
2024
|
+
config = Object.assign({}, config, {
|
|
2025
|
+
areArraysEqual: areArraysEqual2,
|
|
2026
|
+
areMapsEqual: areMapsEqual2,
|
|
2027
|
+
areObjectsEqual: areObjectsEqual2,
|
|
2028
|
+
areSetsEqual: areSetsEqual2
|
|
2063
2029
|
});
|
|
2064
2030
|
}
|
|
2065
2031
|
return config;
|
|
@@ -2069,11 +2035,10 @@ function createInternalEqualityComparator(compare2) {
|
|
|
2069
2035
|
return compare2(a2, b, state);
|
|
2070
2036
|
};
|
|
2071
2037
|
}
|
|
2072
|
-
function createIsEqual(
|
|
2073
|
-
var circular = _a2.circular, comparator2 = _a2.comparator, createState = _a2.createState, equals = _a2.equals, strict = _a2.strict;
|
|
2038
|
+
function createIsEqual({ circular, comparator: comparator2, createState, equals, strict }) {
|
|
2074
2039
|
if (createState) {
|
|
2075
2040
|
return function isEqual(a2, b) {
|
|
2076
|
-
|
|
2041
|
+
const { cache: cache2 = circular ? /* @__PURE__ */ new WeakMap() : void 0, meta } = createState();
|
|
2077
2042
|
return comparator2(a2, b, {
|
|
2078
2043
|
cache: cache2,
|
|
2079
2044
|
equals,
|
|
@@ -2092,7 +2057,7 @@ function createIsEqual(_a2) {
|
|
|
2092
2057
|
});
|
|
2093
2058
|
};
|
|
2094
2059
|
}
|
|
2095
|
-
|
|
2060
|
+
const state = {
|
|
2096
2061
|
cache: void 0,
|
|
2097
2062
|
equals,
|
|
2098
2063
|
meta: void 0,
|
|
@@ -2102,7 +2067,50 @@ function createIsEqual(_a2) {
|
|
|
2102
2067
|
return comparator2(a2, b, state);
|
|
2103
2068
|
};
|
|
2104
2069
|
}
|
|
2105
|
-
|
|
2070
|
+
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 }) {
|
|
2071
|
+
return {
|
|
2072
|
+
"[object Arguments]": areObjectsEqual2,
|
|
2073
|
+
"[object Array]": areArraysEqual2,
|
|
2074
|
+
"[object ArrayBuffer]": areArrayBuffersEqual2,
|
|
2075
|
+
"[object AsyncGeneratorFunction]": areFunctionsEqual,
|
|
2076
|
+
"[object BigInt]": areNumbersEqual,
|
|
2077
|
+
"[object BigInt64Array]": areTypedArraysEqual2,
|
|
2078
|
+
"[object BigUint64Array]": areTypedArraysEqual2,
|
|
2079
|
+
"[object Boolean]": arePrimitiveWrappersEqual2,
|
|
2080
|
+
"[object DataView]": areDataViewsEqual2,
|
|
2081
|
+
"[object Date]": areDatesEqual2,
|
|
2082
|
+
// If an error tag, it should be tested explicitly. Like RegExp, the properties are not
|
|
2083
|
+
// enumerable, and therefore will give false positives if tested like a standard object.
|
|
2084
|
+
"[object Error]": areErrorsEqual2,
|
|
2085
|
+
"[object Float16Array]": areTypedArraysEqual2,
|
|
2086
|
+
"[object Float32Array]": areTypedArraysEqual2,
|
|
2087
|
+
"[object Float64Array]": areTypedArraysEqual2,
|
|
2088
|
+
"[object Function]": areFunctionsEqual,
|
|
2089
|
+
"[object GeneratorFunction]": areFunctionsEqual,
|
|
2090
|
+
"[object Int8Array]": areTypedArraysEqual2,
|
|
2091
|
+
"[object Int16Array]": areTypedArraysEqual2,
|
|
2092
|
+
"[object Int32Array]": areTypedArraysEqual2,
|
|
2093
|
+
"[object Map]": areMapsEqual2,
|
|
2094
|
+
"[object Number]": arePrimitiveWrappersEqual2,
|
|
2095
|
+
"[object Object]": (a2, b, state) => (
|
|
2096
|
+
// The exception for value comparison is custom `Promise`-like class instances. These should
|
|
2097
|
+
// be treated the same as standard `Promise` objects, which means strict equality, and if
|
|
2098
|
+
// it reaches this point then that strict equality comparison has already failed.
|
|
2099
|
+
typeof a2.then !== "function" && typeof b.then !== "function" && areObjectsEqual2(a2, b, state)
|
|
2100
|
+
),
|
|
2101
|
+
// For RegExp, the properties are not enumerable, and therefore will give false positives if
|
|
2102
|
+
// tested like a standard object.
|
|
2103
|
+
"[object RegExp]": areRegExpsEqual2,
|
|
2104
|
+
"[object Set]": areSetsEqual2,
|
|
2105
|
+
"[object String]": arePrimitiveWrappersEqual2,
|
|
2106
|
+
"[object URL]": areUrlsEqual2,
|
|
2107
|
+
"[object Uint8Array]": areTypedArraysEqual2,
|
|
2108
|
+
"[object Uint8ClampedArray]": areTypedArraysEqual2,
|
|
2109
|
+
"[object Uint16Array]": areTypedArraysEqual2,
|
|
2110
|
+
"[object Uint32Array]": areTypedArraysEqual2
|
|
2111
|
+
};
|
|
2112
|
+
}
|
|
2113
|
+
const deepEqual = createCustomEqual();
|
|
2106
2114
|
createCustomEqual({ strict: true });
|
|
2107
2115
|
createCustomEqual({ circular: true });
|
|
2108
2116
|
createCustomEqual({
|
|
@@ -2110,37 +2118,26 @@ createCustomEqual({
|
|
|
2110
2118
|
strict: true
|
|
2111
2119
|
});
|
|
2112
2120
|
createCustomEqual({
|
|
2113
|
-
createInternalComparator:
|
|
2114
|
-
return sameValueZeroEqual;
|
|
2115
|
-
}
|
|
2121
|
+
createInternalComparator: () => sameValueEqual
|
|
2116
2122
|
});
|
|
2117
2123
|
createCustomEqual({
|
|
2118
2124
|
strict: true,
|
|
2119
|
-
createInternalComparator:
|
|
2120
|
-
return sameValueZeroEqual;
|
|
2121
|
-
}
|
|
2125
|
+
createInternalComparator: () => sameValueEqual
|
|
2122
2126
|
});
|
|
2123
2127
|
createCustomEqual({
|
|
2124
2128
|
circular: true,
|
|
2125
|
-
createInternalComparator:
|
|
2126
|
-
return sameValueZeroEqual;
|
|
2127
|
-
}
|
|
2129
|
+
createInternalComparator: () => sameValueEqual
|
|
2128
2130
|
});
|
|
2129
2131
|
createCustomEqual({
|
|
2130
2132
|
circular: true,
|
|
2131
|
-
createInternalComparator:
|
|
2132
|
-
return sameValueZeroEqual;
|
|
2133
|
-
},
|
|
2133
|
+
createInternalComparator: () => sameValueEqual,
|
|
2134
2134
|
strict: true
|
|
2135
2135
|
});
|
|
2136
|
-
function createCustomEqual(options2) {
|
|
2137
|
-
|
|
2138
|
-
|
|
2139
|
-
|
|
2140
|
-
|
|
2141
|
-
var config = createEqualityComparatorConfig(options2);
|
|
2142
|
-
var comparator2 = createEqualityComparator(config);
|
|
2143
|
-
var equals = createCustomInternalComparator ? createCustomInternalComparator(comparator2) : createInternalEqualityComparator(comparator2);
|
|
2136
|
+
function createCustomEqual(options2 = {}) {
|
|
2137
|
+
const { circular = false, createInternalComparator: createCustomInternalComparator, createState, strict = false } = options2;
|
|
2138
|
+
const config = createEqualityComparatorConfig(options2);
|
|
2139
|
+
const comparator2 = createEqualityComparator(config);
|
|
2140
|
+
const equals = createCustomInternalComparator ? createCustomInternalComparator(comparator2) : createInternalEqualityComparator(comparator2);
|
|
2144
2141
|
return createIsEqual({ circular, comparator: comparator2, createState, equals, strict });
|
|
2145
2142
|
}
|
|
2146
2143
|
function listCacheClear$1() {
|
|
@@ -3390,7 +3387,10 @@ class CollectionRegistry {
|
|
|
3390
3387
|
if (!relation) {
|
|
3391
3388
|
throw new Error(`Relation '${relationKey}' not found in collection '${currentCollection.slug}'`);
|
|
3392
3389
|
}
|
|
3393
|
-
|
|
3390
|
+
const target = relation.target();
|
|
3391
|
+
const targetRelationKey = relation.relationName || target.slug;
|
|
3392
|
+
const targetSlug = relation.overrides?.slug ?? targetRelationKey;
|
|
3393
|
+
currentCollection = this.get(targetSlug) || this.normalizeCollection(target);
|
|
3394
3394
|
if (i + 1 < pathSegments.length) ;
|
|
3395
3395
|
}
|
|
3396
3396
|
return currentCollection;
|
|
@@ -3439,7 +3439,7 @@ class CollectionRegistry {
|
|
|
3439
3439
|
if (!subcollection) {
|
|
3440
3440
|
throw new Error(`Subcollection '${subcollectionSlug}' not found in ${currentCollection.slug}`);
|
|
3441
3441
|
}
|
|
3442
|
-
currentCollection = subcollection;
|
|
3442
|
+
currentCollection = this.get(subcollection.slug) || this.normalizeCollection(subcollection);
|
|
3443
3443
|
collections.push(currentCollection);
|
|
3444
3444
|
}
|
|
3445
3445
|
}
|
|
@@ -3806,11 +3806,24 @@ class RestApiGenerator {
|
|
|
3806
3806
|
collections;
|
|
3807
3807
|
router;
|
|
3808
3808
|
driver;
|
|
3809
|
-
|
|
3809
|
+
dataHooks;
|
|
3810
|
+
constructor(collections, driver, dataHooks) {
|
|
3810
3811
|
this.collections = collections;
|
|
3811
3812
|
this.driver = driver;
|
|
3813
|
+
this.dataHooks = dataHooks;
|
|
3812
3814
|
this.router = new Hono();
|
|
3813
3815
|
}
|
|
3816
|
+
/** Build a BackendHookContext from a Hono context */
|
|
3817
|
+
buildHookContext(c, method) {
|
|
3818
|
+
const user = c.get("user");
|
|
3819
|
+
return {
|
|
3820
|
+
requestUser: user ? {
|
|
3821
|
+
userId: user.userId,
|
|
3822
|
+
roles: user.roles ?? []
|
|
3823
|
+
} : void 0,
|
|
3824
|
+
method
|
|
3825
|
+
};
|
|
3826
|
+
}
|
|
3814
3827
|
/**
|
|
3815
3828
|
* Generate REST routes using existing DataDriver
|
|
3816
3829
|
*/
|
|
@@ -3822,16 +3835,10 @@ class RestApiGenerator {
|
|
|
3822
3835
|
return this.router;
|
|
3823
3836
|
}
|
|
3824
3837
|
/**
|
|
3825
|
-
* Get the
|
|
3838
|
+
* Get the typed RestFetchService from a driver if it exposes one (for include support).
|
|
3826
3839
|
*/
|
|
3827
3840
|
getFetchService(driver) {
|
|
3828
|
-
|
|
3829
|
-
const es = driver.entityService;
|
|
3830
|
-
if (typeof es.getFetchService === "function") {
|
|
3831
|
-
return es.getFetchService();
|
|
3832
|
-
}
|
|
3833
|
-
}
|
|
3834
|
-
return null;
|
|
3841
|
+
return driver.restFetchService;
|
|
3835
3842
|
}
|
|
3836
3843
|
/**
|
|
3837
3844
|
* Create REST routes for a collection using existing Rebase patterns
|
|
@@ -3839,15 +3846,26 @@ class RestApiGenerator {
|
|
|
3839
3846
|
createCollectionRoutes(collection) {
|
|
3840
3847
|
const basePath = `/${collection.slug}`;
|
|
3841
3848
|
const resolvedCollection = collection;
|
|
3849
|
+
this.router.get(`${basePath}/count`, async (c) => {
|
|
3850
|
+
const queryDict = c.req.query();
|
|
3851
|
+
const queryOptions = parseQueryOptions(queryDict);
|
|
3852
|
+
const searchString = queryDict.searchString;
|
|
3853
|
+
const driver = c.get("driver") || this.driver;
|
|
3854
|
+
const total = await this.countRawEntities(driver, resolvedCollection, queryOptions, searchString);
|
|
3855
|
+
return c.json({
|
|
3856
|
+
count: total
|
|
3857
|
+
});
|
|
3858
|
+
});
|
|
3842
3859
|
this.router.get(basePath, async (c) => {
|
|
3843
3860
|
const queryDict = c.req.query();
|
|
3844
3861
|
const queryOptions = parseQueryOptions(queryDict);
|
|
3845
3862
|
const searchString = queryDict.searchString;
|
|
3846
3863
|
const driver = c.get("driver") || this.driver;
|
|
3847
3864
|
const fetchService = this.getFetchService(driver);
|
|
3865
|
+
const hookCtx = this.buildHookContext(c, "GET");
|
|
3848
3866
|
if (fetchService) {
|
|
3849
3867
|
const collectionPath = collection.slug;
|
|
3850
|
-
|
|
3868
|
+
let entities2 = await fetchService.fetchCollectionForRest(collectionPath, {
|
|
3851
3869
|
filter: queryOptions.where,
|
|
3852
3870
|
limit: queryOptions.limit,
|
|
3853
3871
|
offset: queryOptions.offset,
|
|
@@ -3855,6 +3873,7 @@ class RestApiGenerator {
|
|
|
3855
3873
|
order: queryOptions.orderBy?.[0]?.direction === "desc" ? "desc" : "asc",
|
|
3856
3874
|
searchString
|
|
3857
3875
|
}, queryOptions.include);
|
|
3876
|
+
entities2 = await this.applyAfterReadBatch(collection.slug, entities2, hookCtx);
|
|
3858
3877
|
const total2 = await this.countRawEntities(driver, resolvedCollection, queryOptions, searchString);
|
|
3859
3878
|
return c.json({
|
|
3860
3879
|
data: entities2,
|
|
@@ -3866,7 +3885,8 @@ class RestApiGenerator {
|
|
|
3866
3885
|
}
|
|
3867
3886
|
});
|
|
3868
3887
|
}
|
|
3869
|
-
|
|
3888
|
+
let entities = await this.fetchRawCollection(driver, resolvedCollection, queryOptions, searchString);
|
|
3889
|
+
entities = await this.applyAfterReadBatch(collection.slug, entities, hookCtx);
|
|
3870
3890
|
const total = await this.countRawEntities(driver, resolvedCollection, queryOptions, searchString);
|
|
3871
3891
|
return c.json({
|
|
3872
3892
|
data: entities,
|
|
@@ -3884,15 +3904,24 @@ class RestApiGenerator {
|
|
|
3884
3904
|
const queryOptions = parseQueryOptions(queryDict);
|
|
3885
3905
|
const driver = c.get("driver") || this.driver;
|
|
3886
3906
|
const fetchService = this.getFetchService(driver);
|
|
3907
|
+
const hookCtx = this.buildHookContext(c, "GET");
|
|
3887
3908
|
if (fetchService) {
|
|
3888
3909
|
const collectionPath = collection.slug;
|
|
3889
|
-
|
|
3910
|
+
let entity2 = await fetchService.fetchEntityForRest(collectionPath, String(id), queryOptions.include);
|
|
3911
|
+
if (!entity2) {
|
|
3912
|
+
throw ApiError.notFound("Entity not found");
|
|
3913
|
+
}
|
|
3914
|
+
entity2 = await this.applyAfterRead(collection.slug, entity2, hookCtx);
|
|
3890
3915
|
if (!entity2) {
|
|
3891
3916
|
throw ApiError.notFound("Entity not found");
|
|
3892
3917
|
}
|
|
3893
3918
|
return c.json(entity2);
|
|
3894
3919
|
}
|
|
3895
|
-
|
|
3920
|
+
let entity = await this.fetchRawEntity(driver, resolvedCollection, String(id));
|
|
3921
|
+
if (!entity) {
|
|
3922
|
+
throw ApiError.notFound("Entity not found");
|
|
3923
|
+
}
|
|
3924
|
+
entity = await this.applyAfterRead(collection.slug, entity, hookCtx);
|
|
3896
3925
|
if (!entity) {
|
|
3897
3926
|
throw ApiError.notFound("Entity not found");
|
|
3898
3927
|
}
|
|
@@ -3902,14 +3931,24 @@ class RestApiGenerator {
|
|
|
3902
3931
|
try {
|
|
3903
3932
|
const driver = c.get("driver") || this.driver;
|
|
3904
3933
|
const path2 = collection.slug;
|
|
3905
|
-
const
|
|
3934
|
+
const hookCtx = this.buildHookContext(c, "POST");
|
|
3935
|
+
let body = await c.req.json().catch(() => ({}));
|
|
3936
|
+
if (this.dataHooks?.beforeSave) {
|
|
3937
|
+
body = await this.dataHooks.beforeSave(path2, body, void 0, hookCtx);
|
|
3938
|
+
}
|
|
3906
3939
|
const entity = await driver.saveEntity({
|
|
3907
3940
|
path: path2,
|
|
3908
3941
|
values: body,
|
|
3909
3942
|
collection: resolvedCollection,
|
|
3910
3943
|
status: "new"
|
|
3911
3944
|
});
|
|
3912
|
-
|
|
3945
|
+
const response = this.formatResponse(entity);
|
|
3946
|
+
if (this.dataHooks?.afterSave) {
|
|
3947
|
+
Promise.resolve(this.dataHooks.afterSave(path2, response, hookCtx)).catch((err) => {
|
|
3948
|
+
console.error("[BackendHooks] data.afterSave error:", err instanceof Error ? err.message : err);
|
|
3949
|
+
});
|
|
3950
|
+
}
|
|
3951
|
+
return c.json(response, 201);
|
|
3913
3952
|
} catch (error2) {
|
|
3914
3953
|
const err = error2;
|
|
3915
3954
|
err.code = err.code || "BAD_REQUEST";
|
|
@@ -3920,6 +3959,7 @@ class RestApiGenerator {
|
|
|
3920
3959
|
try {
|
|
3921
3960
|
const id = c.req.param("id");
|
|
3922
3961
|
const driver = c.get("driver") || this.driver;
|
|
3962
|
+
const hookCtx = this.buildHookContext(c, "PUT");
|
|
3923
3963
|
const existingEntity = await driver.fetchEntity({
|
|
3924
3964
|
path: collection.slug,
|
|
3925
3965
|
entityId: String(id),
|
|
@@ -3928,7 +3968,10 @@ class RestApiGenerator {
|
|
|
3928
3968
|
if (!existingEntity) {
|
|
3929
3969
|
throw ApiError.notFound("Entity not found");
|
|
3930
3970
|
}
|
|
3931
|
-
|
|
3971
|
+
let body = await c.req.json().catch(() => ({}));
|
|
3972
|
+
if (this.dataHooks?.beforeSave) {
|
|
3973
|
+
body = await this.dataHooks.beforeSave(collection.slug, body, String(id), hookCtx);
|
|
3974
|
+
}
|
|
3932
3975
|
const entity = await driver.saveEntity({
|
|
3933
3976
|
path: collection.slug,
|
|
3934
3977
|
entityId: String(id),
|
|
@@ -3936,7 +3979,13 @@ class RestApiGenerator {
|
|
|
3936
3979
|
collection: resolvedCollection,
|
|
3937
3980
|
status: "existing"
|
|
3938
3981
|
});
|
|
3939
|
-
|
|
3982
|
+
const response = this.formatResponse(entity);
|
|
3983
|
+
if (this.dataHooks?.afterSave) {
|
|
3984
|
+
Promise.resolve(this.dataHooks.afterSave(collection.slug, response, hookCtx)).catch((err) => {
|
|
3985
|
+
console.error("[BackendHooks] data.afterSave error:", err instanceof Error ? err.message : err);
|
|
3986
|
+
});
|
|
3987
|
+
}
|
|
3988
|
+
return c.json(response);
|
|
3940
3989
|
} catch (error2) {
|
|
3941
3990
|
const err = error2;
|
|
3942
3991
|
err.code = err.code || "BAD_REQUEST";
|
|
@@ -3946,6 +3995,7 @@ class RestApiGenerator {
|
|
|
3946
3995
|
this.router.delete(`${basePath}/:id`, async (c) => {
|
|
3947
3996
|
const id = c.req.param("id");
|
|
3948
3997
|
const driver = c.get("driver") || this.driver;
|
|
3998
|
+
const hookCtx = this.buildHookContext(c, "DELETE");
|
|
3949
3999
|
const existingEntity = await driver.fetchEntity({
|
|
3950
4000
|
path: collection.slug,
|
|
3951
4001
|
entityId: String(id),
|
|
@@ -3954,10 +4004,18 @@ class RestApiGenerator {
|
|
|
3954
4004
|
if (!existingEntity) {
|
|
3955
4005
|
throw ApiError.notFound("Entity not found");
|
|
3956
4006
|
}
|
|
4007
|
+
if (this.dataHooks?.beforeDelete) {
|
|
4008
|
+
await this.dataHooks.beforeDelete(collection.slug, String(id), hookCtx);
|
|
4009
|
+
}
|
|
3957
4010
|
await driver.deleteEntity({
|
|
3958
4011
|
entity: existingEntity,
|
|
3959
4012
|
collection: resolvedCollection
|
|
3960
4013
|
});
|
|
4014
|
+
if (this.dataHooks?.afterDelete) {
|
|
4015
|
+
Promise.resolve(this.dataHooks.afterDelete(collection.slug, String(id), hookCtx)).catch((err) => {
|
|
4016
|
+
console.error("[BackendHooks] data.afterDelete error:", err instanceof Error ? err.message : err);
|
|
4017
|
+
});
|
|
4018
|
+
}
|
|
3961
4019
|
return new Response(null, {
|
|
3962
4020
|
status: 204
|
|
3963
4021
|
});
|
|
@@ -4006,7 +4064,18 @@ class RestApiGenerator {
|
|
|
4006
4064
|
const parsed = parseSubPath(rawPath);
|
|
4007
4065
|
if (!parsed) return next();
|
|
4008
4066
|
const driver = c.get("driver") || this.driver;
|
|
4009
|
-
if (parsed.entityId) {
|
|
4067
|
+
if (parsed.entityId === "count") {
|
|
4068
|
+
const queryDict = c.req.query();
|
|
4069
|
+
const queryOptions = parseQueryOptions(queryDict);
|
|
4070
|
+
const total = driver.countEntities ? await driver.countEntities({
|
|
4071
|
+
path: parsed.collectionPath,
|
|
4072
|
+
filter: queryOptions.where,
|
|
4073
|
+
searchString: queryDict.searchString
|
|
4074
|
+
}) : 0;
|
|
4075
|
+
return c.json({
|
|
4076
|
+
count: total
|
|
4077
|
+
});
|
|
4078
|
+
} else if (parsed.entityId) {
|
|
4010
4079
|
const entity = await driver.fetchEntity({
|
|
4011
4080
|
path: parsed.collectionPath,
|
|
4012
4081
|
entityId: parsed.entityId
|
|
@@ -4164,6 +4233,22 @@ class RestApiGenerator {
|
|
|
4164
4233
|
});
|
|
4165
4234
|
return entity ? this.flattenEntity(entity) : null;
|
|
4166
4235
|
}
|
|
4236
|
+
/**
|
|
4237
|
+
* Apply data.afterRead hook to a single entity.
|
|
4238
|
+
* Returns the transformed entity, or null to filter it out.
|
|
4239
|
+
*/
|
|
4240
|
+
async applyAfterRead(slug, entity, ctx) {
|
|
4241
|
+
if (!this.dataHooks?.afterRead) return entity;
|
|
4242
|
+
return this.dataHooks.afterRead(slug, entity, ctx);
|
|
4243
|
+
}
|
|
4244
|
+
/**
|
|
4245
|
+
* Apply data.afterRead hook to an array of entities, filtering out nulls.
|
|
4246
|
+
*/
|
|
4247
|
+
async applyAfterReadBatch(slug, entities, ctx) {
|
|
4248
|
+
if (!this.dataHooks?.afterRead) return entities;
|
|
4249
|
+
const results = await Promise.all(entities.map((e) => this.applyAfterRead(slug, e, ctx)));
|
|
4250
|
+
return results.filter((e) => e !== null);
|
|
4251
|
+
}
|
|
4167
4252
|
}
|
|
4168
4253
|
var jws$5 = {};
|
|
4169
4254
|
var safeBuffer = { exports: {} };
|
|
@@ -23614,7 +23699,12 @@ function createRateLimiter(options2 = {}) {
|
|
|
23614
23699
|
};
|
|
23615
23700
|
}
|
|
23616
23701
|
function defaultKeyGenerator(c) {
|
|
23617
|
-
|
|
23702
|
+
const forwardedFor = c.req.header("x-forwarded-for");
|
|
23703
|
+
if (forwardedFor) {
|
|
23704
|
+
const ips = forwardedFor.split(",");
|
|
23705
|
+
return ips[ips.length - 1].trim();
|
|
23706
|
+
}
|
|
23707
|
+
return c.req.header("x-real-ip") || "unknown";
|
|
23618
23708
|
}
|
|
23619
23709
|
const defaultAuthLimiter = createRateLimiter({
|
|
23620
23710
|
windowMs: 15 * 60 * 1e3,
|
|
@@ -24182,8 +24272,45 @@ function createAdminRoutes(config) {
|
|
|
24182
24272
|
const authRepo = config.authRepo;
|
|
24183
24273
|
const {
|
|
24184
24274
|
emailService,
|
|
24185
|
-
emailConfig
|
|
24275
|
+
emailConfig,
|
|
24276
|
+
hooks
|
|
24186
24277
|
} = config;
|
|
24278
|
+
function buildHookContext(c, method) {
|
|
24279
|
+
const user = c.get("user");
|
|
24280
|
+
return {
|
|
24281
|
+
requestUser: user ? {
|
|
24282
|
+
userId: user.userId,
|
|
24283
|
+
roles: user.roles ?? []
|
|
24284
|
+
} : void 0,
|
|
24285
|
+
method
|
|
24286
|
+
};
|
|
24287
|
+
}
|
|
24288
|
+
async function applyUserAfterRead(user, ctx) {
|
|
24289
|
+
if (!hooks?.users?.afterRead) return user;
|
|
24290
|
+
return hooks.users.afterRead(user, ctx);
|
|
24291
|
+
}
|
|
24292
|
+
async function applyUserAfterReadBatch(users, ctx) {
|
|
24293
|
+
if (!hooks?.users?.afterRead) return users;
|
|
24294
|
+
const results = await Promise.all(users.map((u) => applyUserAfterRead(u, ctx)));
|
|
24295
|
+
return results.filter((u) => u !== null);
|
|
24296
|
+
}
|
|
24297
|
+
async function applyRoleAfterReadBatch(roles, ctx) {
|
|
24298
|
+
if (!hooks?.roles?.afterRead) return roles;
|
|
24299
|
+
const results = await Promise.all(roles.map((r) => hooks.roles.afterRead(r, ctx)));
|
|
24300
|
+
return results.filter((r) => r !== null);
|
|
24301
|
+
}
|
|
24302
|
+
function toAdminUser(u, roles) {
|
|
24303
|
+
return {
|
|
24304
|
+
uid: u.id,
|
|
24305
|
+
email: u.email,
|
|
24306
|
+
displayName: u.displayName ?? null,
|
|
24307
|
+
photoURL: u.photoUrl ?? null,
|
|
24308
|
+
provider: "custom",
|
|
24309
|
+
roles,
|
|
24310
|
+
createdAt: u.createdAt instanceof Date ? u.createdAt.toISOString() : u.createdAt ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
24311
|
+
updatedAt: u.updatedAt instanceof Date ? u.updatedAt.toISOString() : u.updatedAt ?? (/* @__PURE__ */ new Date()).toISOString()
|
|
24312
|
+
};
|
|
24313
|
+
}
|
|
24187
24314
|
router.onError(errorHandler);
|
|
24188
24315
|
router.use("/*", createRequireAuth({
|
|
24189
24316
|
serviceKey: config.serviceKey
|
|
@@ -24234,6 +24361,7 @@ function createAdminRoutes(config) {
|
|
|
24234
24361
|
const search = c.req.query("search");
|
|
24235
24362
|
const orderBy = c.req.query("orderBy");
|
|
24236
24363
|
const orderDir = c.req.query("orderDir");
|
|
24364
|
+
const hookCtx = buildHookContext(c, "GET");
|
|
24237
24365
|
if (limitParam !== void 0 || search) {
|
|
24238
24366
|
const limit = limitParam ? parseInt(limitParam, 10) : 25;
|
|
24239
24367
|
const offset = offsetParam ? parseInt(offsetParam, 10) : 0;
|
|
@@ -24245,18 +24373,11 @@ function createAdminRoutes(config) {
|
|
|
24245
24373
|
orderDir: orderDir || void 0,
|
|
24246
24374
|
roleId: c.req.query("role") || void 0
|
|
24247
24375
|
});
|
|
24248
|
-
|
|
24376
|
+
let usersWithRoles2 = await Promise.all(result.users.map(async (u) => {
|
|
24249
24377
|
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
|
-
};
|
|
24378
|
+
return toAdminUser(u, roles);
|
|
24259
24379
|
}));
|
|
24380
|
+
usersWithRoles2 = await applyUserAfterReadBatch(usersWithRoles2, hookCtx);
|
|
24260
24381
|
return c.json({
|
|
24261
24382
|
users: usersWithRoles2,
|
|
24262
24383
|
total: result.total,
|
|
@@ -24265,18 +24386,11 @@ function createAdminRoutes(config) {
|
|
|
24265
24386
|
});
|
|
24266
24387
|
}
|
|
24267
24388
|
const users = await authRepo.listUsers();
|
|
24268
|
-
|
|
24389
|
+
let usersWithRoles = await Promise.all(users.map(async (u) => {
|
|
24269
24390
|
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
|
-
};
|
|
24391
|
+
return toAdminUser(u, roles);
|
|
24279
24392
|
}));
|
|
24393
|
+
usersWithRoles = await applyUserAfterReadBatch(usersWithRoles, hookCtx);
|
|
24280
24394
|
return c.json({
|
|
24281
24395
|
users: usersWithRoles
|
|
24282
24396
|
});
|
|
@@ -24287,21 +24401,19 @@ function createAdminRoutes(config) {
|
|
|
24287
24401
|
if (!result) {
|
|
24288
24402
|
throw ApiError.notFound("User not found");
|
|
24289
24403
|
}
|
|
24404
|
+
const hookCtx = buildHookContext(c, "GET");
|
|
24405
|
+
let adminUser = toAdminUser(result.user, result.roles.map((r) => r.id));
|
|
24406
|
+
adminUser = await applyUserAfterRead(adminUser, hookCtx);
|
|
24407
|
+
if (!adminUser) {
|
|
24408
|
+
throw ApiError.notFound("User not found");
|
|
24409
|
+
}
|
|
24290
24410
|
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
|
-
}
|
|
24411
|
+
user: adminUser
|
|
24300
24412
|
});
|
|
24301
24413
|
});
|
|
24302
24414
|
router.post("/users", requireAdmin, async (c) => {
|
|
24303
24415
|
const body = await c.req.json();
|
|
24304
|
-
|
|
24416
|
+
let {
|
|
24305
24417
|
email,
|
|
24306
24418
|
displayName,
|
|
24307
24419
|
password,
|
|
@@ -24310,6 +24422,17 @@ function createAdminRoutes(config) {
|
|
|
24310
24422
|
if (!email) {
|
|
24311
24423
|
throw ApiError.badRequest("Email is required", "INVALID_INPUT");
|
|
24312
24424
|
}
|
|
24425
|
+
const hookCtx = buildHookContext(c, "POST");
|
|
24426
|
+
if (hooks?.users?.beforeSave) {
|
|
24427
|
+
const hooked = await hooks.users.beforeSave({
|
|
24428
|
+
email,
|
|
24429
|
+
displayName,
|
|
24430
|
+
roles
|
|
24431
|
+
}, hookCtx);
|
|
24432
|
+
email = hooked.email ?? email;
|
|
24433
|
+
displayName = hooked.displayName ?? displayName;
|
|
24434
|
+
roles = hooked.roles ?? roles;
|
|
24435
|
+
}
|
|
24313
24436
|
const existing = await authRepo.getUserByEmail(email);
|
|
24314
24437
|
if (existing) {
|
|
24315
24438
|
throw ApiError.conflict("Email already exists", "EMAIL_EXISTS");
|
|
@@ -24365,13 +24488,14 @@ function createAdminRoutes(config) {
|
|
|
24365
24488
|
} else if (!password) {
|
|
24366
24489
|
temporaryPassword = clearPassword;
|
|
24367
24490
|
}
|
|
24491
|
+
const createdAdminUser = toAdminUser(user, userRoles);
|
|
24492
|
+
if (hooks?.users?.afterSave) {
|
|
24493
|
+
Promise.resolve(hooks.users.afterSave(createdAdminUser, hookCtx)).catch((err) => {
|
|
24494
|
+
console.error("[BackendHooks] users.afterSave error:", err instanceof Error ? err.message : err);
|
|
24495
|
+
});
|
|
24496
|
+
}
|
|
24368
24497
|
return c.json({
|
|
24369
|
-
user:
|
|
24370
|
-
uid: user.id,
|
|
24371
|
-
email: user.email,
|
|
24372
|
-
displayName: user.displayName,
|
|
24373
|
-
roles: userRoles
|
|
24374
|
-
},
|
|
24498
|
+
user: createdAdminUser,
|
|
24375
24499
|
invitationSent,
|
|
24376
24500
|
...temporaryPassword ? {
|
|
24377
24501
|
temporaryPassword
|
|
@@ -24441,7 +24565,7 @@ function createAdminRoutes(config) {
|
|
|
24441
24565
|
router.put("/users/:userId", requireAdmin, async (c) => {
|
|
24442
24566
|
const userId = c.req.param("userId");
|
|
24443
24567
|
const body = await c.req.json();
|
|
24444
|
-
|
|
24568
|
+
let {
|
|
24445
24569
|
email,
|
|
24446
24570
|
displayName,
|
|
24447
24571
|
password,
|
|
@@ -24451,6 +24575,17 @@ function createAdminRoutes(config) {
|
|
|
24451
24575
|
if (!existing) {
|
|
24452
24576
|
throw ApiError.notFound("User not found");
|
|
24453
24577
|
}
|
|
24578
|
+
const hookCtx = buildHookContext(c, "PUT");
|
|
24579
|
+
if (hooks?.users?.beforeSave) {
|
|
24580
|
+
const hooked = await hooks.users.beforeSave({
|
|
24581
|
+
email,
|
|
24582
|
+
displayName,
|
|
24583
|
+
roles
|
|
24584
|
+
}, hookCtx);
|
|
24585
|
+
email = hooked.email ?? email;
|
|
24586
|
+
displayName = hooked.displayName ?? displayName;
|
|
24587
|
+
roles = hooked.roles ?? roles;
|
|
24588
|
+
}
|
|
24454
24589
|
const updates = {};
|
|
24455
24590
|
if (email !== void 0) updates.email = email.toLowerCase();
|
|
24456
24591
|
if (displayName !== void 0) updates.displayName = displayName;
|
|
@@ -24468,13 +24603,14 @@ function createAdminRoutes(config) {
|
|
|
24468
24603
|
await authRepo.setUserRoles(userId, roles);
|
|
24469
24604
|
}
|
|
24470
24605
|
const result = await authRepo.getUserWithRoles(userId);
|
|
24606
|
+
const updatedAdminUser = toAdminUser(result.user, result.roles.map((r) => r.id));
|
|
24607
|
+
if (hooks?.users?.afterSave) {
|
|
24608
|
+
Promise.resolve(hooks.users.afterSave(updatedAdminUser, hookCtx)).catch((err) => {
|
|
24609
|
+
console.error("[BackendHooks] users.afterSave error:", err instanceof Error ? err.message : err);
|
|
24610
|
+
});
|
|
24611
|
+
}
|
|
24471
24612
|
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
|
-
}
|
|
24613
|
+
user: updatedAdminUser
|
|
24478
24614
|
});
|
|
24479
24615
|
});
|
|
24480
24616
|
router.delete("/users/:userId", requireAdmin, async (c) => {
|
|
@@ -24488,21 +24624,33 @@ function createAdminRoutes(config) {
|
|
|
24488
24624
|
if (!existing) {
|
|
24489
24625
|
throw ApiError.notFound("User not found");
|
|
24490
24626
|
}
|
|
24627
|
+
const hookCtx = buildHookContext(c, "DELETE");
|
|
24628
|
+
if (hooks?.users?.beforeDelete) {
|
|
24629
|
+
await hooks.users.beforeDelete(userId, hookCtx);
|
|
24630
|
+
}
|
|
24491
24631
|
await authRepo.deleteUser(userId);
|
|
24632
|
+
if (hooks?.users?.afterDelete) {
|
|
24633
|
+
Promise.resolve(hooks.users.afterDelete(userId, hookCtx)).catch((err) => {
|
|
24634
|
+
console.error("[BackendHooks] users.afterDelete error:", err instanceof Error ? err.message : err);
|
|
24635
|
+
});
|
|
24636
|
+
}
|
|
24492
24637
|
return c.json({
|
|
24493
24638
|
success: true
|
|
24494
24639
|
});
|
|
24495
24640
|
});
|
|
24496
24641
|
router.get("/roles", requireAdmin, async (c) => {
|
|
24497
24642
|
const roles = await authRepo.listRoles();
|
|
24643
|
+
const hookCtx = buildHookContext(c, "GET");
|
|
24644
|
+
let adminRoles = roles.map((r) => ({
|
|
24645
|
+
id: r.id,
|
|
24646
|
+
name: r.name,
|
|
24647
|
+
isAdmin: r.isAdmin,
|
|
24648
|
+
defaultPermissions: r.defaultPermissions,
|
|
24649
|
+
config: r.config
|
|
24650
|
+
}));
|
|
24651
|
+
adminRoles = await applyRoleAfterReadBatch(adminRoles, hookCtx);
|
|
24498
24652
|
return c.json({
|
|
24499
|
-
roles:
|
|
24500
|
-
id: r.id,
|
|
24501
|
-
name: r.name,
|
|
24502
|
-
isAdmin: r.isAdmin,
|
|
24503
|
-
defaultPermissions: r.defaultPermissions,
|
|
24504
|
-
config: r.config
|
|
24505
|
-
}))
|
|
24653
|
+
roles: adminRoles
|
|
24506
24654
|
});
|
|
24507
24655
|
});
|
|
24508
24656
|
router.get("/roles/:roleId", requireAdmin, async (c) => {
|
|
@@ -24630,10 +24778,10 @@ class LocalStorageController {
|
|
|
24630
24778
|
* Includes a path traversal guard to prevent escaping the base directory.
|
|
24631
24779
|
*/
|
|
24632
24780
|
getFullPath(storagePath, bucket) {
|
|
24633
|
-
const
|
|
24634
|
-
const resolved = path$3.resolve(path$3.join(
|
|
24635
|
-
if (!resolved.startsWith(
|
|
24636
|
-
throw new Error("Path traversal detected: resolved storage path is outside the
|
|
24781
|
+
const bucketPath = bucket ? path$3.join(this.basePath, bucket) : this.basePath;
|
|
24782
|
+
const resolved = path$3.resolve(path$3.join(bucketPath, storagePath));
|
|
24783
|
+
if (!resolved.startsWith(bucketPath + path$3.sep) && resolved !== bucketPath) {
|
|
24784
|
+
throw new Error("Path traversal detected: resolved storage path is outside the bucket directory.");
|
|
24637
24785
|
}
|
|
24638
24786
|
return resolved;
|
|
24639
24787
|
}
|
|
@@ -26343,6 +26491,18 @@ function createCollectionClient(transport, slug, ws) {
|
|
|
26343
26491
|
method: "DELETE"
|
|
26344
26492
|
});
|
|
26345
26493
|
},
|
|
26494
|
+
async count(params) {
|
|
26495
|
+
const countParams = {
|
|
26496
|
+
...params,
|
|
26497
|
+
limit: void 0,
|
|
26498
|
+
offset: void 0
|
|
26499
|
+
};
|
|
26500
|
+
const qs = buildQueryString(countParams);
|
|
26501
|
+
const raw = await transport.request(basePath + "/count" + qs, {
|
|
26502
|
+
method: "GET"
|
|
26503
|
+
});
|
|
26504
|
+
return raw.count ?? 0;
|
|
26505
|
+
},
|
|
26346
26506
|
// Fluent builder instantiation
|
|
26347
26507
|
where(column, operator, value) {
|
|
26348
26508
|
return new QueryBuilder(client).where(column, operator, value);
|
|
@@ -37944,7 +38104,8 @@ async function _initializeRebaseBackend(config) {
|
|
|
37944
38104
|
authRepo: authConfigResult.authRepository ?? authConfigResult.userService,
|
|
37945
38105
|
emailService: authConfigResult.emailService,
|
|
37946
38106
|
emailConfig: config.auth.email,
|
|
37947
|
-
serviceKey
|
|
38107
|
+
serviceKey,
|
|
38108
|
+
hooks: config.hooks
|
|
37948
38109
|
});
|
|
37949
38110
|
config.app.route(`${basePath}/admin`, adminRoutes);
|
|
37950
38111
|
}
|
|
@@ -38002,7 +38163,7 @@ async function _initializeRebaseBackend(config) {
|
|
|
38002
38163
|
});
|
|
38003
38164
|
dataRouter.route("/", historyRoutes);
|
|
38004
38165
|
}
|
|
38005
|
-
const restGenerator = new RestApiGenerator(activeCollections, defaultDriver);
|
|
38166
|
+
const restGenerator = new RestApiGenerator(activeCollections, defaultDriver, config.hooks?.data);
|
|
38006
38167
|
dataRouter.route("/", restGenerator.generateRoutes());
|
|
38007
38168
|
config.app.route(`${basePath}/data`, dataRouter);
|
|
38008
38169
|
}
|
|
@@ -49020,9 +49181,9 @@ class RebaseApiServer {
|
|
|
49020
49181
|
if (process.env.NODE_ENV === "production") {
|
|
49021
49182
|
console.warn("[RebaseApiServer] Schema Editor is disabled in production environments for security.");
|
|
49022
49183
|
} else {
|
|
49184
|
+
this.router.use(`${basePath}/schema-editor/*`, requireAuth, requireAdmin);
|
|
49023
49185
|
const schemaEditorRoutes2 = createSchemaEditorRoutes(this.config.collectionsDir);
|
|
49024
49186
|
this.router.route(`${basePath}/schema-editor`, schemaEditorRoutes2);
|
|
49025
|
-
this.router.use(`${basePath}/schema-editor/*`, requireAuth, requireAdmin);
|
|
49026
49187
|
}
|
|
49027
49188
|
}
|
|
49028
49189
|
this.router.get(`${basePath}/docs`, (c) => {
|