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