@cldmv/slothlet 2.11.0 → 3.0.1
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/AGENT-USAGE.md +355 -325
- package/README.md +554 -238
- package/dist/lib/builders/api-assignment.mjs +605 -0
- package/dist/lib/builders/api_builder.mjs +1073 -0
- package/dist/lib/builders/builder.mjs +94 -0
- package/dist/lib/builders/modes-processor.mjs +1816 -0
- package/dist/lib/errors.mjs +227 -0
- package/dist/lib/factories/component-base.mjs +96 -0
- package/dist/lib/factories/context.mjs +38 -0
- package/dist/lib/handlers/api-cache-manager.mjs +216 -0
- package/dist/lib/handlers/api-manager.mjs +2364 -0
- package/dist/lib/handlers/context-async.mjs +184 -0
- package/dist/lib/handlers/context-live.mjs +184 -0
- package/dist/lib/handlers/hook-manager.mjs +789 -0
- package/dist/lib/handlers/lifecycle-token.mjs +44 -0
- package/dist/lib/handlers/lifecycle.mjs +131 -0
- package/dist/lib/handlers/materialize-manager.mjs +64 -0
- package/dist/lib/handlers/metadata.mjs +500 -0
- package/dist/lib/handlers/ownership.mjs +338 -0
- package/dist/lib/handlers/unified-wrapper.mjs +3031 -0
- package/dist/lib/helpers/class-instance-wrapper.mjs +125 -0
- package/dist/lib/helpers/config.mjs +343 -0
- package/dist/lib/helpers/eventemitter-context.mjs +365 -0
- package/dist/lib/helpers/hint-detector.mjs +63 -0
- package/dist/lib/helpers/modes-utils.mjs +53 -0
- package/dist/lib/helpers/resolve-from-caller.mjs +123 -117
- package/dist/lib/helpers/sanitize.mjs +247 -168
- package/dist/lib/helpers/utilities.mjs +46 -81
- package/dist/lib/i18n/languages/de-de.json +377 -0
- package/dist/lib/i18n/languages/en-gb.json +377 -0
- package/dist/lib/i18n/languages/en-us.json +377 -0
- package/dist/lib/i18n/languages/es-mx.json +377 -0
- package/dist/lib/i18n/languages/fr-fr.json +377 -0
- package/dist/lib/i18n/languages/hi-in.json +377 -0
- package/dist/lib/i18n/languages/ja-jp.json +377 -0
- package/dist/lib/i18n/languages/ko-kr.json +377 -0
- package/dist/lib/i18n/languages/pt-br.json +377 -0
- package/dist/lib/i18n/languages/ru-ru.json +377 -0
- package/dist/lib/i18n/languages/zh-cn.json +377 -0
- package/dist/lib/i18n/translations.mjs +140 -0
- package/dist/lib/modes/eager.mjs +75 -0
- package/dist/lib/modes/lazy.mjs +97 -0
- package/dist/lib/processors/flatten.mjs +453 -0
- package/dist/lib/processors/loader.mjs +355 -0
- package/dist/lib/processors/type-generator.mjs +291 -0
- package/dist/lib/processors/typescript.mjs +188 -0
- package/dist/lib/runtime/runtime-asynclocalstorage.mjs +80 -522
- package/dist/lib/runtime/runtime-livebindings.mjs +45 -390
- package/dist/lib/runtime/runtime.mjs +39 -159
- package/dist/slothlet.mjs +525 -744
- package/docs/API-RULES.md +338 -486
- package/index.cjs +4 -4
- package/index.mjs +82 -45
- package/package.json +143 -30
- package/types/dist/lib/builders/api-assignment.d.mts +97 -0
- package/types/dist/lib/builders/api-assignment.d.mts.map +1 -0
- package/types/dist/lib/builders/api_builder.d.mts +96 -0
- package/types/dist/lib/builders/api_builder.d.mts.map +1 -0
- package/types/dist/lib/builders/builder.d.mts +60 -0
- package/types/dist/lib/builders/builder.d.mts.map +1 -0
- package/types/dist/lib/builders/modes-processor.d.mts +32 -0
- package/types/dist/lib/builders/modes-processor.d.mts.map +1 -0
- package/types/dist/lib/errors.d.mts +118 -0
- package/types/dist/lib/errors.d.mts.map +1 -0
- package/types/dist/lib/factories/component-base.d.mts +182 -0
- package/types/dist/lib/factories/component-base.d.mts.map +1 -0
- package/types/dist/lib/factories/context.d.mts +26 -0
- package/types/dist/lib/factories/context.d.mts.map +1 -0
- package/types/dist/lib/handlers/api-cache-manager.d.mts +208 -0
- package/types/dist/lib/handlers/api-cache-manager.d.mts.map +1 -0
- package/types/dist/lib/handlers/api-manager.d.mts +392 -0
- package/types/dist/lib/handlers/api-manager.d.mts.map +1 -0
- package/types/dist/lib/handlers/context-async.d.mts +66 -0
- package/types/dist/lib/handlers/context-async.d.mts.map +1 -0
- package/types/dist/lib/handlers/context-live.d.mts +65 -0
- package/types/dist/lib/handlers/context-live.d.mts.map +1 -0
- package/types/dist/lib/handlers/hook-manager.d.mts +199 -0
- package/types/dist/lib/handlers/hook-manager.d.mts.map +1 -0
- package/types/dist/lib/handlers/lifecycle-token.d.mts +49 -0
- package/types/dist/lib/handlers/lifecycle-token.d.mts.map +1 -0
- package/types/dist/lib/handlers/lifecycle.d.mts +90 -0
- package/types/dist/lib/handlers/lifecycle.d.mts.map +1 -0
- package/types/dist/lib/handlers/materialize-manager.d.mts +75 -0
- package/types/dist/lib/handlers/materialize-manager.d.mts.map +1 -0
- package/types/dist/lib/handlers/metadata.d.mts +215 -0
- package/types/dist/lib/handlers/metadata.d.mts.map +1 -0
- package/types/dist/lib/handlers/ownership.d.mts +170 -0
- package/types/dist/lib/handlers/ownership.d.mts.map +1 -0
- package/types/dist/lib/handlers/unified-wrapper.d.mts +250 -0
- package/types/dist/lib/handlers/unified-wrapper.d.mts.map +1 -0
- package/types/dist/lib/helpers/class-instance-wrapper.d.mts +54 -0
- package/types/dist/lib/helpers/class-instance-wrapper.d.mts.map +1 -0
- package/types/dist/lib/helpers/config.d.mts +96 -0
- package/types/dist/lib/helpers/config.d.mts.map +1 -0
- package/types/dist/lib/helpers/eventemitter-context.d.mts +31 -0
- package/types/dist/lib/helpers/eventemitter-context.d.mts.map +1 -0
- package/types/dist/lib/helpers/hint-detector.d.mts +20 -0
- package/types/dist/lib/helpers/hint-detector.d.mts.map +1 -0
- package/types/dist/lib/helpers/modes-utils.d.mts +35 -0
- package/types/dist/lib/helpers/modes-utils.d.mts.map +1 -0
- package/types/dist/lib/helpers/resolve-from-caller.d.mts +29 -145
- package/types/dist/lib/helpers/resolve-from-caller.d.mts.map +1 -1
- package/types/dist/lib/helpers/sanitize.d.mts +95 -94
- package/types/dist/lib/helpers/sanitize.d.mts.map +1 -1
- package/types/dist/lib/helpers/utilities.d.mts +53 -116
- package/types/dist/lib/helpers/utilities.d.mts.map +1 -1
- package/types/dist/lib/i18n/translations.d.mts +39 -0
- package/types/dist/lib/i18n/translations.d.mts.map +1 -0
- package/types/dist/lib/modes/eager.d.mts +36 -0
- package/types/dist/lib/modes/eager.d.mts.map +1 -0
- package/types/dist/lib/modes/lazy.d.mts +49 -0
- package/types/dist/lib/modes/lazy.d.mts.map +1 -0
- package/types/dist/lib/processors/flatten.d.mts +114 -0
- package/types/dist/lib/processors/flatten.d.mts.map +1 -0
- package/types/dist/lib/processors/loader.d.mts +47 -0
- package/types/dist/lib/processors/loader.d.mts.map +1 -0
- package/types/dist/lib/processors/type-generator.d.mts +19 -0
- package/types/dist/lib/processors/type-generator.d.mts.map +1 -0
- package/types/dist/lib/processors/typescript.d.mts +55 -0
- package/types/dist/lib/processors/typescript.d.mts.map +1 -0
- package/types/dist/lib/runtime/runtime-asynclocalstorage.d.mts +47 -42
- package/types/dist/lib/runtime/runtime-asynclocalstorage.d.mts.map +1 -1
- package/types/dist/lib/runtime/runtime-livebindings.d.mts +34 -65
- package/types/dist/lib/runtime/runtime-livebindings.d.mts.map +1 -1
- package/types/dist/lib/runtime/runtime.d.mts +39 -9
- package/types/dist/lib/runtime/runtime.d.mts.map +1 -1
- package/types/dist/slothlet.d.mts +184 -111
- package/types/dist/slothlet.d.mts.map +1 -1
- package/types/index.d.mts +1 -3
- package/dist/lib/engine/README.md +0 -21
- package/dist/lib/engine/slothlet_child.mjs +0 -59
- package/dist/lib/engine/slothlet_engine.mjs +0 -372
- package/dist/lib/engine/slothlet_esm.mjs +0 -230
- package/dist/lib/engine/slothlet_helpers.mjs +0 -455
- package/dist/lib/engine/slothlet_worker.mjs +0 -149
- package/dist/lib/helpers/als-eventemitter.mjs +0 -256
- package/dist/lib/helpers/api_builder/add_api.mjs +0 -553
- package/dist/lib/helpers/api_builder/analysis.mjs +0 -532
- package/dist/lib/helpers/api_builder/construction.mjs +0 -495
- package/dist/lib/helpers/api_builder/decisions.mjs +0 -748
- package/dist/lib/helpers/api_builder/metadata.mjs +0 -248
- package/dist/lib/helpers/api_builder.mjs +0 -41
- package/dist/lib/helpers/auto-wrap.mjs +0 -62
- package/dist/lib/helpers/hooks.mjs +0 -389
- package/dist/lib/helpers/instance-manager.mjs +0 -111
- package/dist/lib/helpers/metadata-api.mjs +0 -201
- package/dist/lib/helpers/multidefault.mjs +0 -216
- package/dist/lib/modes/slothlet_eager.mjs +0 -154
- package/dist/lib/modes/slothlet_lazy.mjs +0 -594
- package/docs/API-RULES-CONDITIONS.md +0 -712
- package/types/dist/lib/engine/slothlet_child.d.mts +0 -2
- package/types/dist/lib/engine/slothlet_child.d.mts.map +0 -1
- package/types/dist/lib/engine/slothlet_engine.d.mts +0 -31
- package/types/dist/lib/engine/slothlet_engine.d.mts.map +0 -1
- package/types/dist/lib/engine/slothlet_esm.d.mts +0 -19
- package/types/dist/lib/engine/slothlet_esm.d.mts.map +0 -1
- package/types/dist/lib/engine/slothlet_helpers.d.mts +0 -25
- package/types/dist/lib/engine/slothlet_helpers.d.mts.map +0 -1
- package/types/dist/lib/engine/slothlet_worker.d.mts +0 -2
- package/types/dist/lib/engine/slothlet_worker.d.mts.map +0 -1
- package/types/dist/lib/helpers/als-eventemitter.d.mts +0 -56
- package/types/dist/lib/helpers/als-eventemitter.d.mts.map +0 -1
- package/types/dist/lib/helpers/api_builder/add_api.d.mts +0 -102
- package/types/dist/lib/helpers/api_builder/add_api.d.mts.map +0 -1
- package/types/dist/lib/helpers/api_builder/analysis.d.mts +0 -189
- package/types/dist/lib/helpers/api_builder/analysis.d.mts.map +0 -1
- package/types/dist/lib/helpers/api_builder/construction.d.mts +0 -107
- package/types/dist/lib/helpers/api_builder/construction.d.mts.map +0 -1
- package/types/dist/lib/helpers/api_builder/decisions.d.mts +0 -213
- package/types/dist/lib/helpers/api_builder/decisions.d.mts.map +0 -1
- package/types/dist/lib/helpers/api_builder/metadata.d.mts +0 -99
- package/types/dist/lib/helpers/api_builder/metadata.d.mts.map +0 -1
- package/types/dist/lib/helpers/api_builder.d.mts +0 -6
- package/types/dist/lib/helpers/api_builder.d.mts.map +0 -1
- package/types/dist/lib/helpers/auto-wrap.d.mts +0 -49
- package/types/dist/lib/helpers/auto-wrap.d.mts.map +0 -1
- package/types/dist/lib/helpers/hooks.d.mts +0 -342
- package/types/dist/lib/helpers/hooks.d.mts.map +0 -1
- package/types/dist/lib/helpers/instance-manager.d.mts +0 -41
- package/types/dist/lib/helpers/instance-manager.d.mts.map +0 -1
- package/types/dist/lib/helpers/metadata-api.d.mts +0 -132
- package/types/dist/lib/helpers/metadata-api.d.mts.map +0 -1
- package/types/dist/lib/helpers/multidefault.d.mts +0 -90
- package/types/dist/lib/helpers/multidefault.d.mts.map +0 -1
- package/types/dist/lib/modes/slothlet_eager.d.mts +0 -65
- package/types/dist/lib/modes/slothlet_eager.d.mts.map +0 -1
- package/types/dist/lib/modes/slothlet_lazy.d.mts +0 -31
- package/types/dist/lib/modes/slothlet_lazy.d.mts.map +0 -1
- package/types/index.d.mts.map +0 -1
|
@@ -0,0 +1,1073 @@
|
|
|
1
|
+
/*
|
|
2
|
+
Copyright 2026 CLDMV/Shinrai
|
|
3
|
+
|
|
4
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
5
|
+
you may not use this file except in compliance with the License.
|
|
6
|
+
You may obtain a copy of the License at
|
|
7
|
+
|
|
8
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
9
|
+
|
|
10
|
+
Unless required by applicable law or agreed to in writing, software
|
|
11
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
12
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
13
|
+
See the License for the specific language governing permissions and
|
|
14
|
+
limitations under the License.
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
import { ComponentBase } from "@cldmv/slothlet/factories/component-base";
|
|
21
|
+
import { TYPE_STATES } from "@cldmv/slothlet/handlers/unified-wrapper";
|
|
22
|
+
import { getLanguage, initI18n, setLanguage, t, translate } from "@cldmv/slothlet/i18n";
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
function _resolvePathOrModuleId(slothlet, pathOrModuleId) {
|
|
28
|
+
const history = slothlet.handlers?.apiManager?.state?.addHistory;
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
if (history) {
|
|
33
|
+
const match = history.findLast((entry) => entry.moduleID === pathOrModuleId);
|
|
34
|
+
if (match) return match.apiPath;
|
|
35
|
+
}
|
|
36
|
+
return pathOrModuleId;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
export class ApiBuilder extends ComponentBase {
|
|
41
|
+
static slothletProperty = "apiBuilder";
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
constructor(slothlet) {
|
|
45
|
+
super(slothlet);
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
async buildFinalAPI(userApi) {
|
|
50
|
+
this.slothlet.debug("api", {
|
|
51
|
+
key: "DEBUG_MODE_BUILD_FINAL_API_CALLED",
|
|
52
|
+
diagnostics: this.____config.diagnostics,
|
|
53
|
+
userApiKeys: Object.keys(userApi)
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
if (this.slothlet._ownBuiltins) {
|
|
73
|
+
for (const [key, ref] of Object.entries(this.slothlet._ownBuiltins)) {
|
|
74
|
+
if (ref && Object.prototype.hasOwnProperty.call(userApi, key) && userApi[key] === ref) {
|
|
75
|
+
try {
|
|
76
|
+
delete userApi[key];
|
|
77
|
+
} catch (_) {
|
|
78
|
+
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
this.slothlet.userHooks = {
|
|
89
|
+
shutdown: typeof userApi.shutdown === "function" ? userApi.shutdown : null,
|
|
90
|
+
destroy: typeof userApi.destroy === "function" ? userApi.destroy : null
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
if (userApi.slothlet) {
|
|
96
|
+
new this.SlothletWarning("WARNING_RESERVED_PROPERTY_CONFLICT", { properties: "slothlet" });
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
|
|
100
|
+
const slothletNamespace = await this.createSlothletNamespace(userApi);
|
|
101
|
+
|
|
102
|
+
this.slothlet.debug("api", {
|
|
103
|
+
key: "DEBUG_MODE_SLOTHLET_NAMESPACE_CREATED",
|
|
104
|
+
namespaceKeys: Object.keys(slothletNamespace),
|
|
105
|
+
hasDiag: !!slothletNamespace.diag
|
|
106
|
+
});
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
const shutdownFn = this.createShutdownFunction();
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
this.attachBuiltins(userApi, {
|
|
113
|
+
slothlet: slothletNamespace,
|
|
114
|
+
shutdown: shutdownFn,
|
|
115
|
+
destroy: null
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
this.slothlet.debug("api", {
|
|
119
|
+
key: "DEBUG_MODE_BUILT_INS_ATTACHED",
|
|
120
|
+
userApiKeys: Object.keys(userApi),
|
|
121
|
+
hasSlothlet: !!userApi.slothlet,
|
|
122
|
+
hasDiag: !!userApi.slothlet?.diag
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
|
|
126
|
+
const destroyWithApi = this.createDestroyFunction(userApi);
|
|
127
|
+
Object.defineProperty(userApi, "destroy", {
|
|
128
|
+
value: destroyWithApi,
|
|
129
|
+
enumerable: true,
|
|
130
|
+
writable: false,
|
|
131
|
+
configurable: true
|
|
132
|
+
});
|
|
133
|
+
|
|
134
|
+
|
|
135
|
+
|
|
136
|
+
this.slothlet._ownBuiltins = {
|
|
137
|
+
shutdown: shutdownFn,
|
|
138
|
+
slothlet: slothletNamespace,
|
|
139
|
+
destroy: destroyWithApi
|
|
140
|
+
};
|
|
141
|
+
|
|
142
|
+
return userApi;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
async createSlothletNamespace(userApi) {
|
|
147
|
+
const slothlet = this.slothlet;
|
|
148
|
+
const config = this.____config;
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
let version = "unknown";
|
|
152
|
+
try {
|
|
153
|
+
const pkgPath = new URL("../../../package.json", import.meta.url);
|
|
154
|
+
const { readFile } = await import("node:fs/promises");
|
|
155
|
+
const pkgContent = await readFile(pkgPath, "utf-8");
|
|
156
|
+
const pkg = JSON.parse(pkgContent);
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
version = pkg.version || "unknown";
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
|
|
163
|
+
} catch {
|
|
164
|
+
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
const namespace = {
|
|
168
|
+
|
|
169
|
+
i18n: {
|
|
170
|
+
setLanguage,
|
|
171
|
+
getLanguage,
|
|
172
|
+
translate,
|
|
173
|
+
t,
|
|
174
|
+
initI18n
|
|
175
|
+
},
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
version,
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
instanceID: slothlet.instanceID,
|
|
182
|
+
|
|
183
|
+
|
|
184
|
+
types: TYPE_STATES,
|
|
185
|
+
|
|
186
|
+
|
|
187
|
+
api: {
|
|
188
|
+
|
|
189
|
+
add: async function slothlet_api_add(apiPath, folderPath, options = {}) {
|
|
190
|
+
|
|
191
|
+
if (!config.api?.mutations?.add) {
|
|
192
|
+
throw new slothlet.SlothletError("INVALID_CONFIG_MUTATIONS_DISABLED", {
|
|
193
|
+
operation: "api.add",
|
|
194
|
+
validationError: true
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
|
|
202
|
+
const {
|
|
203
|
+
recordHistory: ____recordHistory,
|
|
204
|
+
collisionMode: ____collisionMode,
|
|
205
|
+
mutateExisting: ____mutateExisting,
|
|
206
|
+
...filteredOptions
|
|
207
|
+
} = options;
|
|
208
|
+
return slothlet.handlers.apiManager.addApiComponent({
|
|
209
|
+
apiPath,
|
|
210
|
+
folderPath,
|
|
211
|
+
options: filteredOptions
|
|
212
|
+
});
|
|
213
|
+
},
|
|
214
|
+
|
|
215
|
+
|
|
216
|
+
remove: async function slothlet_api_remove(pathOrModuleId) {
|
|
217
|
+
|
|
218
|
+
if (!config.api?.mutations?.remove) {
|
|
219
|
+
throw new slothlet.SlothletError("INVALID_CONFIG_MUTATIONS_DISABLED", {
|
|
220
|
+
operation: "api.remove",
|
|
221
|
+
validationError: true
|
|
222
|
+
});
|
|
223
|
+
}
|
|
224
|
+
if (typeof pathOrModuleId !== "string") {
|
|
225
|
+
throw new slothlet.SlothletError("INVALID_ARGUMENT", {
|
|
226
|
+
argument: "pathOrModuleId",
|
|
227
|
+
expected: "string",
|
|
228
|
+
received: typeof pathOrModuleId,
|
|
229
|
+
validationError: true
|
|
230
|
+
});
|
|
231
|
+
}
|
|
232
|
+
return slothlet.handlers.apiManager.removeApiComponent(pathOrModuleId);
|
|
233
|
+
},
|
|
234
|
+
|
|
235
|
+
|
|
236
|
+
reload: async function slothlet_api_reload(pathOrModuleId, options) {
|
|
237
|
+
|
|
238
|
+
if (!config.api?.mutations?.reload) {
|
|
239
|
+
throw new slothlet.SlothletError("INVALID_CONFIG_MUTATIONS_DISABLED", {
|
|
240
|
+
operation: "api.reload",
|
|
241
|
+
validationError: true
|
|
242
|
+
});
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
|
|
246
|
+
if (pathOrModuleId == null || pathOrModuleId === "" || pathOrModuleId === ".") {
|
|
247
|
+
return slothlet.handlers.apiManager.reloadApiComponent({ apiPath: ".", options });
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
if (typeof pathOrModuleId !== "string") {
|
|
251
|
+
throw new slothlet.SlothletError("INVALID_ARGUMENT", {
|
|
252
|
+
argument: "pathOrModuleId",
|
|
253
|
+
expected: "string, null, undefined, or '.'",
|
|
254
|
+
received: typeof pathOrModuleId,
|
|
255
|
+
validationError: true
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
|
|
260
|
+
const isModuleId = slothlet.handlers.apiManager.state.addHistory.some((entry) => entry.moduleID === pathOrModuleId);
|
|
261
|
+
|
|
262
|
+
if (isModuleId) {
|
|
263
|
+
return slothlet.handlers.apiManager.reloadApiComponent({ moduleID: pathOrModuleId, options });
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
|
|
267
|
+
const normalizedPath = slothlet.handlers.apiManager.normalizeApiPath(pathOrModuleId).apiPath;
|
|
268
|
+
const pathParts = normalizedPath.split(".");
|
|
269
|
+
let current = slothlet.api;
|
|
270
|
+
for (const part of pathParts) {
|
|
271
|
+
if (!current || (typeof current !== "object" && typeof current !== "function")) {
|
|
272
|
+
throw new slothlet.SlothletError("INVALID_API_PATH", {
|
|
273
|
+
apiPath: pathOrModuleId,
|
|
274
|
+
validationError: true
|
|
275
|
+
});
|
|
276
|
+
}
|
|
277
|
+
current = current[part];
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
if (current === undefined) {
|
|
281
|
+
throw new slothlet.SlothletError("INVALID_API_PATH", {
|
|
282
|
+
apiPath: pathOrModuleId,
|
|
283
|
+
validationError: true
|
|
284
|
+
});
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
|
|
288
|
+
return slothlet.handlers.apiManager.reloadApiComponent({ apiPath: normalizedPath, options });
|
|
289
|
+
}
|
|
290
|
+
},
|
|
291
|
+
|
|
292
|
+
|
|
293
|
+
sanitize: function slothlet_sanitize(str) {
|
|
294
|
+
if (typeof str !== "string") {
|
|
295
|
+
throw new slothlet.SlothletError("INVALID_ARGUMENT", {
|
|
296
|
+
argument: "str",
|
|
297
|
+
expected: "string",
|
|
298
|
+
received: typeof str,
|
|
299
|
+
validationError: true
|
|
300
|
+
});
|
|
301
|
+
}
|
|
302
|
+
return slothlet.helpers.sanitize.sanitizePropertyName(str, slothlet.config.sanitize || {});
|
|
303
|
+
},
|
|
304
|
+
|
|
305
|
+
|
|
306
|
+
context: {
|
|
307
|
+
|
|
308
|
+
get: (key) => {
|
|
309
|
+
|
|
310
|
+
|
|
311
|
+
|
|
312
|
+
|
|
313
|
+
if (slothlet.contextManager.constructor.name === "LiveContextManager") {
|
|
314
|
+
const currentID = slothlet.contextManager.currentInstanceID;
|
|
315
|
+
|
|
316
|
+
|
|
317
|
+
|
|
318
|
+
|
|
319
|
+
if (currentID) {
|
|
320
|
+
const activeStore = slothlet.contextManager.instances.get(currentID);
|
|
321
|
+
const isOurInstance =
|
|
322
|
+
currentID === slothlet.instanceID ||
|
|
323
|
+
currentID?.startsWith(slothlet.instanceID + "__run_") ||
|
|
324
|
+
activeStore?.parentInstanceID === slothlet.instanceID;
|
|
325
|
+
|
|
326
|
+
if (isOurInstance && activeStore) {
|
|
327
|
+
return key ? activeStore.context[key] : { ...activeStore.context };
|
|
328
|
+
}
|
|
329
|
+
}
|
|
330
|
+
|
|
331
|
+
|
|
332
|
+
const store = slothlet.contextManager.instances.get(slothlet.instanceID);
|
|
333
|
+
|
|
334
|
+
|
|
335
|
+
|
|
336
|
+
if (!store) {
|
|
337
|
+
const baseContext = slothlet.context || {};
|
|
338
|
+
return key ? baseContext[key] : { ...baseContext };
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
|
|
342
|
+
return key ? store.context[key] : { ...store.context };
|
|
343
|
+
}
|
|
344
|
+
|
|
345
|
+
|
|
346
|
+
if (slothlet.contextManager.constructor.name === "AsyncContextManager") {
|
|
347
|
+
let currentStore = slothlet.contextManager.tryGetContext();
|
|
348
|
+
|
|
349
|
+
|
|
350
|
+
|
|
351
|
+
if (!currentStore) {
|
|
352
|
+
const baseStore = slothlet.contextManager.instances.get(slothlet.instanceID);
|
|
353
|
+
|
|
354
|
+
|
|
355
|
+
const baseContext = baseStore?.context || {};
|
|
356
|
+
return key ? baseContext[key] : { ...baseContext };
|
|
357
|
+
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
|
|
361
|
+
const isOurInstance =
|
|
362
|
+
currentStore.instanceID === slothlet.instanceID ||
|
|
363
|
+
currentStore.parentInstanceID === slothlet.instanceID ||
|
|
364
|
+
currentStore.instanceID.startsWith(slothlet.instanceID + "__run_");
|
|
365
|
+
|
|
366
|
+
if (isOurInstance) {
|
|
367
|
+
|
|
368
|
+
return key ? currentStore.context[key] : { ...currentStore.context };
|
|
369
|
+
}
|
|
370
|
+
|
|
371
|
+
|
|
372
|
+
const baseStore = slothlet.contextManager.instances.get(slothlet.instanceID);
|
|
373
|
+
|
|
374
|
+
|
|
375
|
+
const baseContext = baseStore?.context || {};
|
|
376
|
+
return key ? baseContext[key] : { ...baseContext };
|
|
377
|
+
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
|
|
381
|
+
|
|
382
|
+
|
|
383
|
+
|
|
384
|
+
const baseContext = slothlet.context || {};
|
|
385
|
+
return key ? baseContext[key] : { ...baseContext };
|
|
386
|
+
|
|
387
|
+
},
|
|
388
|
+
|
|
389
|
+
|
|
390
|
+
diagnostics: () => {
|
|
391
|
+
|
|
392
|
+
|
|
393
|
+
|
|
394
|
+
|
|
395
|
+
if (!slothlet.config?.diagnostics) return undefined;
|
|
396
|
+
const managerType = slothlet.contextManager.constructor.name;
|
|
397
|
+
const result = {
|
|
398
|
+
instanceID: slothlet.instanceID,
|
|
399
|
+
managerType,
|
|
400
|
+
instancesMapSize: slothlet.contextManager.instances.size,
|
|
401
|
+
instancesMapKeys: Array.from(slothlet.contextManager.instances.keys()),
|
|
402
|
+
baseContext: slothlet.context
|
|
403
|
+
};
|
|
404
|
+
|
|
405
|
+
|
|
406
|
+
const store = slothlet.contextManager.instances.get(slothlet.instanceID);
|
|
407
|
+
|
|
408
|
+
|
|
409
|
+
|
|
410
|
+
result.storeFromInstancesMap = store
|
|
411
|
+
? {
|
|
412
|
+
instanceID: store.instanceID,
|
|
413
|
+
context: store.context,
|
|
414
|
+
createdAt: store.createdAt
|
|
415
|
+
}
|
|
416
|
+
: null;
|
|
417
|
+
|
|
418
|
+
|
|
419
|
+
if (managerType === "AsyncContextManager") {
|
|
420
|
+
try {
|
|
421
|
+
const currentCtx = slothlet.contextManager.tryGetContext();
|
|
422
|
+
result.currentALSContext = currentCtx
|
|
423
|
+
? {
|
|
424
|
+
instanceID: currentCtx.instanceID,
|
|
425
|
+
context: currentCtx.context,
|
|
426
|
+
hasParent: !!currentCtx.parentContext,
|
|
427
|
+
parentInstanceID: currentCtx.parentInstanceID
|
|
428
|
+
}
|
|
429
|
+
: null;
|
|
430
|
+
|
|
431
|
+
|
|
432
|
+
|
|
433
|
+
} catch (____error) {
|
|
434
|
+
result.currentALSContext = null;
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
|
|
440
|
+
if (managerType === "LiveContextManager") {
|
|
441
|
+
result.currentInstanceID = slothlet.contextManager.currentInstanceID;
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
return result;
|
|
445
|
+
},
|
|
446
|
+
|
|
447
|
+
|
|
448
|
+
run: this.createRunFunction(),
|
|
449
|
+
|
|
450
|
+
|
|
451
|
+
scope: this.createScopeFunction()
|
|
452
|
+
},
|
|
453
|
+
|
|
454
|
+
|
|
455
|
+
hook: {
|
|
456
|
+
|
|
457
|
+
on: function slothlet_hook_on(typePattern, handler, options = {}) {
|
|
458
|
+
if (!slothlet.handlers?.hookManager) {
|
|
459
|
+
throw new slothlet.SlothletError("HOOKS_NOT_INITIALIZED", { validationError: true });
|
|
460
|
+
}
|
|
461
|
+
return slothlet.handlers.hookManager.on(typePattern, handler, options);
|
|
462
|
+
},
|
|
463
|
+
|
|
464
|
+
|
|
465
|
+
remove: function slothlet_hook_remove(filter = {}) {
|
|
466
|
+
if (!slothlet.handlers?.hookManager) {
|
|
467
|
+
throw new slothlet.SlothletError("HOOKS_NOT_INITIALIZED", { validationError: true });
|
|
468
|
+
}
|
|
469
|
+
return slothlet.handlers.hookManager.remove(filter);
|
|
470
|
+
},
|
|
471
|
+
|
|
472
|
+
|
|
473
|
+
clear: function slothlet_hook_clear(filter = {}) {
|
|
474
|
+
return this.remove(filter);
|
|
475
|
+
},
|
|
476
|
+
|
|
477
|
+
|
|
478
|
+
off: function slothlet_hook_off(idOrFilter) {
|
|
479
|
+
if (!slothlet.handlers?.hookManager) {
|
|
480
|
+
throw new slothlet.SlothletError("HOOKS_NOT_INITIALIZED", { validationError: true });
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
const filter = typeof idOrFilter === "string" ? { id: idOrFilter } : idOrFilter;
|
|
484
|
+
return slothlet.handlers.hookManager.remove(filter);
|
|
485
|
+
},
|
|
486
|
+
|
|
487
|
+
|
|
488
|
+
enable: function slothlet_hook_enable(filter = {}) {
|
|
489
|
+
if (!slothlet.handlers?.hookManager) {
|
|
490
|
+
throw new slothlet.SlothletError("HOOKS_NOT_INITIALIZED", { validationError: true });
|
|
491
|
+
}
|
|
492
|
+
return slothlet.handlers.hookManager.enable(filter);
|
|
493
|
+
},
|
|
494
|
+
|
|
495
|
+
|
|
496
|
+
disable: function slothlet_hook_disable(filter = {}) {
|
|
497
|
+
if (!slothlet.handlers?.hookManager) {
|
|
498
|
+
throw new slothlet.SlothletError("HOOKS_NOT_INITIALIZED", { validationError: true });
|
|
499
|
+
}
|
|
500
|
+
return slothlet.handlers.hookManager.disable(filter);
|
|
501
|
+
},
|
|
502
|
+
|
|
503
|
+
|
|
504
|
+
list: function slothlet_hook_list(filter = {}) {
|
|
505
|
+
if (!slothlet.handlers?.hookManager) {
|
|
506
|
+
throw new slothlet.SlothletError("HOOKS_NOT_INITIALIZED", { validationError: true });
|
|
507
|
+
}
|
|
508
|
+
return slothlet.handlers.hookManager.list(filter);
|
|
509
|
+
}
|
|
510
|
+
},
|
|
511
|
+
|
|
512
|
+
|
|
513
|
+
metadata: {
|
|
514
|
+
|
|
515
|
+
setGlobal: function slothlet_metadata_setGlobal(key, value) {
|
|
516
|
+
|
|
517
|
+
|
|
518
|
+
|
|
519
|
+
|
|
520
|
+
if (!slothlet.handlers?.metadata) {
|
|
521
|
+
throw new slothlet.SlothletError("METADATA_NOT_AVAILABLE", {
|
|
522
|
+
handlersKeys: slothlet.handlers ? Object.keys(slothlet.handlers).join(", ") : "undefined",
|
|
523
|
+
validationError: true
|
|
524
|
+
});
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
return slothlet.handlers.metadata.setGlobalMetadata(key, value);
|
|
528
|
+
},
|
|
529
|
+
|
|
530
|
+
|
|
531
|
+
set: function slothlet_metadata_set(fn, key, value) {
|
|
532
|
+
if (!slothlet.handlers?.metadata) {
|
|
533
|
+
throw new slothlet.SlothletError("METADATA_NOT_AVAILABLE", {
|
|
534
|
+
handlersKeys: slothlet.handlers
|
|
535
|
+
? Object.keys(slothlet.handlers).join(", ")
|
|
536
|
+
:
|
|
537
|
+
|
|
538
|
+
"undefined",
|
|
539
|
+
validationError: true
|
|
540
|
+
});
|
|
541
|
+
}
|
|
542
|
+
return slothlet.handlers.metadata.setUserMetadata(fn, key, value);
|
|
543
|
+
},
|
|
544
|
+
|
|
545
|
+
|
|
546
|
+
remove: function slothlet_metadata_remove(fn, key) {
|
|
547
|
+
return slothlet.handlers.metadata.removeUserMetadata(fn, key);
|
|
548
|
+
},
|
|
549
|
+
|
|
550
|
+
|
|
551
|
+
setFor: function slothlet_metadata_setFor(pathOrModuleId, keyOrObj, value) {
|
|
552
|
+
if (!slothlet.handlers?.metadata) {
|
|
553
|
+
throw new slothlet.SlothletError("METADATA_NOT_AVAILABLE", {
|
|
554
|
+
handlersKeys: slothlet.handlers
|
|
555
|
+
? Object.keys(slothlet.handlers).join(", ")
|
|
556
|
+
:
|
|
557
|
+
|
|
558
|
+
"undefined",
|
|
559
|
+
validationError: true
|
|
560
|
+
});
|
|
561
|
+
}
|
|
562
|
+
const resolvedPath = _resolvePathOrModuleId(slothlet, pathOrModuleId);
|
|
563
|
+
return slothlet.handlers.metadata.setPathMetadata(resolvedPath, keyOrObj, value);
|
|
564
|
+
},
|
|
565
|
+
|
|
566
|
+
|
|
567
|
+
removeFor: function slothlet_metadata_removeFor(pathOrModuleId, key) {
|
|
568
|
+
if (!slothlet.handlers?.metadata) return;
|
|
569
|
+
const resolvedPath = _resolvePathOrModuleId(slothlet, pathOrModuleId);
|
|
570
|
+
return slothlet.handlers.metadata.removePathMetadata(resolvedPath, key);
|
|
571
|
+
}
|
|
572
|
+
},
|
|
573
|
+
|
|
574
|
+
|
|
575
|
+
scope: this.createScopeFunction(),
|
|
576
|
+
|
|
577
|
+
|
|
578
|
+
run: this.createRunFunction(),
|
|
579
|
+
|
|
580
|
+
|
|
581
|
+
reload: async (options = {}) => {
|
|
582
|
+
|
|
583
|
+
if (!config.api?.mutations?.reload) {
|
|
584
|
+
throw new slothlet.SlothletError("INVALID_CONFIG_MUTATIONS_DISABLED", {
|
|
585
|
+
operation: "reload",
|
|
586
|
+
validationError: true
|
|
587
|
+
});
|
|
588
|
+
}
|
|
589
|
+
return slothlet.reload(options);
|
|
590
|
+
},
|
|
591
|
+
|
|
592
|
+
|
|
593
|
+
shutdown: async () => {
|
|
594
|
+
return slothlet.shutdown();
|
|
595
|
+
},
|
|
596
|
+
|
|
597
|
+
|
|
598
|
+
owner: {
|
|
599
|
+
|
|
600
|
+
get: (apiPath) => {
|
|
601
|
+
if (slothlet.handlers?.ownership) {
|
|
602
|
+
return slothlet.handlers.ownership.getPathOwnership(apiPath);
|
|
603
|
+
}
|
|
604
|
+
return null;
|
|
605
|
+
}
|
|
606
|
+
},
|
|
607
|
+
|
|
608
|
+
|
|
609
|
+
materialize: (() => {
|
|
610
|
+
const mgr = slothlet.handlers?.materialize;
|
|
611
|
+
|
|
612
|
+
|
|
613
|
+
if (!mgr) {
|
|
614
|
+
return Object.freeze({
|
|
615
|
+
materialized: false,
|
|
616
|
+
get: () => ({ total: 0, materialized: 0, remaining: 0, percentage: 100 }),
|
|
617
|
+
wait: async () => {}
|
|
618
|
+
});
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
return Object.freeze({
|
|
622
|
+
get materialized() {
|
|
623
|
+
return mgr.materialized;
|
|
624
|
+
},
|
|
625
|
+
get: mgr.get.bind(mgr),
|
|
626
|
+
wait: mgr.wait.bind(mgr)
|
|
627
|
+
});
|
|
628
|
+
})(),
|
|
629
|
+
|
|
630
|
+
|
|
631
|
+
lifecycle: (() => {
|
|
632
|
+
const handler = slothlet.handlers?.lifecycle;
|
|
633
|
+
const noop = () => {};
|
|
634
|
+
if (!handler) return { on: noop, off: noop };
|
|
635
|
+
return {
|
|
636
|
+
on: handler.on.bind(handler),
|
|
637
|
+
off: handler.off.bind(handler)
|
|
638
|
+
};
|
|
639
|
+
})()
|
|
640
|
+
};
|
|
641
|
+
|
|
642
|
+
|
|
643
|
+
|
|
644
|
+
if (!config.hook?.enabled && config.diagnostics !== true) {
|
|
645
|
+
delete namespace.hooks;
|
|
646
|
+
}
|
|
647
|
+
|
|
648
|
+
|
|
649
|
+
if (config.diagnostics === true) {
|
|
650
|
+
namespace.diag = {
|
|
651
|
+
|
|
652
|
+
describe: (showAll = false) => {
|
|
653
|
+
if (showAll) {
|
|
654
|
+
|
|
655
|
+
return { ...userApi };
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
return Reflect.ownKeys(userApi);
|
|
659
|
+
},
|
|
660
|
+
|
|
661
|
+
|
|
662
|
+
reference: slothlet.reference || null,
|
|
663
|
+
|
|
664
|
+
|
|
665
|
+
context: slothlet.context || {},
|
|
666
|
+
|
|
667
|
+
|
|
668
|
+
inspect: () => {
|
|
669
|
+
return slothlet.getDiagnostics();
|
|
670
|
+
},
|
|
671
|
+
|
|
672
|
+
|
|
673
|
+
getAPI: () => {
|
|
674
|
+
return slothlet.getAPI();
|
|
675
|
+
},
|
|
676
|
+
|
|
677
|
+
|
|
678
|
+
getOwnership: () => {
|
|
679
|
+
return slothlet.getOwnership();
|
|
680
|
+
},
|
|
681
|
+
|
|
682
|
+
|
|
683
|
+
owner: {
|
|
684
|
+
|
|
685
|
+
get: (apiPath) => {
|
|
686
|
+
if (slothlet.handlers?.ownership) {
|
|
687
|
+
return slothlet.handlers.ownership.getPathOwnership(apiPath);
|
|
688
|
+
}
|
|
689
|
+
return null;
|
|
690
|
+
}
|
|
691
|
+
},
|
|
692
|
+
|
|
693
|
+
|
|
694
|
+
caches: {
|
|
695
|
+
|
|
696
|
+
get: () => {
|
|
697
|
+
if (slothlet.handlers?.apiCacheManager) {
|
|
698
|
+
return slothlet.handlers.apiCacheManager.getCacheDiagnostics();
|
|
699
|
+
}
|
|
700
|
+
return { totalCaches: 0, caches: [] };
|
|
701
|
+
},
|
|
702
|
+
|
|
703
|
+
|
|
704
|
+
getAllModuleIDs: () => {
|
|
705
|
+
if (slothlet.handlers?.apiCacheManager) {
|
|
706
|
+
return slothlet.handlers.apiCacheManager.getAllModuleIDs();
|
|
707
|
+
}
|
|
708
|
+
return [];
|
|
709
|
+
},
|
|
710
|
+
|
|
711
|
+
|
|
712
|
+
has: (moduleID) => {
|
|
713
|
+
if (slothlet.handlers?.apiCacheManager) {
|
|
714
|
+
return slothlet.handlers.apiCacheManager.has(moduleID);
|
|
715
|
+
}
|
|
716
|
+
return false;
|
|
717
|
+
}
|
|
718
|
+
},
|
|
719
|
+
|
|
720
|
+
|
|
721
|
+
SlothletWarning: slothlet.SlothletWarning,
|
|
722
|
+
|
|
723
|
+
|
|
724
|
+
|
|
725
|
+
|
|
726
|
+
hook: slothlet.handlers?.hookManager
|
|
727
|
+
? {
|
|
728
|
+
|
|
729
|
+
get enabled() {
|
|
730
|
+
return slothlet.handlers.hookManager.enabled;
|
|
731
|
+
},
|
|
732
|
+
|
|
733
|
+
|
|
734
|
+
compilePattern: (pattern) => {
|
|
735
|
+
return slothlet.handlers.hookManager.getCompilePatternForDiagnostics()(pattern);
|
|
736
|
+
}
|
|
737
|
+
}
|
|
738
|
+
: undefined
|
|
739
|
+
|
|
740
|
+
};
|
|
741
|
+
}
|
|
742
|
+
|
|
743
|
+
return namespace;
|
|
744
|
+
}
|
|
745
|
+
|
|
746
|
+
|
|
747
|
+
createShutdownFunction() {
|
|
748
|
+
const slothlet = this.slothlet;
|
|
749
|
+
const shutdownFunction = {
|
|
750
|
+
shutdown: async () => {
|
|
751
|
+
|
|
752
|
+
if (slothlet.userHooks?.shutdown && typeof slothlet.userHooks.shutdown === "function") {
|
|
753
|
+
await slothlet.userHooks.shutdown();
|
|
754
|
+
}
|
|
755
|
+
return slothlet.shutdown();
|
|
756
|
+
}
|
|
757
|
+
}.shutdown;
|
|
758
|
+
return shutdownFunction;
|
|
759
|
+
}
|
|
760
|
+
|
|
761
|
+
|
|
762
|
+
createRunFunction() {
|
|
763
|
+
const slothlet = this.slothlet;
|
|
764
|
+
|
|
765
|
+
const scopeFunc = this.createScopeFunction();
|
|
766
|
+
|
|
767
|
+
const runFunction = {
|
|
768
|
+
run: async (contextData, callback, ...args) => {
|
|
769
|
+
|
|
770
|
+
if (slothlet.config.scope === false) {
|
|
771
|
+
throw new slothlet.SlothletError("SCOPE_DISABLED", {}, null, { validationError: true });
|
|
772
|
+
}
|
|
773
|
+
|
|
774
|
+
|
|
775
|
+
if (!contextData || typeof contextData !== "object") {
|
|
776
|
+
throw new slothlet.SlothletError("SCOPE_INVALID_CONTEXT", { received: typeof contextData }, null, { validationError: true });
|
|
777
|
+
}
|
|
778
|
+
if (typeof callback !== "function") {
|
|
779
|
+
throw new slothlet.SlothletError("SCOPE_INVALID_CALLBACK", { received: typeof callback }, null, { validationError: true });
|
|
780
|
+
}
|
|
781
|
+
|
|
782
|
+
|
|
783
|
+
|
|
784
|
+
return scopeFunc({
|
|
785
|
+
context: contextData,
|
|
786
|
+
fn: callback,
|
|
787
|
+
args: args,
|
|
788
|
+
merge: slothlet.config.scope?.merge || "shallow",
|
|
789
|
+
isolation: slothlet.config.scope?.isolation || "partial"
|
|
790
|
+
});
|
|
791
|
+
}
|
|
792
|
+
}.run;
|
|
793
|
+
return runFunction;
|
|
794
|
+
}
|
|
795
|
+
|
|
796
|
+
|
|
797
|
+
createScopeFunction() {
|
|
798
|
+
const slothlet = this.slothlet;
|
|
799
|
+
const scopeFunction = {
|
|
800
|
+
scope: async (options) => {
|
|
801
|
+
|
|
802
|
+
if (slothlet.config.scope === false) {
|
|
803
|
+
throw new slothlet.SlothletError("SCOPE_DISABLED", {}, null, { validationError: true });
|
|
804
|
+
}
|
|
805
|
+
|
|
806
|
+
|
|
807
|
+
if (!options || typeof options !== "object") {
|
|
808
|
+
throw new slothlet.SlothletError("SCOPE_INVALID_OPTIONS", { received: typeof options }, null, { validationError: true });
|
|
809
|
+
}
|
|
810
|
+
if (!options.fn || typeof options.fn !== "function") {
|
|
811
|
+
throw new slothlet.SlothletError("SCOPE_INVALID_FN", { received: typeof options?.fn }, null, { validationError: true });
|
|
812
|
+
}
|
|
813
|
+
if (!options.context || typeof options.context !== "object") {
|
|
814
|
+
throw new slothlet.SlothletError("SCOPE_INVALID_CONTEXT_OBJECT", { received: typeof options?.context }, null, {
|
|
815
|
+
validationError: true
|
|
816
|
+
});
|
|
817
|
+
}
|
|
818
|
+
|
|
819
|
+
const { context: contextData, fn, args = [], merge = "shallow", isolation } = options;
|
|
820
|
+
|
|
821
|
+
|
|
822
|
+
if (merge !== "shallow" && merge !== "deep") {
|
|
823
|
+
throw new slothlet.SlothletError("SCOPE_INVALID_MERGE_STRATEGY", { merge }, null, { validationError: true });
|
|
824
|
+
}
|
|
825
|
+
|
|
826
|
+
|
|
827
|
+
const isolationMode = isolation || slothlet.config.scope?.isolation || "partial";
|
|
828
|
+
|
|
829
|
+
|
|
830
|
+
if (isolationMode !== "partial" && isolationMode !== "full") {
|
|
831
|
+
throw new slothlet.SlothletError("SCOPE_INVALID_ISOLATION_MODE", { isolationMode }, null, { validationError: true });
|
|
832
|
+
}
|
|
833
|
+
|
|
834
|
+
|
|
835
|
+
const contextManager = slothlet.contextManager;
|
|
836
|
+
if (!contextManager) {
|
|
837
|
+
throw new slothlet.SlothletError("NO_CONTEXT_MANAGER", { validationError: true });
|
|
838
|
+
}
|
|
839
|
+
|
|
840
|
+
const { utilities } = slothlet.helpers;
|
|
841
|
+
|
|
842
|
+
|
|
843
|
+
if (contextManager.constructor.name === "LiveContextManager") {
|
|
844
|
+
|
|
845
|
+
let currentStore = null;
|
|
846
|
+
|
|
847
|
+
|
|
848
|
+
const currentID = contextManager.currentInstanceID;
|
|
849
|
+
if (currentID) {
|
|
850
|
+
const activeStore = contextManager.instances.get(currentID);
|
|
851
|
+
const isOurContext =
|
|
852
|
+
currentID === slothlet.instanceID ||
|
|
853
|
+
activeStore?.parentInstanceID === slothlet.instanceID ||
|
|
854
|
+
currentID.startsWith(slothlet.instanceID + "__run_");
|
|
855
|
+
|
|
856
|
+
if (isOurContext) {
|
|
857
|
+
currentStore = activeStore;
|
|
858
|
+
}
|
|
859
|
+
}
|
|
860
|
+
|
|
861
|
+
|
|
862
|
+
if (!currentStore) {
|
|
863
|
+
currentStore = contextManager.instances.get(slothlet.instanceID);
|
|
864
|
+
}
|
|
865
|
+
|
|
866
|
+
if (!currentStore) {
|
|
867
|
+
throw new slothlet.SlothletError("CONTEXT_NOT_FOUND", {
|
|
868
|
+
instanceID: slothlet.instanceID,
|
|
869
|
+
availableInstances: [...contextManager.instances.keys()].join(", ") || "none",
|
|
870
|
+
validationError: true
|
|
871
|
+
});
|
|
872
|
+
}
|
|
873
|
+
|
|
874
|
+
|
|
875
|
+
|
|
876
|
+
let mergedContext;
|
|
877
|
+
if (merge === "deep") {
|
|
878
|
+
mergedContext = utilities.deepMerge(currentStore.context, contextData);
|
|
879
|
+
|
|
880
|
+
mergedContext = structuredClone(mergedContext);
|
|
881
|
+
} else {
|
|
882
|
+
|
|
883
|
+
const clonedParent = structuredClone(currentStore.context);
|
|
884
|
+
mergedContext = { ...clonedParent, ...contextData };
|
|
885
|
+
}
|
|
886
|
+
|
|
887
|
+
|
|
888
|
+
const childInstanceID = `${slothlet.instanceID}__run_${Date.now()}_${Math.random().toString(36).slice(2, 9)}`;
|
|
889
|
+
|
|
890
|
+
const childStore = {
|
|
891
|
+
instanceID: childInstanceID,
|
|
892
|
+
context: mergedContext,
|
|
893
|
+
self: isolationMode === "full" ? utilities.deepClone(currentStore.self) : currentStore.self,
|
|
894
|
+
config: currentStore.config,
|
|
895
|
+
createdAt: currentStore.createdAt,
|
|
896
|
+
parentInstanceID: slothlet.instanceID
|
|
897
|
+
};
|
|
898
|
+
|
|
899
|
+
|
|
900
|
+
contextManager.instances.set(childInstanceID, childStore);
|
|
901
|
+
const previousInstanceID = contextManager.currentInstanceID;
|
|
902
|
+
|
|
903
|
+
try {
|
|
904
|
+
|
|
905
|
+
contextManager.currentInstanceID = childInstanceID;
|
|
906
|
+
|
|
907
|
+
|
|
908
|
+
return await fn(...args);
|
|
909
|
+
} finally {
|
|
910
|
+
|
|
911
|
+
contextManager.currentInstanceID = previousInstanceID;
|
|
912
|
+
contextManager.instances.delete(childInstanceID);
|
|
913
|
+
}
|
|
914
|
+
}
|
|
915
|
+
|
|
916
|
+
|
|
917
|
+
if (contextManager.constructor.name === "AsyncContextManager") {
|
|
918
|
+
|
|
919
|
+
let currentStore = null;
|
|
920
|
+
|
|
921
|
+
|
|
922
|
+
const activeStore = contextManager.tryGetContext();
|
|
923
|
+
if (activeStore) {
|
|
924
|
+
const isOurContext =
|
|
925
|
+
activeStore.instanceID === slothlet.instanceID ||
|
|
926
|
+
activeStore.parentInstanceID === slothlet.instanceID ||
|
|
927
|
+
activeStore.instanceID.startsWith(slothlet.instanceID + "__run_");
|
|
928
|
+
|
|
929
|
+
if (isOurContext) {
|
|
930
|
+
currentStore = activeStore;
|
|
931
|
+
}
|
|
932
|
+
}
|
|
933
|
+
|
|
934
|
+
|
|
935
|
+
if (!currentStore) {
|
|
936
|
+
const baseStore = contextManager.instances.get(slothlet.instanceID);
|
|
937
|
+
if (!baseStore) {
|
|
938
|
+
throw new slothlet.SlothletError("CONTEXT_NOT_FOUND", {
|
|
939
|
+
instanceID: slothlet.instanceID,
|
|
940
|
+
availableInstances: [...contextManager.instances.keys()].join(", ") || "none",
|
|
941
|
+
validationError: true
|
|
942
|
+
});
|
|
943
|
+
}
|
|
944
|
+
currentStore = baseStore;
|
|
945
|
+
}
|
|
946
|
+
|
|
947
|
+
|
|
948
|
+
|
|
949
|
+
let mergedContext;
|
|
950
|
+
if (merge === "deep") {
|
|
951
|
+
mergedContext = utilities.deepMerge(currentStore.context, contextData);
|
|
952
|
+
|
|
953
|
+
mergedContext = structuredClone(mergedContext);
|
|
954
|
+
} else {
|
|
955
|
+
|
|
956
|
+
const clonedParent = structuredClone(currentStore.context);
|
|
957
|
+
mergedContext = { ...clonedParent, ...contextData };
|
|
958
|
+
}
|
|
959
|
+
|
|
960
|
+
|
|
961
|
+
const childInstanceID = `${slothlet.instanceID}__run_${Date.now()}_${Math.random().toString(36).slice(2, 9)}`;
|
|
962
|
+
|
|
963
|
+
const childStore = {
|
|
964
|
+
instanceID: childInstanceID,
|
|
965
|
+
context: mergedContext,
|
|
966
|
+
self: isolationMode === "full" ? utilities.deepClone(currentStore.self) : currentStore.self,
|
|
967
|
+
config: currentStore.config,
|
|
968
|
+
createdAt: currentStore.createdAt,
|
|
969
|
+
parentInstanceID: slothlet.instanceID
|
|
970
|
+
};
|
|
971
|
+
|
|
972
|
+
|
|
973
|
+
contextManager.instances.set(childInstanceID, childStore);
|
|
974
|
+
|
|
975
|
+
try {
|
|
976
|
+
|
|
977
|
+
return await contextManager.als.run(childStore, async () => {
|
|
978
|
+
return await fn(...args);
|
|
979
|
+
});
|
|
980
|
+
} finally {
|
|
981
|
+
|
|
982
|
+
contextManager.instances.delete(childInstanceID);
|
|
983
|
+
}
|
|
984
|
+
}
|
|
985
|
+
|
|
986
|
+
throw new slothlet.SlothletError("UNSUPPORTED_CONTEXT_MANAGER", {
|
|
987
|
+
manager: contextManager.constructor.name,
|
|
988
|
+
validationError: true
|
|
989
|
+
});
|
|
990
|
+
}
|
|
991
|
+
}.scope;
|
|
992
|
+
return scopeFunction;
|
|
993
|
+
}
|
|
994
|
+
|
|
995
|
+
|
|
996
|
+
createDestroyFunction(api) {
|
|
997
|
+
const slothlet = this.slothlet;
|
|
998
|
+
const destroyFunction = {
|
|
999
|
+
destroy: async () => {
|
|
1000
|
+
|
|
1001
|
+
if (slothlet.userHooks?.destroy && typeof slothlet.userHooks.destroy === "function") {
|
|
1002
|
+
await slothlet.userHooks.destroy();
|
|
1003
|
+
}
|
|
1004
|
+
|
|
1005
|
+
|
|
1006
|
+
if (api && typeof api.shutdown === "function") {
|
|
1007
|
+
await api.shutdown();
|
|
1008
|
+
} else {
|
|
1009
|
+
|
|
1010
|
+
await slothlet.shutdown();
|
|
1011
|
+
}
|
|
1012
|
+
|
|
1013
|
+
|
|
1014
|
+
|
|
1015
|
+
|
|
1016
|
+
slothlet.isDestroyed = true;
|
|
1017
|
+
|
|
1018
|
+
|
|
1019
|
+
const objectsToClear = [api, slothlet.api].filter((obj) => obj && typeof obj === "object");
|
|
1020
|
+
|
|
1021
|
+
for (const obj of objectsToClear) {
|
|
1022
|
+
const keys = Object.keys(obj);
|
|
1023
|
+
for (const key of keys) {
|
|
1024
|
+
try {
|
|
1025
|
+
delete obj[key];
|
|
1026
|
+
} catch (_) {
|
|
1027
|
+
|
|
1028
|
+
}
|
|
1029
|
+
}
|
|
1030
|
+
}
|
|
1031
|
+
|
|
1032
|
+
|
|
1033
|
+
slothlet.api = null;
|
|
1034
|
+
}
|
|
1035
|
+
}.destroy;
|
|
1036
|
+
return destroyFunction;
|
|
1037
|
+
}
|
|
1038
|
+
|
|
1039
|
+
|
|
1040
|
+
attachBuiltins(userApi, builtins) {
|
|
1041
|
+
|
|
1042
|
+
|
|
1043
|
+
Object.defineProperty(userApi, "slothlet", {
|
|
1044
|
+
value: builtins.slothlet,
|
|
1045
|
+
enumerable: true,
|
|
1046
|
+
writable: false,
|
|
1047
|
+
configurable: true
|
|
1048
|
+
});
|
|
1049
|
+
|
|
1050
|
+
|
|
1051
|
+
Object.defineProperty(userApi, "shutdown", {
|
|
1052
|
+
value: builtins.shutdown,
|
|
1053
|
+
enumerable: true,
|
|
1054
|
+
writable: false,
|
|
1055
|
+
configurable: true
|
|
1056
|
+
});
|
|
1057
|
+
|
|
1058
|
+
|
|
1059
|
+
|
|
1060
|
+
|
|
1061
|
+
|
|
1062
|
+
|
|
1063
|
+
if (builtins.destroy !== null) {
|
|
1064
|
+
Object.defineProperty(userApi, "destroy", {
|
|
1065
|
+
value: builtins.destroy,
|
|
1066
|
+
enumerable: true,
|
|
1067
|
+
writable: false,
|
|
1068
|
+
configurable: true
|
|
1069
|
+
});
|
|
1070
|
+
}
|
|
1071
|
+
|
|
1072
|
+
}
|
|
1073
|
+
}
|