@telcomdataperu/zeus-vue-model-manager
Version:
Vue 3 Model Manager for Microfrontends with OpenUI5-style API - Part of ZEUS Platform by TelcomdataPeru
600 lines (599 loc) • 17.4 kB
JavaScript
import { reactive as v, computed as A, watch as w } from "vue";
class b {
constructor(e, t = {}) {
this.validators = {}, this.watchers = [], this.eventListeners = {}, this.changeCount = 0, this.options = {
enableLogging: !1,
enableValidation: !1,
immutable: !1,
pathSeparator: "/",
...t
}, this.data = v(e), this.metadata = {
version: "1.0.0",
created: /* @__PURE__ */ new Date(),
lastModified: /* @__PURE__ */ new Date(),
changeCount: 0,
paths: this.getAllPaths(this.data),
size: JSON.stringify(this.data).length
}, this.options.enableLogging && console.log("[JsonModel] Created with options:", this.options);
}
// ===== BASIC METHODS =====
getData() {
return this.data;
}
getProperty(e) {
return e.replace(/^\//, "").split(this.options.pathSeparator || "/").reduce((s, r) => {
if (s && typeof s == "object" && r in s)
return s[r];
}, this.data);
}
setProperty(e, t) {
const s = this.getProperty(e);
if (this.options.enableValidation) {
const c = this.validatePath(e, t);
if (c.length > 0) {
this.emit("validation-error", { path: e, errors: c });
return;
}
}
const r = e.replace(/^\//, "").split(this.options.pathSeparator || "/"), a = r.pop(), i = r.reduce((c, n) => {
if (c && typeof c == "object" && n in c)
return c[n];
}, this.data);
i && typeof i == "object" && a && (i[a] = t, this.updateMetadata(), this.emit("property-changed", {
path: e,
oldValue: s,
newValue: t,
timestamp: Date.now(),
source: "user"
}), this.options.enableLogging && console.log(`[JsonModel] Property changed: ${e}`, { oldValue: s, newValue: t }));
}
// ===== ADVANCED METHODS =====
updateProperties(e) {
Object.entries(e).forEach(([t, s]) => {
this.setProperty(t, s);
});
}
createBinding(e) {
return A(() => this.getProperty(e));
}
// ===== ARRAY OPERATIONS =====
addToArray(e, t) {
const s = this.getProperty(e);
Array.isArray(s) && (s.push(t), this.updateMetadata(), this.emit("array-changed", {
path: e,
action: "add",
index: s.length - 1,
item: t
}));
}
removeFromArray(e, t) {
const s = this.getProperty(e);
if (Array.isArray(s) && t >= 0 && t < s.length) {
const r = s[t];
s.splice(t, 1), this.updateMetadata(), this.emit("array-changed", {
path: e,
action: "remove",
index: t,
item: r
});
}
}
updateArrayItem(e, t, s) {
const r = this.getProperty(e);
if (Array.isArray(r)) {
const a = r.findIndex(t);
if (a !== -1)
return Object.assign(r[a], s), this.updateMetadata(), this.emit("array-changed", {
path: e,
action: "update",
index: a,
item: r[a]
}), !0;
}
return !1;
}
// ===== UTILITIES =====
getArrayLength(e) {
const t = this.getProperty(e);
return Array.isArray(t) ? t.length : 0;
}
hasProperty(e) {
return this.getProperty(e) !== void 0;
}
resetProperty(e, t = void 0) {
this.setProperty(e, t);
}
getObjectKeys(e) {
const t = this.getProperty(e);
return t && typeof t == "object" && !Array.isArray(t) ? Object.keys(t) : [];
}
// ===== SERIALIZATION =====
clone() {
return new b(JSON.parse(JSON.stringify(this.data)), this.options);
}
toJSON() {
return JSON.stringify(this.data, null, 2);
}
fromJSON(e) {
try {
const t = JSON.parse(e);
Object.assign(this.data, t), this.updateMetadata(), this.emit("model-reset", { timestamp: Date.now() });
} catch (t) {
console.error("[JsonModel] Error parsing JSON:", t);
}
}
// ===== WATCHERS AND EVENTS =====
watch(e, t, s = {}) {
const r = w(
() => this.getProperty(e),
t,
{
immediate: s.immediate || !1,
deep: s.deep || !0,
flush: s.flush || "post"
}
);
return this.watchers.push(r), r;
}
// ===== VALIDATION =====
addValidator(e, t) {
this.validators[e] || (this.validators[e] = []), this.validators[e].push(t);
}
removeValidator(e) {
delete this.validators[e];
}
validate(e) {
if (e) {
const t = this.getProperty(e);
return this.validatePath(e, t).length === 0;
}
for (const t of Object.keys(this.validators))
if (!this.validate(t))
return !1;
return !0;
}
getErrors(e) {
if (e) {
const s = this.getProperty(e);
return this.validatePath(e, s);
}
const t = [];
for (const s of Object.keys(this.validators))
t.push(...this.getErrors(s));
return t;
}
validatePath(e, t) {
const s = this.validators[e] || [], r = [];
for (const a of s) {
const i = a.validate(t);
i !== !0 && r.push(typeof i == "string" ? i : a.message || "Validation failed");
}
return r;
}
// ===== METADATA =====
getMetadata() {
return { ...this.metadata };
}
reset(e) {
e ? e.forEach((t) => {
const s = this.options.defaultValues?.[t];
this.setProperty(t, s);
}) : this.options.defaultValues && Object.assign(this.data, this.options.defaultValues), this.updateMetadata(), this.emit("model-reset", { timestamp: Date.now() });
}
destroy() {
this.watchers.forEach((e) => e()), this.watchers = [], this.validators = {}, this.eventListeners = {}, this.options.enableLogging && console.log("[JsonModel] Destroyed");
}
// ===== PRIVATE HELPERS =====
updateMetadata() {
this.changeCount++, this.metadata.lastModified = /* @__PURE__ */ new Date(), this.metadata.changeCount = this.changeCount, this.metadata.paths = this.getAllPaths(this.data), this.metadata.size = JSON.stringify(this.data).length;
}
getAllPaths(e, t = "") {
const s = [];
for (const r in e)
if (e.hasOwnProperty(r)) {
const a = t ? `${t}/${r}` : r;
s.push(`/${a}`), e[r] && typeof e[r] == "object" && !Array.isArray(e[r]) && s.push(...this.getAllPaths(e[r], a));
}
return s;
}
emit(e, t) {
(this.eventListeners[e] || []).forEach((r) => r(t));
}
// ===== EVENT SYSTEM =====
on(e, t) {
this.eventListeners[e] || (this.eventListeners[e] = []), this.eventListeners[e].push(t);
}
off(e, t) {
const s = this.eventListeners[e] || [], r = s.indexOf(t);
r > -1 && s.splice(r, 1);
}
}
class O {
constructor(e, t = {}) {
this.models = /* @__PURE__ */ new Map(), this.config = {
scope: e,
security: { level: "basic" },
audit: { enabled: !1 },
...t
}, this.config.audit?.enabled && console.log(`[ModelManager] Created for scope: ${e} with config:`, this.config);
}
create(e, t, s) {
const r = {
enableLogging: this.config.audit?.enabled || !1,
enableValidation: this.config.security?.level !== "basic",
...s
}, a = new b(t, r);
return this.models.set(e, a), this.config.audit?.enabled && console.log(`[ModelManager] Model '${e}' created in scope '${this.config.scope}'`), a;
}
createShared(e, t, s) {
const r = {
...s,
enableLogging: !0,
enableValidation: !0
};
return this.create(e, t, r);
}
createGlobal(e, t, s) {
const r = {
...s,
enableLogging: !0,
enableValidation: !0
};
return this.create(e, t, r);
}
getModel(e) {
return this.models.get(e);
}
hasModel(e) {
return this.models.has(e);
}
removeModel(e) {
const t = this.models.get(e);
return t ? (t.destroy(), this.models.delete(e), this.config.audit?.enabled && console.log(`[ModelManager] Model '${e}' removed from scope '${this.config.scope}'`), !0) : !1;
}
getAllModels() {
const e = {};
return this.models.forEach((t, s) => {
e[s] = t;
}), e;
}
getModelNames() {
return Array.from(this.models.keys());
}
getScope() {
return this.config.scope;
}
getConfig() {
return { ...this.config };
}
clear() {
this.models.forEach((e, t) => {
e.destroy();
}), this.models.clear(), this.config.audit?.enabled && console.log(`[ModelManager] All models cleared from scope '${this.config.scope}'`);
}
// Enterprise features
exportModels() {
const e = {};
return this.models.forEach((t, s) => {
e[s] = t.toJSON();
}), e;
}
importModels(e) {
Object.entries(e).forEach(([t, s]) => {
const r = this.models.get(t);
r && r.fromJSON(s);
});
}
getStatistics() {
return {
scope: this.config.scope,
modelCount: this.models.size,
modelNames: this.getModelNames(),
totalSize: Array.from(this.models.values()).reduce((e, t) => e + t.getMetadata().size, 0)
};
}
}
class L {
constructor() {
this.managers = /* @__PURE__ */ new Map(), this.accessLog = [], this.enableAudit = !1;
}
// Basic operations
register(e, t) {
this.managers.has(e) && console.warn(`[GlobalRegistry] Manager for scope '${e}' already exists. Replacing...`), this.managers.set(e, t), this.enableAudit && console.log(`[GlobalRegistry] Manager registered for scope: ${e}`);
}
get(e) {
return this.managers.get(e);
}
unregister(e) {
const t = this.managers.get(e);
t && (t.clear(), this.managers.delete(e), this.enableAudit && console.log(`[GlobalRegistry] Manager unregistered for scope: ${e}`));
}
hasModel(e, t) {
const s = this.managers.get(e);
return s ? s.hasModel(t) : !1;
}
removeModel(e, t) {
const s = this.managers.get(e);
return s && s.hasModel(t) ? (s.removeModel(t), !0) : !1;
}
getAllScopes() {
return Array.from(this.managers.keys());
}
clear() {
this.managers.forEach((e, t) => {
e.clear();
}), this.managers.clear(), this.accessLog = [], this.enableAudit && console.log("[GlobalRegistry] All managers cleared");
}
enableAuditing(e = !0) {
this.enableAudit = e, console.log(`[GlobalRegistry] Auditing ${e ? "enabled" : "disabled"}`);
}
getModelFromScope(e, t, s) {
const r = this.managers.get(t);
if (!r) {
console.warn(`[GlobalRegistry] Target scope '${t}' not found`);
return;
}
const a = r.getModel(s);
return a && this.enableAudit && this.logAccess({
sourceScope: e,
targetScope: t,
modelName: s,
accessType: "read",
timestamp: /* @__PURE__ */ new Date()
}), a;
}
getStatistics() {
const e = this.getAllScopes(), t = Array.from(this.managers.values()).reduce((s, r) => s + r.getModelNames().length, 0);
return {
totalManagers: this.managers.size,
totalModels: t,
scopes: e,
lastActivity: /* @__PURE__ */ new Date()
};
}
getManagerStatistics(e) {
if (e) {
const s = this.managers.get(e);
return s ? { [e]: s.getStatistics() } : {};
}
const t = {};
return this.managers.forEach((s, r) => {
t[r] = s.getStatistics();
}), t;
}
broadcastToScope(e, t, s) {
return this.managers.get(e) ? (this.enableAudit && console.log(`[GlobalRegistry] Broadcasting '${t}' to scope '${e}'`, s), !0) : (console.warn(`[GlobalRegistry] Cannot broadcast to scope '${e}' - not found`), !1);
}
shareModel(e, t, s, r) {
const a = this.managers.get(e), i = this.managers.get(t);
if (!a || !i)
return console.error("[GlobalRegistry] Source or target scope not found for model sharing"), !1;
const c = a.getModel(s);
if (!c)
return console.error(`[GlobalRegistry] Model '${s}' not found in source scope '${e}'`), !1;
const n = JSON.parse(c.toJSON()), l = r || s;
return i.create(l, n), this.enableAudit && console.log(`[GlobalRegistry] Model '${s}' shared from '${e}' to '${t}' as '${l}'`), !0;
}
inspectScope(e) {
const t = this.managers.get(e);
if (!t)
return { error: `Scope '${e}' not found` };
const s = t.getAllModels(), r = {
scope: e,
config: t.getConfig(),
statistics: t.getStatistics(),
models: {}
};
return Object.entries(s).forEach(([a, i]) => {
r.models[a] = {
metadata: i.getMetadata(),
data: i.getData()
};
}), r;
}
getAccessLog() {
return [...this.accessLog];
}
logAccess(e) {
this.accessLog.push(e), this.accessLog.length > 1e3 && (this.accessLog = this.accessLog.slice(-1e3));
}
dumpState() {
console.group("[GlobalRegistry] Current State"), console.log("Statistics:", this.getStatistics()), console.log("Manager Statistics:", this.getManagerStatistics()), this.getAllScopes().forEach((e) => {
console.group(`Scope: ${e}`), console.log(this.inspectScope(e)), console.groupEnd();
}), this.accessLog.length > 0 && console.log("Recent Access Log:", this.accessLog.slice(-10)), console.groupEnd();
}
}
const g = new L();
let f = {
fallbackToGlobalSearch: !0
};
function E(o) {
f.currentScope = o;
}
function p(o) {
if (o)
return g.get(o);
if (f.currentScope)
return g.get(f.currentScope);
if (f.fallbackToGlobalSearch) {
const e = g.getAllScopes();
if (e.length > 0)
return g.get(e[0]);
}
}
function y(o, e) {
if (e) {
const s = g.get(e)?.getModel(o);
if (s)
return { model: s, scope: e };
}
if (f.currentScope) {
const s = g.get(f.currentScope)?.getModel(o);
if (s)
return { model: s, scope: f.currentScope };
}
if (f.fallbackToGlobalSearch)
for (const t of g.getAllScopes()) {
const r = g.get(t)?.getModel(o);
if (r)
return { model: r, scope: t };
}
}
function C(o) {
f = { ...f, ...o };
}
function J() {
return { ...f };
}
function P(o, e, t = {}) {
const { scope: s, fallbackSearch: r = !0, defaultValue: a } = t;
return A({
get() {
if (s) {
const l = p(s)?.getModel(o);
if (l) {
const u = l.getProperty(e);
return u !== void 0 ? u : a;
}
}
if (r) {
const n = y(o, s);
if (n) {
const l = n.model.getProperty(e);
return l !== void 0 ? l : a;
}
}
const c = p()?.getModel(o);
if (c) {
const n = c.getProperty(e);
return n !== void 0 ? n : a;
}
return a;
},
set(i) {
if (i === void 0) return;
if (s) {
const u = p(s)?.getModel(o);
if (u) {
u.setProperty(e, i);
return;
}
}
if (r) {
const l = y(o, s);
if (l) {
l.model.setProperty(e, i);
return;
}
}
const n = p()?.getModel(o);
if (n) {
n.setProperty(e, i);
return;
}
console.warn(`[useModel] No se pudo encontrar el modelo '${o}' para actualizar '${e}'`);
}
});
}
function R(o, e, t) {
return P(e, t, { scope: o, fallbackSearch: !1 });
}
function V(o, e, t) {
return P(o, e, { defaultValue: t });
}
const M = /* @__PURE__ */ new Map();
function S(o, e = "", t = {}) {
const { scope: s, fallbackSearch: r = !0 } = t, a = `${o}:${e}`;
if (M.has(a))
return M.get(a);
const i = new Proxy({}, {
get(c, n) {
if (n === Symbol.toStringTag) return "ZeusModelProxy";
if (n === Symbol.toPrimitive) return () => "[ZeusModelProxy]";
if (typeof n == "symbol") return;
const l = String(n), u = e ? `${e}/${l}` : `/${l}`;
let d;
if (s ? d = p(s)?.getModel(o) : r ? d = y(o, s)?.model : d = p()?.getModel(o), !d) return;
const h = d.getProperty(u);
if (h && typeof h == "object" && !Array.isArray(h)) {
const m = S(o, u, t);
return M.set(`${o}:${u}`, m), m;
}
return h;
},
set(c, n, l) {
if (typeof n == "symbol") return !1;
const u = String(n), d = e ? `${e}/${u}` : `/${u}`;
let h;
return s ? h = p(s)?.getModel(o) : r ? h = y(o, s)?.model : h = p()?.getModel(o), h ? (h.setProperty(d, l), !0) : (console.warn(`[useModels] No se pudo encontrar el modelo '${o}' para actualizar '${d}'`), !1);
},
has(c, n) {
if (typeof n == "symbol") return !1;
const l = String(n), u = e ? `${e}/${l}` : `/${l}`;
let d;
return s ? d = p(s)?.getModel(o) : d = y(o, s)?.model, d ? d.hasProperty(u) : !1;
}
});
return M.set(a, i), i;
}
function $(o, e = {}) {
const t = {};
return o.forEach((s) => {
t[s] = v(S(s, "", e));
}), t;
}
function D(o, e = {}) {
const t = {};
return o.forEach((s) => {
t[s] = S(s, "", e);
}), t;
}
function x(o, e) {
return $(e, { scope: o, fallbackSearch: !1 });
}
function k(o) {
return $(o, {});
}
function z(o, e) {
const t = new O(o, e);
return g.register(o, t), t;
}
function T() {
g.enableAuditing(!0);
}
function F() {
g.dumpState();
}
function j() {
return {
registry: g.getStatistics(),
managers: g.getManagerStatistics()
};
}
function B(o, e, t) {
return g.getModelFromScope(o, e, t);
}
function I(o, e, t, s) {
return g.shareModel(o, e, t, s);
}
export {
g as GlobalRegistry,
b as JsonModel,
O as ModelManager,
C as configureComposables,
z as createModelManager,
F as dumpGlobalState,
T as enableGlobalAuditing,
J as getComposableContext,
j as getGlobalStatistics,
B as getModelFromMicrofrontend,
E as setComposableScope,
I as shareModelBetweenMicrofrontends,
P as useModel,
R as useModelFromScope,
V as useModelWithDefault,
$ as useModels,
x as useModelsFromScope,
D as useModelsRaw,
k as useModelsShallow
};