@hamak/ui-store-impl 0.2.1 → 0.2.2

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.
@@ -1 +1,2 @@
1
- $ tsc -p tsconfig.json
1
+
2
+ $ tsc -p tsconfig.json && tsc -p tsconfig.es2015.json
@@ -0,0 +1,3 @@
1
+ export * from './store-manager';
2
+ export * from './middleware-registry';
3
+ export * from './reducer-registry';
@@ -0,0 +1,47 @@
1
+ /**
2
+ * Middleware Registry Implementation
3
+ */
4
+ export class MiddlewareRegistry {
5
+ constructor() {
6
+ this.registrations = new Map();
7
+ this.locked = false;
8
+ }
9
+ register(registration) {
10
+ if (this.locked) {
11
+ throw new Error(`Cannot register middleware "${registration.id}" - store already created. ` +
12
+ `Register middleware during plugin initialization phase.`);
13
+ }
14
+ if (this.registrations.has(registration.id)) {
15
+ console.warn(`[MiddlewareRegistry] Middleware "${registration.id}" already registered, overwriting.`);
16
+ }
17
+ this.registrations.set(registration.id, Object.assign({ priority: 0 }, registration));
18
+ }
19
+ unregister(id) {
20
+ if (this.locked) {
21
+ throw new Error(`Cannot unregister middleware after store creation`);
22
+ }
23
+ this.registrations.delete(id);
24
+ }
25
+ getAll() {
26
+ const sorted = Array.from(this.registrations.values())
27
+ .sort((a, b) => (b.priority || 0) - (a.priority || 0));
28
+ return sorted.map(reg => reg.middleware);
29
+ }
30
+ has(id) {
31
+ return this.registrations.has(id);
32
+ }
33
+ getInfo(id) {
34
+ return this.registrations.get(id);
35
+ }
36
+ getAllRegistrations() {
37
+ return Array.from(this.registrations.values())
38
+ .sort((a, b) => (b.priority || 0) - (a.priority || 0));
39
+ }
40
+ /**
41
+ * Lock the registry (called when store is created)
42
+ * @internal
43
+ */
44
+ lock() {
45
+ this.locked = true;
46
+ }
47
+ }
@@ -0,0 +1,54 @@
1
+ /**
2
+ * Reducer Registry Implementation
3
+ */
4
+ import { combineReducers } from 'redux';
5
+ export class ReducerRegistry {
6
+ constructor(onReducerChange) {
7
+ this.reducers = new Map();
8
+ this.onReducerChange = onReducerChange;
9
+ }
10
+ register(key, reducer, replace = false) {
11
+ if (!replace && this.reducers.has(key)) {
12
+ console.warn(`[ReducerRegistry] Reducer "${key}" already registered. Use replace=true to override.`);
13
+ return;
14
+ }
15
+ this.reducers.set(key, {
16
+ key,
17
+ reducer,
18
+ registeredAt: new Date(),
19
+ });
20
+ // Notify about reducer change for hot replacement
21
+ if (this.onReducerChange) {
22
+ this.onReducerChange(this.getCombinedReducer());
23
+ }
24
+ }
25
+ unregister(key) {
26
+ this.reducers.delete(key);
27
+ if (this.onReducerChange) {
28
+ this.onReducerChange(this.getCombinedReducer());
29
+ }
30
+ }
31
+ getAll() {
32
+ const map = {};
33
+ this.reducers.forEach((registration, key) => {
34
+ map[key] = registration.reducer;
35
+ });
36
+ return map;
37
+ }
38
+ getCombinedReducer() {
39
+ const reducerMap = this.getAll();
40
+ if (Object.keys(reducerMap).length === 0) {
41
+ return (state = {}) => state;
42
+ }
43
+ return combineReducers(reducerMap);
44
+ }
45
+ has(key) {
46
+ return this.reducers.has(key);
47
+ }
48
+ getInfo(key) {
49
+ return this.reducers.get(key);
50
+ }
51
+ getAllRegistrations() {
52
+ return Array.from(this.reducers.values());
53
+ }
54
+ }
@@ -0,0 +1,91 @@
1
+ /**
2
+ * Store Manager Implementation
3
+ */
4
+ import { createStore, applyMiddleware, compose } from 'redux';
5
+ import { MiddlewareRegistry } from './middleware-registry';
6
+ import { ReducerRegistry } from './reducer-registry';
7
+ export class StoreManager {
8
+ constructor() {
9
+ this.store = null;
10
+ this.initialized = false;
11
+ this.config = null;
12
+ this.middlewareRegistry = new MiddlewareRegistry();
13
+ this.reducerRegistry = new ReducerRegistry((rootReducer) => {
14
+ // Hot replacement callback
15
+ if (this.store) {
16
+ this.store.replaceReducer(rootReducer);
17
+ }
18
+ });
19
+ }
20
+ getMiddlewareRegistry() {
21
+ return this.middlewareRegistry;
22
+ }
23
+ getReducerRegistry() {
24
+ return this.reducerRegistry;
25
+ }
26
+ isInitialized() {
27
+ return this.initialized;
28
+ }
29
+ initialize(config = {}) {
30
+ if (this.initialized) {
31
+ throw new Error('[StoreManager] Store already initialized');
32
+ }
33
+ this.config = config;
34
+ // Get all middleware in priority order
35
+ const middleware = this.middlewareRegistry.getAll();
36
+ // Lock the middleware registry
37
+ this.middlewareRegistry.lock();
38
+ // Get combined reducer
39
+ const rootReducer = this.reducerRegistry.getCombinedReducer();
40
+ // Create enhancers
41
+ const enhancers = config.enhancers || [];
42
+ // Setup Redux DevTools
43
+ let composeEnhancers = compose;
44
+ if (config.devTools !== false && typeof window !== 'undefined') {
45
+ const devToolsExtension = window.__REDUX_DEVTOOLS_EXTENSION_COMPOSE__;
46
+ if (devToolsExtension) {
47
+ composeEnhancers = devToolsExtension({
48
+ trace: true,
49
+ traceLimit: 25,
50
+ });
51
+ }
52
+ }
53
+ // Create store
54
+ const enhancer = composeEnhancers(applyMiddleware(...middleware), ...enhancers);
55
+ this.store = createStore(rootReducer, config.preloadedState, enhancer);
56
+ this.initialized = true;
57
+ console.log('[StoreManager] Store initialized with:', {
58
+ reducers: this.reducerRegistry.getAllRegistrations().map(r => r.key),
59
+ middleware: this.middlewareRegistry.getAllRegistrations().map(m => ({
60
+ id: m.id,
61
+ priority: m.priority,
62
+ plugin: m.plugin,
63
+ })),
64
+ devTools: config.devTools !== false,
65
+ });
66
+ return this.store;
67
+ }
68
+ getStore() {
69
+ if (!this.store) {
70
+ throw new Error('[StoreManager] Store not initialized. Call initialize() first.');
71
+ }
72
+ return this.store;
73
+ }
74
+ dispatch(action) {
75
+ return this.getStore().dispatch(action);
76
+ }
77
+ getState() {
78
+ return this.getStore().getState();
79
+ }
80
+ subscribe(listener) {
81
+ return this.getStore().subscribe(listener);
82
+ }
83
+ replaceReducer(nextReducer) {
84
+ this.getStore().replaceReducer(nextReducer);
85
+ }
86
+ destroy() {
87
+ this.store = null;
88
+ this.initialized = false;
89
+ console.log('[StoreManager] Store destroyed');
90
+ }
91
+ }
@@ -0,0 +1,7 @@
1
+ /**
2
+ * UI Store Implementation
3
+ * Concrete implementations of Redux store management
4
+ */
5
+ export * from './core';
6
+ export * from './middleware';
7
+ export * from './plugin';
@@ -0,0 +1,19 @@
1
+ /**
2
+ * Event Bridge Middleware
3
+ * Bridges Redux actions to microkernel event bus
4
+ */
5
+ export function createEventBridgeMiddleware(hooks) {
6
+ return (store) => (next) => (action) => {
7
+ // Emit before action
8
+ hooks === null || hooks === void 0 ? void 0 : hooks.emit('redux:action:before', { action, state: store.getState() });
9
+ // Execute action
10
+ const result = next(action);
11
+ // Emit after action
12
+ hooks === null || hooks === void 0 ? void 0 : hooks.emit('redux:action:after', { action, state: store.getState() });
13
+ // Emit specific action type event
14
+ if (action === null || action === void 0 ? void 0 : action.type) {
15
+ hooks === null || hooks === void 0 ? void 0 : hooks.emit(`redux:action:${action.type}`, action);
16
+ }
17
+ return result;
18
+ };
19
+ }
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Middleware Export
3
+ */
4
+ export * from './event-bridge-middleware';
5
+ export * from './logger-middleware';
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Logger Middleware
3
+ * Development logger for Redux actions
4
+ */
5
+ export function createLoggerMiddleware() {
6
+ return (store) => (next) => (action) => {
7
+ if (typeof (action === null || action === void 0 ? void 0 : action.type) === 'string') {
8
+ console.group(`[Redux] ${action.type}`);
9
+ console.log('Prev State:', store.getState());
10
+ console.log('Action:', action);
11
+ const result = next(action);
12
+ console.log('Next State:', store.getState());
13
+ console.groupEnd();
14
+ return result;
15
+ }
16
+ return next(action);
17
+ };
18
+ }
@@ -0,0 +1,4 @@
1
+ /**
2
+ * Plugin Export
3
+ */
4
+ export * from './store-plugin-factory';
@@ -0,0 +1,94 @@
1
+ /**
2
+ * Store Plugin Factory
3
+ * Creates a microkernel plugin for Redux store management
4
+ */
5
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
6
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
7
+ return new (P || (P = Promise))(function (resolve, reject) {
8
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
9
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
10
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
11
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
12
+ });
13
+ };
14
+ import { STORE_MANAGER_TOKEN, MIDDLEWARE_REGISTRY_TOKEN, REDUCER_REGISTRY_TOKEN, } from '@hamak/ui-store-api';
15
+ import { StoreManager } from '../core/store-manager';
16
+ import { createEventBridgeMiddleware, createLoggerMiddleware, } from '../middleware';
17
+ export function createStorePlugin(config = {}) {
18
+ const storeManager = new StoreManager();
19
+ const middlewareRegistry = storeManager.getMiddlewareRegistry();
20
+ const reducerRegistry = storeManager.getReducerRegistry();
21
+ return {
22
+ initialize(ctx) {
23
+ return __awaiter(this, void 0, void 0, function* () {
24
+ var _a;
25
+ // Register services via DI
26
+ ctx.provide({ provide: STORE_MANAGER_TOKEN, useValue: storeManager });
27
+ ctx.provide({
28
+ provide: MIDDLEWARE_REGISTRY_TOKEN,
29
+ useValue: middlewareRegistry,
30
+ });
31
+ ctx.provide({
32
+ provide: REDUCER_REGISTRY_TOKEN,
33
+ useValue: reducerRegistry,
34
+ });
35
+ // Register event bridge middleware (high priority)
36
+ middlewareRegistry.register({
37
+ id: 'event-bridge',
38
+ middleware: createEventBridgeMiddleware(ctx.hooks),
39
+ priority: 1000,
40
+ plugin: 'ui-store',
41
+ description: 'Bridges Redux actions to microkernel events',
42
+ });
43
+ // Register logger middleware in development (low priority - runs last)
44
+ if (config.logger !== false &&
45
+ process.env.NODE_ENV === 'development') {
46
+ middlewareRegistry.register({
47
+ id: 'logger',
48
+ middleware: createLoggerMiddleware(),
49
+ priority: -1000,
50
+ plugin: 'ui-store',
51
+ description: 'Development logger',
52
+ });
53
+ }
54
+ // Register user-provided middleware
55
+ (_a = config.middleware) === null || _a === void 0 ? void 0 : _a.forEach((mw) => {
56
+ middlewareRegistry.register(Object.assign(Object.assign({}, mw), { plugin: 'ui-store-config' }));
57
+ });
58
+ // Register user-provided reducers
59
+ if (config.reducers) {
60
+ console.log('[ui-store] Registering reducers:', Object.keys(config.reducers));
61
+ Object.entries(config.reducers).forEach(([key, reducer]) => {
62
+ reducerRegistry.register(key, reducer);
63
+ console.log('[ui-store] Registered reducer:', key);
64
+ });
65
+ }
66
+ else {
67
+ console.log('[ui-store] No reducers provided in config');
68
+ }
69
+ console.log('[ui-store] Plugin initialized');
70
+ });
71
+ },
72
+ activate(ctx) {
73
+ return __awaiter(this, void 0, void 0, function* () {
74
+ // Initialize the store after all plugins have registered middleware/reducers
75
+ const store = storeManager.initialize({
76
+ devTools: config.devTools,
77
+ });
78
+ // Bridge Redux state changes to microkernel events
79
+ store.subscribe(() => {
80
+ ctx.hooks.emit('redux:state-changed', store.getState());
81
+ });
82
+ // Emit ready event
83
+ ctx.hooks.emit('ui-store:ready', { store });
84
+ console.log('[ui-store] Plugin activated');
85
+ });
86
+ },
87
+ deactivate() {
88
+ return __awaiter(this, void 0, void 0, function* () {
89
+ storeManager.destroy();
90
+ console.log('[ui-store] Plugin deactivated');
91
+ });
92
+ },
93
+ };
94
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hamak/ui-store-impl",
3
- "version": "0.2.1",
3
+ "version": "0.2.2",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "description": "UI Store Implementation - Redux store implementation with middleware",
@@ -16,7 +16,7 @@
16
16
  "access": "public"
17
17
  },
18
18
  "scripts": {
19
- "build": "tsc -p tsconfig.json",
19
+ "build": "tsc -p tsconfig.json && tsc -p tsconfig.es2015.json",
20
20
  "clean": "rm -rf dist",
21
21
  "test": "vitest run",
22
22
  "test:watch": "vitest"
@@ -24,14 +24,20 @@
24
24
  "exports": {
25
25
  ".": {
26
26
  "types": "./dist/index.d.ts",
27
- "import": "./dist/index.js"
27
+ "import": "./dist/index.js",
28
+ "default": "./dist/index.js",
29
+ "legacy": "./dist/es2015/index.js"
30
+ },
31
+ "./es2015": {
32
+ "import": "./dist/es2015/index.js",
33
+ "default": "./dist/es2015/index.js"
28
34
  }
29
35
  },
30
36
  "dependencies": {
31
- "@hamak/ui-store-api": "0.2.1",
32
- "@hamak/ui-store-spi": "0.2.1",
33
- "@hamak/microkernel-api": "0.2.1",
34
- "@hamak/microkernel-spi": "0.2.1",
37
+ "@hamak/ui-store-api": "0.2.2",
38
+ "@hamak/ui-store-spi": "0.2.2",
39
+ "@hamak/microkernel-api": "0.2.2",
40
+ "@hamak/microkernel-spi": "0.2.2",
35
41
  "redux": "^5.0.1",
36
42
  "redux-thunk": "^3.1.0"
37
43
  },
@@ -0,0 +1,24 @@
1
+ {
2
+ "extends": "./tsconfig.json",
3
+ "compilerOptions": {
4
+ "target": "ES2015",
5
+ "lib": [
6
+ "ES2015",
7
+ "DOM"
8
+ ],
9
+ "outDir": "./dist/es2015",
10
+ "declaration": false,
11
+ "declarationMap": false,
12
+ "sourceMap": false,
13
+ "downlevelIteration": true,
14
+ "composite": false
15
+ },
16
+ "include": [
17
+ "src/**/*"
18
+ ],
19
+ "exclude": [
20
+ "node_modules",
21
+ "dist",
22
+ "**/*.test.ts"
23
+ ]
24
+ }