@blac/core 2.0.0-rc.14 → 2.0.0-rc.16

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.cjs CHANGED
@@ -834,7 +834,9 @@ var StateContainerRegistry = class {
834
834
  */
835
835
  on(event, listener) {
836
836
  if (!this.listeners.has(event)) this.listeners.set(event, /* @__PURE__ */ new Set());
837
- this.listeners.get(event).add(listener);
837
+ const instance = this.listeners.get(event);
838
+ if (!instance) throw new Error(`${BLAC_ERROR_PREFIX} Failed to register listener for event '${event}'`);
839
+ instance.add(listener);
838
840
  return () => {
839
841
  this.listeners.get(event)?.delete(listener);
840
842
  };
@@ -881,12 +883,12 @@ function getPluginManager() {
881
883
  *
882
884
  * @example
883
885
  * ```ts
884
- * class CounterBloc extends StateContainer<number> {
886
+ * class CounterBloc extends StateContainer<{ count: number }> {
885
887
  * constructor() {
886
- * super(0);
888
+ * super({ count: 0 });
887
889
  * }
888
890
  * increment() {
889
- * this.emit(this.state + 1);
891
+ * this.emit({ count: this.state.count + 1 });
890
892
  * }
891
893
  * }
892
894
  * ```
@@ -1236,33 +1238,70 @@ var Cubit = class extends StateContainer {
1236
1238
  //#endregion
1237
1239
  //#region src/core/Vertex.ts
1238
1240
  /**
1239
- * Event-driven state container that processes events to update state.
1240
- * Use with event handlers registered via the on() method.
1241
+ * Event-driven state container using discriminated union events.
1242
+ * Extends StateContainer with event-based state transitions and
1243
+ * compile-time exhaustive checking for event handlers.
1241
1244
  *
1242
- * @template S - State type
1243
- * @template E - Event type (extends BaseEvent)
1245
+ * @template S - State type (must be an object)
1246
+ * @template E - Event union type (discriminated by 'type' property)
1244
1247
  * @template P - Props type (optional)
1248
+ *
1249
+ * @example
1250
+ * ```typescript
1251
+ * type CounterEvent =
1252
+ * | { type: 'increment'; amount: number }
1253
+ * | { type: 'decrement' }
1254
+ * | { type: 'reset' };
1255
+ *
1256
+ * class CounterVertex extends Vertex<{ count: number }, CounterEvent> {
1257
+ * constructor() {
1258
+ * super({ count: 0 });
1259
+ * this.createHandlers({
1260
+ * increment: (event, emit) => {
1261
+ * emit({ count: this.state.count + event.amount });
1262
+ * },
1263
+ * decrement: (_, emit) => {
1264
+ * emit({ count: this.state.count - 1 });
1265
+ * },
1266
+ * reset: (_, emit) => {
1267
+ * emit({ count: 0 });
1268
+ * },
1269
+ * });
1270
+ * }
1271
+ *
1272
+ * increment = (amount = 1) => this.add({ type: 'increment', amount });
1273
+ * }
1274
+ * ```
1245
1275
  */
1246
1276
  var Vertex = class extends StateContainer {
1247
1277
  constructor(initialState) {
1248
1278
  super(initialState);
1249
- this.eventHandlers = /* @__PURE__ */ new Map();
1279
+ this.handlers = /* @__PURE__ */ new Map();
1250
1280
  this.isProcessing = false;
1251
1281
  this.eventQueue = [];
1252
- this.on = (EventClass, handler) => {
1253
- const className = EventClass.name;
1254
- const registrations = this.eventHandlers.get(className) || [];
1255
- registrations.push({
1256
- eventClass: EventClass,
1257
- handler
1258
- });
1259
- this.eventHandlers.set(className, registrations);
1260
- };
1261
1282
  this.add = (event) => {
1262
- StateContainer._registry.emit("eventAdded", this, event);
1263
- this.processEvent(event);
1283
+ const enrichedEvent = this.enrichEvent(event);
1284
+ StateContainer._registry.emit("eventAdded", this, enrichedEvent);
1285
+ this.processEvent(enrichedEvent);
1286
+ };
1287
+ }
1288
+ /**
1289
+ * Register all event handlers with exhaustive type checking.
1290
+ * TypeScript will error if any event type from the union is missing.
1291
+ *
1292
+ * @param handlers - Map of event type to handler function
1293
+ */
1294
+ createHandlers(handlers) {
1295
+ for (const [eventType, handler] of Object.entries(handlers)) this.handlers.set(eventType, handler);
1296
+ }
1297
+ /** @internal */
1298
+ enrichEvent(event) {
1299
+ return {
1300
+ ...event,
1301
+ timestamp: Date.now()
1264
1302
  };
1265
1303
  }
1304
+ /** @internal */
1266
1305
  processEvent(event) {
1267
1306
  if (this.isProcessing) {
1268
1307
  this.eventQueue.push(event);
@@ -1279,26 +1318,27 @@ var Vertex = class extends StateContainer {
1279
1318
  this.isProcessing = false;
1280
1319
  }
1281
1320
  }
1321
+ /** @internal */
1282
1322
  handleEvent(event) {
1283
- const className = event.constructor.name;
1284
- const registrations = this.eventHandlers.get(className);
1285
- if (!registrations || registrations.length === 0) {
1286
- if (this.debug) console.warn(`No handler registered for event: ${className}`);
1323
+ const handler = this.handlers.get(event.type);
1324
+ if (!handler) {
1325
+ if (this.debug) console.warn(`No handler registered for event type: ${event.type}`);
1287
1326
  return;
1288
1327
  }
1289
1328
  const emitFn = (state) => {
1290
1329
  this.emit(state);
1291
1330
  };
1292
- for (const registration of registrations) try {
1293
- registration.handler(event, emitFn);
1331
+ try {
1332
+ handler(event, emitFn);
1294
1333
  } catch (error$1) {
1295
- if (this.debug) console.error(`Error handling event ${className}:`, error$1);
1334
+ if (this.debug) console.error(`Error handling event ${event.type}:`, error$1);
1296
1335
  this.onEventError(event, error$1);
1297
1336
  }
1298
1337
  }
1299
1338
  /**
1300
- * Handle errors that occur during event processing.
1301
- * Override this method to implement custom error handling.
1339
+ * Called when an error occurs during event processing.
1340
+ * Override to implement custom error handling.
1341
+ *
1302
1342
  * @param _event - The event that caused the error
1303
1343
  * @param _error - The error that occurred
1304
1344
  */
@@ -2036,6 +2076,67 @@ function configureLogger(opts) {
2036
2076
  defaultLogger = createLogger(currentConfig);
2037
2077
  }
2038
2078
 
2079
+ //#endregion
2080
+ //#region src/config.ts
2081
+ const defaultConfig = {
2082
+ devMode: process.env.NODE_ENV !== "production",
2083
+ logger: {
2084
+ enabled: false,
2085
+ level: LogLevel.INFO
2086
+ }
2087
+ };
2088
+ let globalConfig = { ...defaultConfig };
2089
+ /**
2090
+ * Configure global defaults for @blac/core.
2091
+ *
2092
+ * @example
2093
+ * ```ts
2094
+ * import { configureBlac, LogLevel } from '@blac/core';
2095
+ *
2096
+ * configureBlac({
2097
+ * devMode: true,
2098
+ * logger: {
2099
+ * enabled: true,
2100
+ * level: LogLevel.DEBUG
2101
+ * }
2102
+ * });
2103
+ * ```
2104
+ *
2105
+ * @param config - Partial configuration to merge with defaults
2106
+ */
2107
+ function configureBlac(config) {
2108
+ globalConfig = {
2109
+ ...globalConfig,
2110
+ ...config,
2111
+ logger: {
2112
+ ...globalConfig.logger,
2113
+ ...config.logger
2114
+ }
2115
+ };
2116
+ if (config.logger) configureLogger(config.logger);
2117
+ }
2118
+ /**
2119
+ * Get the current global configuration.
2120
+ * @internal
2121
+ */
2122
+ function getBlacConfig() {
2123
+ return globalConfig;
2124
+ }
2125
+ /**
2126
+ * Check if development mode is enabled.
2127
+ */
2128
+ function isDevMode() {
2129
+ return globalConfig.devMode;
2130
+ }
2131
+ /**
2132
+ * Reset configuration to defaults (useful for testing).
2133
+ * @internal
2134
+ */
2135
+ function resetBlacConfig() {
2136
+ globalConfig = { ...defaultConfig };
2137
+ configureLogger(defaultConfig.logger);
2138
+ }
2139
+
2039
2140
  //#endregion
2040
2141
  //#region src/decorators/blac.ts
2041
2142
  /**
@@ -2087,6 +2188,7 @@ exports.captureTrackedPaths = captureTrackedPaths;
2087
2188
  exports.clearActiveTracker = clearActiveTracker;
2088
2189
  exports.clearExternalDependencies = clearExternalDependencies;
2089
2190
  exports.commitTrackedGetters = commitTrackedGetters;
2191
+ exports.configureBlac = configureBlac;
2090
2192
  exports.configureLogger = configureLogger;
2091
2193
  exports.createArrayProxy = createArrayProxy;
2092
2194
  exports.createAutoTrackSnapshot = createAutoTrackSnapshot;
@@ -2112,6 +2214,7 @@ exports.generateId = generateId;
2112
2214
  exports.generateIsolatedKey = generateIsolatedKey;
2113
2215
  exports.generateSimpleId = generateSimpleId;
2114
2216
  exports.getActiveTracker = getActiveTracker;
2217
+ exports.getBlacConfig = getBlacConfig;
2115
2218
  exports.getDescriptor = getDescriptor;
2116
2219
  exports.getGetterExecutionContext = getGetterExecutionContext;
2117
2220
  exports.getPluginManager = getPluginManager;
@@ -2127,6 +2230,7 @@ exports.initAutoTrackState = initAutoTrackState;
2127
2230
  exports.initManualDepsState = initManualDepsState;
2128
2231
  exports.initNoTrackState = initNoTrackState;
2129
2232
  exports.invalidateRenderCache = invalidateRenderCache;
2233
+ exports.isDevMode = isDevMode;
2130
2234
  exports.isExcludedFromDevTools = isExcludedFromDevTools;
2131
2235
  exports.isGetter = isGetter;
2132
2236
  exports.isIsolatedClass = isIsolatedClass;
@@ -2134,6 +2238,7 @@ exports.isIsolatedKey = isIsolatedKey;
2134
2238
  exports.isKeepAliveClass = isKeepAliveClass;
2135
2239
  exports.isProxyable = isProxyable;
2136
2240
  exports.parsePath = parsePath;
2241
+ exports.resetBlacConfig = resetBlacConfig;
2137
2242
  exports.resetGetterTracker = resetGetterTracker;
2138
2243
  exports.setActiveTracker = setActiveTracker;
2139
2244
  exports.shallowEqual = shallowEqual;