@hamak/ui-store-impl 0.2.0 → 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.
- package/.turbo/turbo-build.log +2 -1
- package/dist/es2015/core/index.js +3 -0
- package/dist/es2015/core/middleware-registry.js +47 -0
- package/dist/es2015/core/reducer-registry.js +54 -0
- package/dist/es2015/core/store-manager.js +91 -0
- package/dist/es2015/index.js +7 -0
- package/dist/es2015/middleware/event-bridge-middleware.js +19 -0
- package/dist/es2015/middleware/index.js +5 -0
- package/dist/es2015/middleware/logger-middleware.js +18 -0
- package/dist/es2015/plugin/index.js +4 -0
- package/dist/es2015/plugin/store-plugin-factory.js +94 -0
- package/package.json +13 -7
- package/tsconfig.es2015.json +24 -0
package/.turbo/turbo-build.log
CHANGED
|
@@ -1 +1,2 @@
|
|
|
1
|
-
|
|
1
|
+
|
|
2
|
+
[0m[2m[35m$[0m [2m[1mtsc -p tsconfig.json && tsc -p tsconfig.es2015.json[0m
|
|
@@ -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,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,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,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.
|
|
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.
|
|
32
|
-
"@hamak/ui-store-spi": "0.
|
|
33
|
-
"@hamak/microkernel-api": "0.
|
|
34
|
-
"@hamak/microkernel-spi": "0.
|
|
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
|
+
}
|