@cldmv/slothlet 3.3.0 → 3.3.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/README.md +6 -8
- package/REFERENCE.md +23 -0
- package/dist/lib/builders/api-assignment.mjs +1 -589
- package/dist/lib/builders/api_builder.mjs +1 -1385
- package/dist/lib/builders/builder.mjs +1 -78
- package/dist/lib/builders/modes-processor.mjs +1 -1800
- package/dist/lib/errors.mjs +9 -211
- package/dist/lib/factories/component-base.mjs +1 -80
- package/dist/lib/factories/context.mjs +1 -22
- package/dist/lib/handlers/api-cache-manager.mjs +1 -200
- package/dist/lib/handlers/api-manager.mjs +1 -2536
- package/dist/lib/handlers/context-async.mjs +1 -172
- package/dist/lib/handlers/context-live.mjs +1 -173
- package/dist/lib/handlers/hook-manager.mjs +1 -667
- package/dist/lib/handlers/lifecycle-token.mjs +1 -28
- package/dist/lib/handlers/lifecycle.mjs +1 -115
- package/dist/lib/handlers/materialize-manager.mjs +1 -48
- package/dist/lib/handlers/metadata.mjs +1 -501
- package/dist/lib/handlers/ownership.mjs +1 -322
- package/dist/lib/handlers/permission-manager.mjs +1 -392
- package/dist/lib/handlers/unified-wrapper.mjs +1 -3110
- package/dist/lib/handlers/version-manager.mjs +1 -885
- package/dist/lib/helpers/class-instance-wrapper.mjs +1 -109
- package/dist/lib/helpers/config.mjs +1 -439
- package/dist/lib/helpers/eventemitter-context.mjs +1 -349
- package/dist/lib/helpers/hint-detector.mjs +1 -47
- package/dist/lib/helpers/modes-utils.mjs +1 -37
- package/dist/lib/helpers/pattern-matcher.mjs +1 -125
- package/dist/lib/helpers/resolve-from-caller.mjs +1 -169
- package/dist/lib/helpers/sanitize.mjs +1 -340
- package/dist/lib/helpers/utilities.mjs +1 -70
- package/dist/lib/i18n/translations.mjs +1 -126
- package/dist/lib/modes/eager.mjs +1 -59
- package/dist/lib/modes/lazy.mjs +1 -81
- package/dist/lib/processors/flatten.mjs +1 -437
- package/dist/lib/processors/loader.mjs +1 -339
- package/dist/lib/processors/type-generator.mjs +1 -275
- package/dist/lib/processors/typescript.mjs +1 -172
- package/dist/lib/runtime/runtime-asynclocalstorage.mjs +1 -113
- package/dist/lib/runtime/runtime-livebindings.mjs +1 -78
- package/dist/lib/runtime/runtime.mjs +1 -102
- package/dist/slothlet.mjs +1 -817
- package/package.json +34 -31
- package/types/dist/lib/builders/api-assignment.d.mts +3 -92
- package/types/dist/lib/builders/api-assignment.d.mts.map +1 -1
- package/types/dist/lib/builders/api_builder.d.mts +102 -91
- package/types/dist/lib/builders/api_builder.d.mts.map +1 -1
- package/types/dist/lib/builders/builder.d.mts +1 -55
- package/types/dist/lib/builders/builder.d.mts.map +1 -1
- package/types/dist/lib/builders/modes-processor.d.mts +3 -27
- package/types/dist/lib/builders/modes-processor.d.mts.map +1 -1
- package/types/dist/lib/errors.d.mts +19 -109
- package/types/dist/lib/errors.d.mts.map +1 -1
- package/types/dist/lib/factories/component-base.d.mts +7 -177
- package/types/dist/lib/factories/component-base.d.mts.map +1 -1
- package/types/dist/lib/factories/context.d.mts +4 -22
- package/types/dist/lib/factories/context.d.mts.map +1 -1
- package/types/dist/lib/handlers/api-cache-manager.d.mts +20 -203
- package/types/dist/lib/handlers/api-cache-manager.d.mts.map +1 -1
- package/types/dist/lib/handlers/api-manager.d.mts +33 -408
- package/types/dist/lib/handlers/api-manager.d.mts.map +1 -1
- package/types/dist/lib/handlers/context-async.d.mts +23 -61
- package/types/dist/lib/handlers/context-async.d.mts.map +1 -1
- package/types/dist/lib/handlers/context-live.d.mts +22 -59
- package/types/dist/lib/handlers/context-live.d.mts.map +1 -1
- package/types/dist/lib/handlers/hook-manager.d.mts +46 -185
- package/types/dist/lib/handlers/hook-manager.d.mts.map +1 -1
- package/types/dist/lib/handlers/lifecycle-token.d.mts +3 -48
- package/types/dist/lib/handlers/lifecycle-token.d.mts.map +1 -1
- package/types/dist/lib/handlers/lifecycle.d.mts +5 -82
- package/types/dist/lib/handlers/lifecycle.d.mts.map +1 -1
- package/types/dist/lib/handlers/materialize-manager.d.mts +8 -70
- package/types/dist/lib/handlers/materialize-manager.d.mts.map +1 -1
- package/types/dist/lib/handlers/metadata.d.mts +17 -221
- package/types/dist/lib/handlers/metadata.d.mts.map +1 -1
- package/types/dist/lib/handlers/ownership.d.mts +44 -160
- package/types/dist/lib/handlers/ownership.d.mts.map +1 -1
- package/types/dist/lib/handlers/permission-manager.d.mts +37 -141
- package/types/dist/lib/handlers/permission-manager.d.mts.map +1 -1
- package/types/dist/lib/handlers/unified-wrapper.d.mts +26 -239
- package/types/dist/lib/handlers/unified-wrapper.d.mts.map +1 -1
- package/types/dist/lib/handlers/version-manager.d.mts +28 -225
- package/types/dist/lib/handlers/version-manager.d.mts.map +1 -1
- package/types/dist/lib/helpers/class-instance-wrapper.d.mts +2 -52
- package/types/dist/lib/helpers/class-instance-wrapper.d.mts.map +1 -1
- package/types/dist/lib/helpers/config.d.mts +125 -139
- package/types/dist/lib/helpers/config.d.mts.map +1 -1
- package/types/dist/lib/helpers/eventemitter-context.d.mts +3 -29
- package/types/dist/lib/helpers/eventemitter-context.d.mts.map +1 -1
- package/types/dist/lib/helpers/hint-detector.d.mts +2 -15
- package/types/dist/lib/helpers/hint-detector.d.mts.map +1 -1
- package/types/dist/lib/helpers/modes-utils.d.mts +3 -30
- package/types/dist/lib/helpers/modes-utils.d.mts.map +1 -1
- package/types/dist/lib/helpers/pattern-matcher.d.mts +3 -43
- package/types/dist/lib/helpers/pattern-matcher.d.mts.map +1 -1
- package/types/dist/lib/helpers/resolve-from-caller.d.mts +3 -27
- package/types/dist/lib/helpers/resolve-from-caller.d.mts.map +1 -1
- package/types/dist/lib/helpers/sanitize.d.mts +4 -92
- package/types/dist/lib/helpers/sanitize.d.mts.map +1 -1
- package/types/dist/lib/helpers/utilities.d.mts +4 -52
- package/types/dist/lib/helpers/utilities.d.mts.map +1 -1
- package/types/dist/lib/i18n/translations.d.mts +4 -37
- package/types/dist/lib/i18n/translations.d.mts.map +1 -1
- package/types/dist/lib/modes/eager.d.mts +8 -30
- package/types/dist/lib/modes/eager.d.mts.map +1 -1
- package/types/dist/lib/modes/lazy.d.mts +10 -43
- package/types/dist/lib/modes/lazy.d.mts.map +1 -1
- package/types/dist/lib/processors/flatten.d.mts +56 -107
- package/types/dist/lib/processors/flatten.d.mts.map +1 -1
- package/types/dist/lib/processors/loader.d.mts +6 -41
- package/types/dist/lib/processors/loader.d.mts.map +1 -1
- package/types/dist/lib/processors/type-generator.d.mts +2 -16
- package/types/dist/lib/processors/type-generator.d.mts.map +1 -1
- package/types/dist/lib/processors/typescript.d.mts +6 -53
- package/types/dist/lib/processors/typescript.d.mts.map +1 -1
- package/types/dist/lib/runtime/runtime-asynclocalstorage.d.mts +3 -71
- package/types/dist/lib/runtime/runtime-asynclocalstorage.d.mts.map +1 -1
- package/types/dist/lib/runtime/runtime-livebindings.d.mts +2 -37
- package/types/dist/lib/runtime/runtime-livebindings.d.mts.map +1 -1
- package/types/dist/lib/runtime/runtime.d.mts +3 -39
- package/types/dist/lib/runtime/runtime.d.mts.map +1 -1
- package/types/dist/slothlet.d.mts +3 -249
- package/types/dist/slothlet.d.mts.map +1 -1
- package/types/index.d.mts +36 -16
- package/types/index.d.mts.map +1 -0
- package/AGENT-USAGE.md +0 -736
- package/docs/API-RULES.md +0 -712
package/dist/slothlet.mjs
CHANGED
|
@@ -14,820 +14,4 @@
|
|
|
14
14
|
limitations under the License.
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
import { readdirSync } from "node:fs";
|
|
21
|
-
import { dirname, join } from "node:path";
|
|
22
|
-
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
23
|
-
import { getContextManager } from "@cldmv/slothlet/factories/context";
|
|
24
|
-
import { SlothletError, SlothletWarning, SlothletDebug } from "@cldmv/slothlet/errors";
|
|
25
|
-
import { registerInstance } from "@cldmv/slothlet/handlers/lifecycle-token";
|
|
26
|
-
import { resolveWrapper } from "@cldmv/slothlet/handlers/unified-wrapper";
|
|
27
|
-
import { initI18n } from "@cldmv/slothlet/i18n";
|
|
28
|
-
import {
|
|
29
|
-
enableEventEmitterPatching,
|
|
30
|
-
disableEventEmitterPatching,
|
|
31
|
-
cleanupEventEmitterResources,
|
|
32
|
-
setApiContextChecker
|
|
33
|
-
} from "@cldmv/slothlet/helpers/eventemitter-context";
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
class Slothlet {
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
static RESERVED_ROOT_KEYS = ["slothlet", "shutdown", "destroy"];
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
static SKIP_PROPS = ["__metadata", "__type", "_materialize", "_impl", "____slothletInternal"];
|
|
43
|
-
|
|
44
|
-
constructor() {
|
|
45
|
-
|
|
46
|
-
this.SlothletError = SlothletError;
|
|
47
|
-
this.SlothletWarning = SlothletWarning;
|
|
48
|
-
|
|
49
|
-
this.debugLogger = null;
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
this.instanceID = null;
|
|
53
|
-
this.config = null;
|
|
54
|
-
this.api = null;
|
|
55
|
-
this.boundApi = null;
|
|
56
|
-
this.contextManager = null;
|
|
57
|
-
this.isLoaded = false;
|
|
58
|
-
this.reference = null;
|
|
59
|
-
this.context = null;
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
this.envSnapshot = null;
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
this._totalLazyCount = 0;
|
|
66
|
-
this._unmaterializedLazyCount = 0;
|
|
67
|
-
this._materializationComplete = false;
|
|
68
|
-
this._materializationWaiters = [];
|
|
69
|
-
this._materializationCompleteEmitted = false;
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
this.componentCategories = ["helpers", "handlers", "builders", "processors", "modes"];
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
for (const category of this.componentCategories) {
|
|
76
|
-
this[category] = {};
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
async _initializeComponents() {
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
const baseDir = join(dirname(fileURLToPath(import.meta.url)), "lib");
|
|
89
|
-
|
|
90
|
-
for (const category of this.componentCategories) {
|
|
91
|
-
const categoryDir = join(baseDir, category);
|
|
92
|
-
const files = readdirSync(categoryDir).filter((f) => f.endsWith(".mjs"));
|
|
93
|
-
|
|
94
|
-
for (const file of files) {
|
|
95
|
-
const filePath = join(categoryDir, file);
|
|
96
|
-
|
|
97
|
-
try {
|
|
98
|
-
const module = await import(pathToFileURL(filePath).href);
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
const classExports = Object.values(module).filter((exp) => typeof exp === "function" && exp.slothletProperty);
|
|
102
|
-
|
|
103
|
-
for (const ClassExport of classExports) {
|
|
104
|
-
const propName = ClassExport.slothletProperty;
|
|
105
|
-
|
|
106
|
-
this[category][propName] = new ClassExport(this);
|
|
107
|
-
|
|
108
|
-
if (this.config?.debug?.initialization) {
|
|
109
|
-
this.debug("initialization", {
|
|
110
|
-
key: "DEBUG_MODE_COMPONENT_INITIALIZED",
|
|
111
|
-
component: ClassExport.name,
|
|
112
|
-
category,
|
|
113
|
-
propertyName: propName
|
|
114
|
-
});
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
} catch (error) {
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
throw new this.SlothletError(
|
|
123
|
-
"MODULE_IMPORT_FAILED",
|
|
124
|
-
{
|
|
125
|
-
modulePath: filePath
|
|
126
|
-
},
|
|
127
|
-
error
|
|
128
|
-
);
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
_setupLifecycleSubscribers() {
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
if (!this.handlers.lifecycle) {
|
|
139
|
-
return;
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
if (this.handlers.metadata) {
|
|
147
|
-
this.handlers.lifecycle.subscribe("impl:created", (data, token) => {
|
|
148
|
-
this.handlers.metadata.tagSystemMetadata(
|
|
149
|
-
data.impl,
|
|
150
|
-
{
|
|
151
|
-
filePath: data.filePath,
|
|
152
|
-
apiPath: data.apiPath,
|
|
153
|
-
moduleID: data.moduleID,
|
|
154
|
-
sourceFolder: data.sourceFolder
|
|
155
|
-
},
|
|
156
|
-
token
|
|
157
|
-
);
|
|
158
|
-
});
|
|
159
|
-
|
|
160
|
-
this.handlers.lifecycle.subscribe("impl:changed", (data, token) => {
|
|
161
|
-
this.handlers.metadata.tagSystemMetadata(
|
|
162
|
-
data.impl,
|
|
163
|
-
{
|
|
164
|
-
filePath: data.filePath,
|
|
165
|
-
apiPath: data.apiPath,
|
|
166
|
-
moduleID: data.moduleID,
|
|
167
|
-
sourceFolder: data.sourceFolder
|
|
168
|
-
},
|
|
169
|
-
token
|
|
170
|
-
);
|
|
171
|
-
});
|
|
172
|
-
|
|
173
|
-
this.handlers.lifecycle.subscribe("impl:removed", (data) => {
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
if (data.apiPath) {
|
|
178
|
-
const rootSegment = data.apiPath.split(".")[0];
|
|
179
|
-
this.handlers.metadata.removeUserMetadataByApiPath(rootSegment);
|
|
180
|
-
}
|
|
181
|
-
});
|
|
182
|
-
}
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
if (this.handlers.ownership) {
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
this.handlers.lifecycle.subscribe("impl:created", (data) => {
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
const collisionMode = this.config?.collision?.api || "merge";
|
|
195
|
-
|
|
196
|
-
const implValue = data.wrapper?.__impl ?? data.impl;
|
|
197
|
-
this.handlers.ownership.register({
|
|
198
|
-
moduleID: data.moduleID,
|
|
199
|
-
apiPath: data.apiPath,
|
|
200
|
-
value: implValue,
|
|
201
|
-
source: data.source,
|
|
202
|
-
filePath: data.filePath,
|
|
203
|
-
collisionMode: collisionMode
|
|
204
|
-
});
|
|
205
|
-
});
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
this.handlers.lifecycle.subscribe("impl:changed", (data) => {
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
const collisionMode = this.config?.collision?.api || "merge";
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
const implValue = data.wrapper?.__impl ?? data.impl;
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
const currentOwner = this.handlers.ownership.getCurrentOwner(data.apiPath);
|
|
222
|
-
if (currentOwner?.moduleID !== data.moduleID) {
|
|
223
|
-
this.handlers.ownership.register({
|
|
224
|
-
moduleID: data.moduleID,
|
|
225
|
-
apiPath: data.apiPath,
|
|
226
|
-
value: implValue,
|
|
227
|
-
source: data.source,
|
|
228
|
-
filePath: data.filePath,
|
|
229
|
-
collisionMode: collisionMode
|
|
230
|
-
});
|
|
231
|
-
}
|
|
232
|
-
});
|
|
233
|
-
}
|
|
234
|
-
}
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
_registerLazyWrapper() {
|
|
238
|
-
this._totalLazyCount++;
|
|
239
|
-
this._unmaterializedLazyCount++;
|
|
240
|
-
|
|
241
|
-
if (this.config?.debug?.materialize) {
|
|
242
|
-
this.debug("materialize", {
|
|
243
|
-
key: "DEBUG_MODE_LAZY_WRAPPER_REGISTERED",
|
|
244
|
-
total: this._totalLazyCount,
|
|
245
|
-
unmaterialized: this._unmaterializedLazyCount
|
|
246
|
-
});
|
|
247
|
-
}
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
_onWrapperMaterialized() {
|
|
252
|
-
this._unmaterializedLazyCount--;
|
|
253
|
-
|
|
254
|
-
if (this.config?.debug?.materialize) {
|
|
255
|
-
this.debug("materialize", {
|
|
256
|
-
key: "DEBUG_MODE_LAZY_WRAPPER_MATERIALIZED",
|
|
257
|
-
total: this._totalLazyCount,
|
|
258
|
-
unmaterialized: this._unmaterializedLazyCount,
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
percentage: this._totalLazyCount > 0 ? ((this._totalLazyCount - this._unmaterializedLazyCount) / this._totalLazyCount) * 100 : 100
|
|
262
|
-
});
|
|
263
|
-
}
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
if (this._unmaterializedLazyCount === 0 && !this._materializationComplete) {
|
|
267
|
-
this._materializationComplete = true;
|
|
268
|
-
|
|
269
|
-
if (this.config?.debug?.materialize) {
|
|
270
|
-
this.debug("materialize", {
|
|
271
|
-
key: "DEBUG_MODE_ALL_LAZY_WRAPPERS_MATERIALIZED",
|
|
272
|
-
total: this._totalLazyCount
|
|
273
|
-
});
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
const waiters = this._materializationWaiters.splice(0);
|
|
278
|
-
for (const resolve of waiters) {
|
|
279
|
-
resolve();
|
|
280
|
-
}
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
if (this.config?.tracking?.materialization && !this._materializationCompleteEmitted) {
|
|
284
|
-
this._materializationCompleteEmitted = true;
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
if (this.handlers?.lifecycle) {
|
|
288
|
-
this.handlers.lifecycle.emit("materialized:complete", {
|
|
289
|
-
total: this._totalLazyCount,
|
|
290
|
-
timestamp: Date.now()
|
|
291
|
-
});
|
|
292
|
-
}
|
|
293
|
-
}
|
|
294
|
-
}
|
|
295
|
-
}
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
_captureEnvSnapshot(envConfig) {
|
|
299
|
-
const rawInclude = envConfig?.include;
|
|
300
|
-
const include = Array.isArray(rawInclude) ? rawInclude.filter((key) => typeof key === "string") : null;
|
|
301
|
-
const useAllowlist = include !== null && include.length > 0;
|
|
302
|
-
const raw = useAllowlist
|
|
303
|
-
? include.reduce((acc, key) => {
|
|
304
|
-
if (Object.prototype.hasOwnProperty.call(process.env, key)) {
|
|
305
|
-
acc[key] = process.env[key];
|
|
306
|
-
}
|
|
307
|
-
return acc;
|
|
308
|
-
}, Object.create(null))
|
|
309
|
-
: { ...process.env };
|
|
310
|
-
return Object.freeze(raw);
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
async load(config = {}, preservedInstanceID = null) {
|
|
315
|
-
|
|
316
|
-
this.config = config;
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
if (!this.envSnapshot) {
|
|
324
|
-
this.envSnapshot = this._captureEnvSnapshot(config.env);
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
this.debugLogger = new SlothletDebug(config);
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
await this._initializeComponents();
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
registerInstance(this);
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
this._setupLifecycleSubscribers();
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
this.config = this.helpers.config.transformConfig(config);
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
if (this.config?.i18n?.language) {
|
|
347
|
-
initI18n({ language: this.config.i18n.language });
|
|
348
|
-
}
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
this.debugLogger = new SlothletDebug(this.config);
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
this.instanceID = preservedInstanceID || this.helpers.utilities.generateId();
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
this.reference = this.config.reference;
|
|
359
|
-
this.context = this.config.context;
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
this.contextManager = getContextManager(this.config.runtime);
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
setApiContextChecker(() => {
|
|
373
|
-
|
|
374
|
-
const ctx = this.contextManager.tryGetContext();
|
|
375
|
-
return !!(ctx && ctx.self);
|
|
376
|
-
|
|
377
|
-
});
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
let store;
|
|
382
|
-
if (preservedInstanceID && this.contextManager.instances.has(preservedInstanceID)) {
|
|
383
|
-
|
|
384
|
-
this.contextManager.cleanup(preservedInstanceID);
|
|
385
|
-
store = this.contextManager.initialize(this.instanceID, this.config);
|
|
386
|
-
} else {
|
|
387
|
-
|
|
388
|
-
store = this.contextManager.initialize(this.instanceID, this.config);
|
|
389
|
-
}
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
enableEventEmitterPatching();
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
if (typeof this.contextManager.registerEventEmitterContextChecker === "function") {
|
|
399
|
-
this.contextManager.registerEventEmitterContextChecker();
|
|
400
|
-
}
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
const baseModuleId = `base_${this.helpers.utilities.generateId().substring(0, 8)}`;
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
const baseApi = await this.builders.builder.buildAPI({
|
|
410
|
-
dir: this.config.dir,
|
|
411
|
-
mode: this.config.mode,
|
|
412
|
-
moduleID: baseModuleId
|
|
413
|
-
});
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
this.api = baseApi;
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
const apiWithBuiltins = await this.buildFinalAPI(this.api);
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
if (this.handlers.apiCacheManager) {
|
|
427
|
-
this.handlers.apiCacheManager.set(baseModuleId, {
|
|
428
|
-
endpoint: ".",
|
|
429
|
-
moduleID: baseModuleId,
|
|
430
|
-
api: this.api,
|
|
431
|
-
folderPath: this.config.dir,
|
|
432
|
-
mode: this.config.mode,
|
|
433
|
-
sanitizeOptions: this.config.sanitize || {},
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
collisionMode: this.config.collision?.api || "merge",
|
|
437
|
-
config: { ...this.config },
|
|
438
|
-
timestamp: Date.now()
|
|
439
|
-
});
|
|
440
|
-
}
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
this.injectRuntimeMetadataFunctions(apiWithBuiltins);
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
if (this.config.metadata && typeof this.config.metadata === "object") {
|
|
447
|
-
|
|
448
|
-
for (const [key, value] of Object.entries(this.config.metadata)) {
|
|
449
|
-
this.handlers.metadata.setGlobalMetadata(key, value);
|
|
450
|
-
}
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
this.handlers.metadata.registerUserMetadata(baseModuleId, this.config.metadata);
|
|
454
|
-
}
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
if (this.handlers.ownership) {
|
|
461
|
-
this.handlers.ownership.registerSubtree(apiWithBuiltins, baseModuleId, "");
|
|
462
|
-
}
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
if (!this.boundApi) {
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
const isCallable = typeof this.api === "function" || (this.api && typeof this.api.default === "function");
|
|
473
|
-
const proxyTarget = isCallable ? function () {} : {};
|
|
474
|
-
|
|
475
|
-
this.boundApi = new Proxy(proxyTarget, {
|
|
476
|
-
get: (target, prop) => (this.api ? this.api[prop] : undefined),
|
|
477
|
-
set: (target, prop, value) => {
|
|
478
|
-
if (this.api) {
|
|
479
|
-
this.api[prop] = value;
|
|
480
|
-
}
|
|
481
|
-
return true;
|
|
482
|
-
},
|
|
483
|
-
has: (target, prop) => (this.api ? prop in this.api : false),
|
|
484
|
-
ownKeys: (____target) => (this.api ? Reflect.ownKeys(this.api) : []),
|
|
485
|
-
deleteProperty: (target, prop) => (this.api ? delete this.api[prop] : true),
|
|
486
|
-
apply: (target, thisArg, args) => (this.api ? Reflect.apply(this.api, thisArg, args) : undefined),
|
|
487
|
-
construct: (target, args) => (this.api ? Reflect.construct(this.api, args) : {}),
|
|
488
|
-
getOwnPropertyDescriptor: (target, prop) => {
|
|
489
|
-
|
|
490
|
-
if (isCallable && prop === "prototype") {
|
|
491
|
-
return Object.getOwnPropertyDescriptor(target, prop);
|
|
492
|
-
}
|
|
493
|
-
if (this.api && prop in this.api) {
|
|
494
|
-
const desc = Object.getOwnPropertyDescriptor(this.api, prop);
|
|
495
|
-
if (desc) {
|
|
496
|
-
return { ...desc, configurable: true };
|
|
497
|
-
}
|
|
498
|
-
}
|
|
499
|
-
return undefined;
|
|
500
|
-
}
|
|
501
|
-
});
|
|
502
|
-
|
|
503
|
-
}
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
store.self = this.boundApi;
|
|
507
|
-
store.context = this.context || {};
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
if (this.reference && typeof this.reference === "object") {
|
|
512
|
-
Object.assign(this.boundApi, this.reference);
|
|
513
|
-
}
|
|
514
|
-
|
|
515
|
-
this.isLoaded = true;
|
|
516
|
-
|
|
517
|
-
return this.boundApi;
|
|
518
|
-
}
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
async reload(options = {}) {
|
|
522
|
-
const { keepInstanceID = false } = options;
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
if (!this.config?.dir) {
|
|
527
|
-
throw new SlothletError("INVALID_CONFIG_NOT_LOADED", {
|
|
528
|
-
operation: "reload",
|
|
529
|
-
validationError: true
|
|
530
|
-
});
|
|
531
|
-
}
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
const operationHistory = this.handlers.apiManager?.state?.operationHistory ? [...this.handlers.apiManager.state.operationHistory] : [];
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
await this._clearModuleCaches();
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
const oldInstanceID = this.instanceID;
|
|
546
|
-
if (!keepInstanceID) {
|
|
547
|
-
this.instanceID = `${oldInstanceID}_reload_${Date.now()}`;
|
|
548
|
-
}
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
const savedMetadataState = this.handlers.metadata?.exportUserState?.();
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
const savedHooks = this.handlers.hookManager?.exportHooks?.();
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
await this.load(this.config, this.instanceID);
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
if (savedMetadataState && this.handlers.metadata) {
|
|
566
|
-
this.handlers.metadata.importUserState(savedMetadataState);
|
|
567
|
-
}
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
if (savedHooks?.length && this.handlers.hookManager) {
|
|
573
|
-
this.handlers.hookManager.importHooks(savedHooks);
|
|
574
|
-
}
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
for (const [, store] of this.contextManager.instances) {
|
|
580
|
-
if (store.parentInstanceID === oldInstanceID) {
|
|
581
|
-
store.parentInstanceID = this.instanceID;
|
|
582
|
-
}
|
|
583
|
-
}
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
if (oldInstanceID && oldInstanceID !== this.instanceID && this.contextManager.instances?.has(oldInstanceID)) {
|
|
588
|
-
this.contextManager.cleanup(oldInstanceID);
|
|
589
|
-
}
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
for (const operation of operationHistory) {
|
|
593
|
-
if (operation.type === "add") {
|
|
594
|
-
await this.handlers.apiManager.addApiComponent({
|
|
595
|
-
apiPath: operation.apiPath,
|
|
596
|
-
folderPath: operation.folderPath,
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
options: { ...(operation.options || {}), recordHistory: false },
|
|
600
|
-
moduleID: `replay_${this.helpers.utilities.generateId().substring(0, 8)}`,
|
|
601
|
-
versionConfig: operation.versionConfig || null
|
|
602
|
-
});
|
|
603
|
-
} else if (operation.type === "remove") {
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
const { parts } = this.handlers.apiManager.normalizeApiPath(operation.apiPath);
|
|
607
|
-
this.handlers.apiManager.deletePath(this.api, parts);
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
if (this.handlers.metadata) {
|
|
612
|
-
const rootSegment = operation.apiPath.split(".")[0];
|
|
613
|
-
this.handlers.metadata.removeUserMetadataByApiPath(rootSegment);
|
|
614
|
-
}
|
|
615
|
-
} else if (operation.type === "addPermissionRule") {
|
|
616
|
-
if (this.handlers.permissionManager) {
|
|
617
|
-
this.handlers.permissionManager.addRule(operation.rule, operation.ownerModuleID, operation.ruleId);
|
|
618
|
-
}
|
|
619
|
-
} else if (operation.type === "removePermissionRule") {
|
|
620
|
-
if (this.handlers.permissionManager) {
|
|
621
|
-
this.handlers.permissionManager.removeRule(operation.ruleId, operation.callerModuleID);
|
|
622
|
-
}
|
|
623
|
-
}
|
|
624
|
-
}
|
|
625
|
-
|
|
626
|
-
return this.boundApi;
|
|
627
|
-
}
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
async _clearModuleCaches() {
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
const targetDir = this.config.dir;
|
|
634
|
-
const { resolve } = await import("node:path");
|
|
635
|
-
const { createRequire } = await import("node:module");
|
|
636
|
-
const require = createRequire(import.meta.url);
|
|
637
|
-
const absoluteTargetDir = resolve(targetDir);
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
for (const key of Object.keys(require.cache)) {
|
|
641
|
-
if (key.startsWith(absoluteTargetDir)) {
|
|
642
|
-
delete require.cache[key];
|
|
643
|
-
}
|
|
644
|
-
}
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
}
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
injectRuntimeMetadataFunctions(api) {
|
|
652
|
-
if (!api.slothlet?.metadata) {
|
|
653
|
-
return;
|
|
654
|
-
}
|
|
655
|
-
|
|
656
|
-
const metadataHandler = this.handlers.metadata;
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
api.slothlet.metadata.get = async function slothlet_metadata_get_runtime(path) {
|
|
660
|
-
return metadataHandler.get(path);
|
|
661
|
-
};
|
|
662
|
-
|
|
663
|
-
api.slothlet.metadata.self = function slothlet_metadata_self_runtime() {
|
|
664
|
-
return metadataHandler.self();
|
|
665
|
-
};
|
|
666
|
-
|
|
667
|
-
api.slothlet.metadata.caller = function slothlet_metadata_caller_runtime() {
|
|
668
|
-
return metadataHandler.caller();
|
|
669
|
-
};
|
|
670
|
-
}
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
async _drainInFlightLoads() {
|
|
674
|
-
if (!this.api) return;
|
|
675
|
-
|
|
676
|
-
const pending = [];
|
|
677
|
-
const seen = new Set();
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
const collect = (obj, depth = 0) => {
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
const objType = typeof obj;
|
|
686
|
-
if (!obj || (objType !== "object" && objType !== "function") || depth > 15 || seen.has(obj)) return;
|
|
687
|
-
seen.add(obj);
|
|
688
|
-
|
|
689
|
-
try {
|
|
690
|
-
|
|
691
|
-
if (obj.__isVersionDispatcher === true) return;
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
const wrapper = resolveWrapper(obj);
|
|
698
|
-
if (wrapper) {
|
|
699
|
-
const mat = wrapper.____slothletInternal.materializationPromise;
|
|
700
|
-
if (mat) pending.push(mat);
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
for (const key of Object.keys(wrapper)) {
|
|
708
|
-
if (!key.startsWith("____")) collect(wrapper[key], depth + 1);
|
|
709
|
-
}
|
|
710
|
-
return;
|
|
711
|
-
}
|
|
712
|
-
|
|
713
|
-
for (const key of Object.keys(obj)) {
|
|
714
|
-
collect(obj[key], depth + 1);
|
|
715
|
-
}
|
|
716
|
-
} catch {
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
}
|
|
720
|
-
};
|
|
721
|
-
|
|
722
|
-
for (const key of Object.keys(this.api)) {
|
|
723
|
-
collect(this.api[key]);
|
|
724
|
-
}
|
|
725
|
-
|
|
726
|
-
if (pending.length > 0) {
|
|
727
|
-
await Promise.allSettled(pending);
|
|
728
|
-
}
|
|
729
|
-
}
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
async shutdown() {
|
|
733
|
-
if (!this.isLoaded) {
|
|
734
|
-
return;
|
|
735
|
-
}
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
await this._drainInFlightLoads();
|
|
741
|
-
|
|
742
|
-
|
|
743
|
-
disableEventEmitterPatching();
|
|
744
|
-
cleanupEventEmitterResources();
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
if (this.instanceID && this.contextManager) {
|
|
748
|
-
this.contextManager.cleanup(this.instanceID);
|
|
749
|
-
}
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
|
|
754
|
-
if (this.handlers.ownership) {
|
|
755
|
-
this.handlers.ownership.clear();
|
|
756
|
-
}
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
this.handlers.versionManager?.shutdown();
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
await this.handlers.permissionManager?.shutdown();
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
this.isLoaded = false;
|
|
767
|
-
}
|
|
768
|
-
|
|
769
|
-
|
|
770
|
-
debug(code, context = {}) {
|
|
771
|
-
if (this.debugLogger) {
|
|
772
|
-
this.debugLogger.log(code, context);
|
|
773
|
-
}
|
|
774
|
-
}
|
|
775
|
-
|
|
776
|
-
|
|
777
|
-
getAPI() {
|
|
778
|
-
if (!this.isLoaded) {
|
|
779
|
-
throw new SlothletError(
|
|
780
|
-
"INVALID_CONFIG_NOT_LOADED",
|
|
781
|
-
{
|
|
782
|
-
operation: "getAPI"
|
|
783
|
-
},
|
|
784
|
-
null,
|
|
785
|
-
{ validationError: true }
|
|
786
|
-
);
|
|
787
|
-
}
|
|
788
|
-
return this.boundApi;
|
|
789
|
-
}
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
getDiagnostics() {
|
|
793
|
-
return {
|
|
794
|
-
instanceID: this.instanceID,
|
|
795
|
-
isLoaded: this.isLoaded,
|
|
796
|
-
config: this.config,
|
|
797
|
-
context: this.contextManager?.getDiagnostics() || null,
|
|
798
|
-
ownership: this.handlers.ownership?.getDiagnostics() || null
|
|
799
|
-
};
|
|
800
|
-
}
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
getOwnership() {
|
|
804
|
-
if (!this.handlers.ownership) {
|
|
805
|
-
return null;
|
|
806
|
-
}
|
|
807
|
-
return this.handlers.ownership.getDiagnostics();
|
|
808
|
-
}
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
buildFinalAPI(userApi) {
|
|
812
|
-
return this.builders.apiBuilder.buildFinalAPI(userApi);
|
|
813
|
-
}
|
|
814
|
-
}
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
export async function slothlet(config) {
|
|
818
|
-
const instance = new Slothlet();
|
|
819
|
-
const api = await instance.load(config);
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
return api;
|
|
823
|
-
}
|
|
824
|
-
|
|
825
|
-
export default slothlet;
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
17
|
+
import{readdirSync}from"node:fs";import{dirname,join}from"node:path";import{fileURLToPath,pathToFileURL}from"node:url";import{getContextManager}from"@cldmv/slothlet/factories/context";import{SlothletError,SlothletWarning,SlothletDebug}from"@cldmv/slothlet/errors";import{registerInstance}from"@cldmv/slothlet/handlers/lifecycle-token";import{resolveWrapper}from"@cldmv/slothlet/handlers/unified-wrapper";import{initI18n}from"@cldmv/slothlet/i18n";import{enableEventEmitterPatching,disableEventEmitterPatching,cleanupEventEmitterResources,setApiContextChecker}from"@cldmv/slothlet/helpers/eventemitter-context";class Slothlet{static RESERVED_ROOT_KEYS=["slothlet","shutdown","destroy"];static SKIP_PROPS=["__metadata","__type","_materialize","_impl","____slothletInternal"];constructor(){this.SlothletError=SlothletError;this.SlothletWarning=SlothletWarning;this.debugLogger=null;this.instanceID=null;this.config=null;this.api=null;this.boundApi=null;this.contextManager=null;this.isLoaded=false;this.reference=null;this.context=null;this.envSnapshot=null;this._totalLazyCount=0;this._unmaterializedLazyCount=0;this._materializationComplete=false;this._materializationWaiters=[];this._materializationCompleteEmitted=false;this.componentCategories=["helpers","handlers","builders","processors","modes"];for(const category of this.componentCategories){this[category]={}}}async _initializeComponents(){const baseDir=join(dirname(fileURLToPath(import.meta.url)),"lib");for(const category of this.componentCategories){const categoryDir=join(baseDir,category);const files=readdirSync(categoryDir).filter(f=>f.endsWith(".mjs"));for(const file of files){const filePath=join(categoryDir,file);try{const module=await import(pathToFileURL(filePath).href);const classExports=Object.values(module).filter(exp=>typeof exp==="function"&&exp.slothletProperty);for(const ClassExport of classExports){const propName=ClassExport.slothletProperty;this[category][propName]=new ClassExport(this);if(this.config?.debug?.initialization){this.debug("initialization",{key:"DEBUG_MODE_COMPONENT_INITIALIZED",component:ClassExport.name,category,propertyName:propName})}}}catch(error){throw new this.SlothletError("MODULE_IMPORT_FAILED",{modulePath:filePath},error)}}}}_setupLifecycleSubscribers(){if(!this.handlers.lifecycle){return}if(this.handlers.metadata){this.handlers.lifecycle.subscribe("impl:created",(data,token)=>{this.handlers.metadata.tagSystemMetadata(data.impl,{filePath:data.filePath,apiPath:data.apiPath,moduleID:data.moduleID,sourceFolder:data.sourceFolder},token)});this.handlers.lifecycle.subscribe("impl:changed",(data,token)=>{this.handlers.metadata.tagSystemMetadata(data.impl,{filePath:data.filePath,apiPath:data.apiPath,moduleID:data.moduleID,sourceFolder:data.sourceFolder},token)});this.handlers.lifecycle.subscribe("impl:removed",data=>{if(data.apiPath){const rootSegment=data.apiPath.split(".")[0];this.handlers.metadata.removeUserMetadataByApiPath(rootSegment)}})}if(this.handlers.ownership){this.handlers.lifecycle.subscribe("impl:created",data=>{const collisionMode=this.config?.collision?.api||"merge";const implValue=data.wrapper?.__impl??data.impl;this.handlers.ownership.register({moduleID:data.moduleID,apiPath:data.apiPath,value:implValue,source:data.source,filePath:data.filePath,collisionMode})});this.handlers.lifecycle.subscribe("impl:changed",data=>{const collisionMode=this.config?.collision?.api||"merge";const implValue=data.wrapper?.__impl??data.impl;const currentOwner=this.handlers.ownership.getCurrentOwner(data.apiPath);if(currentOwner?.moduleID!==data.moduleID){this.handlers.ownership.register({moduleID:data.moduleID,apiPath:data.apiPath,value:implValue,source:data.source,filePath:data.filePath,collisionMode})}})}}_registerLazyWrapper(){this._totalLazyCount++;this._unmaterializedLazyCount++;if(this.config?.debug?.materialize){this.debug("materialize",{key:"DEBUG_MODE_LAZY_WRAPPER_REGISTERED",total:this._totalLazyCount,unmaterialized:this._unmaterializedLazyCount})}}_onWrapperMaterialized(){this._unmaterializedLazyCount--;if(this.config?.debug?.materialize){this.debug("materialize",{key:"DEBUG_MODE_LAZY_WRAPPER_MATERIALIZED",total:this._totalLazyCount,unmaterialized:this._unmaterializedLazyCount,percentage:this._totalLazyCount>0?(this._totalLazyCount-this._unmaterializedLazyCount)/this._totalLazyCount*100:100})}if(this._unmaterializedLazyCount===0&&!this._materializationComplete){this._materializationComplete=true;if(this.config?.debug?.materialize){this.debug("materialize",{key:"DEBUG_MODE_ALL_LAZY_WRAPPERS_MATERIALIZED",total:this._totalLazyCount})}const waiters=this._materializationWaiters.splice(0);for(const resolve of waiters){resolve()}if(this.config?.tracking?.materialization&&!this._materializationCompleteEmitted){this._materializationCompleteEmitted=true;if(this.handlers?.lifecycle){this.handlers.lifecycle.emit("materialized:complete",{total:this._totalLazyCount,timestamp:Date.now()})}}}}_captureEnvSnapshot(envConfig){const rawInclude=envConfig?.include;const include=Array.isArray(rawInclude)?rawInclude.filter(key=>typeof key==="string"):null;const useAllowlist=include!==null&&include.length>0;const raw=useAllowlist?include.reduce((acc,key)=>{if(Object.prototype.hasOwnProperty.call(process.env,key)){acc[key]=process.env[key]}return acc},Object.create(null)):{...process.env};return Object.freeze(raw)}async load(config={},preservedInstanceID=null){this.config=config;if(!this.envSnapshot){this.envSnapshot=this._captureEnvSnapshot(config.env)}this.debugLogger=new SlothletDebug(config);await this._initializeComponents();registerInstance(this);this._setupLifecycleSubscribers();this.config=this.helpers.config.transformConfig(config);if(this.config?.i18n?.language){initI18n({language:this.config.i18n.language})}this.debugLogger=new SlothletDebug(this.config);this.instanceID=preservedInstanceID||this.helpers.utilities.generateId();this.reference=this.config.reference;this.context=this.config.context;this.contextManager=getContextManager(this.config.runtime);setApiContextChecker(()=>{const ctx=this.contextManager.tryGetContext();return!!(ctx&&ctx.self)});let store;if(preservedInstanceID&&this.contextManager.instances.has(preservedInstanceID)){this.contextManager.cleanup(preservedInstanceID);store=this.contextManager.initialize(this.instanceID,this.config)}else{store=this.contextManager.initialize(this.instanceID,this.config)}enableEventEmitterPatching();if(typeof this.contextManager.registerEventEmitterContextChecker==="function"){this.contextManager.registerEventEmitterContextChecker()}const baseModuleId=`base_${this.helpers.utilities.generateId().substring(0,8)}`;const baseApi=await this.builders.builder.buildAPI({dir:this.config.dir,mode:this.config.mode,moduleID:baseModuleId});this.api=baseApi;const apiWithBuiltins=await this.buildFinalAPI(this.api);if(this.handlers.apiCacheManager){this.handlers.apiCacheManager.set(baseModuleId,{endpoint:".",moduleID:baseModuleId,api:this.api,folderPath:this.config.dir,mode:this.config.mode,sanitizeOptions:this.config.sanitize||{},collisionMode:this.config.collision?.api||"merge",config:{...this.config},timestamp:Date.now()})}this.injectRuntimeMetadataFunctions(apiWithBuiltins);if(this.config.metadata&&typeof this.config.metadata==="object"){for(const[key,value]of Object.entries(this.config.metadata)){this.handlers.metadata.setGlobalMetadata(key,value)}this.handlers.metadata.registerUserMetadata(baseModuleId,this.config.metadata)}if(this.handlers.ownership){this.handlers.ownership.registerSubtree(apiWithBuiltins,baseModuleId,"")}if(!this.boundApi){const isCallable=typeof this.api==="function"||this.api&&typeof this.api.default==="function";const proxyTarget=isCallable?function(){}:{};this.boundApi=new Proxy(proxyTarget,{get:(target,prop)=>this.api?this.api[prop]:void 0,set:(target,prop,value)=>{if(this.api){this.api[prop]=value}return true},has:(target,prop)=>this.api?prop in this.api:false,ownKeys:____target=>this.api?Reflect.ownKeys(this.api):[],deleteProperty:(target,prop)=>this.api?delete this.api[prop]:true,apply:(target,thisArg,args)=>this.api?Reflect.apply(this.api,thisArg,args):void 0,construct:(target,args)=>this.api?Reflect.construct(this.api,args):{},getOwnPropertyDescriptor:(target,prop)=>{if(isCallable&&prop==="prototype"){return Object.getOwnPropertyDescriptor(target,prop)}if(this.api&&prop in this.api){const desc=Object.getOwnPropertyDescriptor(this.api,prop);if(desc){return{...desc,configurable:true}}}return void 0}})}store.self=this.boundApi;store.context=this.context||{};if(this.reference&&typeof this.reference==="object"){Object.assign(this.boundApi,this.reference)}this.isLoaded=true;return this.boundApi}async reload(options={}){const{keepInstanceID=false}=options;if(!this.config?.dir){throw new SlothletError("INVALID_CONFIG_NOT_LOADED",{operation:"reload",validationError:true})}const operationHistory=this.handlers.apiManager?.state?.operationHistory?[...this.handlers.apiManager.state.operationHistory]:[];await this._clearModuleCaches();const oldInstanceID=this.instanceID;if(!keepInstanceID){this.instanceID=`${oldInstanceID}_reload_${Date.now()}`}const savedMetadataState=this.handlers.metadata?.exportUserState?.();const savedHooks=this.handlers.hookManager?.exportHooks?.();await this.load(this.config,this.instanceID);if(savedMetadataState&&this.handlers.metadata){this.handlers.metadata.importUserState(savedMetadataState)}if(savedHooks?.length&&this.handlers.hookManager){this.handlers.hookManager.importHooks(savedHooks)}for(const[,store]of this.contextManager.instances){if(store.parentInstanceID===oldInstanceID){store.parentInstanceID=this.instanceID}}if(oldInstanceID&&oldInstanceID!==this.instanceID&&this.contextManager.instances?.has(oldInstanceID)){this.contextManager.cleanup(oldInstanceID)}for(const operation of operationHistory){if(operation.type==="add"){await this.handlers.apiManager.addApiComponent({apiPath:operation.apiPath,folderPath:operation.folderPath,options:{...operation.options||{},recordHistory:false},moduleID:`replay_${this.helpers.utilities.generateId().substring(0,8)}`,versionConfig:operation.versionConfig||null})}else if(operation.type==="remove"){const{parts}=this.handlers.apiManager.normalizeApiPath(operation.apiPath);this.handlers.apiManager.deletePath(this.api,parts);if(this.handlers.metadata){const rootSegment=operation.apiPath.split(".")[0];this.handlers.metadata.removeUserMetadataByApiPath(rootSegment)}}else if(operation.type==="addPermissionRule"){if(this.handlers.permissionManager){this.handlers.permissionManager.addRule(operation.rule,operation.ownerModuleID,operation.ruleId)}}else if(operation.type==="removePermissionRule"){if(this.handlers.permissionManager){this.handlers.permissionManager.removeRule(operation.ruleId,operation.callerModuleID)}}}return this.boundApi}async _clearModuleCaches(){const targetDir=this.config.dir;const{resolve}=await import("node:path");const{createRequire}=await import("node:module");const require2=createRequire(import.meta.url);const absoluteTargetDir=resolve(targetDir);for(const key of Object.keys(require2.cache)){if(key.startsWith(absoluteTargetDir)){delete require2.cache[key]}}}injectRuntimeMetadataFunctions(api){if(!api.slothlet?.metadata){return}const metadataHandler=this.handlers.metadata;api.slothlet.metadata.get=async function slothlet_metadata_get_runtime(path){return metadataHandler.get(path)};api.slothlet.metadata.self=function slothlet_metadata_self_runtime(){return metadataHandler.self()};api.slothlet.metadata.caller=function slothlet_metadata_caller_runtime(){return metadataHandler.caller()}}async _drainInFlightLoads(){if(!this.api)return;const pending=[];const seen=new Set;const collect=(obj,depth=0)=>{const objType=typeof obj;if(!obj||objType!=="object"&&objType!=="function"||depth>15||seen.has(obj))return;seen.add(obj);try{if(obj.__isVersionDispatcher===true)return;const wrapper=resolveWrapper(obj);if(wrapper){const mat=wrapper.____slothletInternal.materializationPromise;if(mat)pending.push(mat);for(const key of Object.keys(wrapper)){if(!key.startsWith("____"))collect(wrapper[key],depth+1)}return}for(const key of Object.keys(obj)){collect(obj[key],depth+1)}}catch{}};for(const key of Object.keys(this.api)){collect(this.api[key])}if(pending.length>0){await Promise.allSettled(pending)}}async shutdown(){if(!this.isLoaded){return}await this._drainInFlightLoads();disableEventEmitterPatching();cleanupEventEmitterResources();if(this.instanceID&&this.contextManager){this.contextManager.cleanup(this.instanceID)}if(this.handlers.ownership){this.handlers.ownership.clear()}this.handlers.versionManager?.shutdown();await this.handlers.permissionManager?.shutdown();this.isLoaded=false}debug(code,context={}){if(this.debugLogger){this.debugLogger.log(code,context)}}getAPI(){if(!this.isLoaded){throw new SlothletError("INVALID_CONFIG_NOT_LOADED",{operation:"getAPI"},null,{validationError:true})}return this.boundApi}getDiagnostics(){return{instanceID:this.instanceID,isLoaded:this.isLoaded,config:this.config,context:this.contextManager?.getDiagnostics()||null,ownership:this.handlers.ownership?.getDiagnostics()||null}}getOwnership(){if(!this.handlers.ownership){return null}return this.handlers.ownership.getDiagnostics()}buildFinalAPI(userApi){return this.builders.apiBuilder.buildFinalAPI(userApi)}}async function slothlet(config){const instance=new Slothlet;const api=await instance.load(config);return api}var stdin_default=slothlet;export{stdin_default as default,slothlet};
|