@abdokouta/react-support 1.1.0 → 1.2.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.
package/dist/index.mjs CHANGED
@@ -1,3 +1,7 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
3
+ var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value);
4
+
1
5
  // src/str/str.ts
2
6
  var Str = class _Str {
3
7
  /**
@@ -20,7 +24,23 @@ var Str = class _Str {
20
24
  * Convert a string to title case following APA guidelines
21
25
  */
22
26
  static apa(value) {
23
- const minorWords = ["a", "an", "and", "as", "at", "but", "by", "for", "in", "of", "on", "or", "the", "to", "up"];
27
+ const minorWords = [
28
+ "a",
29
+ "an",
30
+ "and",
31
+ "as",
32
+ "at",
33
+ "but",
34
+ "by",
35
+ "for",
36
+ "in",
37
+ "of",
38
+ "on",
39
+ "or",
40
+ "the",
41
+ "to",
42
+ "up"
43
+ ];
24
44
  const words = value.split(" ");
25
45
  return words.map((word, index) => {
26
46
  if (index === 0 || !minorWords.includes(word.toLowerCase())) {
@@ -628,6 +648,7 @@ var Str = class _Str {
628
648
  import collectJs from "collect.js";
629
649
  var Collection = class _Collection {
630
650
  constructor(items = []) {
651
+ __publicField(this, "collection");
631
652
  this.collection = collectJs(items);
632
653
  }
633
654
  /**
@@ -780,7 +801,10 @@ var Collection = class _Collection {
780
801
  * Join all items from the collection using a string
781
802
  */
782
803
  join(glue, finalGlue) {
783
- return this.collection.join(glue, finalGlue);
804
+ if (finalGlue) {
805
+ return this.collection.join(glue, finalGlue);
806
+ }
807
+ return this.collection.join(glue);
784
808
  }
785
809
  /**
786
810
  * Key the collection by the given key
@@ -1039,6 +1063,7 @@ function collect(items = []) {
1039
1063
  // src/collections/map.collection.ts
1040
1064
  var MapCollection = class _MapCollection {
1041
1065
  constructor(entries) {
1066
+ __publicField(this, "internalMap");
1042
1067
  if (entries && typeof entries === "object" && !(Symbol.iterator in entries)) {
1043
1068
  this.internalMap = new Map(Object.entries(entries));
1044
1069
  } else {
@@ -1338,6 +1363,7 @@ function collectMap(entries) {
1338
1363
  // src/collections/set.collection.ts
1339
1364
  var SetCollection = class _SetCollection {
1340
1365
  constructor(items) {
1366
+ __publicField(this, "set");
1341
1367
  this.set = new Set(items);
1342
1368
  }
1343
1369
  /**
@@ -1655,731 +1681,296 @@ function collectSet(items) {
1655
1681
  }
1656
1682
 
1657
1683
  // src/registry/base-registry.ts
1658
- var RegistryCollection = class {
1659
- constructor() {
1660
- this._storage = new MapCollection();
1661
- }
1662
- add(key, value) {
1663
- this._storage.set(key, value);
1664
- }
1665
- get(key) {
1666
- return this._storage.get(key);
1667
- }
1668
- getAll() {
1669
- return this._storage.values();
1670
- }
1671
- getKeys() {
1672
- return this._storage.keys();
1673
- }
1674
- getAsRecord() {
1675
- return this._storage.toObject();
1676
- }
1677
- has(key) {
1678
- return this._storage.has(key);
1679
- }
1680
- remove(key) {
1681
- return this._storage.delete(key);
1682
- }
1683
- clear() {
1684
- this._storage.clear();
1685
- }
1686
- size() {
1687
- return this._storage.size();
1688
- }
1689
- isEmpty() {
1690
- return this._storage.isEmpty();
1691
- }
1692
- forEach(callback) {
1693
- this._storage.each((value, key) => {
1694
- callback(value, key);
1695
- });
1696
- }
1697
- map(callback) {
1698
- const result = [];
1699
- this._storage.each((value, key) => {
1700
- result.push(callback(value, key));
1701
- });
1702
- return result;
1703
- }
1704
- filter(predicate) {
1705
- const result = [];
1706
- this._storage.each((value, key) => {
1707
- if (predicate(value, key)) {
1708
- result.push(value);
1709
- }
1710
- });
1711
- return result;
1712
- }
1713
- find(predicate) {
1714
- return this._storage.first(predicate);
1715
- }
1716
- };
1717
1684
  var BaseRegistry = class {
1718
1685
  /**
1719
- * Creates a new BaseRegistry instance
1720
- *
1721
- * Initializes the registry with optional configuration for default
1722
- * item and validation hooks. By default, uses MapCollection for storage.
1723
- *
1724
- * @param options - Registry configuration options
1725
- *
1726
- * @example
1727
- * ```typescript
1728
- * // Simple registry without options
1729
- * const registry = new BaseRegistry<Theme>();
1730
- * ```
1731
- *
1732
- * @example
1733
- * ```typescript
1734
- * // Registry with default item
1735
- * const registry = new BaseRegistry<Theme>({
1736
- * defaultItem: defaultTheme
1737
- * });
1738
- * ```
1739
- *
1740
- * @example
1741
- * ```typescript
1742
- * // Registry with validation
1743
- * const registry = new BaseRegistry<Theme>({
1744
- * validateBeforeAdd: (key, theme) => {
1745
- * if (!theme.name) {
1746
- * return { valid: false, error: 'Theme must have a name' };
1747
- * }
1748
- * return { valid: true };
1749
- * },
1750
- * afterAdd: (key, theme) => {
1751
- * console.log(`Registered theme: ${theme.name}`);
1752
- * }
1753
- * });
1754
- * ```
1686
+ * Create a new registry.
1687
+ *
1688
+ * @param options - Optional default item, validation, and lifecycle hooks
1755
1689
  */
1756
1690
  constructor(options = {}) {
1757
- this.collection = new RegistryCollection();
1691
+ /**
1692
+ * Internal map-based storage.
1693
+ */
1694
+ __publicField(this, "storage", new MapCollection());
1695
+ /**
1696
+ * Fallback value returned by {@link get} when a key is missing.
1697
+ */
1698
+ __publicField(this, "defaultItem");
1699
+ /**
1700
+ * Optional validation executed before every {@link register} call.
1701
+ */
1702
+ __publicField(this, "validateBeforeAdd");
1703
+ /**
1704
+ * Optional callback executed after a successful {@link register}.
1705
+ */
1706
+ __publicField(this, "afterAdd");
1758
1707
  this.defaultItem = options.defaultItem;
1759
1708
  this.validateBeforeAdd = options.validateBeforeAdd;
1760
1709
  this.afterAdd = options.afterAdd;
1761
1710
  }
1711
+ // ──────────────────────────────────────────────────────────────────────────
1712
+ // Core
1713
+ // ──────────────────────────────────────────────────────────────────────────
1762
1714
  /**
1763
- * Register an item in the registry
1764
- *
1765
- * Adds or updates an item in the registry with the specified key.
1766
- * If an item with the same key already exists, it will be replaced.
1767
- *
1768
- * If a validation hook is configured, it will be called before adding
1769
- * the item. If validation fails, an error is thrown and the item is
1770
- * not added.
1771
- *
1772
- * If an afterAdd hook is configured, it will be called after the item
1773
- * is successfully added.
1774
- *
1775
- * Time Complexity: O(1) + validation time
1776
- *
1777
- * @param key - Unique identifier for the item
1778
- * @param item - Item to register
1715
+ * Register (add or replace) an item.
1716
+ *
1717
+ * Runs the `validateBeforeAdd` hook first; throws on failure.
1718
+ * Fires the `afterAdd` hook on success.
1719
+ *
1720
+ * @param key - Unique identifier
1721
+ * @param item - Value to store
1779
1722
  * @throws Error if validation fails
1780
- *
1781
- * @example
1782
- * ```typescript
1783
- * const registry = new BaseRegistry<Theme>();
1784
- *
1785
- * // Register a theme
1786
- * registry.register('blue', {
1787
- * name: 'Blue',
1788
- * colors: { accent: '#0000FF' }
1789
- * });
1790
- *
1791
- * // Update existing theme
1792
- * registry.register('blue', {
1793
- * name: 'Blue',
1794
- * colors: { accent: '#0066FF' }
1795
- * });
1796
- * ```
1797
1723
  */
1798
1724
  register(key, item) {
1799
1725
  if (this.validateBeforeAdd) {
1800
1726
  const result = this.validateBeforeAdd(key, item);
1801
1727
  if (!result.valid) {
1802
- throw new Error(
1803
- `Validation failed for key "${key}": ${result.error || "Unknown error"}`
1804
- );
1728
+ throw new Error(`Validation failed for key "${key}": ${result.error || "Unknown error"}`);
1805
1729
  }
1806
1730
  }
1807
- this.collection.add(key, item);
1731
+ this.storage.set(key, item);
1808
1732
  if (this.afterAdd) {
1809
1733
  this.afterAdd(key, item);
1810
1734
  }
1811
1735
  }
1812
- // ============================================================================
1813
- // Collection Interface Implementation
1814
- // All methods below delegate directly to the internal collection
1815
- // ============================================================================
1816
- /**
1817
- * Add an item to the collection (alias for register)
1818
- *
1819
- * This method is part of the Collection interface.
1820
- * It delegates to register() to ensure validation hooks are called.
1821
- *
1822
- * Time Complexity: O(1) + validation time
1823
- *
1824
- * @param key - Unique identifier for the item
1825
- * @param value - Item to add
1736
+ // ──────────────────────────────────────────────────────────────────────────
1737
+ // Collection interface
1738
+ // ──────────────────────────────────────────────────────────────────────────
1739
+ /**
1740
+ * @inheritdoc — delegates to {@link register} so hooks still fire.
1826
1741
  */
1827
1742
  add(key, value) {
1828
1743
  this.register(key, value);
1829
1744
  }
1830
1745
  /**
1831
- * Get an item from the registry
1832
- *
1833
- * Retrieves an item by its key. If the item doesn't exist:
1834
- * - Returns the default item if one was configured
1835
- * - Returns undefined if no default item was configured
1836
- *
1837
- * Time Complexity: O(1)
1838
- *
1746
+ * Retrieve an item by key.
1747
+ *
1748
+ * Falls back to {@link defaultItem} when the key is not found.
1749
+ *
1839
1750
  * @param key - Item identifier
1840
- * @returns Item if found, default item if configured, or undefined
1841
- *
1842
- * @example
1843
- * ```typescript
1844
- * const theme = registry.get('blue');
1845
- * ```
1751
+ * @returns The stored value, the default item, or `undefined`
1846
1752
  */
1847
1753
  get(key) {
1848
- const item = this.collection.get(key);
1849
- if (item !== void 0) {
1850
- return item;
1851
- }
1852
- return this.defaultItem;
1853
- }
1854
- /**
1855
- * Get all items in the registry
1856
- *
1857
- * Returns an array containing all items in the registry.
1858
- * The order of items depends on the collection implementation
1859
- * (MapCollection maintains insertion order).
1860
- *
1861
- * Time Complexity: O(n) where n is the number of items
1862
- *
1863
- * @returns Array of all items in the registry
1864
- *
1865
- * @example
1866
- * ```typescript
1867
- * const allThemes = registry.getAll();
1868
- * ```
1754
+ return this.storage.get(key) ?? this.defaultItem;
1755
+ }
1756
+ /**
1757
+ * Return every stored value in insertion order.
1869
1758
  */
1870
1759
  getAll() {
1871
- return this.collection.getAll();
1872
- }
1873
- /**
1874
- * Get all keys in the registry
1875
- *
1876
- * Returns an array containing all keys in the registry.
1877
- * Useful for iteration or checking what items are registered.
1878
- *
1879
- * Time Complexity: O(n) where n is the number of items
1880
- *
1881
- * @returns Array of all keys in the registry
1882
- *
1883
- * @example
1884
- * ```typescript
1885
- * const keys = registry.getKeys();
1886
- * ```
1760
+ return this.storage.values();
1761
+ }
1762
+ /**
1763
+ * Return every registered key in insertion order.
1887
1764
  */
1888
1765
  getKeys() {
1889
- return this.collection.getKeys();
1890
- }
1891
- /**
1892
- * Get registry as a record object
1893
- *
1894
- * Converts the registry to a plain JavaScript object (record)
1895
- * with keys mapping to values. Useful for serialization.
1896
- *
1897
- * Time Complexity: O(n) where n is the number of items
1898
- *
1899
- * @returns Record object with keys mapping to values
1900
- *
1901
- * @example
1902
- * ```typescript
1903
- * const record = registry.getAsRecord();
1904
- * ```
1766
+ return this.storage.keys();
1767
+ }
1768
+ /**
1769
+ * Convert the registry to a plain `Record<string, T>`.
1905
1770
  */
1906
1771
  getAsRecord() {
1907
- return this.collection.getAsRecord();
1908
- }
1909
- /**
1910
- * Check if an item is registered
1911
- *
1912
- * Checks whether an item with the specified key exists in the registry.
1913
- * Does not check the value, only the presence of the key.
1914
- *
1915
- * Time Complexity: O(1)
1916
- *
1917
- * @param key - Item identifier to check
1918
- * @returns True if item is registered, false otherwise
1919
- *
1920
- * @example
1921
- * ```typescript
1922
- * if (registry.has('blue')) {
1923
- * console.log('Blue theme exists');
1924
- * }
1925
- * ```
1772
+ return this.storage.toObject();
1773
+ }
1774
+ /**
1775
+ * Check whether a key exists.
1926
1776
  */
1927
1777
  has(key) {
1928
- return this.collection.has(key);
1778
+ return this.storage.has(key);
1929
1779
  }
1930
1780
  /**
1931
- * Remove an item from the registry
1932
- *
1933
- * Removes an item with the specified key from the registry.
1934
- * Returns true if the item was removed, false if it didn't exist.
1935
- *
1936
- * Time Complexity: O(1)
1937
- *
1938
- * @param key - Item identifier to remove
1939
- * @returns True if item was removed, false if it didn't exist
1940
- *
1941
- * @example
1942
- * ```typescript
1943
- * const removed = registry.remove('blue');
1944
- * ```
1781
+ * Remove an item by key.
1782
+ *
1783
+ * @returns `true` if the key existed and was removed
1945
1784
  */
1946
1785
  remove(key) {
1947
- return this.collection.remove(key);
1786
+ return this.storage.delete(key);
1948
1787
  }
1949
1788
  /**
1950
- * Clear all items from the registry
1951
- *
1952
- * Removes all items from the registry, leaving it empty.
1953
- * This operation is irreversible.
1954
- *
1955
- * Time Complexity: O(1)
1956
- *
1957
- * @example
1958
- * ```typescript
1959
- * registry.clear();
1960
- * ```
1789
+ * Remove all items from the registry.
1961
1790
  */
1962
1791
  clear() {
1963
- this.collection.clear();
1964
- }
1965
- /**
1966
- * Get the number of items in the registry
1967
- *
1968
- * Returns the total count of items currently registered.
1969
- *
1970
- * Time Complexity: O(1)
1971
- *
1972
- * @returns Number of items in the registry
1973
- *
1974
- * @example
1975
- * ```typescript
1976
- * console.log(registry.size()); // 2
1977
- * ```
1978
- */
1979
- size() {
1980
- return this.collection.size();
1981
- }
1982
- /**
1983
- * Check if the registry is empty
1984
- *
1985
- * Returns true if the registry contains no items, false otherwise.
1986
- * This is a convenience method equivalent to checking if size() === 0.
1987
- *
1988
- * Time Complexity: O(1)
1989
- *
1990
- * @returns True if registry has no items, false otherwise
1991
- *
1992
- * @example
1993
- * ```typescript
1994
- * console.log(registry.isEmpty()); // true
1995
- * ```
1996
- */
1997
- isEmpty() {
1998
- return this.collection.isEmpty();
1792
+ this.storage.clear();
1999
1793
  }
2000
1794
  /**
2001
- * Iterate over all items in the registry
2002
- *
2003
- * Executes a callback function for each item in the registry.
2004
- * Items are iterated in insertion order (for MapCollection).
2005
- *
2006
- * Time Complexity: O(n) where n is the number of items
2007
- *
2008
- * @param callback - Function to call for each item (value, key)
2009
- *
2010
- * @example
2011
- * ```typescript
2012
- * registry.forEach((theme, key) => {
2013
- * console.log(`${key}: ${theme.name}`);
2014
- * });
2015
- * ```
1795
+ * Return the number of registered items.
2016
1796
  */
2017
- forEach(callback) {
2018
- this.collection.forEach(callback);
2019
- }
2020
- /**
2021
- * Map over all items in the registry
2022
- *
2023
- * Transforms each item in the registry using a callback function
2024
- * and returns an array of the transformed values.
2025
- *
2026
- * Time Complexity: O(n) where n is the number of items
2027
- *
2028
- * @template U - The type of the transformed items
2029
- * @param callback - Function to transform each item (value, key) => U
2030
- * @returns Array of transformed items
2031
- *
2032
- * @example
2033
- * ```typescript
2034
- * const names = registry.map(theme => theme.name);
2035
- * ```
2036
- */
2037
- map(callback) {
2038
- return this.collection.map(callback);
2039
- }
2040
- /**
2041
- * Filter items in the registry
2042
- *
2043
- * Returns an array of items that pass the test implemented by the
2044
- * provided predicate function.
2045
- *
2046
- * Time Complexity: O(n) where n is the number of items
2047
- *
2048
- * @param predicate - Function to test each item (value, key) => boolean
2049
- * @returns Array of items that pass the test
2050
- *
2051
- * @example
2052
- * ```typescript
2053
- * const darkThemes = registry.filter(theme => theme.isDark);
2054
- * ```
2055
- */
2056
- filter(predicate) {
2057
- return this.collection.filter(predicate);
2058
- }
2059
- /**
2060
- * Find an item in the registry
2061
- *
2062
- * Returns the first item that satisfies the provided predicate function.
2063
- * Returns undefined if no item passes the test.
2064
- *
2065
- * Time Complexity: O(n) worst case, O(1) best case
2066
- *
2067
- * @param predicate - Function to test each item (value, key) => boolean
2068
- * @returns First item that passes the test, or undefined
2069
- *
2070
- * @example
2071
- * ```typescript
2072
- * const defaultTheme = registry.find(theme => theme.isDefault);
2073
- * ```
2074
- */
2075
- find(predicate) {
2076
- return this.collection.find(predicate);
1797
+ size() {
1798
+ return this.storage.size();
2077
1799
  }
2078
- };
2079
-
2080
- // src/facades/facade.ts
2081
- import { getModuleContainer } from "@abdokouta/react-di";
2082
-
2083
- // src/facades/facade.interface.ts
2084
- function isFake(obj) {
2085
- return typeof obj === "object" && obj !== null && "__isFake" in obj && obj.__isFake === true;
2086
- }
2087
-
2088
- // src/facades/facade.ts
2089
- var Facade = class {
2090
1800
  /**
2091
- * Hotswap the underlying instance behind the facade
2092
- *
2093
- * Useful for testing - swap the real service with a mock or fake.
2094
- *
2095
- * @param instance - Instance to swap in
2096
- *
2097
- * @example
2098
- * ```typescript
2099
- * // In tests
2100
- * const mockLogger = { info: vi.fn(), error: vi.fn() };
2101
- * Log.swap(mockLogger);
2102
- *
2103
- * // Now Log.info() calls mockLogger.info()
2104
- * Log.info('test');
2105
- * expect(mockLogger.info).toHaveBeenCalledWith('test');
2106
- * ```
1801
+ * Return `true` when the registry is empty.
2107
1802
  */
2108
- static swap(instance) {
2109
- const accessor = this.getFacadeAccessor();
2110
- const key = this.getAccessorKey(accessor);
2111
- this.resolvedInstance.set(key, instance);
1803
+ isEmpty() {
1804
+ return this.storage.isEmpty();
2112
1805
  }
2113
1806
  /**
2114
- * Determines whether a "fake" has been set as the facade instance
2115
- *
2116
- * @returns True if the current instance is a Fake
2117
- *
2118
- * @example
2119
- * ```typescript
2120
- * if (Log.isFake()) {
2121
- * console.log('Using fake logger');
2122
- * }
2123
- * ```
1807
+ * Iterate over every entry in insertion order.
2124
1808
  */
2125
- static isFake() {
2126
- const accessor = this.getFacadeAccessor();
2127
- const key = this.getAccessorKey(accessor);
2128
- const instance = this.resolvedInstance.get(key);
2129
- return instance !== void 0 && isFake(instance);
1809
+ forEach(callback) {
1810
+ this.storage.each((value, key) => {
1811
+ callback(value, key);
1812
+ });
2130
1813
  }
2131
1814
  /**
2132
- * Get the root object behind the facade
2133
- *
2134
- * Resolves and returns the actual service instance.
2135
- *
2136
- * @returns The resolved service instance
1815
+ * Map every entry to a new value and return the results as an array.
2137
1816
  */
2138
- static getFacadeRoot() {
2139
- return this.resolveFacadeInstance(this.getFacadeAccessor());
1817
+ map(callback) {
1818
+ const result = [];
1819
+ this.storage.each((value, key) => {
1820
+ result.push(callback(value, key));
1821
+ });
1822
+ return result;
2140
1823
  }
2141
1824
  /**
2142
- * Get the registered name of the component
2143
- *
2144
- * Subclasses MUST override this method to specify which service
2145
- * the facade represents.
2146
- *
2147
- * @returns Service identifier (string, symbol, or class)
2148
- * @throws Error if not implemented
2149
- *
2150
- * @example
2151
- * ```typescript
2152
- * class Log extends Facade {
2153
- * protected static getFacadeAccessor(): ServiceIdentifier {
2154
- * return LoggerService; // or 'logger' string token
2155
- * }
2156
- * }
2157
- * ```
1825
+ * Return all values whose entries satisfy the predicate.
2158
1826
  */
2159
- static getFacadeAccessor() {
2160
- throw new Error("Facade does not implement getFacadeAccessor method.");
1827
+ filter(predicate) {
1828
+ const result = [];
1829
+ this.storage.each((value, key) => {
1830
+ if (predicate(value, key)) {
1831
+ result.push(value);
1832
+ }
1833
+ });
1834
+ return result;
2161
1835
  }
2162
1836
  /**
2163
- * Get a consistent key for the accessor
1837
+ * Return the first value whose entry satisfies the predicate.
2164
1838
  */
2165
- static getAccessorKey(accessor) {
2166
- if (typeof accessor === "function") {
2167
- return accessor.name || accessor.toString();
2168
- }
2169
- return accessor;
1839
+ find(predicate) {
1840
+ return this.storage.first(predicate);
2170
1841
  }
2171
- /**
2172
- * Resolve the facade root instance from the container
1842
+ };
1843
+
1844
+ // src/managers/multiple-instance-manager.ts
1845
+ var MultipleInstanceManager = class {
1846
+ constructor() {
1847
+ // ──────────────────────────────────────────────────────────────────────────
1848
+ // State
1849
+ // ──────────────────────────────────────────────────────────────────────────
1850
+ /**
1851
+ * Resolved instances, keyed by instance name.
1852
+ * Instances are created once and reused on subsequent calls.
1853
+ */
1854
+ __publicField(this, "instances", /* @__PURE__ */ new Map());
1855
+ /**
1856
+ * Custom driver creators registered via `extend()`.
1857
+ * Keyed by driver name.
1858
+ */
1859
+ __publicField(this, "customCreators", /* @__PURE__ */ new Map());
1860
+ /**
1861
+ * The config key that identifies the driver.
1862
+ * Override in subclasses if your config uses a different field name.
1863
+ *
1864
+ * @default 'driver'
1865
+ */
1866
+ __publicField(this, "driverKey", "driver");
1867
+ }
1868
+ // ──────────────────────────────────────────────────────────────────────────
1869
+ // Public API
1870
+ // ──────────────────────────────────────────────────────────────────────────
1871
+ /**
1872
+ * Get an instance by name.
2173
1873
  *
2174
- * @param identifier - Service identifier
2175
- * @returns Resolved service instance
2176
- */
2177
- static resolveFacadeInstance(identifier) {
2178
- const key = this.getAccessorKey(identifier);
2179
- if (this.resolvedInstance.has(key)) {
2180
- return this.resolvedInstance.get(key);
2181
- }
2182
- const container = this.getContainer();
2183
- if (!container) {
2184
- throw new Error(
2185
- `Unable to resolve facade instance. Module not set. Call Facade.setFacadeModule(YourModule) first.`
2186
- );
2187
- }
2188
- const instance = container.get(identifier);
2189
- if (this.cached) {
2190
- this.resolvedInstance.set(key, instance);
2191
- }
2192
- return instance;
2193
- }
2194
- /**
2195
- * Get the module container
1874
+ * Returns a cached instance if available, otherwise resolves and caches it.
1875
+ * If no name is provided, returns the default instance.
2196
1876
  *
2197
- * @returns The module container instance
2198
- */
2199
- static getContainer() {
2200
- if (this.container) {
2201
- return this.container;
1877
+ * @param name - Instance name (uses default if omitted)
1878
+ * @returns The resolved instance
1879
+ * @throws Error if the instance is not configured
1880
+ */
1881
+ instance(name) {
1882
+ const instanceName = name ?? this.getDefaultInstance();
1883
+ const existing = this.instances.get(instanceName);
1884
+ if (existing) {
1885
+ return existing;
2202
1886
  }
2203
- if (this.moduleClass) {
2204
- this.container = getModuleContainer(this.moduleClass);
2205
- return this.container;
2206
- }
2207
- return null;
1887
+ const resolved = this.resolve(instanceName);
1888
+ this.instances.set(instanceName, resolved);
1889
+ return resolved;
2208
1890
  }
2209
1891
  /**
2210
- * Clear a resolved facade instance
1892
+ * Register a custom driver creator.
2211
1893
  *
2212
- * @param name - Service identifier to clear (defaults to this facade's accessor)
2213
- */
2214
- static clearResolvedInstance(name) {
2215
- const key = name ?? this.getAccessorKey(this.getFacadeAccessor());
2216
- this.resolvedInstance.delete(key);
2217
- }
2218
- /**
2219
- * Clear all resolved instances
1894
+ * Custom creators take priority over built-in drivers.
2220
1895
  *
2221
- * Useful for test cleanup.
1896
+ * @param driver - Driver name
1897
+ * @param creator - Factory function that creates an instance from config
1898
+ * @returns this (for chaining)
2222
1899
  */
2223
- static clearResolvedInstances() {
2224
- this.resolvedInstance.clear();
1900
+ extend(driver, creator) {
1901
+ this.customCreators.set(driver, creator);
1902
+ return this;
2225
1903
  }
2226
1904
  /**
2227
- * Get the module class
1905
+ * Remove a cached instance, forcing re-creation on next access.
2228
1906
  *
2229
- * @returns The module class
1907
+ * @param name - Instance name (uses default if omitted)
1908
+ * @returns this (for chaining)
2230
1909
  */
2231
- static getFacadeModule() {
2232
- return this.moduleClass;
1910
+ forgetInstance(name) {
1911
+ const instanceName = name ?? this.getDefaultInstance();
1912
+ this.instances.delete(instanceName);
1913
+ return this;
2233
1914
  }
2234
1915
  /**
2235
- * Set the module class for facade resolution
2236
- *
2237
- * Must be called during application bootstrap to enable facades.
2238
- * Call this AFTER Inversiland.run() or Container.configure().build().
2239
- *
2240
- * @param module - The root module class
2241
- *
2242
- * @example
2243
- * ```typescript
2244
- * // In your app bootstrap (main.tsx)
2245
- * import { Facade } from '@abdokouta/react-support';
2246
- * import { Container, ContainerProvider } from '@abdokouta/react-di';
2247
- * import { AppModule } from './app.module';
2248
- *
2249
- * // Initialize container
2250
- * Container.configure().withModule(AppModule).withDefaults().build();
2251
- *
2252
- * // Set facade module
2253
- * Facade.setFacadeModule(AppModule);
2254
- *
2255
- * // Now facades work anywhere
2256
- * ReactDOM.createRoot(document.getElementById("root")!).render(
2257
- * <ContainerProvider module={AppModule}>
2258
- * <App />
2259
- * </ContainerProvider>
2260
- * );
2261
- * ```
1916
+ * Remove all cached instances.
2262
1917
  */
2263
- static setFacadeModule(module) {
2264
- this.moduleClass = module;
2265
- this.container = null;
1918
+ purge() {
1919
+ this.instances.clear();
2266
1920
  }
2267
1921
  /**
2268
- * Set the container directly (alternative to setFacadeModule)
1922
+ * Check if an instance has been resolved and cached.
2269
1923
  *
2270
- * @param container - The module container instance
1924
+ * @param name - Instance name
2271
1925
  */
2272
- static setFacadeContainer(container) {
2273
- this.container = container;
1926
+ hasResolvedInstance(name) {
1927
+ return this.instances.has(name);
2274
1928
  }
2275
- // ============================================================================
2276
- // Legacy API (for compatibility with FacadeApplication interface)
2277
- // ============================================================================
2278
1929
  /**
2279
- * @deprecated Use setFacadeModule instead
1930
+ * Get all resolved instance names.
2280
1931
  */
2281
- static setFacadeApplication(app) {
2282
- if (app) {
2283
- this.container = {
2284
- get: (id) => app.get(id)
2285
- };
2286
- } else {
2287
- this.container = null;
2288
- }
1932
+ getResolvedInstances() {
1933
+ return Array.from(this.instances.keys());
2289
1934
  }
1935
+ // ──────────────────────────────────────────────────────────────────────────
1936
+ // Resolution (private)
1937
+ // ──────────────────────────────────────────────────────────────────────────
2290
1938
  /**
2291
- * @deprecated Use getFacadeModule instead
1939
+ * Resolve an instance by name.
1940
+ *
1941
+ * 1. Reads config via `getInstanceConfig()` (from injected config)
1942
+ * 2. Extracts the driver name from the config
1943
+ * 3. Checks custom creators first
1944
+ * 4. Falls back to `createDriver()`
1945
+ *
1946
+ * @param name - Instance name
1947
+ * @returns A new instance
2292
1948
  */
2293
- static getFacadeApplication() {
2294
- const container = this.getContainer();
2295
- if (!container) return null;
2296
- return {
2297
- get: (abstract) => container.get(abstract)
2298
- };
2299
- }
2300
- };
2301
- /**
2302
- * The root module class for resolving services
2303
- */
2304
- Facade.moduleClass = null;
2305
- /**
2306
- * The module container instance (cached)
2307
- */
2308
- Facade.container = null;
2309
- /**
2310
- * The resolved object instances
2311
- *
2312
- * Caches resolved instances by their accessor key for performance.
2313
- */
2314
- Facade.resolvedInstance = /* @__PURE__ */ new Map();
2315
- /**
2316
- * Indicates if the resolved instance should be cached
2317
- *
2318
- * Set to false in subclasses to always resolve fresh instances.
2319
- */
2320
- Facade.cached = true;
2321
-
2322
- // src/facades/create-facade.ts
2323
- import { getModuleContainer as getModuleContainer2 } from "@abdokouta/react-di";
2324
- function createFacade(options) {
2325
- const { accessor, cached = true } = options;
2326
- class ConcreteFacade extends Facade {
2327
- static getFacadeAccessor() {
2328
- return accessor;
1949
+ resolve(name) {
1950
+ const config = this.getInstanceConfig(name);
1951
+ if (!config) {
1952
+ throw new Error(`Instance [${name}] is not defined.`);
2329
1953
  }
2330
- }
2331
- ConcreteFacade.cached = cached;
2332
- const proxy = new Proxy(ConcreteFacade, {
2333
- get(target, prop, receiver) {
2334
- if (prop in target) {
2335
- const value = Reflect.get(target, prop, receiver);
2336
- if (typeof value === "function") {
2337
- return value.bind(target);
2338
- }
2339
- return value;
2340
- }
2341
- return (...args) => {
2342
- const instance = target.getFacadeRoot();
2343
- if (!instance) {
2344
- throw new Error(
2345
- `A facade root has not been set. Call Facade.setFacadeModule() first.`
2346
- );
2347
- }
2348
- const method = instance[prop];
2349
- if (typeof method !== "function") {
2350
- throw new Error(
2351
- `Method "${String(prop)}" does not exist on the facade root.`
2352
- );
2353
- }
2354
- return method.apply(instance, args);
2355
- };
1954
+ const driver = config[this.driverKey];
1955
+ if (!driver) {
1956
+ throw new Error(`Instance [${name}] does not specify a "${this.driverKey}".`);
2356
1957
  }
2357
- });
2358
- return proxy;
2359
- }
2360
- function createFacadeClass(accessor) {
2361
- return class extends Facade {
2362
- static getFacadeAccessor() {
2363
- return accessor;
1958
+ const customCreator = this.customCreators.get(driver);
1959
+ if (customCreator) {
1960
+ return customCreator(config);
2364
1961
  }
2365
- };
2366
- }
2367
- function getContainerFromModule(moduleClass) {
2368
- return getModuleContainer2(moduleClass);
2369
- }
1962
+ return this.createDriver(driver, config);
1963
+ }
1964
+ };
2370
1965
  export {
2371
1966
  BaseRegistry,
2372
1967
  Collection,
2373
- Facade,
2374
1968
  MapCollection,
1969
+ MultipleInstanceManager,
2375
1970
  SetCollection,
2376
1971
  Str,
2377
1972
  collect,
2378
1973
  collectMap,
2379
- collectSet,
2380
- createFacade,
2381
- createFacadeClass,
2382
- getContainerFromModule,
2383
- isFake
1974
+ collectSet
2384
1975
  };
2385
1976
  //# sourceMappingURL=index.mjs.map