@hamak/microkernel-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.
- package/.turbo/turbo-build.log +2 -1
- package/dist/es2015/index.js +5 -0
- package/dist/es2015/runtime/di.js +38 -0
- package/dist/es2015/runtime/graph-utils.js +36 -0
- package/dist/es2015/runtime/host.js +163 -0
- package/dist/es2015/runtime/loader.js +70 -0
- package/dist/es2015/runtime/registries.js +6 -0
- package/dist/es2015/ui/adapter.js +1 -0
- package/package.json +11 -5
- package/tsconfig.lib.es2015.json +23 -0
package/.turbo/turbo-build.log
CHANGED
|
@@ -1 +1,2 @@
|
|
|
1
|
-
|
|
1
|
+
|
|
2
|
+
[0m[2m[35m$[0m [2m[1mtsc -p tsconfig.lib.json && tsc -p tsconfig.lib.es2015.json[0m
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
const INJECT_KEY = Symbol('di:inject');
|
|
2
|
+
export function Injectable(deps = []) { return (t) => { t[INJECT_KEY] = deps; }; }
|
|
3
|
+
export class Container {
|
|
4
|
+
constructor(parent) {
|
|
5
|
+
this.providers = new Map();
|
|
6
|
+
this.instances = new Map();
|
|
7
|
+
this.parent = parent;
|
|
8
|
+
}
|
|
9
|
+
createChild() { return new Container(this); }
|
|
10
|
+
provide(prov) { this.providers.set(prov.provide, prov); return this; }
|
|
11
|
+
resolve(token) {
|
|
12
|
+
var _a, _b;
|
|
13
|
+
if (this.instances.has(token))
|
|
14
|
+
return this.instances.get(token);
|
|
15
|
+
if (this.providers.has(token)) {
|
|
16
|
+
const prov = this.providers.get(token);
|
|
17
|
+
let value;
|
|
18
|
+
if ('useValue' in prov)
|
|
19
|
+
value = prov.useValue;
|
|
20
|
+
else if ('useClass' in prov) {
|
|
21
|
+
const C = prov.useClass;
|
|
22
|
+
const deps = C[INJECT_KEY] || [];
|
|
23
|
+
const args = deps.map((d) => this.resolve(d));
|
|
24
|
+
value = new C(...args);
|
|
25
|
+
}
|
|
26
|
+
else {
|
|
27
|
+
const deps = prov.deps || [];
|
|
28
|
+
const args = deps.map((d) => this.resolve(d));
|
|
29
|
+
value = prov.useFactory(...args);
|
|
30
|
+
}
|
|
31
|
+
this.instances.set(token, value);
|
|
32
|
+
return value;
|
|
33
|
+
}
|
|
34
|
+
if (this.parent)
|
|
35
|
+
return this.parent.resolve(token);
|
|
36
|
+
throw new Error(`No provider for token: ${(_b = (_a = token.toString) === null || _a === void 0 ? void 0 : _a.call(token)) !== null && _b !== void 0 ? _b : String(token)}`);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dependency graph utilities for topological sorting
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Performs topological sort on items based on their dependencies
|
|
6
|
+
* @param items Items to sort (must have name and optional dependsOn properties)
|
|
7
|
+
* @returns Sorted items in dependency order
|
|
8
|
+
* @throws Error if circular dependency is detected
|
|
9
|
+
*/
|
|
10
|
+
export function topologicalSort(items) {
|
|
11
|
+
const index = new Map(items.map(i => [i.name, i]));
|
|
12
|
+
const visited = new Set();
|
|
13
|
+
const result = [];
|
|
14
|
+
const visit = (item, path = new Set()) => {
|
|
15
|
+
var _a;
|
|
16
|
+
if (visited.has(item.name))
|
|
17
|
+
return;
|
|
18
|
+
// Cycle detection
|
|
19
|
+
if (path.has(item.name)) {
|
|
20
|
+
throw new Error(`Circular dependency detected: ${[...path, item.name].join(' -> ')}`);
|
|
21
|
+
}
|
|
22
|
+
path.add(item.name);
|
|
23
|
+
((_a = item.dependsOn) !== null && _a !== void 0 ? _a : []).forEach(depName => {
|
|
24
|
+
const dep = index.get(depName);
|
|
25
|
+
if (!dep) {
|
|
26
|
+
console.warn(`Dependency not found: ${depName} (required by ${item.name})`);
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
visit(dep, new Set(path));
|
|
30
|
+
});
|
|
31
|
+
visited.add(item.name);
|
|
32
|
+
result.push(item);
|
|
33
|
+
};
|
|
34
|
+
items.forEach(item => visit(item));
|
|
35
|
+
return result;
|
|
36
|
+
}
|
|
@@ -0,0 +1,163 @@
|
|
|
1
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
import { Container } from './di';
|
|
11
|
+
import { createCommandRegistry, createHooks, createViewRegistry } from './registries';
|
|
12
|
+
import { PluginRegistry } from './loader';
|
|
13
|
+
function createSharedRegistries() {
|
|
14
|
+
return {
|
|
15
|
+
commands: createCommandRegistry(),
|
|
16
|
+
views: createViewRegistry(),
|
|
17
|
+
hooks: createHooks(),
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
function createInitContext(container, registries, env) {
|
|
21
|
+
return {
|
|
22
|
+
provide: (prov) => container.provide(prov),
|
|
23
|
+
resolve: (t) => container.resolve(t),
|
|
24
|
+
commands: {
|
|
25
|
+
register: (id, h) => registries.commands.register(id, h)
|
|
26
|
+
},
|
|
27
|
+
views: {
|
|
28
|
+
register: (slot, vf) => registries.views.register(slot, vf)
|
|
29
|
+
},
|
|
30
|
+
hooks: {
|
|
31
|
+
on: (ev, fn) => registries.hooks.on(ev, fn),
|
|
32
|
+
emit: (ev, ...a) => registries.hooks.emit(ev, ...a)
|
|
33
|
+
},
|
|
34
|
+
env,
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
function createActivateContext(container, registries, env) {
|
|
38
|
+
return {
|
|
39
|
+
resolve: (t) => container.resolve(t),
|
|
40
|
+
commands: registries.commands,
|
|
41
|
+
views: registries.views,
|
|
42
|
+
hooks: registries.hooks,
|
|
43
|
+
env,
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
export class Host {
|
|
47
|
+
constructor(initialProviders = [], env) {
|
|
48
|
+
this.root = new Container();
|
|
49
|
+
initialProviders.forEach(p => this.root.provide(p));
|
|
50
|
+
this._registry = new PluginRegistry();
|
|
51
|
+
this.env = env;
|
|
52
|
+
}
|
|
53
|
+
loadPlugins(manifests) {
|
|
54
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
55
|
+
yield this._registry.loadAllAtRoot(manifests);
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Register a plugin programmatically (useful for testing/inline plugins)
|
|
60
|
+
* @param name Plugin name
|
|
61
|
+
* @param manifest Plugin manifest
|
|
62
|
+
* @param module Plugin module implementation
|
|
63
|
+
*/
|
|
64
|
+
registerPlugin(name, manifest, module) {
|
|
65
|
+
this._registry.register(name, manifest, module);
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Get plugin manifest by name
|
|
69
|
+
* @param name Plugin name
|
|
70
|
+
* @returns Plugin manifest or undefined if not found
|
|
71
|
+
*/
|
|
72
|
+
getPlugin(name) {
|
|
73
|
+
var _a;
|
|
74
|
+
return (_a = this._registry.get(name)) === null || _a === void 0 ? void 0 : _a.manifest;
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* List all loaded plugins
|
|
78
|
+
* @returns Array of plugin manifests
|
|
79
|
+
*/
|
|
80
|
+
listPlugins() {
|
|
81
|
+
return this._registry.list();
|
|
82
|
+
}
|
|
83
|
+
bootstrapAllAtRoot() {
|
|
84
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
85
|
+
var _a, _b;
|
|
86
|
+
const registries = createSharedRegistries();
|
|
87
|
+
const initCtx = createInitContext(this.root, registries, this.env);
|
|
88
|
+
const mods = this._registry.getModulesInOrder('all');
|
|
89
|
+
// Initialize phase with error handling
|
|
90
|
+
for (const m of mods) {
|
|
91
|
+
try {
|
|
92
|
+
yield ((_a = m.initialize) === null || _a === void 0 ? void 0 : _a.call(m, initCtx));
|
|
93
|
+
}
|
|
94
|
+
catch (error) {
|
|
95
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
96
|
+
const initError = new Error(`Plugin initialization failed: ${err.message}`);
|
|
97
|
+
initError.cause = error;
|
|
98
|
+
throw initError;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
const actCtx = createActivateContext(this.root, registries, this.env);
|
|
102
|
+
this.rootActivationCtx = actCtx;
|
|
103
|
+
// Activation phase with error handling
|
|
104
|
+
for (const m of mods) {
|
|
105
|
+
try {
|
|
106
|
+
yield ((_b = m.activate) === null || _b === void 0 ? void 0 : _b.call(m, actCtx));
|
|
107
|
+
}
|
|
108
|
+
catch (error) {
|
|
109
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
110
|
+
console.error(`Plugin activation failed:`, err);
|
|
111
|
+
// Continue with other plugins rather than failing completely
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
actCtx.hooks.emit('host:activated');
|
|
115
|
+
});
|
|
116
|
+
}
|
|
117
|
+
createChildHost(overrides = [], env) {
|
|
118
|
+
const child = this.root.createChild();
|
|
119
|
+
overrides.forEach(p => child.provide(p));
|
|
120
|
+
const childEnv = Object.assign(Object.assign({}, (this.env || {})), (env || {}));
|
|
121
|
+
return new ChildHost(child, this._registry, childEnv);
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
class ChildHost {
|
|
125
|
+
constructor(container, registry, env) {
|
|
126
|
+
this.container = container;
|
|
127
|
+
this.registry = registry;
|
|
128
|
+
this.env = env;
|
|
129
|
+
}
|
|
130
|
+
bootstrap() {
|
|
131
|
+
return __awaiter(this, arguments, void 0, function* (pluginNames = 'all') {
|
|
132
|
+
var _a, _b;
|
|
133
|
+
const registries = createSharedRegistries();
|
|
134
|
+
const initCtx = createInitContext(this.container, registries, this.env);
|
|
135
|
+
const mods = this.registry.getModulesInOrder(pluginNames);
|
|
136
|
+
// Initialize phase with error handling
|
|
137
|
+
for (const m of mods) {
|
|
138
|
+
try {
|
|
139
|
+
yield ((_a = m.initialize) === null || _a === void 0 ? void 0 : _a.call(m, initCtx));
|
|
140
|
+
}
|
|
141
|
+
catch (error) {
|
|
142
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
143
|
+
const initError = new Error(`Plugin initialization failed: ${err.message}`);
|
|
144
|
+
initError.cause = error;
|
|
145
|
+
throw initError;
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
const actCtx = createActivateContext(this.container, registries, this.env);
|
|
149
|
+
// Activation phase with error handling
|
|
150
|
+
for (const m of mods) {
|
|
151
|
+
try {
|
|
152
|
+
yield ((_b = m.activate) === null || _b === void 0 ? void 0 : _b.call(m, actCtx));
|
|
153
|
+
}
|
|
154
|
+
catch (error) {
|
|
155
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
156
|
+
console.error(`Plugin activation failed:`, err);
|
|
157
|
+
// Continue with other plugins rather than failing completely
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
actCtx.hooks.emit('child:activated');
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
|
|
2
|
+
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
|
|
3
|
+
return new (P || (P = Promise))(function (resolve, reject) {
|
|
4
|
+
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
|
|
5
|
+
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
|
|
6
|
+
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
|
|
7
|
+
step((generator = generator.apply(thisArg, _arguments || [])).next());
|
|
8
|
+
});
|
|
9
|
+
};
|
|
10
|
+
import { topologicalSort } from './graph-utils';
|
|
11
|
+
class PluginRecord {
|
|
12
|
+
constructor(manifest, module) {
|
|
13
|
+
this.manifest = manifest;
|
|
14
|
+
this.module = module;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
export class PluginRegistry {
|
|
18
|
+
constructor() {
|
|
19
|
+
this.byName = new Map();
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Get a plugin record by name
|
|
23
|
+
*/
|
|
24
|
+
get(name) {
|
|
25
|
+
return this.byName.get(name);
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* List all loaded plugin manifests
|
|
29
|
+
*/
|
|
30
|
+
list() {
|
|
31
|
+
return [...this.byName.values()].map(r => r.manifest);
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Register a plugin programmatically (useful for testing/inline plugins)
|
|
35
|
+
*/
|
|
36
|
+
register(name, manifest, module) {
|
|
37
|
+
this.byName.set(name, new PluginRecord(manifest, module));
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Load plugins from manifest URLs or objects
|
|
41
|
+
*/
|
|
42
|
+
loadAllAtRoot(manifestInputs) {
|
|
43
|
+
return __awaiter(this, void 0, void 0, function* () {
|
|
44
|
+
var _a;
|
|
45
|
+
const mfs = [];
|
|
46
|
+
for (const m of manifestInputs) {
|
|
47
|
+
if (typeof m === 'string') {
|
|
48
|
+
mfs.push(yield fetch(m).then(r => r.json()));
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
mfs.push(m);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
const sorted = topologicalSort(mfs);
|
|
55
|
+
for (const m of sorted) {
|
|
56
|
+
const url = new URL(m.entry, ((_a = m.baseUrl) !== null && _a !== void 0 ? _a : location.origin) + '/').toString();
|
|
57
|
+
const mod = yield import(/* @vite-ignore */ url);
|
|
58
|
+
this.byName.set(m.name, new PluginRecord(m, mod));
|
|
59
|
+
}
|
|
60
|
+
});
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Get plugin modules in dependency order
|
|
64
|
+
*/
|
|
65
|
+
getModulesInOrder(names = 'all') {
|
|
66
|
+
const t = names === 'all' ? [...this.byName.keys()] : names;
|
|
67
|
+
const order = topologicalSort(t.map(n => this.byName.get(n).manifest));
|
|
68
|
+
return order.map(m => this.byName.get(m.name).module).filter(Boolean);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export function createHooks() { const map = new Map(); return { on(e, f) { if (!map.has(e))
|
|
2
|
+
map.set(e, new Set()); map.get(e).add(f); }, off(e, f) { var _a; (_a = map.get(e)) === null || _a === void 0 ? void 0 : _a.delete(f); }, emit(e, ...a) { var _a; for (const fn of (_a = map.get(e)) !== null && _a !== void 0 ? _a : [])
|
|
3
|
+
fn(...a); } }; }
|
|
4
|
+
export function createCommandRegistry() { const h = new Map(); return { register(id, fn) { h.set(id, fn); }, run(id, ...a) { const fn = h.get(id); if (!fn)
|
|
5
|
+
throw new Error(`Command not found: ${id}`); return fn(...a); }, has(id) { return h.has(id); } }; }
|
|
6
|
+
export function createViewRegistry() { const s = new Map(); return { register(slot, v) { var _a; const arr = (_a = s.get(slot)) !== null && _a !== void 0 ? _a : []; arr.push(v); s.set(slot, arr); }, list(slot) { var _a; return [...((_a = s.get(slot)) !== null && _a !== void 0 ? _a : [])]; } }; }
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const UI = { registerView(ctx, slot, viewFactory) { ctx.views.register(slot, viewFactory); }, getViews(ctx, slot) { return ctx.views.list(slot); } };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hamak/microkernel-impl",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.2",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Microkernel Implementation - Core microkernel functionality",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -15,17 +15,23 @@
|
|
|
15
15
|
"access": "public"
|
|
16
16
|
},
|
|
17
17
|
"scripts": {
|
|
18
|
-
"build": "tsc -p tsconfig.lib.json",
|
|
18
|
+
"build": "tsc -p tsconfig.lib.json && tsc -p tsconfig.lib.es2015.json",
|
|
19
19
|
"clean": "rm -rf dist"
|
|
20
20
|
},
|
|
21
21
|
"exports": {
|
|
22
22
|
".": {
|
|
23
23
|
"types": "./dist/index.d.ts",
|
|
24
|
-
"import": "./dist/index.js"
|
|
24
|
+
"import": "./dist/index.js",
|
|
25
|
+
"default": "./dist/index.js",
|
|
26
|
+
"legacy": "./dist/es2015/index.js"
|
|
27
|
+
},
|
|
28
|
+
"./es2015": {
|
|
29
|
+
"import": "./dist/es2015/index.js",
|
|
30
|
+
"default": "./dist/es2015/index.js"
|
|
25
31
|
}
|
|
26
32
|
},
|
|
27
33
|
"dependencies": {
|
|
28
|
-
"@hamak/microkernel-api": "0.2.
|
|
29
|
-
"@hamak/microkernel-spi": "0.2.
|
|
34
|
+
"@hamak/microkernel-api": "0.2.2",
|
|
35
|
+
"@hamak/microkernel-spi": "0.2.2"
|
|
30
36
|
}
|
|
31
37
|
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
{
|
|
2
|
+
"extends": "./tsconfig.lib.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/**/*.ts"
|
|
18
|
+
],
|
|
19
|
+
"exclude": [
|
|
20
|
+
"node_modules",
|
|
21
|
+
"dist"
|
|
22
|
+
]
|
|
23
|
+
}
|