@reidelsaltres/pureper 0.2.28 → 0.2.30
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/out/foundation/Module.d.ts +55 -0
- package/out/foundation/Module.d.ts.map +1 -0
- package/out/foundation/Module.js +187 -0
- package/out/foundation/Module.js.map +1 -0
- package/out/index.d.ts +1 -0
- package/out/index.d.ts.map +1 -1
- package/out/index.js +1 -0
- package/out/index.js.map +1 -1
- package/package.json +1 -1
- package/src/foundation/Module.ts +214 -0
- package/src/index.ts +1 -0
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import Observable from "./api/Observer.js";
|
|
2
|
+
export type ModuleStruct = {
|
|
3
|
+
name: string;
|
|
4
|
+
description?: string;
|
|
5
|
+
icon?: string;
|
|
6
|
+
core?: boolean;
|
|
7
|
+
enabled?: boolean;
|
|
8
|
+
};
|
|
9
|
+
export default class Module {
|
|
10
|
+
readonly name: string;
|
|
11
|
+
readonly description?: string;
|
|
12
|
+
readonly icon?: string;
|
|
13
|
+
readonly core: boolean;
|
|
14
|
+
readonly enabled: Observable<boolean>;
|
|
15
|
+
readonly downloaded: Observable<boolean>;
|
|
16
|
+
private _registrations;
|
|
17
|
+
constructor(struct: ModuleStruct);
|
|
18
|
+
addRegistration(fn: () => Promise<void>): void;
|
|
19
|
+
getRegistrations(): ReadonlyArray<() => Promise<void>>;
|
|
20
|
+
/**
|
|
21
|
+
* Takes current entries from the global REGISTRY, moves them into this
|
|
22
|
+
* module's internal list, and removes them from REGISTRY.
|
|
23
|
+
*
|
|
24
|
+
* Call this in consumer code AFTER importing the module's components so
|
|
25
|
+
* that all their REGISTRY entries have been pushed.
|
|
26
|
+
*/
|
|
27
|
+
captureRegistrations(registry: (() => Promise<void>)[]): void;
|
|
28
|
+
enable(): void;
|
|
29
|
+
disable(): void;
|
|
30
|
+
isActive(): boolean;
|
|
31
|
+
/** True if enabled but not downloaded — works only in the current session. */
|
|
32
|
+
get ephemeral(): boolean;
|
|
33
|
+
download(): void;
|
|
34
|
+
undownload(): void;
|
|
35
|
+
}
|
|
36
|
+
export declare class ModuleManager {
|
|
37
|
+
private static _modules;
|
|
38
|
+
private static readonly STORAGE_KEY;
|
|
39
|
+
private static readonly SESSION_KEY;
|
|
40
|
+
static register(struct: ModuleStruct): Module;
|
|
41
|
+
static get(name: string): Module | undefined;
|
|
42
|
+
static getAll(): Module[];
|
|
43
|
+
static isActive(name: string): boolean;
|
|
44
|
+
/**
|
|
45
|
+
* Initializes all modules:
|
|
46
|
+
* 1. Restores saved enabled/disabled preferences
|
|
47
|
+
* 2. Runs registrations from all enabled modules
|
|
48
|
+
* 3. Runs any remaining global REGISTRY entries (backward compat)
|
|
49
|
+
* 4. Returns all promises
|
|
50
|
+
*/
|
|
51
|
+
static initialize(): Promise<void>[];
|
|
52
|
+
static persistState(): void;
|
|
53
|
+
static restoreState(): void;
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=Module.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Module.d.ts","sourceRoot":"","sources":["../../src/foundation/Module.ts"],"names":[],"mappings":"AAAA,OAAO,UAAU,MAAM,mBAAmB,CAAC;AAG3C,MAAM,MAAM,YAAY,GAAG;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,OAAO,CAAC,EAAE,OAAO,CAAC;CACrB,CAAC;AAEF,MAAM,CAAC,OAAO,OAAO,MAAM;IACvB,SAAgB,IAAI,EAAE,MAAM,CAAC;IAC7B,SAAgB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrC,SAAgB,IAAI,CAAC,EAAE,MAAM,CAAC;IAC9B,SAAgB,IAAI,EAAE,OAAO,CAAC;IAC9B,SAAgB,OAAO,EAAE,UAAU,CAAC,OAAO,CAAC,CAAC;IAC7C,SAAgB,UAAU,EAAE,UAAU,CAAC,OAAO,CAAC,CAAC;IAEhD,OAAO,CAAC,cAAc,CAA+B;gBAElC,MAAM,EAAE,YAAY;IAShC,eAAe,CAAC,EAAE,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI;IAI9C,gBAAgB,IAAI,aAAa,CAAC,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAI7D;;;;;;OAMG;IACI,oBAAoB,CAAC,QAAQ,EAAE,CAAC,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC,EAAE,GAAG,IAAI;IAM7D,MAAM,IAAI,IAAI;IAMd,OAAO,IAAI,IAAI;IASf,QAAQ,IAAI,OAAO;IAI1B,8EAA8E;IAC9E,IAAW,SAAS,IAAI,OAAO,CAE9B;IAEM,QAAQ,IAAI,IAAI;IAKhB,UAAU,IAAI,IAAI;CAO5B;AAED,qBAAa,aAAa;IACtB,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAkC;IACzD,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,WAAW,CAAoB;IACvD,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,WAAW,CAA4B;IAE/D,MAAM,CAAC,QAAQ,CAAC,MAAM,EAAE,YAAY,GAAG,MAAM;IAU7C,MAAM,CAAC,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS;IAI5C,MAAM,CAAC,MAAM,IAAI,MAAM,EAAE;IAIzB,MAAM,CAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO;IAKtC;;;;;;OAMG;IACH,MAAM,CAAC,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC,EAAE;IA4BpC,MAAM,CAAC,YAAY,IAAI,IAAI;IAuB3B,MAAM,CAAC,YAAY,IAAI,IAAI;CAsC9B"}
|
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
import Observable from "./api/Observer.js";
|
|
2
|
+
import { REGISTRY } from "./Triplet.js";
|
|
3
|
+
export default class Module {
|
|
4
|
+
name;
|
|
5
|
+
description;
|
|
6
|
+
icon;
|
|
7
|
+
core;
|
|
8
|
+
enabled;
|
|
9
|
+
downloaded;
|
|
10
|
+
_registrations = [];
|
|
11
|
+
constructor(struct) {
|
|
12
|
+
this.name = struct.name;
|
|
13
|
+
this.description = struct.description;
|
|
14
|
+
this.icon = struct.icon;
|
|
15
|
+
this.core = struct.core ?? false;
|
|
16
|
+
this.enabled = new Observable(this.core ? true : (struct.enabled ?? false));
|
|
17
|
+
this.downloaded = new Observable(this.core ? true : false);
|
|
18
|
+
}
|
|
19
|
+
addRegistration(fn) {
|
|
20
|
+
this._registrations.push(fn);
|
|
21
|
+
}
|
|
22
|
+
getRegistrations() {
|
|
23
|
+
return this._registrations;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Takes current entries from the global REGISTRY, moves them into this
|
|
27
|
+
* module's internal list, and removes them from REGISTRY.
|
|
28
|
+
*
|
|
29
|
+
* Call this in consumer code AFTER importing the module's components so
|
|
30
|
+
* that all their REGISTRY entries have been pushed.
|
|
31
|
+
*/
|
|
32
|
+
captureRegistrations(registry) {
|
|
33
|
+
const captured = registry.splice(0, registry.length);
|
|
34
|
+
this._registrations.push(...captured);
|
|
35
|
+
console.log(`[Module]: "${this.name}" captured ${captured.length} registration(s)`);
|
|
36
|
+
}
|
|
37
|
+
enable() {
|
|
38
|
+
if (this.enabled.getObject() === true)
|
|
39
|
+
return;
|
|
40
|
+
this.enabled.setObject(true);
|
|
41
|
+
console.log(`[Module]: "${this.name}" enabled`);
|
|
42
|
+
}
|
|
43
|
+
disable() {
|
|
44
|
+
if (this.core) {
|
|
45
|
+
throw new Error(`[Module]: Cannot disable core module "${this.name}"`);
|
|
46
|
+
}
|
|
47
|
+
if (this.enabled.getObject() === false)
|
|
48
|
+
return;
|
|
49
|
+
this.enabled.setObject(false);
|
|
50
|
+
console.log(`[Module]: "${this.name}" disabled`);
|
|
51
|
+
}
|
|
52
|
+
isActive() {
|
|
53
|
+
return this.enabled.getObject() === true;
|
|
54
|
+
}
|
|
55
|
+
/** True if enabled but not downloaded — works only in the current session. */
|
|
56
|
+
get ephemeral() {
|
|
57
|
+
return this.isActive() && !this.downloaded.getObject();
|
|
58
|
+
}
|
|
59
|
+
download() {
|
|
60
|
+
this.downloaded.setObject(true);
|
|
61
|
+
console.log(`[Module]: "${this.name}" downloaded`);
|
|
62
|
+
}
|
|
63
|
+
undownload() {
|
|
64
|
+
if (this.core) {
|
|
65
|
+
throw new Error(`[Module]: Cannot remove core module "${this.name}" from downloads`);
|
|
66
|
+
}
|
|
67
|
+
this.downloaded.setObject(false);
|
|
68
|
+
console.log(`[Module]: "${this.name}" removed from downloads`);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
export class ModuleManager {
|
|
72
|
+
static _modules = new Map();
|
|
73
|
+
static STORAGE_KEY = "purper:modules";
|
|
74
|
+
static SESSION_KEY = "purper:modules:session";
|
|
75
|
+
static register(struct) {
|
|
76
|
+
if (this._modules.has(struct.name)) {
|
|
77
|
+
throw new Error(`[Module]: Module "${struct.name}" is already registered`);
|
|
78
|
+
}
|
|
79
|
+
const mod = new Module(struct);
|
|
80
|
+
this._modules.set(struct.name, mod);
|
|
81
|
+
console.log(`[Module]: Registered module "${struct.name}"`);
|
|
82
|
+
return mod;
|
|
83
|
+
}
|
|
84
|
+
static get(name) {
|
|
85
|
+
return this._modules.get(name);
|
|
86
|
+
}
|
|
87
|
+
static getAll() {
|
|
88
|
+
return Array.from(this._modules.values());
|
|
89
|
+
}
|
|
90
|
+
static isActive(name) {
|
|
91
|
+
const mod = this._modules.get(name);
|
|
92
|
+
return mod ? mod.isActive() : false;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* Initializes all modules:
|
|
96
|
+
* 1. Restores saved enabled/disabled preferences
|
|
97
|
+
* 2. Runs registrations from all enabled modules
|
|
98
|
+
* 3. Runs any remaining global REGISTRY entries (backward compat)
|
|
99
|
+
* 4. Returns all promises
|
|
100
|
+
*/
|
|
101
|
+
static initialize() {
|
|
102
|
+
this.restoreState();
|
|
103
|
+
const promises = [];
|
|
104
|
+
for (const mod of this._modules.values()) {
|
|
105
|
+
if (mod.isActive()) {
|
|
106
|
+
console.log(`[Module]: Initializing module "${mod.name}" (${mod.getRegistrations().length} registration(s))`);
|
|
107
|
+
for (const reg of mod.getRegistrations()) {
|
|
108
|
+
promises.push(reg());
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
else {
|
|
112
|
+
console.log(`[Module]: Skipping disabled module "${mod.name}"`);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
// Backward compat: run any remaining global REGISTRY entries
|
|
116
|
+
// that were not captured by any module
|
|
117
|
+
if (REGISTRY.length > 0) {
|
|
118
|
+
console.log(`[Module]: Running ${REGISTRY.length} uncaptured global registration(s)`);
|
|
119
|
+
for (const reg of REGISTRY) {
|
|
120
|
+
promises.push(reg());
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
return promises;
|
|
124
|
+
}
|
|
125
|
+
static persistState() {
|
|
126
|
+
const localState = {};
|
|
127
|
+
const sessionState = {};
|
|
128
|
+
for (const mod of this._modules.values()) {
|
|
129
|
+
if (mod.core)
|
|
130
|
+
continue;
|
|
131
|
+
if (mod.downloaded.getObject()) {
|
|
132
|
+
localState[mod.name] = { enabled: mod.isActive(), downloaded: true };
|
|
133
|
+
}
|
|
134
|
+
else if (mod.isActive()) {
|
|
135
|
+
sessionState[mod.name] = { enabled: true };
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
try {
|
|
139
|
+
localStorage.setItem(this.STORAGE_KEY, JSON.stringify(localState));
|
|
140
|
+
sessionStorage.setItem(this.SESSION_KEY, JSON.stringify(sessionState));
|
|
141
|
+
console.log(`[Module]: Persisted module state`);
|
|
142
|
+
}
|
|
143
|
+
catch (e) {
|
|
144
|
+
console.warn(`[Module]: Failed to persist module state`, e);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
static restoreState() {
|
|
148
|
+
// Restore from localStorage (downloaded modules)
|
|
149
|
+
try {
|
|
150
|
+
const raw = localStorage.getItem(this.STORAGE_KEY);
|
|
151
|
+
if (raw) {
|
|
152
|
+
const state = JSON.parse(raw);
|
|
153
|
+
for (const [name, data] of Object.entries(state)) {
|
|
154
|
+
const mod = this._modules.get(name);
|
|
155
|
+
if (mod && !mod.core) {
|
|
156
|
+
if (data.downloaded) {
|
|
157
|
+
mod.downloaded.setObject(true);
|
|
158
|
+
}
|
|
159
|
+
mod.enabled.setObject(data.enabled);
|
|
160
|
+
console.log(`[Module]: Restored "${name}" → downloaded=${data.downloaded}, enabled=${data.enabled}`);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
catch (e) {
|
|
166
|
+
console.warn(`[Module]: Failed to restore localStorage state`, e);
|
|
167
|
+
}
|
|
168
|
+
// Restore from sessionStorage (ephemeral modules)
|
|
169
|
+
try {
|
|
170
|
+
const raw = sessionStorage.getItem(this.SESSION_KEY);
|
|
171
|
+
if (raw) {
|
|
172
|
+
const state = JSON.parse(raw);
|
|
173
|
+
for (const [name, data] of Object.entries(state)) {
|
|
174
|
+
const mod = this._modules.get(name);
|
|
175
|
+
if (mod && !mod.core && !mod.downloaded.getObject()) {
|
|
176
|
+
mod.enabled.setObject(data.enabled);
|
|
177
|
+
console.log(`[Module]: Restored ephemeral "${name}" → enabled=${data.enabled}`);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
catch (e) {
|
|
183
|
+
console.warn(`[Module]: Failed to restore sessionStorage state`, e);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
//# sourceMappingURL=Module.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Module.js","sourceRoot":"","sources":["../../src/foundation/Module.ts"],"names":[],"mappings":"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"}
|
package/out/index.d.ts
CHANGED
|
@@ -10,6 +10,7 @@ export { default as Attribute } from './foundation/component_api/Attribute.js';
|
|
|
10
10
|
export { default as Triplet, TripletStruct, AccessType, REGISTRY } from './foundation/Triplet.js';
|
|
11
11
|
export { ReComponent, RePage, ReImplementation } from './foundation/TripletDecorator.js';
|
|
12
12
|
export { Implementation, ImplementationStruct, Placeholder } from './foundation/Injection.js';
|
|
13
|
+
export { default as Module, ModuleStruct, ModuleManager } from './foundation/Module.js';
|
|
13
14
|
export { default as Fetcher } from './foundation/Fetcher.js';
|
|
14
15
|
export * from './foundation/engine/TemplateEngine.js';
|
|
15
16
|
export { Router } from './foundation/worker/Router.js';
|
package/out/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,IAAI,cAAc,EAAE,MAAM,mCAAmC,CAAC;AAC9E,OAAO,EAAE,OAAO,IAAI,gBAAgB,EAAE,MAAM,sCAAsC,CAAC;AACnF,OAAO,EAAE,OAAO,IAAI,IAAI,EAAE,MAAM,0BAA0B,CAAC;AAE3D,cAAc,2CAA2C,CAAC;AAC1D,OAAO,EACN,OAAO,IAAI,UAAU,EACrB,SAAS,EAAE,iBAAiB,EAAE,oBAAoB,EAAE,QAAQ,EAAE,gBAAgB,EAAE,WAAW,EAC3F,YAAY,EACZ,MAAM,8BAA8B,CAAA;AAErC,OAAO,EAAE,OAAO,IAAI,OAAO,EAAE,MAAM,uCAAuC,CAAC;AAC3E,OAAO,EAAE,OAAO,IAAI,IAAI,EAAE,MAAM,oCAAoC,CAAC;AACrE,OAAO,EAAE,OAAO,IAAI,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAC/E,OAAO,EAAE,OAAO,IAAI,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAE/E,OAAO,EAAE,OAAO,IAAI,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AAClG,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,gBAAgB,EAAE,MAAM,kCAAkC,CAAC;AAEzF,OAAO,EAAE,cAAc,EAAE,oBAAoB,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AAC9F,OAAO,EAAE,OAAO,IAAI,OAAO,EAAE,MAAM,yBAAyB,CAAC;AAE7D,cAAc,uCAAuC,CAAC;AAEtD,OAAO,EAAE,MAAM,EAAE,MAAM,+BAA+B,CAAC;AACvD,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,cAAc,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,sCAAsC,CAAC;AAErK,cAAc,yBAAyB,CAAC;AACxC,cAAc,uBAAuB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,IAAI,cAAc,EAAE,MAAM,mCAAmC,CAAC;AAC9E,OAAO,EAAE,OAAO,IAAI,gBAAgB,EAAE,MAAM,sCAAsC,CAAC;AACnF,OAAO,EAAE,OAAO,IAAI,IAAI,EAAE,MAAM,0BAA0B,CAAC;AAE3D,cAAc,2CAA2C,CAAC;AAC1D,OAAO,EACN,OAAO,IAAI,UAAU,EACrB,SAAS,EAAE,iBAAiB,EAAE,oBAAoB,EAAE,QAAQ,EAAE,gBAAgB,EAAE,WAAW,EAC3F,YAAY,EACZ,MAAM,8BAA8B,CAAA;AAErC,OAAO,EAAE,OAAO,IAAI,OAAO,EAAE,MAAM,uCAAuC,CAAC;AAC3E,OAAO,EAAE,OAAO,IAAI,IAAI,EAAE,MAAM,oCAAoC,CAAC;AACrE,OAAO,EAAE,OAAO,IAAI,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAC/E,OAAO,EAAE,OAAO,IAAI,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAE/E,OAAO,EAAE,OAAO,IAAI,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AAClG,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,gBAAgB,EAAE,MAAM,kCAAkC,CAAC;AAEzF,OAAO,EAAE,cAAc,EAAE,oBAAoB,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AAC9F,OAAO,EAAE,OAAO,IAAI,MAAM,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,wBAAwB,CAAC;AACxF,OAAO,EAAE,OAAO,IAAI,OAAO,EAAE,MAAM,yBAAyB,CAAC;AAE7D,cAAc,uCAAuC,CAAC;AAEtD,OAAO,EAAE,MAAM,EAAE,MAAM,+BAA+B,CAAC;AACvD,OAAO,EAAE,OAAO,IAAI,aAAa,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,cAAc,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,sCAAsC,CAAC;AAErK,cAAc,yBAAyB,CAAC;AACxC,cAAc,uBAAuB,CAAC"}
|
package/out/index.js
CHANGED
|
@@ -8,6 +8,7 @@ export { default as Attribute } from './foundation/component_api/Attribute.js';
|
|
|
8
8
|
export { default as Triplet, AccessType, REGISTRY } from './foundation/Triplet.js';
|
|
9
9
|
export { ReComponent, RePage, ReImplementation } from './foundation/TripletDecorator.js';
|
|
10
10
|
export { Implementation, Placeholder } from './foundation/Injection.js';
|
|
11
|
+
export { default as Module, ModuleManager } from './foundation/Module.js';
|
|
11
12
|
export { default as Fetcher } from './foundation/Fetcher.js';
|
|
12
13
|
export * from './foundation/engine/TemplateEngine.js';
|
|
13
14
|
export { Router } from './foundation/worker/Router.js';
|
package/out/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,OAAO,IAAI,IAAI,EAAE,MAAM,0BAA0B,CAAC;AAE3D,cAAc,2CAA2C,CAAC;AAC1D,OAAO,EACN,OAAO,IAAI,UAAU,EAC+B,QAAQ,EAAE,gBAAgB,EAAE,WAAW,EAC3F,YAAY,EACZ,MAAM,8BAA8B,CAAA;AAErC,OAAO,EAAE,OAAO,IAAI,OAAO,EAAE,MAAM,uCAAuC,CAAC;AAC3E,OAAO,EAAE,OAAO,IAAI,IAAI,EAAE,MAAM,oCAAoC,CAAC;AACrE,OAAO,EAAE,OAAO,IAAI,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAC/E,OAAO,EAAE,OAAO,IAAI,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAE/E,OAAO,EAAE,OAAO,IAAI,OAAO,EAAiB,UAAU,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AAClG,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,gBAAgB,EAAE,MAAM,kCAAkC,CAAC;AAEzF,OAAO,EAAE,cAAc,EAAwB,WAAW,EAAE,MAAM,2BAA2B,CAAC;AAC9F,OAAO,EAAE,OAAO,IAAI,OAAO,EAAE,MAAM,yBAAyB,CAAC;AAE7D,cAAc,uCAAuC,CAAC;AAEtD,OAAO,EAAE,MAAM,EAAE,MAAM,+BAA+B,CAAC;AACvD,OAAO,EAAE,OAAO,IAAI,aAAa,EAAuF,MAAM,sCAAsC,CAAC;AAErK,cAAc,yBAAyB,CAAC;AACxC,cAAc,uBAAuB,CAAC;AAGtC,qEAAqE;AACrE;;WAEQ;AAER,yEAAyE"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,OAAO,IAAI,IAAI,EAAE,MAAM,0BAA0B,CAAC;AAE3D,cAAc,2CAA2C,CAAC;AAC1D,OAAO,EACN,OAAO,IAAI,UAAU,EAC+B,QAAQ,EAAE,gBAAgB,EAAE,WAAW,EAC3F,YAAY,EACZ,MAAM,8BAA8B,CAAA;AAErC,OAAO,EAAE,OAAO,IAAI,OAAO,EAAE,MAAM,uCAAuC,CAAC;AAC3E,OAAO,EAAE,OAAO,IAAI,IAAI,EAAE,MAAM,oCAAoC,CAAC;AACrE,OAAO,EAAE,OAAO,IAAI,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAC/E,OAAO,EAAE,OAAO,IAAI,SAAS,EAAE,MAAM,yCAAyC,CAAC;AAE/E,OAAO,EAAE,OAAO,IAAI,OAAO,EAAiB,UAAU,EAAE,QAAQ,EAAE,MAAM,yBAAyB,CAAC;AAClG,OAAO,EAAE,WAAW,EAAE,MAAM,EAAE,gBAAgB,EAAE,MAAM,kCAAkC,CAAC;AAEzF,OAAO,EAAE,cAAc,EAAwB,WAAW,EAAE,MAAM,2BAA2B,CAAC;AAC9F,OAAO,EAAE,OAAO,IAAI,MAAM,EAAgB,aAAa,EAAE,MAAM,wBAAwB,CAAC;AACxF,OAAO,EAAE,OAAO,IAAI,OAAO,EAAE,MAAM,yBAAyB,CAAC;AAE7D,cAAc,uCAAuC,CAAC;AAEtD,OAAO,EAAE,MAAM,EAAE,MAAM,+BAA+B,CAAC;AACvD,OAAO,EAAE,OAAO,IAAI,aAAa,EAAuF,MAAM,sCAAsC,CAAC;AAErK,cAAc,yBAAyB,CAAC;AACxC,cAAc,uBAAuB,CAAC;AAGtC,qEAAqE;AACrE;;WAEQ;AAER,yEAAyE"}
|
package/package.json
CHANGED
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
import Observable from "./api/Observer.js";
|
|
2
|
+
import { REGISTRY } from "./Triplet.js";
|
|
3
|
+
|
|
4
|
+
export type ModuleStruct = {
|
|
5
|
+
name: string;
|
|
6
|
+
description?: string;
|
|
7
|
+
icon?: string;
|
|
8
|
+
core?: boolean;
|
|
9
|
+
enabled?: boolean;
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
export default class Module {
|
|
13
|
+
public readonly name: string;
|
|
14
|
+
public readonly description?: string;
|
|
15
|
+
public readonly icon?: string;
|
|
16
|
+
public readonly core: boolean;
|
|
17
|
+
public readonly enabled: Observable<boolean>;
|
|
18
|
+
public readonly downloaded: Observable<boolean>;
|
|
19
|
+
|
|
20
|
+
private _registrations: (() => Promise<void>)[] = [];
|
|
21
|
+
|
|
22
|
+
public constructor(struct: ModuleStruct) {
|
|
23
|
+
this.name = struct.name;
|
|
24
|
+
this.description = struct.description;
|
|
25
|
+
this.icon = struct.icon;
|
|
26
|
+
this.core = struct.core ?? false;
|
|
27
|
+
this.enabled = new Observable<boolean>(this.core ? true : (struct.enabled ?? false));
|
|
28
|
+
this.downloaded = new Observable<boolean>(this.core ? true : false);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
public addRegistration(fn: () => Promise<void>): void {
|
|
32
|
+
this._registrations.push(fn);
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
public getRegistrations(): ReadonlyArray<() => Promise<void>> {
|
|
36
|
+
return this._registrations;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Takes current entries from the global REGISTRY, moves them into this
|
|
41
|
+
* module's internal list, and removes them from REGISTRY.
|
|
42
|
+
*
|
|
43
|
+
* Call this in consumer code AFTER importing the module's components so
|
|
44
|
+
* that all their REGISTRY entries have been pushed.
|
|
45
|
+
*/
|
|
46
|
+
public captureRegistrations(registry: (() => Promise<void>)[]): void {
|
|
47
|
+
const captured = registry.splice(0, registry.length);
|
|
48
|
+
this._registrations.push(...captured);
|
|
49
|
+
console.log(`[Module]: "${this.name}" captured ${captured.length} registration(s)`);
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
public enable(): void {
|
|
53
|
+
if (this.enabled.getObject() === true) return;
|
|
54
|
+
this.enabled.setObject(true);
|
|
55
|
+
console.log(`[Module]: "${this.name}" enabled`);
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
public disable(): void {
|
|
59
|
+
if (this.core) {
|
|
60
|
+
throw new Error(`[Module]: Cannot disable core module "${this.name}"`);
|
|
61
|
+
}
|
|
62
|
+
if (this.enabled.getObject() === false) return;
|
|
63
|
+
this.enabled.setObject(false);
|
|
64
|
+
console.log(`[Module]: "${this.name}" disabled`);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
public isActive(): boolean {
|
|
68
|
+
return this.enabled.getObject() === true;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/** True if enabled but not downloaded — works only in the current session. */
|
|
72
|
+
public get ephemeral(): boolean {
|
|
73
|
+
return this.isActive() && !this.downloaded.getObject();
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
public download(): void {
|
|
77
|
+
this.downloaded.setObject(true);
|
|
78
|
+
console.log(`[Module]: "${this.name}" downloaded`);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
public undownload(): void {
|
|
82
|
+
if (this.core) {
|
|
83
|
+
throw new Error(`[Module]: Cannot remove core module "${this.name}" from downloads`);
|
|
84
|
+
}
|
|
85
|
+
this.downloaded.setObject(false);
|
|
86
|
+
console.log(`[Module]: "${this.name}" removed from downloads`);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export class ModuleManager {
|
|
91
|
+
private static _modules: Map<string, Module> = new Map();
|
|
92
|
+
private static readonly STORAGE_KEY = "purper:modules";
|
|
93
|
+
private static readonly SESSION_KEY = "purper:modules:session";
|
|
94
|
+
|
|
95
|
+
static register(struct: ModuleStruct): Module {
|
|
96
|
+
if (this._modules.has(struct.name)) {
|
|
97
|
+
throw new Error(`[Module]: Module "${struct.name}" is already registered`);
|
|
98
|
+
}
|
|
99
|
+
const mod = new Module(struct);
|
|
100
|
+
this._modules.set(struct.name, mod);
|
|
101
|
+
console.log(`[Module]: Registered module "${struct.name}"`);
|
|
102
|
+
return mod;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
static get(name: string): Module | undefined {
|
|
106
|
+
return this._modules.get(name);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
static getAll(): Module[] {
|
|
110
|
+
return Array.from(this._modules.values());
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
static isActive(name: string): boolean {
|
|
114
|
+
const mod = this._modules.get(name);
|
|
115
|
+
return mod ? mod.isActive() : false;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/**
|
|
119
|
+
* Initializes all modules:
|
|
120
|
+
* 1. Restores saved enabled/disabled preferences
|
|
121
|
+
* 2. Runs registrations from all enabled modules
|
|
122
|
+
* 3. Runs any remaining global REGISTRY entries (backward compat)
|
|
123
|
+
* 4. Returns all promises
|
|
124
|
+
*/
|
|
125
|
+
static initialize(): Promise<void>[] {
|
|
126
|
+
this.restoreState();
|
|
127
|
+
|
|
128
|
+
const promises: Promise<void>[] = [];
|
|
129
|
+
|
|
130
|
+
for (const mod of this._modules.values()) {
|
|
131
|
+
if (mod.isActive()) {
|
|
132
|
+
console.log(`[Module]: Initializing module "${mod.name}" (${mod.getRegistrations().length} registration(s))`);
|
|
133
|
+
for (const reg of mod.getRegistrations()) {
|
|
134
|
+
promises.push(reg());
|
|
135
|
+
}
|
|
136
|
+
} else {
|
|
137
|
+
console.log(`[Module]: Skipping disabled module "${mod.name}"`);
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
// Backward compat: run any remaining global REGISTRY entries
|
|
142
|
+
// that were not captured by any module
|
|
143
|
+
if (REGISTRY.length > 0) {
|
|
144
|
+
console.log(`[Module]: Running ${REGISTRY.length} uncaptured global registration(s)`);
|
|
145
|
+
for (const reg of REGISTRY) {
|
|
146
|
+
promises.push(reg());
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
return promises;
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
static persistState(): void {
|
|
154
|
+
const localState: Record<string, { enabled: boolean, downloaded: boolean }> = {};
|
|
155
|
+
const sessionState: Record<string, { enabled: boolean }> = {};
|
|
156
|
+
|
|
157
|
+
for (const mod of this._modules.values()) {
|
|
158
|
+
if (mod.core) continue;
|
|
159
|
+
|
|
160
|
+
if (mod.downloaded.getObject()) {
|
|
161
|
+
localState[mod.name] = { enabled: mod.isActive(), downloaded: true };
|
|
162
|
+
} else if (mod.isActive()) {
|
|
163
|
+
sessionState[mod.name] = { enabled: true };
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
try {
|
|
168
|
+
localStorage.setItem(this.STORAGE_KEY, JSON.stringify(localState));
|
|
169
|
+
sessionStorage.setItem(this.SESSION_KEY, JSON.stringify(sessionState));
|
|
170
|
+
console.log(`[Module]: Persisted module state`);
|
|
171
|
+
} catch (e) {
|
|
172
|
+
console.warn(`[Module]: Failed to persist module state`, e);
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
static restoreState(): void {
|
|
177
|
+
// Restore from localStorage (downloaded modules)
|
|
178
|
+
try {
|
|
179
|
+
const raw = localStorage.getItem(this.STORAGE_KEY);
|
|
180
|
+
if (raw) {
|
|
181
|
+
const state: Record<string, { enabled: boolean, downloaded: boolean }> = JSON.parse(raw);
|
|
182
|
+
for (const [name, data] of Object.entries(state)) {
|
|
183
|
+
const mod = this._modules.get(name);
|
|
184
|
+
if (mod && !mod.core) {
|
|
185
|
+
if (data.downloaded) {
|
|
186
|
+
mod.downloaded.setObject(true);
|
|
187
|
+
}
|
|
188
|
+
mod.enabled.setObject(data.enabled);
|
|
189
|
+
console.log(`[Module]: Restored "${name}" → downloaded=${data.downloaded}, enabled=${data.enabled}`);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
} catch (e) {
|
|
194
|
+
console.warn(`[Module]: Failed to restore localStorage state`, e);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
// Restore from sessionStorage (ephemeral modules)
|
|
198
|
+
try {
|
|
199
|
+
const raw = sessionStorage.getItem(this.SESSION_KEY);
|
|
200
|
+
if (raw) {
|
|
201
|
+
const state: Record<string, { enabled: boolean }> = JSON.parse(raw);
|
|
202
|
+
for (const [name, data] of Object.entries(state)) {
|
|
203
|
+
const mod = this._modules.get(name);
|
|
204
|
+
if (mod && !mod.core && !mod.downloaded.getObject()) {
|
|
205
|
+
mod.enabled.setObject(data.enabled);
|
|
206
|
+
console.log(`[Module]: Restored ephemeral "${name}" → enabled=${data.enabled}`);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
} catch (e) {
|
|
211
|
+
console.warn(`[Module]: Failed to restore sessionStorage state`, e);
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -19,6 +19,7 @@ export { default as Triplet, TripletStruct, AccessType, REGISTRY } from './found
|
|
|
19
19
|
export { ReComponent, RePage, ReImplementation } from './foundation/TripletDecorator.js';
|
|
20
20
|
|
|
21
21
|
export { Implementation, ImplementationStruct, Placeholder } from './foundation/Injection.js';
|
|
22
|
+
export { default as Module, ModuleStruct, ModuleManager } from './foundation/Module.js';
|
|
22
23
|
export { default as Fetcher } from './foundation/Fetcher.js';
|
|
23
24
|
|
|
24
25
|
export * from './foundation/engine/TemplateEngine.js';
|