@cldmv/slothlet 3.2.3 → 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.
Files changed (138) hide show
  1. package/README.md +22 -9
  2. package/REFERENCE.md +23 -0
  3. package/dist/lib/builders/api-assignment.mjs +1 -589
  4. package/dist/lib/builders/api_builder.mjs +1 -1155
  5. package/dist/lib/builders/builder.mjs +1 -78
  6. package/dist/lib/builders/modes-processor.mjs +1 -1800
  7. package/dist/lib/errors.mjs +9 -211
  8. package/dist/lib/factories/component-base.mjs +1 -80
  9. package/dist/lib/factories/context.mjs +1 -22
  10. package/dist/lib/handlers/api-cache-manager.mjs +1 -200
  11. package/dist/lib/handlers/api-manager.mjs +1 -2513
  12. package/dist/lib/handlers/context-async.mjs +1 -168
  13. package/dist/lib/handlers/context-live.mjs +1 -168
  14. package/dist/lib/handlers/hook-manager.mjs +1 -773
  15. package/dist/lib/handlers/lifecycle-token.mjs +1 -28
  16. package/dist/lib/handlers/lifecycle.mjs +1 -115
  17. package/dist/lib/handlers/materialize-manager.mjs +1 -48
  18. package/dist/lib/handlers/metadata.mjs +1 -501
  19. package/dist/lib/handlers/ownership.mjs +1 -322
  20. package/dist/lib/handlers/permission-manager.mjs +17 -0
  21. package/dist/lib/handlers/unified-wrapper.mjs +1 -3042
  22. package/dist/lib/handlers/version-manager.mjs +1 -885
  23. package/dist/lib/helpers/class-instance-wrapper.mjs +1 -109
  24. package/dist/lib/helpers/config.mjs +1 -355
  25. package/dist/lib/helpers/eventemitter-context.mjs +1 -349
  26. package/dist/lib/helpers/hint-detector.mjs +1 -47
  27. package/dist/lib/helpers/modes-utils.mjs +1 -37
  28. package/dist/lib/helpers/pattern-matcher.mjs +17 -0
  29. package/dist/lib/helpers/resolve-from-caller.mjs +1 -169
  30. package/dist/lib/helpers/sanitize.mjs +1 -340
  31. package/dist/lib/helpers/utilities.mjs +1 -70
  32. package/dist/lib/i18n/languages/de-de.json +21 -1
  33. package/dist/lib/i18n/languages/en-gb.json +21 -1
  34. package/dist/lib/i18n/languages/en-us.json +21 -1
  35. package/dist/lib/i18n/languages/es-mx.json +21 -1
  36. package/dist/lib/i18n/languages/fr-fr.json +21 -1
  37. package/dist/lib/i18n/languages/hi-in.json +21 -1
  38. package/dist/lib/i18n/languages/ja-jp.json +21 -1
  39. package/dist/lib/i18n/languages/ko-kr.json +21 -1
  40. package/dist/lib/i18n/languages/pt-br.json +21 -1
  41. package/dist/lib/i18n/languages/ru-ru.json +21 -1
  42. package/dist/lib/i18n/languages/zh-cn.json +21 -1
  43. package/dist/lib/i18n/translations.mjs +1 -126
  44. package/dist/lib/modes/eager.mjs +1 -59
  45. package/dist/lib/modes/lazy.mjs +1 -81
  46. package/dist/lib/processors/flatten.mjs +1 -437
  47. package/dist/lib/processors/loader.mjs +1 -339
  48. package/dist/lib/processors/type-generator.mjs +1 -275
  49. package/dist/lib/processors/typescript.mjs +1 -172
  50. package/dist/lib/runtime/runtime-asynclocalstorage.mjs +1 -113
  51. package/dist/lib/runtime/runtime-livebindings.mjs +1 -78
  52. package/dist/lib/runtime/runtime.mjs +1 -102
  53. package/dist/slothlet.mjs +1 -808
  54. package/package.json +37 -31
  55. package/types/dist/lib/builders/api-assignment.d.mts +3 -92
  56. package/types/dist/lib/builders/api-assignment.d.mts.map +1 -1
  57. package/types/dist/lib/builders/api_builder.d.mts +102 -91
  58. package/types/dist/lib/builders/api_builder.d.mts.map +1 -1
  59. package/types/dist/lib/builders/builder.d.mts +1 -55
  60. package/types/dist/lib/builders/builder.d.mts.map +1 -1
  61. package/types/dist/lib/builders/modes-processor.d.mts +3 -27
  62. package/types/dist/lib/builders/modes-processor.d.mts.map +1 -1
  63. package/types/dist/lib/errors.d.mts +19 -109
  64. package/types/dist/lib/errors.d.mts.map +1 -1
  65. package/types/dist/lib/factories/component-base.d.mts +7 -177
  66. package/types/dist/lib/factories/component-base.d.mts.map +1 -1
  67. package/types/dist/lib/factories/context.d.mts +4 -22
  68. package/types/dist/lib/factories/context.d.mts.map +1 -1
  69. package/types/dist/lib/handlers/api-cache-manager.d.mts +20 -203
  70. package/types/dist/lib/handlers/api-cache-manager.d.mts.map +1 -1
  71. package/types/dist/lib/handlers/api-manager.d.mts +33 -408
  72. package/types/dist/lib/handlers/api-manager.d.mts.map +1 -1
  73. package/types/dist/lib/handlers/context-async.d.mts +23 -61
  74. package/types/dist/lib/handlers/context-async.d.mts.map +1 -1
  75. package/types/dist/lib/handlers/context-live.d.mts +22 -59
  76. package/types/dist/lib/handlers/context-live.d.mts.map +1 -1
  77. package/types/dist/lib/handlers/hook-manager.d.mts +46 -185
  78. package/types/dist/lib/handlers/hook-manager.d.mts.map +1 -1
  79. package/types/dist/lib/handlers/lifecycle-token.d.mts +3 -48
  80. package/types/dist/lib/handlers/lifecycle-token.d.mts.map +1 -1
  81. package/types/dist/lib/handlers/lifecycle.d.mts +5 -82
  82. package/types/dist/lib/handlers/lifecycle.d.mts.map +1 -1
  83. package/types/dist/lib/handlers/materialize-manager.d.mts +8 -70
  84. package/types/dist/lib/handlers/materialize-manager.d.mts.map +1 -1
  85. package/types/dist/lib/handlers/metadata.d.mts +17 -221
  86. package/types/dist/lib/handlers/metadata.d.mts.map +1 -1
  87. package/types/dist/lib/handlers/ownership.d.mts +44 -160
  88. package/types/dist/lib/handlers/ownership.d.mts.map +1 -1
  89. package/types/dist/lib/handlers/permission-manager.d.mts +47 -0
  90. package/types/dist/lib/handlers/permission-manager.d.mts.map +1 -0
  91. package/types/dist/lib/handlers/unified-wrapper.d.mts +26 -239
  92. package/types/dist/lib/handlers/unified-wrapper.d.mts.map +1 -1
  93. package/types/dist/lib/handlers/version-manager.d.mts +28 -225
  94. package/types/dist/lib/handlers/version-manager.d.mts.map +1 -1
  95. package/types/dist/lib/helpers/class-instance-wrapper.d.mts +2 -52
  96. package/types/dist/lib/helpers/class-instance-wrapper.d.mts.map +1 -1
  97. package/types/dist/lib/helpers/config.d.mts +125 -123
  98. package/types/dist/lib/helpers/config.d.mts.map +1 -1
  99. package/types/dist/lib/helpers/eventemitter-context.d.mts +3 -29
  100. package/types/dist/lib/helpers/eventemitter-context.d.mts.map +1 -1
  101. package/types/dist/lib/helpers/hint-detector.d.mts +2 -15
  102. package/types/dist/lib/helpers/hint-detector.d.mts.map +1 -1
  103. package/types/dist/lib/helpers/modes-utils.d.mts +3 -30
  104. package/types/dist/lib/helpers/modes-utils.d.mts.map +1 -1
  105. package/types/dist/lib/helpers/pattern-matcher.d.mts +4 -0
  106. package/types/dist/lib/helpers/pattern-matcher.d.mts.map +1 -0
  107. package/types/dist/lib/helpers/resolve-from-caller.d.mts +3 -27
  108. package/types/dist/lib/helpers/resolve-from-caller.d.mts.map +1 -1
  109. package/types/dist/lib/helpers/sanitize.d.mts +4 -92
  110. package/types/dist/lib/helpers/sanitize.d.mts.map +1 -1
  111. package/types/dist/lib/helpers/utilities.d.mts +4 -52
  112. package/types/dist/lib/helpers/utilities.d.mts.map +1 -1
  113. package/types/dist/lib/i18n/translations.d.mts +4 -37
  114. package/types/dist/lib/i18n/translations.d.mts.map +1 -1
  115. package/types/dist/lib/modes/eager.d.mts +8 -30
  116. package/types/dist/lib/modes/eager.d.mts.map +1 -1
  117. package/types/dist/lib/modes/lazy.d.mts +10 -43
  118. package/types/dist/lib/modes/lazy.d.mts.map +1 -1
  119. package/types/dist/lib/processors/flatten.d.mts +56 -107
  120. package/types/dist/lib/processors/flatten.d.mts.map +1 -1
  121. package/types/dist/lib/processors/loader.d.mts +6 -41
  122. package/types/dist/lib/processors/loader.d.mts.map +1 -1
  123. package/types/dist/lib/processors/type-generator.d.mts +2 -16
  124. package/types/dist/lib/processors/type-generator.d.mts.map +1 -1
  125. package/types/dist/lib/processors/typescript.d.mts +6 -53
  126. package/types/dist/lib/processors/typescript.d.mts.map +1 -1
  127. package/types/dist/lib/runtime/runtime-asynclocalstorage.d.mts +3 -71
  128. package/types/dist/lib/runtime/runtime-asynclocalstorage.d.mts.map +1 -1
  129. package/types/dist/lib/runtime/runtime-livebindings.d.mts +2 -37
  130. package/types/dist/lib/runtime/runtime-livebindings.d.mts.map +1 -1
  131. package/types/dist/lib/runtime/runtime.d.mts +3 -39
  132. package/types/dist/lib/runtime/runtime.d.mts.map +1 -1
  133. package/types/dist/slothlet.d.mts +3 -249
  134. package/types/dist/slothlet.d.mts.map +1 -1
  135. package/types/index.d.mts +36 -16
  136. package/types/index.d.mts.map +1 -0
  137. package/AGENT-USAGE.md +0 -736
  138. package/docs/API-RULES.md +0 -712
@@ -14,2516 +14,4 @@
14
14
  limitations under the License.
15
15
  */
16
16
 
17
-
18
-
19
-
20
- import fs from "node:fs/promises";
21
- import path from "node:path";
22
- import { translate } from "@cldmv/slothlet/i18n";
23
- import { ComponentBase } from "@cldmv/slothlet/factories/component-base";
24
- import { UnifiedWrapper, resolveWrapper } from "@cldmv/slothlet/handlers/unified-wrapper";
25
-
26
-
27
- export class ApiManager extends ComponentBase {
28
- static slothletProperty = "apiManager";
29
-
30
-
31
- constructor(slothlet) {
32
- super(slothlet);
33
- this.state = {
34
- addHistory: [],
35
-
36
-
37
- initialConfig: slothlet?.config || null,
38
- operationHistory: []
39
- };
40
- }
41
-
42
-
43
- normalizeApiPath(apiPath) {
44
-
45
- if (apiPath === "" || apiPath === null || apiPath === undefined) {
46
- return { apiPath: "", parts: [] };
47
- }
48
-
49
-
50
- if (Array.isArray(apiPath)) {
51
-
52
- if (apiPath.length === 0) {
53
- return { apiPath: "", parts: [] };
54
- }
55
-
56
- for (let i = 0; i < apiPath.length; i++) {
57
- if (typeof apiPath[i] !== "string") {
58
- throw new this.SlothletError("INVALID_CONFIG_API_PATH_INVALID", {
59
- apiPath,
60
- segment: apiPath[i],
61
- index: i,
62
- reason: translate("API_PATH_REASON_ARRAY_ELEMENTS"),
63
- validationError: true
64
- });
65
- }
66
- if (apiPath[i].trim() === "") {
67
- throw new this.SlothletError("INVALID_CONFIG_API_PATH_INVALID", {
68
- apiPath,
69
- segment: apiPath[i],
70
- index: i,
71
- reason: translate("API_PATH_REASON_ARRAY_EMPTY_SEGMENTS"),
72
- validationError: true
73
- });
74
- }
75
- }
76
-
77
-
78
- if (apiPath[0] === "slothlet" || (apiPath.length === 1 && (apiPath[0] === "shutdown" || apiPath[0] === "destroy"))) {
79
- throw new this.SlothletError("INVALID_CONFIG_API_PATH_INVALID", {
80
- apiPath,
81
- reason: translate("API_PATH_REASON_RESERVED_NAME"),
82
- index: undefined,
83
- segment: undefined,
84
- validationError: true
85
- });
86
- }
87
-
88
- return { apiPath: apiPath.join("."), parts: apiPath };
89
- }
90
-
91
- if (typeof apiPath !== "string") {
92
- throw new this.SlothletError("INVALID_CONFIG_API_PATH_INVALID", {
93
- apiPath,
94
- reason: translate("API_PATH_REASON_INVALID_TYPE"),
95
- index: undefined,
96
- segment: undefined,
97
- validationError: true
98
- });
99
- }
100
-
101
- const normalized = apiPath.trim();
102
-
103
-
104
- if (normalized === "") {
105
- return { apiPath: "", parts: [] };
106
- }
107
-
108
- const parts = normalized.split(".");
109
- if (parts.length === 0 || parts.some((part) => part.trim() === "")) {
110
- throw new this.SlothletError("INVALID_CONFIG_API_PATH_INVALID", {
111
- apiPath: normalized,
112
- reason: translate("API_PATH_REASON_EMPTY_SEGMENTS"),
113
- index: undefined,
114
- segment: undefined,
115
- validationError: true
116
- });
117
- }
118
-
119
- if (parts[0] === "slothlet" || normalized === "shutdown" || normalized === "destroy") {
120
- throw new this.SlothletError("INVALID_CONFIG_API_PATH_INVALID", {
121
- apiPath: normalized,
122
- reason: translate("API_PATH_REASON_RESERVED_NAME"),
123
- index: undefined,
124
- segment: undefined,
125
- validationError: true
126
- });
127
- }
128
-
129
- return { apiPath: normalized, parts };
130
- }
131
-
132
-
133
- async resolvePath(inputPath) {
134
- if (!inputPath || typeof inputPath !== "string") {
135
- throw new this.SlothletError("INVALID_CONFIG_DIR_INVALID", {
136
- dir: inputPath,
137
- validationError: true
138
- });
139
- }
140
-
141
- const resolvedPath = this.slothlet.helpers.resolver.resolvePathFromCaller(inputPath);
142
- try {
143
- const stats = await fs.stat(resolvedPath);
144
- return {
145
- resolvedPath,
146
- isDirectory: stats.isDirectory(),
147
- isFile: stats.isFile()
148
- };
149
- } catch (error) {
150
-
151
-
152
-
153
-
154
- if (error instanceof this.SlothletError) {
155
- throw error;
156
- }
157
-
158
-
159
- throw new this.SlothletError("INVALID_CONFIG_DIR_INVALID", {
160
- dir: resolvedPath,
161
- validationError: true
162
- });
163
- }
164
- }
165
-
166
-
167
- async resolveFolderPath(folderPath) {
168
- if (!folderPath || typeof folderPath !== "string") {
169
- throw new this.SlothletError("INVALID_CONFIG_DIR_INVALID", {
170
- dir: folderPath,
171
- validationError: true
172
- });
173
- }
174
-
175
- const resolvedPath = this.slothlet.helpers.resolver.resolvePathFromCaller(folderPath);
176
- try {
177
- const stats = await fs.stat(resolvedPath);
178
- if (!stats.isDirectory()) {
179
- throw new this.SlothletError("INVALID_CONFIG_DIR_INVALID", {
180
- dir: resolvedPath,
181
- validationError: true
182
- });
183
- }
184
- } catch (error) {
185
- if (error instanceof this.SlothletError) {
186
- throw error;
187
- }
188
- throw new this.SlothletError("INVALID_CONFIG_DIR_INVALID", {
189
- dir: resolvedPath,
190
- validationError: true
191
- });
192
- }
193
-
194
- return resolvedPath;
195
- }
196
-
197
-
198
- buildDefaultModuleId(apiPath, ____resolvedFolderPath) {
199
- const randomSuffix = Math.random().toString(36).substring(2, 8);
200
- const prefix = apiPath || "auto";
201
- return `${prefix}_${randomSuffix}`;
202
- }
203
-
204
-
205
- getValueAtPath(root, parts) {
206
- let current = root;
207
- for (const part of parts) {
208
- if (!current || (typeof current !== "object" && typeof current !== "function")) {
209
- return undefined;
210
- }
211
- current = current[part];
212
- }
213
- return current;
214
- }
215
-
216
-
217
- ensureParentPath(root, parts, options = {}) {
218
- const { moduleID, sourceFolder } = options;
219
- let current = root;
220
- for (let i = 0; i < parts.length - 1; i += 1) {
221
- const part = parts[i];
222
- const next = current[part];
223
- if (next === undefined) {
224
-
225
- const containerPath = parts.slice(0, i + 1).join(".");
226
- const containerWrapper = new UnifiedWrapper(this.slothlet, {
227
- mode: this.____config.mode,
228
- apiPath: containerPath,
229
- moduleID: moduleID,
230
- sourceFolder: sourceFolder
231
- });
232
-
233
- containerWrapper.___setImpl({}, moduleID);
234
- current[part] = containerWrapper.createProxy();
235
- current = current[part];
236
- continue;
237
- }
238
- if (next && (typeof next === "object" || typeof next === "function")) {
239
- current = next;
240
- continue;
241
- }
242
- throw new this.SlothletError("INVALID_CONFIG_API_PATH_INVALID", {
243
- apiPath: parts.slice(0, i + 1).join("."),
244
- reason: translate("API_PATH_REASON_NOT_TRAVERSABLE"),
245
- index: undefined,
246
- segment: undefined,
247
- validationError: true
248
- });
249
- }
250
- return current;
251
- }
252
-
253
-
254
- isWrapperProxy(value) {
255
- return !!(value && (typeof value === "object" || typeof value === "function") && resolveWrapper(value) !== null);
256
- }
257
-
258
-
259
- async syncWrapper(existingProxy, nextProxy, config, collisionMode = "replace", moduleID = null) {
260
- if (config?.debug?.api) {
261
- this.slothlet.debug("api", {
262
- key: "DEBUG_MODE_SYNC_WRAPPER_ENTRY_EXISTING",
263
- apiPath: resolveWrapper(existingProxy)?.apiPath
264
- });
265
- this.slothlet.debug("api", {
266
- key: "DEBUG_MODE_SYNC_WRAPPER_ENTRY_NEXT",
267
- apiPath: resolveWrapper(nextProxy)?.apiPath
268
- });
269
- }
270
-
271
-
272
-
273
- if (!this.isWrapperProxy(existingProxy) || !this.isWrapperProxy(nextProxy)) {
274
- return false;
275
- }
276
-
277
-
278
-
279
- const existingWrapper = resolveWrapper(existingProxy) ?? existingProxy;
280
-
281
-
282
- const nextWrapper = resolveWrapper(nextProxy) ?? nextProxy;
283
-
284
- if (config?.debug?.api) {
285
- this.slothlet.debug("api", {
286
- key: "DEBUG_MODE_SYNC_WRAPPER_EXISTING",
287
- apiPath: existingWrapper.apiPath
288
- });
289
- this.slothlet.debug("api", {
290
- key: "DEBUG_MODE_SYNC_WRAPPER_NEXT",
291
- apiPath: nextWrapper.apiPath
292
- });
293
- }
294
-
295
-
296
-
297
-
298
-
299
- if (nextWrapper.____slothletInternal.materializeFunc && collisionMode !== "merge") {
300
- existingWrapper.____slothletInternal.materializeFunc = nextWrapper.____slothletInternal.materializeFunc;
301
- }
302
-
303
-
304
-
305
-
306
-
307
- const existingChildKeys = Object.keys(existingWrapper).filter((k) => !k.startsWith("_") && !k.startsWith("__"));
308
- const nextChildKeys = Object.keys(nextWrapper).filter((k) => !k.startsWith("_") && !k.startsWith("__"));
309
-
310
- if (config?.debug?.api) {
311
- this.slothlet.debug("api", {
312
- key: "DEBUG_MODE_SYNC_WRAPPER_BEFORE_MERGE",
313
- existingCacheSize: existingChildKeys.length,
314
- nextCacheSize: nextChildKeys.length
315
- });
316
- this.slothlet.debug("api", {
317
- key: "DEBUG_MODE_SYNC_WRAPPER_NEXT_IMPL_KEYS",
318
-
319
-
320
- implKeys: Object.keys(nextWrapper.____slothletInternal.impl || {})
321
- });
322
- this.slothlet.debug("api", {
323
- key: "DEBUG_MODE_SYNC_WRAPPER_NEXT_CHILDCACHE_KEYS",
324
- childCacheKeys: nextChildKeys
325
- });
326
- }
327
-
328
-
329
-
330
-
331
-
332
- if (collisionMode === "replace") {
333
-
334
-
335
-
336
-
337
- if (existingWrapper.___setImpl && nextWrapper.____slothletInternal.impl !== undefined) {
338
-
339
- existingWrapper.___setImpl(nextWrapper.____slothletInternal.impl, moduleID);
340
-
341
-
342
-
343
-
344
-
345
- } else if (nextWrapper.____slothletInternal.impl === undefined) {
346
-
347
-
348
- existingWrapper.____slothletInternal.impl = null;
349
- } else {
350
-
351
-
352
-
353
-
354
- if (nextWrapper.____slothletInternal.impl !== undefined) {
355
- existingWrapper.____slothletInternal.impl = nextWrapper.____slothletInternal.impl;
356
-
357
- if (
358
- typeof nextWrapper.____slothletInternal.impl === "function" ||
359
- (nextWrapper.____slothletInternal.impl && typeof nextWrapper.____slothletInternal.impl.default === "function")
360
- ) {
361
- existingWrapper.isCallable = true;
362
- }
363
- }
364
-
365
- }
366
-
367
-
368
- for (const key of existingChildKeys) {
369
- delete existingWrapper[key];
370
- }
371
- existingWrapper.___adoptImplChildren();
372
-
373
-
374
-
375
- for (const key of nextChildKeys) {
376
- const childValue = nextWrapper[key];
377
- Object.defineProperty(existingWrapper, key, {
378
- value: childValue,
379
- writable: false,
380
- enumerable: true,
381
- configurable: true
382
- });
383
- }
384
- } else if (collisionMode === "merge") {
385
-
386
-
387
-
388
-
389
- for (const key of nextChildKeys) {
390
- const isInternal = typeof key === "string" && (key.startsWith("_") || key.startsWith("__"));
391
-
392
-
393
- if (!isInternal && !Object.prototype.hasOwnProperty.call(existingWrapper, key)) {
394
- const childValue = nextWrapper[key];
395
- Object.defineProperty(existingWrapper, key, {
396
- value: childValue,
397
- writable: false,
398
- enumerable: true,
399
- configurable: true
400
- });
401
- } else if (!isInternal) {
402
-
403
-
404
- const existingChild = existingWrapper[key];
405
- const nextChild = nextWrapper[key];
406
- if (this.isWrapperProxy(existingChild) && this.isWrapperProxy(nextChild)) {
407
-
408
-
409
- const syncWrapper_nextChildWrapper = resolveWrapper(nextChild) ?? nextChild;
410
- const syncWrapper_hasGrandChildren = Object.keys(syncWrapper_nextChildWrapper).some(
411
- (k) => !k.startsWith("_") && !k.startsWith("__")
412
- );
413
- if (syncWrapper_hasGrandChildren) {
414
- await this.syncWrapper(existingChild, nextChild, config, collisionMode, moduleID);
415
- }
416
- }
417
- }
418
-
419
- }
420
-
421
-
422
- } else if (collisionMode === "merge-replace") {
423
-
424
- for (const key of nextChildKeys) {
425
- const childValue = nextWrapper[key];
426
- const isInternal = typeof key === "string" && (key.startsWith("_") || key.startsWith("__"));
427
-
428
- if (!isInternal && Object.prototype.hasOwnProperty.call(existingWrapper, key)) {
429
-
430
- const existingChild = existingWrapper[key];
431
- if (this.isWrapperProxy(existingChild) && this.isWrapperProxy(childValue)) {
432
- await this.syncWrapper(existingChild, childValue, config, collisionMode, moduleID);
433
- } else {
434
-
435
- delete existingWrapper[key];
436
- Object.defineProperty(existingWrapper, key, {
437
- value: childValue,
438
- writable: false,
439
- enumerable: true,
440
- configurable: true
441
- });
442
- }
443
-
444
-
445
- } else if (!isInternal) {
446
-
447
- Object.defineProperty(existingWrapper, key, {
448
- value: childValue,
449
- writable: false,
450
- enumerable: true,
451
- configurable: true
452
- });
453
- }
454
- }
455
- }
456
-
457
-
458
-
459
-
460
-
461
- if (existingWrapper.____slothletInternal.state) {
462
-
463
- const isActuallyMaterialized =
464
- existingWrapper.____slothletInternal.impl && typeof existingWrapper.____slothletInternal.impl !== "function";
465
- existingWrapper.____slothletInternal.state.materialized = isActuallyMaterialized;
466
- existingWrapper.____slothletInternal.state.inFlight = false;
467
- }
468
-
469
- return true;
470
- }
471
-
472
-
473
- async mutateApiValue(existingValue, nextValue, options, config) {
474
- if (config?.debug?.api) {
475
- this.slothlet.debug("api", {
476
- key: "DEBUG_MODE_MUTATE_API_VALUE_CALLED",
477
- existingType: typeof existingValue,
478
- nextType: typeof nextValue
479
- });
480
- this.slothlet.debug("api", {
481
- key: "DEBUG_MODE_MUTATE_API_VALUE_WRAPPER_STATUS",
482
- existingIsWrapper: this.isWrapperProxy(existingValue),
483
- nextIsWrapper: this.isWrapperProxy(nextValue)
484
- });
485
- this.slothlet.debug("api", {
486
- key: "DEBUG_MODE_MUTATE_API_VALUE_NEXT_VALUE",
487
- nextValue
488
- });
489
- this.slothlet.debug("api", {
490
- key: "DEBUG_MODE_MUTATE_API_VALUE_NEXT_VALUE_KEYS",
491
-
492
-
493
- nextValueKeys: nextValue ? Object.keys(nextValue) : []
494
- });
495
- }
496
-
497
- if (existingValue === nextValue) {
498
- return;
499
- }
500
-
501
-
502
- if (this.isWrapperProxy(existingValue) && this.isWrapperProxy(nextValue)) {
503
- if (config?.debug?.api) {
504
- this.slothlet.debug("api", {
505
- key: "DEBUG_MODE_MUTATE_API_VALUE_SYNC_WRAPPERS"
506
- });
507
- }
508
- await this.syncWrapper(existingValue, nextValue, config, options.collisionMode, options.moduleID);
509
- return;
510
- }
511
-
512
-
513
-
514
- if (this.isWrapperProxy(existingValue) && !this.isWrapperProxy(nextValue)) {
515
-
516
- const nextIsObjectLike = nextValue && (typeof nextValue === "object" || typeof nextValue === "function");
517
- const nextHasKeys = nextIsObjectLike && Object.keys(nextValue).length > 0;
518
-
519
- if (nextHasKeys) {
520
- if (config?.debug?.api) {
521
- this.slothlet.debug("api", {
522
- key: "DEBUG_MODE_MUTATE_API_VALUE_MERGE_INTO_WRAPPER"
523
- });
524
- this.slothlet.debug("api", {
525
- key: "DEBUG_MODE_MUTATE_API_VALUE_MERGE_KEYS",
526
- keys: Object.keys(nextValue)
527
- });
528
- }
529
-
530
- await this.slothlet.builders.apiAssignment.mergeApiObjects(existingValue, nextValue, {
531
- removeMissing: options.removeMissing,
532
- mutateExisting: true,
533
- allowOverwrite: true,
534
- syncWrapper: this.syncWrapper.bind(this),
535
- collisionMode: options.collisionMode,
536
- moduleID: options.moduleID
537
- });
538
- return;
539
- }
540
-
541
-
542
- const existingValueRaw = resolveWrapper(existingValue);
543
-
544
-
545
- if (existingValueRaw !== null) {
546
- if (config?.debug?.api) {
547
- this.slothlet.debug("api", {
548
- key: "DEBUG_MODE_MUTATE_API_VALUE_SETIMPL_FALLBACK"
549
- });
550
- }
551
- existingValueRaw.___setImpl(resolveWrapper(nextValue)?.__impl ?? nextValue);
552
- return;
553
- }
554
- }
555
-
556
-
557
- if (existingValue && typeof existingValue === "object" && nextValue && typeof nextValue === "object") {
558
- await this.slothlet.builders.apiAssignment.mergeApiObjects(existingValue, nextValue, {
559
- removeMissing: options.removeMissing,
560
- mutateExisting: true,
561
- allowOverwrite: true,
562
- syncWrapper: this.syncWrapper.bind(this),
563
- collisionMode: options.collisionMode,
564
- moduleID: options.moduleID
565
- });
566
- return existingValue;
567
- }
568
-
569
-
570
- return nextValue;
571
- }
572
-
573
-
574
- async setValueAtPath(root, parts, value, options) {
575
- const parent = this.ensureParentPath(root, parts, {
576
- moduleID: options.moduleID,
577
- sourceFolder: options.sourceFolder
578
- });
579
- const finalKey = parts[parts.length - 1];
580
-
581
-
582
- const existing = parent ? parent[finalKey] : undefined;
583
-
584
-
585
- const collisionMode = options.collisionMode || "merge";
586
- const moduleID = options.moduleID;
587
-
588
- this.slothlet.debug("api", {
589
- key: "DEBUG_MODE_SET_VALUE_AT_PATH",
590
- finalKey,
591
- existingType: typeof existing,
592
- valueType: typeof value,
593
- collisionMode,
594
- options
595
- });
596
-
597
-
598
- if (existing !== undefined) {
599
- if (collisionMode === "error") {
600
- throw new this.SlothletError("INVALID_CONFIG_API_PATH_INVALID", {
601
- apiPath: parts.join("."),
602
- reason: translate("API_PATH_REASON_COLLISION_ERROR"),
603
- index: undefined,
604
- segment: undefined,
605
- validationError: true
606
- });
607
- }
608
-
609
- if (collisionMode === "skip") {
610
- this.slothlet.debug("api", {
611
- key: "DEBUG_MODE_SET_VALUE_AT_PATH_SKIP_COLLISION",
612
- path: parts.join("."),
613
- mode: "skip"
614
- });
615
- return false;
616
- }
617
-
618
- if (collisionMode === "warn") {
619
- if (this.slothlet && !this.____config?.silent) {
620
- new this.SlothletWarning("WARNING_HOT_RELOAD_PATH_COLLISION", {
621
- apiPath: parts.join(".")
622
- });
623
- }
624
- return false;
625
- }
626
-
627
- if (collisionMode === "replace") {
628
- const existingIsObject = typeof existing === "object" || typeof existing === "function";
629
- const valueIsObject = typeof value === "object" || typeof value === "function";
630
-
631
- if (existingIsObject && valueIsObject) {
632
- this.slothlet.debug("api", {
633
- key: "DEBUG_MODE_SET_VALUE_AT_PATH_REPLACE_MERGE",
634
- path: parts.join("."),
635
- mode: "replace"
636
- });
637
-
638
- await this.mutateApiValue(
639
- existing,
640
- value,
641
- { removeMissing: false, allowOverwrite: true, collisionMode: "replace", moduleID },
642
- this.____config
643
- );
644
- return true;
645
- } else {
646
-
647
- parent[finalKey] = value;
648
- return true;
649
- }
650
- }
651
-
652
-
653
-
654
- if (collisionMode === "merge" || collisionMode === "merge-replace") {
655
- const existingIsObject = typeof existing === "object" || typeof existing === "function";
656
- const valueIsObject = typeof value === "object" || typeof value === "function";
657
-
658
- if (existingIsObject && valueIsObject) {
659
- this.slothlet.debug("api", {
660
- key: "DEBUG_MODE_SET_VALUE_AT_PATH_MERGE_PROPS",
661
- mode: collisionMode
662
- });
663
- await this.mutateApiValue(existing, value, { removeMissing: false, allowOverwrite: true, collisionMode }, this.____config);
664
- return true;
665
- } else {
666
-
667
- if (this.slothlet && !this.____config?.silent) {
668
- new this.SlothletWarning("WARNING_HOT_RELOAD_MERGE_PRIMITIVES", {
669
- apiPath: parts.join(".")
670
- });
671
- }
672
- return false;
673
- }
674
- }
675
- }
676
-
677
-
678
- this.slothlet.debug("api", {
679
- key: "DEBUG_MODE_SET_VALUE_AT_PATH_ASSIGN",
680
- finalKey
681
- });
682
- parent[finalKey] = value;
683
- return true;
684
- }
685
-
686
-
687
- async deletePath(root, parts) {
688
- let current = root;
689
- const stack = [];
690
- for (const part of parts.slice(0, -1)) {
691
- if (!current || (typeof current !== "object" && typeof current !== "function")) {
692
- return false;
693
- }
694
- stack.push({ parent: current, key: part });
695
- current = current[part];
696
- }
697
-
698
- const finalKey = parts[parts.length - 1];
699
- if (!current || (typeof current !== "object" && typeof current !== "function")) {
700
- return false;
701
- }
702
- if (!Object.prototype.hasOwnProperty.call(current, finalKey)) {
703
- return false;
704
- }
705
-
706
-
707
- const removedImpl = current[finalKey];
708
- const apiPath = parts.join(".");
709
-
710
-
711
- if (removedImpl && this.slothlet.handlers?.lifecycle) {
712
- const metadata = this.slothlet.handlers.metadata?.getMetadata?.(removedImpl);
713
- await this.slothlet.handlers.lifecycle.emit("impl:removed", {
714
- apiPath,
715
- impl: removedImpl,
716
- source: "removal",
717
- moduleID: metadata?.moduleID,
718
- filePath: metadata?.filePath,
719
- sourceFolder: metadata?.sourceFolder
720
- });
721
- }
722
-
723
-
724
-
725
- if (resolveWrapper(current)) {
726
- const wrapper = resolveWrapper(current);
727
-
728
- const isInternal = typeof finalKey === "string" && (finalKey.startsWith("_") || finalKey.startsWith("__"));
729
- if (!isInternal && finalKey in wrapper) {
730
- delete wrapper[finalKey];
731
- }
732
-
733
- if (wrapper.____slothletInternal.impl && typeof wrapper.____slothletInternal.impl === "object") {
734
- delete wrapper.____slothletInternal.impl[finalKey];
735
- }
736
- }
737
-
738
-
739
- delete current[finalKey];
740
-
741
-
742
-
743
-
744
- if (removedImpl && (typeof removedImpl === "object" || typeof removedImpl === "function")) {
745
-
746
-
747
-
748
- if (resolveWrapper(removedImpl)) {
749
- const wrapper = resolveWrapper(removedImpl);
750
-
751
- if (wrapper.____slothletInternal.impl !== undefined) {
752
- wrapper.____slothletInternal.impl = null;
753
- }
754
-
755
- const childKeys = Object.keys(wrapper).filter((k) => !k.startsWith("_") && !k.startsWith("__"));
756
- for (const key of childKeys) {
757
- delete wrapper[key];
758
- }
759
-
760
-
761
-
762
- if (wrapper.____slothletInternal.state) {
763
- wrapper.____slothletInternal.state.materialized = false;
764
- wrapper.____slothletInternal.state.inFlight = false;
765
- }
766
- }
767
- }
768
-
769
-
770
-
771
-
772
- if (this.slothlet.handlers?.metadata) {
773
- const rootSegment = apiPath.split(".")[0];
774
- this.slothlet.handlers.metadata.removeUserMetadataByApiPath(rootSegment);
775
- }
776
-
777
- for (let i = stack.length - 1; i >= 0; i -= 1) {
778
- const { parent, key } = stack[i];
779
- const value = parent[key];
780
- if (value && (typeof value === "object" || typeof value === "function") && Object.keys(value).length === 0) {
781
- delete parent[key];
782
- }
783
- }
784
-
785
- return true;
786
- }
787
-
788
- async restoreApiPath(apiPath, moduleID) {
789
-
790
-
791
- const normalizedModuleId = moduleID || null;
792
- const historyEntry = this.state.addHistory
793
- .slice()
794
- .reverse()
795
-
796
-
797
- .find((entry) => entry.apiPath === apiPath && (normalizedModuleId ? entry.moduleID === normalizedModuleId : true));
798
-
799
-
800
-
801
-
802
- if (historyEntry) {
803
- await this.addApiComponent({
804
- apiPath: historyEntry.apiPath,
805
- folderPath: historyEntry.folderPath,
806
- options: {
807
- ...historyEntry.options,
808
- metadata: historyEntry.metadata,
809
- mutateExisting: true,
810
- forceOverwrite: true,
811
- collisionMode: "replace",
812
- recordHistory: false
813
- }
814
- });
815
- return;
816
- }
817
-
818
-
819
-
820
-
821
- if (normalizedModuleId === "base" || normalizedModuleId === "core") {
822
- const baseApi = await this.slothlet.builders.builder.buildAPI({
823
- dir: this.____config.dir,
824
- mode: this.____config.mode,
825
- moduleID: "base"
826
- });
827
-
828
- const { parts } = this.normalizeApiPath(apiPath);
829
- let baseValue = this.getValueAtPath(baseApi, parts);
830
- if (baseValue === undefined) {
831
- await this.deletePath(this.slothlet.api, parts);
832
- await this.deletePath(this.slothlet.boundApi, parts);
833
- return;
834
- }
835
-
836
-
837
-
838
-
839
-
840
- const baseValueRaw = resolveWrapper(baseValue);
841
-
842
-
843
- if (baseValue && baseValueRaw !== null) {
844
- baseValue = baseValueRaw.__impl;
845
- }
846
-
847
- await this.setValueAtPath(this.slothlet.api, parts, baseValue, {
848
- mutateExisting: true,
849
- allowOverwrite: true,
850
- collisionMode: "replace",
851
- moduleID: normalizedModuleId
852
- });
853
- await this.setValueAtPath(this.slothlet.boundApi, parts, baseValue, {
854
- mutateExisting: true,
855
- allowOverwrite: true,
856
- collisionMode: "replace",
857
- moduleID: normalizedModuleId
858
- });
859
- }
860
- }
861
-
862
-
863
- async addApiComponent(params) {
864
-
865
-
866
- const { apiPath, folderPath, options = {}, versionConfig = null } = params || {};
867
-
868
-
869
- if (Array.isArray(folderPath)) {
870
- const moduleIDs = [];
871
- for (const singlePath of folderPath) {
872
- const moduleID = await this.addApiComponent({
873
- apiPath,
874
- folderPath: singlePath,
875
- options,
876
- versionConfig
877
- });
878
- moduleIDs.push(moduleID);
879
- }
880
- return moduleIDs;
881
- }
882
-
883
- const { metadata = {}, ...restOptions } = options;
884
- if (!this.slothlet || !this.slothlet.isLoaded) {
885
- throw new this.SlothletError("INVALID_CONFIG_NOT_LOADED", {
886
- operation: "addApi",
887
- validationError: true
888
- });
889
- }
890
-
891
- const { apiPath: normalizedPath, parts } = this.normalizeApiPath(apiPath);
892
-
893
-
894
- let effectivePath = normalizedPath;
895
- let effectiveParts = parts;
896
- if (versionConfig?.version !== undefined && versionConfig?.version !== null) {
897
-
898
-
899
-
900
- if (normalizedPath === "") {
901
- throw new this.SlothletError("INVALID_CONFIG_API_PATH_INVALID", {
902
- apiPath,
903
- reason: translate("API_PATH_REASON_VERSIONED_ROOT"),
904
- index: undefined,
905
- segment: undefined,
906
- validationError: true
907
- });
908
- }
909
- if (typeof versionConfig.version !== "string" || !String(versionConfig.version).trim()) {
910
- throw new this.SlothletError("INVALID_CONFIG_VERSION_TAG", {
911
- received: versionConfig.version,
912
- validationError: true
913
- });
914
- }
915
- const versionTag = String(versionConfig.version).trim();
916
-
917
-
918
-
919
-
920
- effectiveParts = [versionTag, ...parts];
921
- effectivePath = effectiveParts.join(".");
922
- }
923
-
924
-
925
- const { resolvedPath, isDirectory, isFile } = await this.resolvePath(folderPath);
926
-
927
-
928
- if (!isDirectory && !isFile) {
929
- throw new this.SlothletError("INVALID_CONFIG_PATH_TYPE", {
930
- path: resolvedPath,
931
- validationError: true
932
- });
933
- }
934
-
935
- if (isFile) {
936
-
937
- const ext = path.extname(resolvedPath);
938
- if (![".mjs", ".cjs", ".js"].includes(ext)) {
939
- throw new this.SlothletError("INVALID_CONFIG_FILE_TYPE", {
940
- path: resolvedPath,
941
- extension: ext,
942
- validationError: true
943
- });
944
- }
945
- }
946
-
947
-
948
- const resolvedFolderPath = resolvedPath;
949
-
950
-
951
-
952
-
953
- let collisionMode;
954
- if (restOptions.forceOverwrite) {
955
- collisionMode = "replace";
956
- } else {
957
-
958
-
959
- collisionMode = restOptions.collisionMode || this.____config.api?.collision?.api || "error";
960
- }
961
-
962
- const mutateExisting = !!(restOptions.mutateExisting || collisionMode === "merge");
963
-
964
- const moduleID = restOptions.moduleID ? String(restOptions.moduleID) : this.buildDefaultModuleId(normalizedPath, resolvedFolderPath);
965
-
966
-
967
-
968
-
969
- if (restOptions.forceOverwrite && !moduleID) {
970
- throw new this.SlothletError("INVALID_CONFIG_FORCE_OVERWRITE_REQUIRES_MODULE_ID", {
971
- apiPath: normalizedPath,
972
- validationError: true
973
- });
974
- }
975
-
976
-
977
-
978
-
979
- let dirForBuild = resolvedFolderPath;
980
- let fileFilter = null;
981
-
982
- if (isFile) {
983
- dirForBuild = path.dirname(resolvedFolderPath);
984
- const fileName = path.basename(resolvedFolderPath);
985
- fileFilter = (file) => file === fileName;
986
- }
987
-
988
- const newApi = await this.slothlet.builders.builder.buildAPI({
989
- dir: dirForBuild,
990
- mode: this.____config.mode,
991
-
992
-
993
-
994
-
995
- apiPathPrefix: effectivePath,
996
- collisionContext: "addApi",
997
- moduleID: moduleID,
998
-
999
- collisionMode: collisionMode,
1000
-
1001
- fileFilter: fileFilter
1002
- });
1003
-
1004
-
1005
-
1006
-
1007
- if (this.slothlet.handlers.apiCacheManager) {
1008
- this.slothlet.handlers.apiCacheManager.set(moduleID, {
1009
- endpoint: effectivePath,
1010
- moduleID: moduleID,
1011
- api: newApi,
1012
- folderPath: resolvedFolderPath,
1013
- mode: this.____config.mode,
1014
- sanitizeOptions: this.____config.sanitize || {},
1015
- collisionMode: collisionMode,
1016
- config: { ...this.____config },
1017
- timestamp: Date.now()
1018
- });
1019
- }
1020
-
1021
- this.slothlet.debug("api", {
1022
- key: "DEBUG_MODE_ADD_API_COMPONENT_BUILD_RETURN",
1023
- topLevelKeys: Object.keys(newApi),
1024
- dottedKeys: Object.keys(newApi).filter((k) => k.includes(".")),
1025
- wrappers: Object.keys(newApi)
1026
- .filter((k) => resolveWrapper(newApi[k]) !== null)
1027
- .map((k) => {
1028
- const _w = resolveWrapper(newApi[k]);
1029
- return {
1030
- key: k,
1031
- apiPath: _w.apiPath,
1032
- implKeys: Object.keys(_w.____slothletInternal.impl || {}),
1033
- childCacheSize: Object.keys(_w).filter((k) => !k.startsWith("_") && !k.startsWith("__")).length,
1034
- childCacheKeys: Object.keys(_w).filter((k) => !k.startsWith("_") && !k.startsWith("__"))
1035
- };
1036
- }),
1037
- nonWrappers: Object.keys(newApi)
1038
- .filter((k) => resolveWrapper(newApi[k]) === null)
1039
- .map((k) => ({ key: k, type: typeof newApi[k] }))
1040
- });
1041
-
1042
-
1043
-
1044
-
1045
-
1046
- let apiToMerge = newApi;
1047
-
1048
-
1049
-
1050
-
1051
- if (isFile && Object.keys(newApi).length === 1) {
1052
- const fileName = Object.keys(newApi)[0];
1053
- apiToMerge = newApi[fileName];
1054
- }
1055
-
1056
-
1057
-
1058
-
1059
-
1060
-
1061
-
1062
-
1063
-
1064
-
1065
-
1066
-
1067
-
1068
- if (!isFile && normalizedPath) {
1069
- const lastPart = normalizedPath.includes(".") ? normalizedPath.split(".").pop() : normalizedPath;
1070
- if (lastPart && Object.prototype.hasOwnProperty.call(apiToMerge, lastPart)) {
1071
- const dupValue = apiToMerge[lastPart];
1072
- const dupType = typeof dupValue;
1073
-
1074
-
1075
- if (dupValue !== null && (dupType === "object" || dupType === "function")) {
1076
-
1077
-
1078
-
1079
-
1080
- const dupWrapper = resolveWrapper(dupValue);
1081
- const dupFilePath = dupWrapper?.____slothletInternal?.filePath;
1082
-
1083
-
1084
- const dupFileDir = dupFilePath ? dupFilePath.replace(/\\/g, "/").split("/").slice(0, -1).join("/") : null;
1085
- const normalizedFolderPath = resolvedFolderPath.replace(/\\/g, "/").replace(/\/$/, "");
1086
- const expectedDir = normalizedFolderPath + "/" + lastPart;
1087
-
1088
-
1089
-
1090
-
1091
-
1092
-
1093
-
1094
- const isDirectChild = dupFileDir === expectedDir || dupFileDir === normalizedFolderPath;
1095
-
1096
- if (isDirectChild) {
1097
-
1098
- const hoisted = {};
1099
- for (const k of Object.keys(apiToMerge)) {
1100
- if (k !== lastPart) hoisted[k] = apiToMerge[k];
1101
- }
1102
-
1103
-
1104
-
1105
- if (dupWrapper) {
1106
-
1107
- for (const k of Object.keys(dupWrapper).filter((k) => !k.startsWith("_") && !k.startsWith("__"))) {
1108
- hoisted[k] = dupWrapper[k];
1109
- }
1110
- } else {
1111
-
1112
-
1113
-
1114
-
1115
- for (const k of Object.keys(dupValue)) {
1116
- hoisted[k] = dupValue[k];
1117
- }
1118
-
1119
- }
1120
- apiToMerge = hoisted;
1121
- this.slothlet.debug("api", {
1122
- key: "DEBUG_MODE_RULE_13_DEDUP_HOISTED_KEY",
1123
- lastPart,
1124
- newKeys: Object.keys(apiToMerge)
1125
- });
1126
- }
1127
- }
1128
- }
1129
- }
1130
-
1131
- if (this.____config.debug?.api) {
1132
- this.slothlet.debug("api", {
1133
- key: "DEBUG_MODE_ADD_API_COMPONENT_MERGE_KEYS",
1134
- keys: Object.keys(apiToMerge),
1135
- isRootLevel: parts.length === 0
1136
- });
1137
- }
1138
-
1139
-
1140
-
1141
-
1142
- let anyAssignmentSucceeded = false;
1143
-
1144
- if (parts.length === 0) {
1145
-
1146
- for (const key of Object.keys(newApi)) {
1147
- const result1 = await this.setValueAtPath(this.slothlet.api, [key], newApi[key], {
1148
- mutateExisting,
1149
- collisionMode,
1150
- moduleID,
1151
- sourceFolder: resolvedFolderPath
1152
- });
1153
-
1154
- const result2 = await this.setValueAtPath(this.slothlet.boundApi, [key], newApi[key], {
1155
- mutateExisting,
1156
- collisionMode,
1157
- moduleID,
1158
- sourceFolder: resolvedFolderPath
1159
- });
1160
-
1161
-
1162
- if (result1 || result2) {
1163
- anyAssignmentSucceeded = true;
1164
- }
1165
- }
1166
- } else {
1167
-
1168
-
1169
-
1170
- if (resolveWrapper(apiToMerge) === null) {
1171
-
1172
-
1173
-
1174
- const isCallableNamespace = typeof apiToMerge === "function";
1175
-
1176
- const containerWrapper = new UnifiedWrapper(this.slothlet, {
1177
- apiPath: effectivePath,
1178
- mode: this.____config.mode,
1179
- isCallable: isCallableNamespace,
1180
- moduleID: moduleID,
1181
- filePath: resolvedFolderPath,
1182
- sourceFolder: resolvedFolderPath
1183
- });
1184
-
1185
- containerWrapper.___setImpl(apiToMerge, moduleID);
1186
-
1187
- apiToMerge = containerWrapper.createProxy();
1188
- }
1189
-
1190
- const result1 = await this.setValueAtPath(this.slothlet.api, effectiveParts, apiToMerge, {
1191
- mutateExisting,
1192
- collisionMode,
1193
- moduleID,
1194
- sourceFolder: resolvedFolderPath
1195
- });
1196
-
1197
- const result2 = await this.setValueAtPath(this.slothlet.boundApi, effectiveParts, apiToMerge, {
1198
- mutateExisting,
1199
- collisionMode,
1200
- moduleID,
1201
- sourceFolder: resolvedFolderPath
1202
- });
1203
-
1204
-
1205
- if (result1 || result2) {
1206
- anyAssignmentSucceeded = true;
1207
- }
1208
- }
1209
-
1210
-
1211
-
1212
-
1213
-
1214
-
1215
-
1216
- if (anyAssignmentSucceeded) {
1217
- const pendingMaterializations = [];
1218
- const seenWrappers = new Set();
1219
-
1220
-
1221
- const collectPendingMaterializations = (obj, depth = 0) => {
1222
- if (!obj || typeof obj !== "object" || depth > 10) return;
1223
-
1224
-
1225
-
1226
-
1227
- if (obj.__isVersionDispatcher === true) return;
1228
-
1229
- const wrapper = resolveWrapper(obj);
1230
- if (wrapper) {
1231
-
1232
- if (seenWrappers.has(wrapper)) return;
1233
- seenWrappers.add(wrapper);
1234
-
1235
-
1236
-
1237
-
1238
- if (wrapper.____slothletInternal.materializationPromise) {
1239
- pendingMaterializations.push(wrapper.____slothletInternal.materializationPromise);
1240
- }
1241
-
1242
-
1243
- const childKeys = Object.keys(wrapper).filter((k) => !k.startsWith("_") && !k.startsWith("__"));
1244
- for (const key of childKeys) {
1245
- collectPendingMaterializations(wrapper[key], depth + 1);
1246
- }
1247
- }
1248
-
1249
-
1250
- for (const key of Object.keys(obj)) {
1251
-
1252
-
1253
- if (key !== "____slothletInternal") {
1254
- collectPendingMaterializations(obj[key], depth + 1);
1255
- }
1256
- }
1257
- };
1258
-
1259
-
1260
-
1261
-
1262
-
1263
- if (effectiveParts.length === 0) {
1264
-
1265
- for (const key of Object.keys(newApi)) {
1266
-
1267
-
1268
- if (this.slothlet.api[key]) {
1269
- collectPendingMaterializations(this.slothlet.api[key]);
1270
- }
1271
- }
1272
- } else {
1273
-
1274
- let current = this.slothlet.api;
1275
- for (const part of effectiveParts) {
1276
-
1277
-
1278
- if (current && current[part]) {
1279
- current = current[part];
1280
- } else {
1281
- break;
1282
- }
1283
-
1284
- }
1285
-
1286
-
1287
- if (current) {
1288
- collectPendingMaterializations(current);
1289
- }
1290
- }
1291
-
1292
-
1293
-
1294
-
1295
- if (pendingMaterializations.length > 0) {
1296
- if (this.____config.debug?.api) {
1297
- this.slothlet.debug("api", {
1298
- key: "DEBUG_MODE_AWAITING_PENDING_MATERIALIZATIONS",
1299
- count: pendingMaterializations.length,
1300
- apiPath: normalizedPath
1301
- });
1302
- }
1303
- await Promise.all(pendingMaterializations);
1304
- }
1305
-
1306
- }
1307
-
1308
-
1309
-
1310
-
1311
-
1312
-
1313
- if (anyAssignmentSucceeded && metadata && Object.keys(metadata).length > 0 && this.slothlet.handlers.metadata) {
1314
- if (parts.length === 0) {
1315
-
1316
- for (const key of Object.keys(newApi)) {
1317
- this.slothlet.handlers.metadata.registerUserMetadata(key, metadata);
1318
- }
1319
- } else {
1320
-
1321
-
1322
-
1323
-
1324
- const rootSegment = effectiveParts[0];
1325
- this.slothlet.handlers.metadata.registerUserMetadata(rootSegment, metadata);
1326
- }
1327
- }
1328
-
1329
-
1330
-
1331
-
1332
-
1333
-
1334
- if (this.slothlet.handlers.ownership && moduleID) {
1335
- this.slothlet.handlers.ownership.registerSubtree(apiToMerge, moduleID, effectivePath);
1336
- }
1337
-
1338
-
1339
-
1340
- if (this.slothlet.handlers.ownership) {
1341
- if (restOptions.recordHistory !== false) {
1342
- this.state.addHistory.push({
1343
- apiPath: normalizedPath,
1344
- folderPath: resolvedFolderPath,
1345
- options: { ...restOptions, metadata, moduleID },
1346
- moduleID,
1347
- versionConfig: versionConfig || null
1348
- });
1349
-
1350
-
1351
-
1352
- this.state.operationHistory.push({
1353
- type: "add",
1354
- apiPath: normalizedPath,
1355
- folderPath: resolvedFolderPath,
1356
- options: { ...restOptions, metadata, moduleID },
1357
- moduleID,
1358
- versionConfig: versionConfig || null
1359
- });
1360
- }
1361
- }
1362
-
1363
-
1364
-
1365
-
1366
-
1367
- if (versionConfig?.version && this.slothlet.handlers.versionManager) {
1368
- const versionTag = String(versionConfig.version).trim();
1369
- try {
1370
- this.slothlet.handlers.versionManager.registerVersion(
1371
- normalizedPath,
1372
- versionTag,
1373
- moduleID,
1374
- versionConfig.metadata ?? {},
1375
- versionConfig.default ?? false
1376
- );
1377
- } catch (error) {
1378
- await this._rollbackFailedVersionedAdd({ moduleID, effectivePath, normalizedPath });
1379
- throw error;
1380
- }
1381
- }
1382
-
1383
- return moduleID;
1384
- }
1385
-
1386
-
1387
- async _rollbackFailedVersionedAdd({ moduleID, effectivePath, normalizedPath }) {
1388
-
1389
-
1390
-
1391
-
1392
-
1393
- let addIndex = -1;
1394
- for (let i = this.state.operationHistory.length - 1; i >= 0; i--) {
1395
- const entry = this.state.operationHistory[i];
1396
- if (entry?.type === "add" && entry?.apiPath === normalizedPath && entry?.moduleID === moduleID) {
1397
- addIndex = i;
1398
- break;
1399
- }
1400
- }
1401
- if (addIndex !== -1) {
1402
- this.state.operationHistory.splice(addIndex, 1);
1403
- }
1404
-
1405
-
1406
-
1407
-
1408
-
1409
- this.state.addHistory = this.state.addHistory.filter((entry) => entry?.moduleID !== moduleID);
1410
-
1411
-
1412
-
1413
-
1414
- try {
1415
- await this.removeApiComponent(moduleID || effectivePath, { recordHistory: false });
1416
- } catch {
1417
-
1418
-
1419
- }
1420
- }
1421
-
1422
-
1423
- async removeApiComponent(pathOrModuleId, options = {}) {
1424
- const recordHistory = options.recordHistory !== false;
1425
- if (typeof pathOrModuleId !== "string" || !pathOrModuleId) {
1426
- throw new this.SlothletError("INVALID_ARGUMENT", {
1427
- argument: "pathOrModuleId",
1428
- expected: "non-empty string",
1429
- received: typeof pathOrModuleId,
1430
- validationError: true
1431
- });
1432
- }
1433
-
1434
-
1435
-
1436
- let apiPath = null;
1437
- let moduleID = null;
1438
-
1439
- if (this.slothlet.handlers.ownership) {
1440
-
1441
- const candidateModuleID = pathOrModuleId.split(":")[0];
1442
-
1443
-
1444
-
1445
-
1446
-
1447
- const registeredModules = Array.from(this.slothlet.handlers.ownership.moduleToPath.keys());
1448
- let matchingModule = null;
1449
- for (let i = registeredModules.length - 1; i >= 0; i--) {
1450
- const candidate = registeredModules[i];
1451
- if (candidate === candidateModuleID || candidate.startsWith(`${candidateModuleID}_`)) {
1452
- matchingModule = candidate;
1453
- break;
1454
- }
1455
- }
1456
-
1457
- if (matchingModule) {
1458
-
1459
- moduleID = matchingModule;
1460
- } else {
1461
-
1462
- const owner = this.slothlet.handlers.ownership.getCurrentOwner(pathOrModuleId);
1463
- if (owner) {
1464
-
1465
- apiPath = pathOrModuleId;
1466
- moduleID = owner.moduleID;
1467
- } else {
1468
-
1469
- return false;
1470
- }
1471
- }
1472
- } else {
1473
-
1474
- const isModuleId = !pathOrModuleId.includes(".");
1475
- apiPath = isModuleId ? null : pathOrModuleId;
1476
- moduleID = isModuleId ? pathOrModuleId.split(":")[0] : null;
1477
- }
1478
- if (!this.slothlet || !this.slothlet.isLoaded) {
1479
- throw new this.SlothletError("INVALID_CONFIG_NOT_LOADED", {
1480
- operation: "removeApi",
1481
- validationError: true
1482
- });
1483
- }
1484
-
1485
- if (apiPath && moduleID) {
1486
- const normalizedPath = this.normalizeApiPath(apiPath).apiPath;
1487
- const moduleIDKey = String(moduleID);
1488
-
1489
-
1490
- const history = this.slothlet.handlers.ownership?.getPathHistory?.(normalizedPath) || [];
1491
-
1492
-
1493
- const ownershipResult = this.slothlet.handlers.ownership?.removePath?.(normalizedPath, moduleIDKey) || {
1494
- action: "none",
1495
- removedModuleId: null,
1496
- restoreModuleId: null
1497
- };
1498
- const pathParts = this.normalizeApiPath(apiPath).parts;
1499
- if (ownershipResult.action === "delete") {
1500
- await this.deletePath(this.slothlet.api, pathParts);
1501
- await this.deletePath(this.slothlet.boundApi, pathParts);
1502
-
1503
-
1504
-
1505
- if (this.slothlet.handlers.metadata) {
1506
- const rootSegment = normalizedPath.split(".")[0];
1507
- this.slothlet.handlers.metadata.removeUserMetadataByApiPath(rootSegment);
1508
- }
1509
-
1510
- if (this.slothlet.handlers.versionManager) {
1511
- const versionKey = this.slothlet.handlers.versionManager.getVersionKeyForModule(moduleIDKey);
1512
- if (versionKey) {
1513
- this.slothlet.handlers.versionManager.unregisterVersion(versionKey.logicalPath, versionKey.versionTag);
1514
- }
1515
-
1516
-
1517
-
1518
- if (this.slothlet.handlers.versionManager.hasDispatcher(normalizedPath)) {
1519
- this.slothlet.handlers.versionManager.teardownDispatcher(normalizedPath);
1520
- }
1521
- }
1522
-
1523
- this.state.operationHistory.push({
1524
- type: "remove",
1525
- apiPath: normalizedPath
1526
- });
1527
- return true;
1528
- }
1529
-
1530
-
1531
-
1532
- if (ownershipResult.action === "restore") {
1533
- const restoredValue = this.slothlet.handlers.ownership?.getCurrentValue?.(normalizedPath);
1534
- const restoredModuleId = this.slothlet.handlers.ownership?.getCurrentOwner?.(normalizedPath)?.moduleID;
1535
- if (restoredValue !== undefined && restoredModuleId) {
1536
- await this.setValueAtPath(this.slothlet.api, pathParts, restoredValue, {
1537
- mutateExisting: true,
1538
- allowOverwrite: true,
1539
- collisionMode: "replace",
1540
- moduleID: restoredModuleId
1541
- });
1542
- await this.setValueAtPath(this.slothlet.boundApi, pathParts, restoredValue, {
1543
- mutateExisting: true,
1544
- allowOverwrite: true,
1545
- collisionMode: "replace",
1546
- moduleID: restoredModuleId
1547
- });
1548
-
1549
- this.state.operationHistory.push({
1550
- type: "remove",
1551
- apiPath: normalizedPath
1552
- });
1553
- return true;
1554
- }
1555
- await this.restoreApiPath(normalizedPath, ownershipResult.restoreModuleId);
1556
-
1557
- this.state.operationHistory.push({
1558
- type: "remove",
1559
- apiPath: normalizedPath
1560
- });
1561
- return true;
1562
- }
1563
- if (ownershipResult.action === "none" && history.length === 0) {
1564
- await this.deletePath(this.slothlet.api, pathParts);
1565
- await this.deletePath(this.slothlet.boundApi, pathParts);
1566
- return true;
1567
- }
1568
- return false;
1569
-
1570
- }
1571
-
1572
- if (moduleID) {
1573
- const moduleIDKey = String(moduleID);
1574
-
1575
-
1576
- const result = this.slothlet.handlers.ownership?.unregister?.(moduleIDKey) || { removed: [], rolledBack: [] };
1577
-
1578
-
1579
-
1580
-
1581
- if (this.slothlet.handlers.versionManager) {
1582
- const versionKey = this.slothlet.handlers.versionManager.getVersionKeyForModule(moduleIDKey);
1583
- if (versionKey) {
1584
- this.slothlet.handlers.versionManager.unregisterVersion(versionKey.logicalPath, versionKey.versionTag);
1585
- }
1586
- }
1587
-
1588
-
1589
- const allPaths = [...result.removed, ...result.rolledBack.map((r) => r.apiPath)];
1590
-
1591
-
1592
- const uniquePaths = [...new Set(allPaths)];
1593
-
1594
-
1595
- const pathsToDelete = [];
1596
- const pathsToRollback = [];
1597
-
1598
- for (const path of uniquePaths) {
1599
- const currentOwner = this.slothlet.handlers.ownership?.getCurrentOwner?.(path);
1600
-
1601
-
1602
-
1603
- const hasChildrenWithOtherOwners = uniquePaths.some((p) => {
1604
- if (p === path || !p.startsWith(path + ".")) return false;
1605
- const childOwner = this.slothlet.handlers.ownership?.getCurrentOwner?.(p);
1606
- return childOwner && childOwner.moduleID !== moduleIDKey;
1607
- });
1608
-
1609
-
1610
- if (currentOwner && currentOwner.moduleID !== moduleIDKey) {
1611
-
1612
- pathsToRollback.push({ apiPath: path, restoredTo: currentOwner.moduleID });
1613
- } else if (!hasChildrenWithOtherOwners) {
1614
-
1615
- pathsToDelete.push(path);
1616
- }
1617
-
1618
- }
1619
-
1620
-
1621
-
1622
- pathsToDelete.sort((a, b) => {
1623
- const depthA = (a.match(/\./g) || []).length;
1624
- const depthB = (b.match(/\./g) || []).length;
1625
- return depthB - depthA;
1626
- });
1627
-
1628
-
1629
- for (const removedPath of pathsToDelete) {
1630
- const { parts } = this.normalizeApiPath(removedPath);
1631
- await this.deletePath(this.slothlet.api, parts);
1632
- await this.deletePath(this.slothlet.boundApi, parts);
1633
-
1634
-
1635
-
1636
- if (this.slothlet.handlers.metadata) {
1637
- const rootSegment = removedPath.split(".")[0];
1638
- this.slothlet.handlers.metadata.removeUserMetadataByApiPath(rootSegment);
1639
- }
1640
- }
1641
-
1642
-
1643
-
1644
-
1645
-
1646
- if (pathsToDelete.length > 0) {
1647
- const rootSegment = pathsToDelete[0].split(".")[0];
1648
-
1649
-
1650
-
1651
-
1652
- if (rootSegment in this.slothlet.api) {
1653
- delete this.slothlet.api[rootSegment];
1654
- }
1655
-
1656
-
1657
-
1658
- if (rootSegment in this.slothlet.boundApi) {
1659
- delete this.slothlet.boundApi[rootSegment];
1660
- }
1661
- }
1662
-
1663
-
1664
- for (const rollback of pathsToRollback) {
1665
-
1666
- const { parts } = this.normalizeApiPath(rollback.apiPath);
1667
- const previousImpl = this.slothlet.handlers.ownership?.getCurrentValue?.(rollback.apiPath);
1668
-
1669
- if (previousImpl !== undefined) {
1670
-
1671
- const existingWrapper = this.getValueAtPath(this.slothlet.api, parts);
1672
- const existingWrapperRaw = resolveWrapper(existingWrapper);
1673
- if (existingWrapperRaw) {
1674
-
1675
- existingWrapperRaw.___setImpl(previousImpl, rollback.restoredTo);
1676
- }
1677
-
1678
- const existingBoundWrapper = this.getValueAtPath(this.slothlet.boundApi, parts);
1679
- const existingBoundWrapperRaw = resolveWrapper(existingBoundWrapper);
1680
- if (existingBoundWrapperRaw) {
1681
- existingBoundWrapperRaw.___setImpl(previousImpl, rollback.restoredTo);
1682
- }
1683
- }
1684
- }
1685
-
1686
- this.state.addHistory = this.state.addHistory.filter((entry) => String(entry.moduleID) !== moduleIDKey);
1687
-
1688
-
1689
-
1690
-
1691
- if (this.slothlet.handlers.apiCacheManager) {
1692
- const deleted = this.slothlet.handlers.apiCacheManager.delete(moduleIDKey);
1693
-
1694
-
1695
- if (deleted) {
1696
- this.slothlet.debug("cache", {
1697
- key: "DEBUG_MODE_CACHE_DELETED_MODULE_REMOVED",
1698
- moduleID: moduleIDKey
1699
- });
1700
- }
1701
- }
1702
-
1703
-
1704
-
1705
-
1706
- if (recordHistory && pathsToDelete.length > 0) {
1707
- const rootSegment = pathsToDelete[0].split(".")[0];
1708
- this.state.operationHistory.push({
1709
- type: "remove",
1710
- apiPath: rootSegment
1711
- });
1712
- }
1713
-
1714
- return pathsToDelete.length > 0 || pathsToRollback.length > 0;
1715
- }
1716
-
1717
-
1718
-
1719
- if (!apiPath) {
1720
- throw new this.SlothletError("INVALID_CONFIG_API_PATH_INVALID", {
1721
- apiPath,
1722
- reason: translate("API_PATH_REASON_REQUIRED"),
1723
- index: undefined,
1724
- segment: undefined,
1725
- validationError: true
1726
- });
1727
- }
1728
-
1729
- const { apiPath: normalizedPath, parts } = this.normalizeApiPath(apiPath);
1730
- const ownershipResult = this.slothlet.handlers.ownership?.removePath?.(normalizedPath, null) || {
1731
- action: "none",
1732
- removedModuleId: null,
1733
- restoreModuleId: null
1734
- };
1735
-
1736
-
1737
- const pathExists = this.getValueAtPath(this.slothlet.api, parts) !== undefined;
1738
-
1739
- if (ownershipResult.action === "none") {
1740
- if (pathExists) {
1741
- await this.deletePath(this.slothlet.api, parts);
1742
- await this.deletePath(this.slothlet.boundApi, parts);
1743
-
1744
-
1745
-
1746
- if (this.slothlet.handlers.metadata) {
1747
- this.slothlet.handlers.metadata.removeUserMetadataByApiPath(normalizedPath);
1748
- }
1749
-
1750
-
1751
-
1752
- if (recordHistory) {
1753
- this.state.operationHistory.push({
1754
- type: "remove",
1755
- apiPath: normalizedPath
1756
- });
1757
- }
1758
- return true;
1759
- }
1760
-
1761
- return false;
1762
- }
1763
-
1764
-
1765
- if (ownershipResult.action === "delete") {
1766
- await this.deletePath(this.slothlet.api, parts);
1767
- await this.deletePath(this.slothlet.boundApi, parts);
1768
-
1769
- if (this.slothlet.handlers.metadata) {
1770
- this.slothlet.handlers.metadata.removeUserMetadataByApiPath(normalizedPath);
1771
- }
1772
-
1773
- if (recordHistory) {
1774
- this.state.operationHistory.push({
1775
- type: "remove",
1776
- apiPath: normalizedPath
1777
- });
1778
- }
1779
- return true;
1780
- }
1781
- if (ownershipResult.action === "restore") {
1782
- const restoredValue = this.slothlet.handlers.ownership?.getCurrentValue?.(normalizedPath);
1783
- const restoredModuleId = this.slothlet.handlers.ownership?.getCurrentOwner?.(normalizedPath)?.moduleID;
1784
- if (restoredValue !== undefined && restoredModuleId) {
1785
- await this.setValueAtPath(this.slothlet.api, parts, restoredValue, {
1786
- mutateExisting: true,
1787
- allowOverwrite: true,
1788
- collisionMode: "replace",
1789
- moduleID: restoredModuleId
1790
- });
1791
- await this.setValueAtPath(this.slothlet.boundApi, parts, restoredValue, {
1792
- mutateExisting: true,
1793
- allowOverwrite: true,
1794
- collisionMode: "replace",
1795
- moduleID: restoredModuleId
1796
- });
1797
-
1798
- if (recordHistory) {
1799
- this.state.operationHistory.push({
1800
- type: "remove",
1801
- apiPath: normalizedPath
1802
- });
1803
- }
1804
- return true;
1805
- }
1806
- await this.restoreApiPath(normalizedPath, ownershipResult.restoreModuleId);
1807
-
1808
- if (recordHistory) {
1809
- this.state.operationHistory.push({
1810
- type: "remove",
1811
- apiPath: normalizedPath
1812
- });
1813
- }
1814
- return true;
1815
- }
1816
-
1817
-
1818
-
1819
- return false;
1820
- }
1821
-
1822
-
1823
- async reloadApiComponent(params) {
1824
- const { apiPath, moduleID, options } = params || {};
1825
- if (!this.slothlet || !this.slothlet.isLoaded) {
1826
- throw new this.SlothletError("INVALID_CONFIG_NOT_LOADED", {
1827
- operation: "reloadApi",
1828
- validationError: true
1829
- });
1830
- }
1831
-
1832
-
1833
- if (moduleID) {
1834
- await this._reloadByModuleID(moduleID);
1835
- return;
1836
- }
1837
-
1838
-
1839
- if (apiPath) {
1840
- await this._reloadByApiPath(apiPath, options);
1841
- return;
1842
- }
1843
-
1844
- throw new this.SlothletError("INVALID_ARGUMENT", {
1845
- argument: "params",
1846
- expected: "{ moduleID } or { apiPath }",
1847
- received: params,
1848
- validationError: true
1849
- });
1850
- }
1851
-
1852
-
1853
- async _reloadByModuleID(moduleID, { forceReplace = true } = {}) {
1854
- const cacheManager = this.slothlet.handlers.apiCacheManager;
1855
- if (!cacheManager) {
1856
- throw new this.SlothletError("CACHE_MANAGER_NOT_AVAILABLE", {
1857
- operation: "reload",
1858
- validationError: true
1859
- });
1860
- }
1861
-
1862
-
1863
- if (!cacheManager.has(moduleID)) {
1864
- throw new this.SlothletError("CACHE_NOT_FOUND", {
1865
- moduleID,
1866
- operation: "reload",
1867
- validationError: true
1868
- });
1869
- }
1870
-
1871
-
1872
- const oldEntry = cacheManager.get(moduleID);
1873
-
1874
- this.slothlet.debug("reload", {
1875
- key: "DEBUG_MODE_RELOADING_MODULE_BY_ID",
1876
- moduleID,
1877
- endpoint: oldEntry.endpoint,
1878
- folderPath: oldEntry.folderPath
1879
- });
1880
-
1881
-
1882
- const freshApi = await cacheManager.rebuildCache(moduleID);
1883
-
1884
-
1885
- cacheManager.set(moduleID, {
1886
- ...oldEntry,
1887
- api: freshApi,
1888
- timestamp: Date.now()
1889
- });
1890
-
1891
-
1892
- this.slothlet.debug("reload", {
1893
- key: "DEBUG_MODE_FRESH_API_KEYS_BEFORE_RESTORE",
1894
- moduleID,
1895
- endpoint: oldEntry.endpoint,
1896
-
1897
-
1898
- freshApiKeys: Object.keys(freshApi || {})
1899
- });
1900
-
1901
-
1902
- await this._restoreApiTree(freshApi, oldEntry.endpoint, moduleID, oldEntry.collisionMode, forceReplace);
1903
-
1904
-
1905
- this.slothlet.debug("reload", {
1906
- key: "DEBUG_MODE_FRESH_API_KEYS_AFTER_RESTORE",
1907
- moduleID,
1908
- endpoint: oldEntry.endpoint,
1909
-
1910
-
1911
- freshApiKeys: Object.keys(freshApi || {})
1912
- });
1913
-
1914
- this.slothlet.debug("reload", {
1915
- key: "DEBUG_MODE_MODULE_RELOAD_COMPLETE",
1916
- moduleID
1917
- });
1918
-
1919
-
1920
- if (this.slothlet.handlers.versionManager) {
1921
- this.slothlet.handlers.versionManager.onVersionedModuleReload(moduleID);
1922
- }
1923
- }
1924
-
1925
-
1926
- async _reloadByApiPath(apiPath, options = {}) {
1927
- this.slothlet.debug("reload", {
1928
- key: "DEBUG_MODE_RELOADING_BY_API_PATH",
1929
- apiPath
1930
- });
1931
-
1932
-
1933
- const moduleIDsToReload = this._findAffectedCaches(apiPath);
1934
-
1935
-
1936
-
1937
-
1938
- if (moduleIDsToReload.length === 0) {
1939
- this.slothlet.debug("reload", {
1940
- key: "DEBUG_MODE_NO_CACHES_ATTEMPTING_RESTORE",
1941
- apiPath
1942
- });
1943
-
1944
- if (apiPath !== "." && apiPath !== "") {
1945
- await this.restoreApiPath(apiPath, "base");
1946
- }
1947
- return;
1948
- }
1949
-
1950
-
1951
-
1952
-
1953
-
1954
- const cacheManager = this.slothlet.handlers.apiCacheManager;
1955
- moduleIDsToReload.sort((a, b) => {
1956
- const entryA = cacheManager.get(a);
1957
- const entryB = cacheManager.get(b);
1958
-
1959
-
1960
-
1961
-
1962
- if (entryA?.endpoint === "." && entryB?.endpoint !== ".") return -1;
1963
- if (entryB?.endpoint === "." && entryA?.endpoint !== ".") return 1;
1964
-
1965
-
1966
- const indexA = this.state.addHistory.findIndex((h) => h.moduleID === a);
1967
- const indexB = this.state.addHistory.findIndex((h) => h.moduleID === b);
1968
- return indexA - indexB;
1969
- });
1970
-
1971
-
1972
-
1973
-
1974
-
1975
- const endpointOrder = new Map();
1976
- for (const moduleID of moduleIDsToReload) {
1977
- const entry = cacheManager.get(moduleID);
1978
-
1979
-
1980
- const ep = entry?.endpoint ?? ".";
1981
- if (!endpointOrder.has(ep)) endpointOrder.set(ep, []);
1982
- endpointOrder.get(ep).push(moduleID);
1983
- }
1984
-
1985
- for (const [, moduleIDs] of endpointOrder) {
1986
- for (let i = 0; i < moduleIDs.length; i++) {
1987
- await this._reloadByModuleID(moduleIDs[i], { forceReplace: i === 0 });
1988
- }
1989
- }
1990
-
1991
-
1992
-
1993
-
1994
- const reloadMetadata = options?.metadata;
1995
- if (reloadMetadata && typeof reloadMetadata === "object" && Object.keys(reloadMetadata).length > 0) {
1996
-
1997
-
1998
- if (this.slothlet.handlers.metadata) {
1999
- const targetPath = apiPath === "." ? null : apiPath.split(".")[0];
2000
- if (targetPath) {
2001
- this.slothlet.handlers.metadata.registerUserMetadata(targetPath, reloadMetadata);
2002
- }
2003
- }
2004
- }
2005
-
2006
- this.slothlet.debug("reload", {
2007
- key: "DEBUG_MODE_API_PATH_RELOAD_COMPLETE",
2008
- apiPath,
2009
- reloadedModules: moduleIDsToReload.length,
2010
- loadOrder: moduleIDsToReload
2011
- });
2012
- }
2013
-
2014
-
2015
- _findAffectedCaches(apiPath) {
2016
- const cacheManager = this.slothlet.handlers.apiCacheManager;
2017
-
2018
-
2019
- if (!cacheManager) return [];
2020
-
2021
- const allModuleIDs = cacheManager.getAllModuleIDs();
2022
-
2023
-
2024
- if (apiPath === "." || apiPath === "" || apiPath == null) {
2025
- const baseModules = [];
2026
- for (const moduleID of allModuleIDs) {
2027
- const entry = cacheManager.get(moduleID);
2028
- if (entry && entry.endpoint === ".") {
2029
- baseModules.push(moduleID);
2030
- }
2031
- }
2032
- return baseModules;
2033
- }
2034
-
2035
-
2036
- const exactMatches = [];
2037
- for (const moduleID of allModuleIDs) {
2038
- const entry = cacheManager.get(moduleID);
2039
- if (entry && entry.endpoint === apiPath) {
2040
- exactMatches.push(moduleID);
2041
- }
2042
- }
2043
- if (exactMatches.length > 0) return exactMatches;
2044
-
2045
-
2046
- const children = [];
2047
- const pathPrefix = apiPath + ".";
2048
- for (const moduleID of allModuleIDs) {
2049
- const entry = cacheManager.get(moduleID);
2050
- if (entry?.endpoint?.startsWith(pathPrefix)) {
2051
- children.push(moduleID);
2052
- }
2053
- }
2054
- if (children.length > 0) return children;
2055
-
2056
-
2057
- const ownership = this.slothlet.handlers.ownership;
2058
- const history = ownership?.getPathHistory?.(apiPath);
2059
- if (history && history.length > 0) {
2060
- const owned = [];
2061
- for (const { moduleID } of history) {
2062
-
2063
-
2064
- if (cacheManager.has(moduleID)) {
2065
- owned.push(moduleID);
2066
- }
2067
- }
2068
-
2069
-
2070
- if (owned.length > 0) return owned;
2071
- }
2072
-
2073
-
2074
-
2075
-
2076
- let bestMatch = null;
2077
- let bestLength = -1;
2078
- for (const moduleID of allModuleIDs) {
2079
- const entry = cacheManager.get(moduleID);
2080
-
2081
-
2082
- if (!entry?.endpoint) continue;
2083
-
2084
- const ep = entry.endpoint;
2085
-
2086
-
2087
-
2088
-
2089
- if (ep === "." || apiPath.startsWith(ep + ".")) {
2090
-
2091
-
2092
- if (ep.length > bestLength) {
2093
- bestLength = ep.length;
2094
- bestMatch = moduleID;
2095
- }
2096
- }
2097
- }
2098
-
2099
-
2100
- if (bestMatch) return [bestMatch];
2101
-
2102
-
2103
-
2104
- return [];
2105
- }
2106
-
2107
-
2108
- _collectCustomProperties(existingProxy, freshApi) {
2109
- const customProps = {};
2110
-
2111
-
2112
-
2113
- if (!existingProxy || (typeof existingProxy !== "object" && typeof existingProxy !== "function")) {
2114
- return customProps;
2115
- }
2116
-
2117
-
2118
- const wrapper = resolveWrapper(existingProxy);
2119
-
2120
-
2121
- if (!wrapper) {
2122
- return customProps;
2123
- }
2124
-
2125
-
2126
-
2127
-
2128
-
2129
- const freshKeys = new Set(freshApi ? Object.keys(freshApi) : []);
2130
-
2131
-
2132
-
2133
-
2134
- const ownKeys = Object.keys(wrapper).filter((k) => !ComponentBase.INTERNAL_KEYS.has(k));
2135
-
2136
- for (const key of ownKeys) {
2137
- try {
2138
-
2139
- const val = wrapper[key];
2140
-
2141
-
2142
-
2143
- if (val && (typeof val === "object" || typeof val === "function") && resolveWrapper(val)) {
2144
- continue;
2145
- }
2146
-
2147
-
2148
-
2149
- if (!freshKeys.has(key)) {
2150
-
2151
- customProps[key] = val;
2152
- } else {
2153
-
2154
-
2155
- customProps[key] = val;
2156
- }
2157
- } catch {
2158
-
2159
- }
2160
- }
2161
-
2162
- return customProps;
2163
- }
2164
-
2165
-
2166
- _restoreCustomProperties(proxy, customProps) {
2167
-
2168
-
2169
-
2170
- if (!proxy || !customProps || typeof customProps !== "object") {
2171
- return;
2172
- }
2173
-
2174
- for (const [key, value] of Object.entries(customProps)) {
2175
- try {
2176
- proxy[key] = value;
2177
- } catch {
2178
-
2179
- }
2180
- }
2181
- }
2182
-
2183
-
2184
- async _restoreApiTree(freshApi, endpoint, moduleID, collisionMode, forceReplace = true) {
2185
-
2186
-
2187
-
2188
- if (!freshApi || (typeof freshApi !== "object" && typeof freshApi !== "function")) {
2189
- return;
2190
- }
2191
-
2192
-
2193
- const parts = endpoint === "." ? [] : endpoint.split(".");
2194
-
2195
- if (parts.length === 0) {
2196
-
2197
-
2198
-
2199
- for (const key of Object.keys(freshApi)) {
2200
-
2201
-
2202
-
2203
- if (typeof key === "string" && (key.startsWith("_") || key.startsWith("__"))) continue;
2204
-
2205
-
2206
-
2207
- if (key === "slothlet" || key === "shutdown" || key === "destroy") continue;
2208
-
2209
- const existingAtKey = this.slothlet.api[key];
2210
- const freshValue = freshApi[key];
2211
-
2212
- if (existingAtKey && resolveWrapper(existingAtKey) !== null) {
2213
-
2214
- const customProps = this._collectCustomProperties(existingAtKey, freshValue);
2215
-
2216
-
2217
-
2218
- const freshWrapper = resolveWrapper(freshValue);
2219
- const isLazyFresh =
2220
- freshWrapper &&
2221
- freshWrapper.____slothletInternal.mode === "lazy" &&
2222
- !freshWrapper.____slothletInternal.state.materialized &&
2223
- typeof freshWrapper.____slothletInternal.materializeFunc === "function";
2224
-
2225
-
2226
- this.slothlet.debug("reload", {
2227
- key: "DEBUG_MODE_RESTORE_ROOT_KEY_INSPECT",
2228
- rootKey: key,
2229
- hasFreshWrapper: !!freshWrapper,
2230
- freshMode: freshWrapper?.____slothletInternal.mode,
2231
- freshMaterialized: freshWrapper?.____slothletInternal.state?.materialized,
2232
- hasMaterializeFunc: typeof freshWrapper?.____slothletInternal.materializeFunc === "function",
2233
- isLazyFresh,
2234
- existingMaterialized: resolveWrapper(existingAtKey)?.____slothletInternal?.state?.materialized
2235
- });
2236
-
2237
- if (isLazyFresh) {
2238
-
2239
-
2240
-
2241
-
2242
- resolveWrapper(existingAtKey).___resetLazy(freshWrapper.____slothletInternal.materializeFunc);
2243
-
2244
-
2245
- this._restoreCustomProperties(existingAtKey, customProps);
2246
-
2247
- this.slothlet.debug("reload", {
2248
- key: "DEBUG_MODE_ROOT_KEY_RESET_LAZY",
2249
- rootKey: key,
2250
- restoredCustomProps: Object.keys(customProps)
2251
- });
2252
- } else {
2253
-
2254
-
2255
-
2256
-
2257
-
2258
-
2259
-
2260
-
2261
- let implForReload;
2262
-
2263
-
2264
-
2265
- if (freshValue && resolveWrapper(freshValue) !== null) {
2266
- implForReload = freshWrapper ? UnifiedWrapper._extractFullImpl(freshWrapper) : freshValue;
2267
- } else {
2268
-
2269
-
2270
-
2271
-
2272
- implForReload = freshValue;
2273
- }
2274
-
2275
-
2276
- if (typeof implForReload === "function") {
2277
- const extracted = {};
2278
- for (const k of Object.keys(implForReload)) {
2279
- extracted[k] = implForReload[k];
2280
- }
2281
- implForReload = extracted;
2282
- }
2283
-
2284
-
2285
-
2286
-
2287
- const wrapper = resolveWrapper(existingAtKey);
2288
-
2289
-
2290
- const originalCollisionMode = wrapper ? wrapper.____slothletInternal.state.collisionMode : null;
2291
- if (forceReplace && wrapper) {
2292
- wrapper.____slothletInternal.state.collisionMode = "replace";
2293
- }
2294
-
2295
-
2296
-
2297
-
2298
- if (wrapper && originalCollisionMode !== null) {
2299
- wrapper.____slothletInternal.state.collisionMode = originalCollisionMode;
2300
- }
2301
-
2302
-
2303
- this._restoreCustomProperties(existingAtKey, customProps);
2304
-
2305
- this.slothlet.debug("reload", {
2306
- key: "DEBUG_MODE_ROOT_KEY_UPDATED_SETIMPL",
2307
- rootKey: key,
2308
- restoredCustomProps: Object.keys(customProps)
2309
- });
2310
- }
2311
- } else if (existingAtKey === undefined) {
2312
-
2313
- const cacheManager = this.slothlet.handlers.apiCacheManager;
2314
- const cacheEntry = cacheManager.get(moduleID);
2315
-
2316
-
2317
- const resolvedFolderPath = cacheEntry?.folderPath || "";
2318
-
2319
- await this.setValueAtPath(this.slothlet.api, [key], freshValue, {
2320
- mutateExisting: true,
2321
- collisionMode,
2322
- moduleID,
2323
- sourceFolder: resolvedFolderPath
2324
- });
2325
-
2326
-
2327
-
2328
- if (this.slothlet.boundApi) {
2329
- await this.setValueAtPath(this.slothlet.boundApi, [key], freshValue, {
2330
- mutateExisting: true,
2331
- collisionMode,
2332
- moduleID,
2333
- sourceFolder: resolvedFolderPath
2334
- });
2335
- }
2336
- }
2337
-
2338
- }
2339
- } else {
2340
-
2341
-
2342
- const existing = this.getValueAtPath(this.slothlet.api, parts);
2343
-
2344
- this.slothlet.debug("reload", {
2345
- key: "DEBUG_MODE_RESTORE_NESTED_PATH",
2346
- endpoint,
2347
- moduleID,
2348
- partsPath: parts.join("."),
2349
- existingFound: !!existing,
2350
-
2351
-
2352
-
2353
- hasSetImpl: existing ? resolveWrapper(existing) !== null : false,
2354
- freshApiKeys: Object.keys(freshApi || {})
2355
-
2356
- });
2357
-
2358
- if (existing && resolveWrapper(existing) !== null) {
2359
-
2360
- const customProps = this._collectCustomProperties(existing, freshApi);
2361
-
2362
-
2363
-
2364
-
2365
- const wrapper = resolveWrapper(existing);
2366
-
2367
-
2368
- const originalCollisionMode = wrapper ? wrapper.____slothletInternal.state.collisionMode : null;
2369
-
2370
- if (forceReplace && wrapper) {
2371
- wrapper.____slothletInternal.state.collisionMode = "replace";
2372
- this.slothlet.debug("reload", {
2373
- key: "DEBUG_MODE_RESTORE_FORCING_REPLACE",
2374
- endpoint,
2375
- originalCollisionMode,
2376
- wrapperApiPath: wrapper.____slothletInternal.apiPath
2377
- });
2378
- }
2379
-
2380
-
2381
-
2382
-
2383
-
2384
-
2385
- let implForReload;
2386
-
2387
-
2388
-
2389
-
2390
-
2391
-
2392
- if (resolveWrapper(freshApi) !== null) {
2393
- const freshWrapper = resolveWrapper(freshApi);
2394
- implForReload = freshWrapper ? UnifiedWrapper._extractFullImpl(freshWrapper) : freshApi;
2395
- } else if (typeof freshApi === "function") {
2396
- implForReload = {};
2397
- for (const key of Object.keys(freshApi)) {
2398
- implForReload[key] = freshApi[key];
2399
- }
2400
- } else {
2401
- implForReload = freshApi;
2402
- }
2403
-
2404
-
2405
-
2406
-
2407
-
2408
-
2409
-
2410
-
2411
- if (parts.length > 0 && implForReload && typeof implForReload === "object") {
2412
- const lastEndpointPart = parts[parts.length - 1];
2413
- if (lastEndpointPart && Object.prototype.hasOwnProperty.call(implForReload, lastEndpointPart)) {
2414
- const dupValue = implForReload[lastEndpointPart];
2415
- const dupWrapperForDedup = resolveWrapper(dupValue);
2416
- if (dupWrapperForDedup) {
2417
- const hoisted = {};
2418
- for (const k of Object.keys(implForReload)) {
2419
- if (k !== lastEndpointPart) hoisted[k] = implForReload[k];
2420
- }
2421
- for (const k of Object.keys(dupWrapperForDedup).filter((k) => !k.startsWith("_") && !k.startsWith("__"))) {
2422
- hoisted[k] = dupWrapperForDedup[k];
2423
- }
2424
- implForReload = hoisted;
2425
- }
2426
- }
2427
- }
2428
-
2429
-
2430
-
2431
-
2432
-
2433
-
2434
-
2435
-
2436
-
2437
- if (implForReload && typeof implForReload === "object") {
2438
- for (const key of Object.keys(implForReload)) {
2439
- const val = implForReload[key];
2440
- if (resolveWrapper(val) !== null) {
2441
- const childWrapper = resolveWrapper(val);
2442
- if (childWrapper.____slothletInternal.state.materialized) {
2443
- implForReload[key] = UnifiedWrapper._extractFullImpl(childWrapper);
2444
- }
2445
- }
2446
- }
2447
- }
2448
-
2449
- resolveWrapper(existing).___setImpl(implForReload, moduleID);
2450
-
2451
-
2452
-
2453
-
2454
-
2455
- if (wrapper && originalCollisionMode !== null) {
2456
- wrapper.____slothletInternal.state.collisionMode = originalCollisionMode;
2457
- }
2458
-
2459
-
2460
- this._restoreCustomProperties(existing, customProps);
2461
-
2462
- this.slothlet.debug("reload", {
2463
- key: "DEBUG_MODE_UPDATED_WRAPPER_IMPL",
2464
- endpoint,
2465
- moduleID,
2466
- forcedReplaceMode: true,
2467
- restoredCustomProps: Object.keys(customProps)
2468
- });
2469
- } else {
2470
-
2471
-
2472
- const cacheManager = this.slothlet.handlers.apiCacheManager;
2473
- const cacheEntry = cacheManager.get(moduleID);
2474
-
2475
-
2476
- const resolvedFolderPath = cacheEntry?.folderPath || "";
2477
-
2478
-
2479
- let implForContainer = freshApi;
2480
-
2481
-
2482
-
2483
-
2484
-
2485
-
2486
- if (typeof freshApi === "function") {
2487
- implForContainer = {};
2488
- for (const key of Object.keys(freshApi)) {
2489
- implForContainer[key] = freshApi[key];
2490
- }
2491
- }
2492
- const containerWrapper = new UnifiedWrapper(this.slothlet, {
2493
- apiPath: endpoint,
2494
- mode: this.____config.mode,
2495
- moduleID: moduleID,
2496
- filePath: resolvedFolderPath,
2497
- sourceFolder: resolvedFolderPath
2498
- });
2499
- containerWrapper.___setImpl(implForContainer, moduleID);
2500
- const apiToSet = containerWrapper.createProxy();
2501
-
2502
-
2503
- await this.setValueAtPath(this.slothlet.api, parts, apiToSet, {
2504
- mutateExisting: true,
2505
- collisionMode,
2506
- moduleID,
2507
- sourceFolder: resolvedFolderPath
2508
- });
2509
-
2510
-
2511
-
2512
- if (this.slothlet.boundApi) {
2513
- await this.setValueAtPath(this.slothlet.boundApi, parts, apiToSet, {
2514
- mutateExisting: true,
2515
- collisionMode,
2516
- moduleID,
2517
- sourceFolder: resolvedFolderPath
2518
- });
2519
- }
2520
-
2521
- this.slothlet.debug("reload", {
2522
- key: "DEBUG_MODE_CREATED_NEW_WRAPPER_UNEXPECTED",
2523
- endpoint,
2524
- moduleID
2525
- });
2526
- }
2527
- }
2528
- }
2529
- }
17
+ import fs from"node:fs/promises";import path from"node:path";import{translate}from"@cldmv/slothlet/i18n";import{ComponentBase}from"@cldmv/slothlet/factories/component-base";import{UnifiedWrapper,resolveWrapper}from"@cldmv/slothlet/handlers/unified-wrapper";class ApiManager extends ComponentBase{static slothletProperty="apiManager";constructor(slothlet){super(slothlet);this.state={addHistory:[],initialConfig:slothlet?.config||null,operationHistory:[]}}normalizeApiPath(apiPath){if(apiPath===""||apiPath===null||apiPath===void 0){return{apiPath:"",parts:[]}}if(Array.isArray(apiPath)){if(apiPath.length===0){return{apiPath:"",parts:[]}}for(let i=0;i<apiPath.length;i++){if(typeof apiPath[i]!=="string"){throw new this.SlothletError("INVALID_CONFIG_API_PATH_INVALID",{apiPath,segment:apiPath[i],index:i,reason:translate("API_PATH_REASON_ARRAY_ELEMENTS"),validationError:true})}if(apiPath[i].trim()===""){throw new this.SlothletError("INVALID_CONFIG_API_PATH_INVALID",{apiPath,segment:apiPath[i],index:i,reason:translate("API_PATH_REASON_ARRAY_EMPTY_SEGMENTS"),validationError:true})}}if(apiPath[0]==="slothlet"||apiPath.length===1&&(apiPath[0]==="shutdown"||apiPath[0]==="destroy")){throw new this.SlothletError("INVALID_CONFIG_API_PATH_INVALID",{apiPath,reason:translate("API_PATH_REASON_RESERVED_NAME"),index:void 0,segment:void 0,validationError:true})}return{apiPath:apiPath.join("."),parts:apiPath}}if(typeof apiPath!=="string"){throw new this.SlothletError("INVALID_CONFIG_API_PATH_INVALID",{apiPath,reason:translate("API_PATH_REASON_INVALID_TYPE"),index:void 0,segment:void 0,validationError:true})}const normalized=apiPath.trim();if(normalized===""){return{apiPath:"",parts:[]}}const parts=normalized.split(".");if(parts.length===0||parts.some(part=>part.trim()==="")){throw new this.SlothletError("INVALID_CONFIG_API_PATH_INVALID",{apiPath:normalized,reason:translate("API_PATH_REASON_EMPTY_SEGMENTS"),index:void 0,segment:void 0,validationError:true})}if(parts[0]==="slothlet"||normalized==="shutdown"||normalized==="destroy"){throw new this.SlothletError("INVALID_CONFIG_API_PATH_INVALID",{apiPath:normalized,reason:translate("API_PATH_REASON_RESERVED_NAME"),index:void 0,segment:void 0,validationError:true})}return{apiPath:normalized,parts}}async resolvePath(inputPath){if(!inputPath||typeof inputPath!=="string"){throw new this.SlothletError("INVALID_CONFIG_DIR_INVALID",{dir:inputPath,validationError:true})}const resolvedPath=this.slothlet.helpers.resolver.resolvePathFromCaller(inputPath);try{const stats=await fs.stat(resolvedPath);return{resolvedPath,isDirectory:stats.isDirectory(),isFile:stats.isFile()}}catch(error){if(error instanceof this.SlothletError){throw error}throw new this.SlothletError("INVALID_CONFIG_DIR_INVALID",{dir:resolvedPath,validationError:true})}}async resolveFolderPath(folderPath){if(!folderPath||typeof folderPath!=="string"){throw new this.SlothletError("INVALID_CONFIG_DIR_INVALID",{dir:folderPath,validationError:true})}const resolvedPath=this.slothlet.helpers.resolver.resolvePathFromCaller(folderPath);try{const stats=await fs.stat(resolvedPath);if(!stats.isDirectory()){throw new this.SlothletError("INVALID_CONFIG_DIR_INVALID",{dir:resolvedPath,validationError:true})}}catch(error){if(error instanceof this.SlothletError){throw error}throw new this.SlothletError("INVALID_CONFIG_DIR_INVALID",{dir:resolvedPath,validationError:true})}return resolvedPath}buildDefaultModuleId(apiPath,____resolvedFolderPath){const randomSuffix=Math.random().toString(36).substring(2,8);const prefix=apiPath||"auto";return`${prefix}_${randomSuffix}`}getValueAtPath(root,parts){let current=root;for(const part of parts){if(!current||typeof current!=="object"&&typeof current!=="function"){return void 0}current=current[part]}return current}ensureParentPath(root,parts,options={}){const{moduleID,sourceFolder}=options;let current=root;for(let i=0;i<parts.length-1;i+=1){const part=parts[i];const next=current[part];if(next===void 0){const containerPath=parts.slice(0,i+1).join(".");const containerWrapper=new UnifiedWrapper(this.slothlet,{mode:this.____config.mode,apiPath:containerPath,moduleID,sourceFolder});containerWrapper.___setImpl({},moduleID);current[part]=containerWrapper.createProxy();current=current[part];continue}if(next&&(typeof next==="object"||typeof next==="function")){current=next;continue}throw new this.SlothletError("INVALID_CONFIG_API_PATH_INVALID",{apiPath:parts.slice(0,i+1).join("."),reason:translate("API_PATH_REASON_NOT_TRAVERSABLE"),index:void 0,segment:void 0,validationError:true})}return current}isWrapperProxy(value){return!!(value&&(typeof value==="object"||typeof value==="function")&&resolveWrapper(value)!==null)}async syncWrapper(existingProxy,nextProxy,config,collisionMode="replace",moduleID=null){if(config?.debug?.api){this.slothlet.debug("api",{key:"DEBUG_MODE_SYNC_WRAPPER_ENTRY_EXISTING",apiPath:resolveWrapper(existingProxy)?.apiPath});this.slothlet.debug("api",{key:"DEBUG_MODE_SYNC_WRAPPER_ENTRY_NEXT",apiPath:resolveWrapper(nextProxy)?.apiPath})}if(!this.isWrapperProxy(existingProxy)||!this.isWrapperProxy(nextProxy)){return false}const existingWrapper=resolveWrapper(existingProxy)??existingProxy;const nextWrapper=resolveWrapper(nextProxy)??nextProxy;if(config?.debug?.api){this.slothlet.debug("api",{key:"DEBUG_MODE_SYNC_WRAPPER_EXISTING",apiPath:existingWrapper.apiPath});this.slothlet.debug("api",{key:"DEBUG_MODE_SYNC_WRAPPER_NEXT",apiPath:nextWrapper.apiPath})}if(nextWrapper.____slothletInternal.materializeFunc&&collisionMode!=="merge"){existingWrapper.____slothletInternal.materializeFunc=nextWrapper.____slothletInternal.materializeFunc}const existingChildKeys=Object.keys(existingWrapper).filter(k=>!k.startsWith("_")&&!k.startsWith("__"));const nextChildKeys=Object.keys(nextWrapper).filter(k=>!k.startsWith("_")&&!k.startsWith("__"));if(config?.debug?.api){this.slothlet.debug("api",{key:"DEBUG_MODE_SYNC_WRAPPER_BEFORE_MERGE",existingCacheSize:existingChildKeys.length,nextCacheSize:nextChildKeys.length});this.slothlet.debug("api",{key:"DEBUG_MODE_SYNC_WRAPPER_NEXT_IMPL_KEYS",implKeys:Object.keys(nextWrapper.____slothletInternal.impl||{})});this.slothlet.debug("api",{key:"DEBUG_MODE_SYNC_WRAPPER_NEXT_CHILDCACHE_KEYS",childCacheKeys:nextChildKeys})}if(collisionMode==="replace"){if(existingWrapper.___setImpl&&nextWrapper.____slothletInternal.impl!==void 0){existingWrapper.___setImpl(nextWrapper.____slothletInternal.impl,moduleID)}else if(nextWrapper.____slothletInternal.impl===void 0){existingWrapper.____slothletInternal.impl=null}else{if(nextWrapper.____slothletInternal.impl!==void 0){existingWrapper.____slothletInternal.impl=nextWrapper.____slothletInternal.impl;if(typeof nextWrapper.____slothletInternal.impl==="function"||nextWrapper.____slothletInternal.impl&&typeof nextWrapper.____slothletInternal.impl.default==="function"){existingWrapper.isCallable=true}}}for(const key of existingChildKeys){delete existingWrapper[key]}existingWrapper.___adoptImplChildren();for(const key of nextChildKeys){const childValue=nextWrapper[key];Object.defineProperty(existingWrapper,key,{value:childValue,writable:false,enumerable:true,configurable:true})}}else if(collisionMode==="merge"){for(const key of nextChildKeys){const isInternal=typeof key==="string"&&(key.startsWith("_")||key.startsWith("__"));if(!isInternal&&!Object.prototype.hasOwnProperty.call(existingWrapper,key)){const childValue=nextWrapper[key];Object.defineProperty(existingWrapper,key,{value:childValue,writable:false,enumerable:true,configurable:true})}else if(!isInternal){const existingChild=existingWrapper[key];const nextChild=nextWrapper[key];if(this.isWrapperProxy(existingChild)&&this.isWrapperProxy(nextChild)){const syncWrapper_nextChildWrapper=resolveWrapper(nextChild)??nextChild;const syncWrapper_hasGrandChildren=Object.keys(syncWrapper_nextChildWrapper).some(k=>!k.startsWith("_")&&!k.startsWith("__"));if(syncWrapper_hasGrandChildren){await this.syncWrapper(existingChild,nextChild,config,collisionMode,moduleID)}}}}}else if(collisionMode==="merge-replace"){for(const key of nextChildKeys){const childValue=nextWrapper[key];const isInternal=typeof key==="string"&&(key.startsWith("_")||key.startsWith("__"));if(!isInternal&&Object.prototype.hasOwnProperty.call(existingWrapper,key)){const existingChild=existingWrapper[key];if(this.isWrapperProxy(existingChild)&&this.isWrapperProxy(childValue)){await this.syncWrapper(existingChild,childValue,config,collisionMode,moduleID)}else{delete existingWrapper[key];Object.defineProperty(existingWrapper,key,{value:childValue,writable:false,enumerable:true,configurable:true})}}else if(!isInternal){Object.defineProperty(existingWrapper,key,{value:childValue,writable:false,enumerable:true,configurable:true})}}}if(existingWrapper.____slothletInternal.state){const isActuallyMaterialized=existingWrapper.____slothletInternal.impl&&typeof existingWrapper.____slothletInternal.impl!=="function";existingWrapper.____slothletInternal.state.materialized=isActuallyMaterialized;existingWrapper.____slothletInternal.state.inFlight=false}return true}async mutateApiValue(existingValue,nextValue,options,config){if(config?.debug?.api){this.slothlet.debug("api",{key:"DEBUG_MODE_MUTATE_API_VALUE_CALLED",existingType:typeof existingValue,nextType:typeof nextValue});this.slothlet.debug("api",{key:"DEBUG_MODE_MUTATE_API_VALUE_WRAPPER_STATUS",existingIsWrapper:this.isWrapperProxy(existingValue),nextIsWrapper:this.isWrapperProxy(nextValue)});this.slothlet.debug("api",{key:"DEBUG_MODE_MUTATE_API_VALUE_NEXT_VALUE",nextValue});this.slothlet.debug("api",{key:"DEBUG_MODE_MUTATE_API_VALUE_NEXT_VALUE_KEYS",nextValueKeys:nextValue?Object.keys(nextValue):[]})}if(existingValue===nextValue){return}if(this.isWrapperProxy(existingValue)&&this.isWrapperProxy(nextValue)){if(config?.debug?.api){this.slothlet.debug("api",{key:"DEBUG_MODE_MUTATE_API_VALUE_SYNC_WRAPPERS"})}await this.syncWrapper(existingValue,nextValue,config,options.collisionMode,options.moduleID);return}if(this.isWrapperProxy(existingValue)&&!this.isWrapperProxy(nextValue)){const nextIsObjectLike=nextValue&&(typeof nextValue==="object"||typeof nextValue==="function");const nextHasKeys=nextIsObjectLike&&Object.keys(nextValue).length>0;if(nextHasKeys){if(config?.debug?.api){this.slothlet.debug("api",{key:"DEBUG_MODE_MUTATE_API_VALUE_MERGE_INTO_WRAPPER"});this.slothlet.debug("api",{key:"DEBUG_MODE_MUTATE_API_VALUE_MERGE_KEYS",keys:Object.keys(nextValue)})}await this.slothlet.builders.apiAssignment.mergeApiObjects(existingValue,nextValue,{removeMissing:options.removeMissing,mutateExisting:true,allowOverwrite:true,syncWrapper:this.syncWrapper.bind(this),collisionMode:options.collisionMode,moduleID:options.moduleID});return}const existingValueRaw=resolveWrapper(existingValue);if(existingValueRaw!==null){if(config?.debug?.api){this.slothlet.debug("api",{key:"DEBUG_MODE_MUTATE_API_VALUE_SETIMPL_FALLBACK"})}existingValueRaw.___setImpl(resolveWrapper(nextValue)?.__impl??nextValue);return}}if(existingValue&&typeof existingValue==="object"&&nextValue&&typeof nextValue==="object"){await this.slothlet.builders.apiAssignment.mergeApiObjects(existingValue,nextValue,{removeMissing:options.removeMissing,mutateExisting:true,allowOverwrite:true,syncWrapper:this.syncWrapper.bind(this),collisionMode:options.collisionMode,moduleID:options.moduleID});return existingValue}return nextValue}async setValueAtPath(root,parts,value,options){const parent=this.ensureParentPath(root,parts,{moduleID:options.moduleID,sourceFolder:options.sourceFolder});const finalKey=parts[parts.length-1];const existing=parent?parent[finalKey]:void 0;const collisionMode=options.collisionMode||"merge";const moduleID=options.moduleID;this.slothlet.debug("api",{key:"DEBUG_MODE_SET_VALUE_AT_PATH",finalKey,existingType:typeof existing,valueType:typeof value,collisionMode,options});if(existing!==void 0){if(collisionMode==="error"){throw new this.SlothletError("INVALID_CONFIG_API_PATH_INVALID",{apiPath:parts.join("."),reason:translate("API_PATH_REASON_COLLISION_ERROR"),index:void 0,segment:void 0,validationError:true})}if(collisionMode==="skip"){this.slothlet.debug("api",{key:"DEBUG_MODE_SET_VALUE_AT_PATH_SKIP_COLLISION",path:parts.join("."),mode:"skip"});return false}if(collisionMode==="warn"){if(this.slothlet&&!this.____config?.silent){new this.SlothletWarning("WARNING_HOT_RELOAD_PATH_COLLISION",{apiPath:parts.join(".")})}return false}if(collisionMode==="replace"){const existingIsObject=typeof existing==="object"||typeof existing==="function";const valueIsObject=typeof value==="object"||typeof value==="function";if(existingIsObject&&valueIsObject){this.slothlet.debug("api",{key:"DEBUG_MODE_SET_VALUE_AT_PATH_REPLACE_MERGE",path:parts.join("."),mode:"replace"});await this.mutateApiValue(existing,value,{removeMissing:false,allowOverwrite:true,collisionMode:"replace",moduleID},this.____config);return true}else{parent[finalKey]=value;return true}}if(collisionMode==="merge"||collisionMode==="merge-replace"){const existingIsObject=typeof existing==="object"||typeof existing==="function";const valueIsObject=typeof value==="object"||typeof value==="function";if(existingIsObject&&valueIsObject){this.slothlet.debug("api",{key:"DEBUG_MODE_SET_VALUE_AT_PATH_MERGE_PROPS",mode:collisionMode});await this.mutateApiValue(existing,value,{removeMissing:false,allowOverwrite:true,collisionMode},this.____config);return true}else{if(this.slothlet&&!this.____config?.silent){new this.SlothletWarning("WARNING_HOT_RELOAD_MERGE_PRIMITIVES",{apiPath:parts.join(".")})}return false}}}this.slothlet.debug("api",{key:"DEBUG_MODE_SET_VALUE_AT_PATH_ASSIGN",finalKey});parent[finalKey]=value;return true}async deletePath(root,parts){let current=root;const stack=[];for(const part of parts.slice(0,-1)){if(!current||typeof current!=="object"&&typeof current!=="function"){return false}stack.push({parent:current,key:part});current=current[part]}const finalKey=parts[parts.length-1];if(!current||typeof current!=="object"&&typeof current!=="function"){return false}if(!Object.prototype.hasOwnProperty.call(current,finalKey)){return false}const removedImpl=current[finalKey];const apiPath=parts.join(".");if(removedImpl&&this.slothlet.handlers?.lifecycle){const metadata=this.slothlet.handlers.metadata?.getMetadata?.(removedImpl);await this.slothlet.handlers.lifecycle.emit("impl:removed",{apiPath,impl:removedImpl,source:"removal",moduleID:metadata?.moduleID,filePath:metadata?.filePath,sourceFolder:metadata?.sourceFolder})}if(resolveWrapper(current)){const wrapper=resolveWrapper(current);const isInternal=typeof finalKey==="string"&&(finalKey.startsWith("_")||finalKey.startsWith("__"));if(!isInternal&&finalKey in wrapper){delete wrapper[finalKey]}if(wrapper.____slothletInternal.impl&&typeof wrapper.____slothletInternal.impl==="object"){delete wrapper.____slothletInternal.impl[finalKey]}}delete current[finalKey];if(removedImpl&&(typeof removedImpl==="object"||typeof removedImpl==="function")){if(resolveWrapper(removedImpl)){const wrapper=resolveWrapper(removedImpl);if(wrapper.____slothletInternal.impl!==void 0){wrapper.____slothletInternal.impl=null}const childKeys=Object.keys(wrapper).filter(k=>!k.startsWith("_")&&!k.startsWith("__"));for(const key of childKeys){delete wrapper[key]}if(wrapper.____slothletInternal.state){wrapper.____slothletInternal.state.materialized=false;wrapper.____slothletInternal.state.inFlight=false}}}if(this.slothlet.handlers?.metadata){const rootSegment=apiPath.split(".")[0];this.slothlet.handlers.metadata.removeUserMetadataByApiPath(rootSegment)}for(let i=stack.length-1;i>=0;i-=1){const{parent,key}=stack[i];const value=parent[key];if(value&&(typeof value==="object"||typeof value==="function")&&Object.keys(value).length===0){delete parent[key]}}return true}async restoreApiPath(apiPath,moduleID){const normalizedModuleId=moduleID||null;const historyEntry=this.state.addHistory.slice().reverse().find(entry=>entry.apiPath===apiPath&&(normalizedModuleId?entry.moduleID===normalizedModuleId:true));if(historyEntry){await this.addApiComponent({apiPath:historyEntry.apiPath,folderPath:historyEntry.folderPath,options:{...historyEntry.options,metadata:historyEntry.metadata,mutateExisting:true,forceOverwrite:true,collisionMode:"replace",recordHistory:false}});return}if(normalizedModuleId==="base"||normalizedModuleId==="core"){const baseApi=await this.slothlet.builders.builder.buildAPI({dir:this.____config.dir,mode:this.____config.mode,moduleID:"base"});const{parts}=this.normalizeApiPath(apiPath);let baseValue=this.getValueAtPath(baseApi,parts);if(baseValue===void 0){await this.deletePath(this.slothlet.api,parts);await this.deletePath(this.slothlet.boundApi,parts);return}const baseValueRaw=resolveWrapper(baseValue);if(baseValue&&baseValueRaw!==null){baseValue=baseValueRaw.__impl}await this.setValueAtPath(this.slothlet.api,parts,baseValue,{mutateExisting:true,allowOverwrite:true,collisionMode:"replace",moduleID:normalizedModuleId});await this.setValueAtPath(this.slothlet.boundApi,parts,baseValue,{mutateExisting:true,allowOverwrite:true,collisionMode:"replace",moduleID:normalizedModuleId})}}async addApiComponent(params){const{apiPath,folderPath,options={},versionConfig=null}=params||{};if(Array.isArray(folderPath)){const moduleIDs=[];for(const singlePath of folderPath){const moduleID2=await this.addApiComponent({apiPath,folderPath:singlePath,options,versionConfig});moduleIDs.push(moduleID2)}return moduleIDs}const{metadata={},...restOptions}=options;if(!this.slothlet||!this.slothlet.isLoaded){throw new this.SlothletError("INVALID_CONFIG_NOT_LOADED",{operation:"addApi",validationError:true})}const{apiPath:normalizedPath,parts}=this.normalizeApiPath(apiPath);let effectivePath=normalizedPath;let effectiveParts=parts;if(versionConfig?.version!==void 0&&versionConfig?.version!==null){if(normalizedPath===""){throw new this.SlothletError("INVALID_CONFIG_API_PATH_INVALID",{apiPath,reason:translate("API_PATH_REASON_VERSIONED_ROOT"),index:void 0,segment:void 0,validationError:true})}if(typeof versionConfig.version!=="string"||!String(versionConfig.version).trim()){throw new this.SlothletError("INVALID_CONFIG_VERSION_TAG",{received:versionConfig.version,validationError:true})}const versionTag=String(versionConfig.version).trim();effectiveParts=[versionTag,...parts];effectivePath=effectiveParts.join(".")}const{resolvedPath,isDirectory,isFile}=await this.resolvePath(folderPath);if(!isDirectory&&!isFile){throw new this.SlothletError("INVALID_CONFIG_PATH_TYPE",{path:resolvedPath,validationError:true})}if(isFile){const ext=path.extname(resolvedPath);if(![".mjs",".cjs",".js"].includes(ext)){throw new this.SlothletError("INVALID_CONFIG_FILE_TYPE",{path:resolvedPath,extension:ext,validationError:true})}}const resolvedFolderPath=resolvedPath;let collisionMode;if(restOptions.forceOverwrite){collisionMode="replace"}else{collisionMode=restOptions.collisionMode||this.____config.api?.collision?.api||"error"}const mutateExisting=!!(restOptions.mutateExisting||collisionMode==="merge");const moduleID=restOptions.moduleID?String(restOptions.moduleID):this.buildDefaultModuleId(normalizedPath,resolvedFolderPath);if(restOptions.forceOverwrite&&!moduleID){throw new this.SlothletError("INVALID_CONFIG_FORCE_OVERWRITE_REQUIRES_MODULE_ID",{apiPath:normalizedPath,validationError:true})}let dirForBuild=resolvedFolderPath;let fileFilter=null;if(isFile){dirForBuild=path.dirname(resolvedFolderPath);const fileName=path.basename(resolvedFolderPath);fileFilter=file=>file===fileName}const newApi=await this.slothlet.builders.builder.buildAPI({dir:dirForBuild,mode:this.____config.mode,apiPathPrefix:effectivePath,collisionContext:"addApi",moduleID,collisionMode,fileFilter});if(this.slothlet.handlers.apiCacheManager){this.slothlet.handlers.apiCacheManager.set(moduleID,{endpoint:effectivePath,moduleID,api:newApi,folderPath:resolvedFolderPath,mode:this.____config.mode,sanitizeOptions:this.____config.sanitize||{},collisionMode,config:{...this.____config},timestamp:Date.now()})}this.slothlet.debug("api",{key:"DEBUG_MODE_ADD_API_COMPONENT_BUILD_RETURN",topLevelKeys:Object.keys(newApi),dottedKeys:Object.keys(newApi).filter(k=>k.includes(".")),wrappers:Object.keys(newApi).filter(k=>resolveWrapper(newApi[k])!==null).map(k=>{const _w=resolveWrapper(newApi[k]);return{key:k,apiPath:_w.apiPath,implKeys:Object.keys(_w.____slothletInternal.impl||{}),childCacheSize:Object.keys(_w).filter(k2=>!k2.startsWith("_")&&!k2.startsWith("__")).length,childCacheKeys:Object.keys(_w).filter(k2=>!k2.startsWith("_")&&!k2.startsWith("__"))}}),nonWrappers:Object.keys(newApi).filter(k=>resolveWrapper(newApi[k])===null).map(k=>({key:k,type:typeof newApi[k]}))});let apiToMerge=newApi;if(isFile&&Object.keys(newApi).length===1){const fileName=Object.keys(newApi)[0];apiToMerge=newApi[fileName]}if(!isFile&&normalizedPath){const lastPart=normalizedPath.includes(".")?normalizedPath.split(".").pop():normalizedPath;if(lastPart&&Object.prototype.hasOwnProperty.call(apiToMerge,lastPart)){const dupValue=apiToMerge[lastPart];const dupType=typeof dupValue;if(dupValue!==null&&(dupType==="object"||dupType==="function")){const dupWrapper=resolveWrapper(dupValue);const dupFilePath=dupWrapper?.____slothletInternal?.filePath;const dupFileDir=dupFilePath?dupFilePath.replace(/\\/g,"/").split("/").slice(0,-1).join("/"):null;const normalizedFolderPath=resolvedFolderPath.replace(/\\/g,"/").replace(/\/$/,"");const expectedDir=normalizedFolderPath+"/"+lastPart;const isDirectChild=dupFileDir===expectedDir||dupFileDir===normalizedFolderPath;if(isDirectChild){const hoisted={};for(const k of Object.keys(apiToMerge)){if(k!==lastPart)hoisted[k]=apiToMerge[k]}if(dupWrapper){for(const k of Object.keys(dupWrapper).filter(k2=>!k2.startsWith("_")&&!k2.startsWith("__"))){hoisted[k]=dupWrapper[k]}}else{for(const k of Object.keys(dupValue)){hoisted[k]=dupValue[k]}}apiToMerge=hoisted;this.slothlet.debug("api",{key:"DEBUG_MODE_RULE_13_DEDUP_HOISTED_KEY",lastPart,newKeys:Object.keys(apiToMerge)})}}}}if(this.____config.debug?.api){this.slothlet.debug("api",{key:"DEBUG_MODE_ADD_API_COMPONENT_MERGE_KEYS",keys:Object.keys(apiToMerge),isRootLevel:parts.length===0})}let anyAssignmentSucceeded=false;if(parts.length===0){for(const key of Object.keys(newApi)){const result1=await this.setValueAtPath(this.slothlet.api,[key],newApi[key],{mutateExisting,collisionMode,moduleID,sourceFolder:resolvedFolderPath});const result2=await this.setValueAtPath(this.slothlet.boundApi,[key],newApi[key],{mutateExisting,collisionMode,moduleID,sourceFolder:resolvedFolderPath});if(result1||result2){anyAssignmentSucceeded=true}}}else{if(resolveWrapper(apiToMerge)===null){const isCallableNamespace=typeof apiToMerge==="function";const containerWrapper=new UnifiedWrapper(this.slothlet,{apiPath:effectivePath,mode:this.____config.mode,isCallable:isCallableNamespace,moduleID,filePath:resolvedFolderPath,sourceFolder:resolvedFolderPath});containerWrapper.___setImpl(apiToMerge,moduleID);apiToMerge=containerWrapper.createProxy()}const result1=await this.setValueAtPath(this.slothlet.api,effectiveParts,apiToMerge,{mutateExisting,collisionMode,moduleID,sourceFolder:resolvedFolderPath});const result2=await this.setValueAtPath(this.slothlet.boundApi,effectiveParts,apiToMerge,{mutateExisting,collisionMode,moduleID,sourceFolder:resolvedFolderPath});if(result1||result2){anyAssignmentSucceeded=true}}if(anyAssignmentSucceeded){const pendingMaterializations=[];const seenWrappers=new Set;const collectPendingMaterializations=(obj,depth=0)=>{if(!obj||typeof obj!=="object"||depth>10)return;if(obj.__isVersionDispatcher===true)return;const wrapper=resolveWrapper(obj);if(wrapper){if(seenWrappers.has(wrapper))return;seenWrappers.add(wrapper);if(wrapper.____slothletInternal.materializationPromise){pendingMaterializations.push(wrapper.____slothletInternal.materializationPromise)}const childKeys=Object.keys(wrapper).filter(k=>!k.startsWith("_")&&!k.startsWith("__"));for(const key of childKeys){collectPendingMaterializations(wrapper[key],depth+1)}}for(const key of Object.keys(obj)){if(key!=="____slothletInternal"){collectPendingMaterializations(obj[key],depth+1)}}};if(effectiveParts.length===0){for(const key of Object.keys(newApi)){if(this.slothlet.api[key]){collectPendingMaterializations(this.slothlet.api[key])}}}else{let current=this.slothlet.api;for(const part of effectiveParts){if(current&&current[part]){current=current[part]}else{break}}if(current){collectPendingMaterializations(current)}}if(pendingMaterializations.length>0){if(this.____config.debug?.api){this.slothlet.debug("api",{key:"DEBUG_MODE_AWAITING_PENDING_MATERIALIZATIONS",count:pendingMaterializations.length,apiPath:normalizedPath})}await Promise.all(pendingMaterializations)}}if(anyAssignmentSucceeded&&metadata&&Object.keys(metadata).length>0&&this.slothlet.handlers.metadata){if(parts.length===0){for(const key of Object.keys(newApi)){this.slothlet.handlers.metadata.registerUserMetadata(key,metadata)}}else{const rootSegment=effectiveParts[0];this.slothlet.handlers.metadata.registerUserMetadata(rootSegment,metadata)}}if(this.slothlet.handlers.ownership&&moduleID){this.slothlet.handlers.ownership.registerSubtree(apiToMerge,moduleID,effectivePath)}if(this.slothlet.handlers.ownership){if(restOptions.recordHistory!==false){this.state.addHistory.push({apiPath:normalizedPath,folderPath:resolvedFolderPath,options:{...restOptions,metadata,moduleID},moduleID,versionConfig:versionConfig||null});this.state.operationHistory.push({type:"add",apiPath:normalizedPath,folderPath:resolvedFolderPath,options:{...restOptions,metadata,moduleID},moduleID,versionConfig:versionConfig||null})}}if(versionConfig?.version&&this.slothlet.handlers.versionManager){const versionTag=String(versionConfig.version).trim();try{this.slothlet.handlers.versionManager.registerVersion(normalizedPath,versionTag,moduleID,versionConfig.metadata??{},versionConfig.default??false)}catch(error){await this._rollbackFailedVersionedAdd({moduleID,effectivePath,normalizedPath});throw error}}if(restOptions.permissions&&this.slothlet.handlers?.permissionManager){const perms=restOptions.permissions;const callerPattern=`${normalizedPath}.**`;if(Array.isArray(perms.deny)){for(const target of perms.deny){this.slothlet.handlers.permissionManager.addRule({caller:callerPattern,target,effect:"deny"},moduleID)}}if(Array.isArray(perms.allow)){for(const target of perms.allow){this.slothlet.handlers.permissionManager.addRule({caller:callerPattern,target,effect:"allow"},moduleID)}}}return moduleID}async _rollbackFailedVersionedAdd({moduleID,effectivePath,normalizedPath}){let addIndex=-1;for(let i=this.state.operationHistory.length-1;i>=0;i--){const entry=this.state.operationHistory[i];if(entry?.type==="add"&&entry?.apiPath===normalizedPath&&entry?.moduleID===moduleID){addIndex=i;break}}if(addIndex!==-1){this.state.operationHistory.splice(addIndex,1)}this.state.addHistory=this.state.addHistory.filter(entry=>entry?.moduleID!==moduleID);try{await this.removeApiComponent(moduleID||effectivePath,{recordHistory:false})}catch{}}async removeApiComponent(pathOrModuleId,options={}){const recordHistory=options.recordHistory!==false;if(typeof pathOrModuleId!=="string"||!pathOrModuleId){throw new this.SlothletError("INVALID_ARGUMENT",{argument:"pathOrModuleId",expected:"non-empty string",received:typeof pathOrModuleId,validationError:true})}let apiPath=null;let moduleID=null;if(this.slothlet.handlers.ownership){const candidateModuleID=pathOrModuleId.split(":")[0];const registeredModules=Array.from(this.slothlet.handlers.ownership.moduleToPath.keys());let matchingModule=null;for(let i=registeredModules.length-1;i>=0;i--){const candidate=registeredModules[i];if(candidate===candidateModuleID||candidate.startsWith(`${candidateModuleID}_`)){matchingModule=candidate;break}}if(matchingModule){moduleID=matchingModule}else{const owner=this.slothlet.handlers.ownership.getCurrentOwner(pathOrModuleId);if(owner){apiPath=pathOrModuleId;moduleID=owner.moduleID}else{return false}}}else{const isModuleId=!pathOrModuleId.includes(".");apiPath=isModuleId?null:pathOrModuleId;moduleID=isModuleId?pathOrModuleId.split(":")[0]:null}if(!this.slothlet||!this.slothlet.isLoaded){throw new this.SlothletError("INVALID_CONFIG_NOT_LOADED",{operation:"removeApi",validationError:true})}if(apiPath&&moduleID){const normalizedPath2=this.normalizeApiPath(apiPath).apiPath;const moduleIDKey=String(moduleID);const history=this.slothlet.handlers.ownership?.getPathHistory?.(normalizedPath2)||[];const ownershipResult2=this.slothlet.handlers.ownership?.removePath?.(normalizedPath2,moduleIDKey)||{action:"none",removedModuleId:null,restoreModuleId:null};const pathParts=this.normalizeApiPath(apiPath).parts;if(ownershipResult2.action==="delete"){await this.deletePath(this.slothlet.api,pathParts);await this.deletePath(this.slothlet.boundApi,pathParts);if(this.slothlet.handlers.metadata){const rootSegment=normalizedPath2.split(".")[0];this.slothlet.handlers.metadata.removeUserMetadataByApiPath(rootSegment)}if(this.slothlet.handlers.versionManager){const versionKey=this.slothlet.handlers.versionManager.getVersionKeyForModule(moduleIDKey);if(versionKey){this.slothlet.handlers.versionManager.unregisterVersion(versionKey.logicalPath,versionKey.versionTag)}if(this.slothlet.handlers.versionManager.hasDispatcher(normalizedPath2)){this.slothlet.handlers.versionManager.teardownDispatcher(normalizedPath2)}}this.state.operationHistory.push({type:"remove",apiPath:normalizedPath2});return true}if(ownershipResult2.action==="restore"){const restoredValue=this.slothlet.handlers.ownership?.getCurrentValue?.(normalizedPath2);const restoredModuleId=this.slothlet.handlers.ownership?.getCurrentOwner?.(normalizedPath2)?.moduleID;if(restoredValue!==void 0&&restoredModuleId){await this.setValueAtPath(this.slothlet.api,pathParts,restoredValue,{mutateExisting:true,allowOverwrite:true,collisionMode:"replace",moduleID:restoredModuleId});await this.setValueAtPath(this.slothlet.boundApi,pathParts,restoredValue,{mutateExisting:true,allowOverwrite:true,collisionMode:"replace",moduleID:restoredModuleId});this.state.operationHistory.push({type:"remove",apiPath:normalizedPath2});return true}await this.restoreApiPath(normalizedPath2,ownershipResult2.restoreModuleId);this.state.operationHistory.push({type:"remove",apiPath:normalizedPath2});return true}if(ownershipResult2.action==="none"&&history.length===0){await this.deletePath(this.slothlet.api,pathParts);await this.deletePath(this.slothlet.boundApi,pathParts);return true}return false}if(moduleID){const moduleIDKey=String(moduleID);const result=this.slothlet.handlers.ownership?.unregister?.(moduleIDKey)||{removed:[],rolledBack:[]};if(this.slothlet.handlers.versionManager){const versionKey=this.slothlet.handlers.versionManager.getVersionKeyForModule(moduleIDKey);if(versionKey){this.slothlet.handlers.versionManager.unregisterVersion(versionKey.logicalPath,versionKey.versionTag)}}const allPaths=[...result.removed,...result.rolledBack.map(r=>r.apiPath)];const uniquePaths=[...new Set(allPaths)];const pathsToDelete=[];const pathsToRollback=[];for(const path2 of uniquePaths){const currentOwner=this.slothlet.handlers.ownership?.getCurrentOwner?.(path2);const hasChildrenWithOtherOwners=uniquePaths.some(p=>{if(p===path2||!p.startsWith(path2+"."))return false;const childOwner=this.slothlet.handlers.ownership?.getCurrentOwner?.(p);return childOwner&&childOwner.moduleID!==moduleIDKey});if(currentOwner&&currentOwner.moduleID!==moduleIDKey){pathsToRollback.push({apiPath:path2,restoredTo:currentOwner.moduleID})}else if(!hasChildrenWithOtherOwners){pathsToDelete.push(path2)}}pathsToDelete.sort((a,b)=>{const depthA=(a.match(/\./g)||[]).length;const depthB=(b.match(/\./g)||[]).length;return depthB-depthA});for(const removedPath of pathsToDelete){const{parts:parts2}=this.normalizeApiPath(removedPath);await this.deletePath(this.slothlet.api,parts2);await this.deletePath(this.slothlet.boundApi,parts2);if(this.slothlet.handlers.metadata){const rootSegment=removedPath.split(".")[0];this.slothlet.handlers.metadata.removeUserMetadataByApiPath(rootSegment)}}if(pathsToDelete.length>0){const rootSegment=pathsToDelete[0].split(".")[0];if(rootSegment in this.slothlet.api){delete this.slothlet.api[rootSegment]}if(rootSegment in this.slothlet.boundApi){delete this.slothlet.boundApi[rootSegment]}}for(const rollback of pathsToRollback){const{parts:parts2}=this.normalizeApiPath(rollback.apiPath);const previousImpl=this.slothlet.handlers.ownership?.getCurrentValue?.(rollback.apiPath);if(previousImpl!==void 0){const existingWrapper=this.getValueAtPath(this.slothlet.api,parts2);const existingWrapperRaw=resolveWrapper(existingWrapper);if(existingWrapperRaw){existingWrapperRaw.___setImpl(previousImpl,rollback.restoredTo)}const existingBoundWrapper=this.getValueAtPath(this.slothlet.boundApi,parts2);const existingBoundWrapperRaw=resolveWrapper(existingBoundWrapper);if(existingBoundWrapperRaw){existingBoundWrapperRaw.___setImpl(previousImpl,rollback.restoredTo)}}}this.state.addHistory=this.state.addHistory.filter(entry=>String(entry.moduleID)!==moduleIDKey);if(this.slothlet.handlers.apiCacheManager){const deleted=this.slothlet.handlers.apiCacheManager.delete(moduleIDKey);if(deleted){this.slothlet.debug("cache",{key:"DEBUG_MODE_CACHE_DELETED_MODULE_REMOVED",moduleID:moduleIDKey})}}if(recordHistory&&pathsToDelete.length>0){const rootSegment=pathsToDelete[0].split(".")[0];this.state.operationHistory.push({type:"remove",apiPath:rootSegment})}return pathsToDelete.length>0||pathsToRollback.length>0}if(!apiPath){throw new this.SlothletError("INVALID_CONFIG_API_PATH_INVALID",{apiPath,reason:translate("API_PATH_REASON_REQUIRED"),index:void 0,segment:void 0,validationError:true})}const{apiPath:normalizedPath,parts}=this.normalizeApiPath(apiPath);const ownershipResult=this.slothlet.handlers.ownership?.removePath?.(normalizedPath,null)||{action:"none",removedModuleId:null,restoreModuleId:null};const pathExists=this.getValueAtPath(this.slothlet.api,parts)!==void 0;if(ownershipResult.action==="none"){if(pathExists){await this.deletePath(this.slothlet.api,parts);await this.deletePath(this.slothlet.boundApi,parts);if(this.slothlet.handlers.metadata){this.slothlet.handlers.metadata.removeUserMetadataByApiPath(normalizedPath)}if(recordHistory){this.state.operationHistory.push({type:"remove",apiPath:normalizedPath})}return true}return false}if(ownershipResult.action==="delete"){await this.deletePath(this.slothlet.api,parts);await this.deletePath(this.slothlet.boundApi,parts);if(this.slothlet.handlers.metadata){this.slothlet.handlers.metadata.removeUserMetadataByApiPath(normalizedPath)}if(recordHistory){this.state.operationHistory.push({type:"remove",apiPath:normalizedPath})}return true}if(ownershipResult.action==="restore"){const restoredValue=this.slothlet.handlers.ownership?.getCurrentValue?.(normalizedPath);const restoredModuleId=this.slothlet.handlers.ownership?.getCurrentOwner?.(normalizedPath)?.moduleID;if(restoredValue!==void 0&&restoredModuleId){await this.setValueAtPath(this.slothlet.api,parts,restoredValue,{mutateExisting:true,allowOverwrite:true,collisionMode:"replace",moduleID:restoredModuleId});await this.setValueAtPath(this.slothlet.boundApi,parts,restoredValue,{mutateExisting:true,allowOverwrite:true,collisionMode:"replace",moduleID:restoredModuleId});if(recordHistory){this.state.operationHistory.push({type:"remove",apiPath:normalizedPath})}return true}await this.restoreApiPath(normalizedPath,ownershipResult.restoreModuleId);if(recordHistory){this.state.operationHistory.push({type:"remove",apiPath:normalizedPath})}return true}return false}async reloadApiComponent(params){const{apiPath,moduleID,options}=params||{};if(!this.slothlet||!this.slothlet.isLoaded){throw new this.SlothletError("INVALID_CONFIG_NOT_LOADED",{operation:"reloadApi",validationError:true})}if(moduleID){await this._reloadByModuleID(moduleID);return}if(apiPath){await this._reloadByApiPath(apiPath,options);return}throw new this.SlothletError("INVALID_ARGUMENT",{argument:"params",expected:"{ moduleID } or { apiPath }",received:params,validationError:true})}async _reloadByModuleID(moduleID,{forceReplace=true}={}){const cacheManager=this.slothlet.handlers.apiCacheManager;if(!cacheManager){throw new this.SlothletError("CACHE_MANAGER_NOT_AVAILABLE",{operation:"reload",validationError:true})}if(!cacheManager.has(moduleID)){throw new this.SlothletError("CACHE_NOT_FOUND",{moduleID,operation:"reload",validationError:true})}const oldEntry=cacheManager.get(moduleID);this.slothlet.debug("reload",{key:"DEBUG_MODE_RELOADING_MODULE_BY_ID",moduleID,endpoint:oldEntry.endpoint,folderPath:oldEntry.folderPath});const freshApi=await cacheManager.rebuildCache(moduleID);cacheManager.set(moduleID,{...oldEntry,api:freshApi,timestamp:Date.now()});this.slothlet.debug("reload",{key:"DEBUG_MODE_FRESH_API_KEYS_BEFORE_RESTORE",moduleID,endpoint:oldEntry.endpoint,freshApiKeys:Object.keys(freshApi||{})});await this._restoreApiTree(freshApi,oldEntry.endpoint,moduleID,oldEntry.collisionMode,forceReplace);this.slothlet.debug("reload",{key:"DEBUG_MODE_FRESH_API_KEYS_AFTER_RESTORE",moduleID,endpoint:oldEntry.endpoint,freshApiKeys:Object.keys(freshApi||{})});this.slothlet.debug("reload",{key:"DEBUG_MODE_MODULE_RELOAD_COMPLETE",moduleID});if(this.slothlet.handlers.versionManager){this.slothlet.handlers.versionManager.onVersionedModuleReload(moduleID)}}async _reloadByApiPath(apiPath,options={}){this.slothlet.debug("reload",{key:"DEBUG_MODE_RELOADING_BY_API_PATH",apiPath});const moduleIDsToReload=this._findAffectedCaches(apiPath);if(moduleIDsToReload.length===0){this.slothlet.debug("reload",{key:"DEBUG_MODE_NO_CACHES_ATTEMPTING_RESTORE",apiPath});if(apiPath!=="."&&apiPath!==""){await this.restoreApiPath(apiPath,"base")}return}const cacheManager=this.slothlet.handlers.apiCacheManager;moduleIDsToReload.sort((a,b)=>{const entryA=cacheManager.get(a);const entryB=cacheManager.get(b);if(entryA?.endpoint==="."&&entryB?.endpoint!==".")return-1;if(entryB?.endpoint==="."&&entryA?.endpoint!==".")return 1;const indexA=this.state.addHistory.findIndex(h=>h.moduleID===a);const indexB=this.state.addHistory.findIndex(h=>h.moduleID===b);return indexA-indexB});const endpointOrder=new Map;for(const moduleID of moduleIDsToReload){const entry=cacheManager.get(moduleID);const ep=entry?.endpoint??".";if(!endpointOrder.has(ep))endpointOrder.set(ep,[]);endpointOrder.get(ep).push(moduleID)}for(const[,moduleIDs]of endpointOrder){for(let i=0;i<moduleIDs.length;i++){await this._reloadByModuleID(moduleIDs[i],{forceReplace:i===0})}}const reloadMetadata=options?.metadata;if(reloadMetadata&&typeof reloadMetadata==="object"&&Object.keys(reloadMetadata).length>0){if(this.slothlet.handlers.metadata){const targetPath=apiPath==="."?null:apiPath.split(".")[0];if(targetPath){this.slothlet.handlers.metadata.registerUserMetadata(targetPath,reloadMetadata)}}}this.slothlet.debug("reload",{key:"DEBUG_MODE_API_PATH_RELOAD_COMPLETE",apiPath,reloadedModules:moduleIDsToReload.length,loadOrder:moduleIDsToReload})}_findAffectedCaches(apiPath){const cacheManager=this.slothlet.handlers.apiCacheManager;if(!cacheManager)return[];const allModuleIDs=cacheManager.getAllModuleIDs();if(apiPath==="."||apiPath===""||apiPath==null){const baseModules=[];for(const moduleID of allModuleIDs){const entry=cacheManager.get(moduleID);if(entry&&entry.endpoint==="."){baseModules.push(moduleID)}}return baseModules}const exactMatches=[];for(const moduleID of allModuleIDs){const entry=cacheManager.get(moduleID);if(entry&&entry.endpoint===apiPath){exactMatches.push(moduleID)}}if(exactMatches.length>0)return exactMatches;const children=[];const pathPrefix=apiPath+".";for(const moduleID of allModuleIDs){const entry=cacheManager.get(moduleID);if(entry?.endpoint?.startsWith(pathPrefix)){children.push(moduleID)}}if(children.length>0)return children;const ownership=this.slothlet.handlers.ownership;const history=ownership?.getPathHistory?.(apiPath);if(history&&history.length>0){const owned=[];for(const{moduleID}of history){if(cacheManager.has(moduleID)){owned.push(moduleID)}}if(owned.length>0)return owned}let bestMatch=null;let bestLength=-1;for(const moduleID of allModuleIDs){const entry=cacheManager.get(moduleID);if(!entry?.endpoint)continue;const ep=entry.endpoint;if(ep==="."||apiPath.startsWith(ep+".")){if(ep.length>bestLength){bestLength=ep.length;bestMatch=moduleID}}}if(bestMatch)return[bestMatch];return[]}_collectCustomProperties(existingProxy,freshApi){const customProps={};if(!existingProxy||typeof existingProxy!=="object"&&typeof existingProxy!=="function"){return customProps}const wrapper=resolveWrapper(existingProxy);if(!wrapper){return customProps}const freshKeys=new Set(freshApi?Object.keys(freshApi):[]);const ownKeys=Object.keys(wrapper).filter(k=>!ComponentBase.INTERNAL_KEYS.has(k));for(const key of ownKeys){try{const val=wrapper[key];if(val&&(typeof val==="object"||typeof val==="function")&&resolveWrapper(val)){continue}if(!freshKeys.has(key)){customProps[key]=val}else{customProps[key]=val}}catch{}}return customProps}_restoreCustomProperties(proxy,customProps){if(!proxy||!customProps||typeof customProps!=="object"){return}for(const[key,value]of Object.entries(customProps)){try{proxy[key]=value}catch{}}}async _restoreApiTree(freshApi,endpoint,moduleID,collisionMode,forceReplace=true){if(!freshApi||typeof freshApi!=="object"&&typeof freshApi!=="function"){return}const parts=endpoint==="."?[]:endpoint.split(".");if(parts.length===0){for(const key of Object.keys(freshApi)){if(typeof key==="string"&&(key.startsWith("_")||key.startsWith("__")))continue;if(key==="slothlet"||key==="shutdown"||key==="destroy")continue;const existingAtKey=this.slothlet.api[key];const freshValue=freshApi[key];if(existingAtKey&&resolveWrapper(existingAtKey)!==null){const customProps=this._collectCustomProperties(existingAtKey,freshValue);const freshWrapper=resolveWrapper(freshValue);const isLazyFresh=freshWrapper&&freshWrapper.____slothletInternal.mode==="lazy"&&!freshWrapper.____slothletInternal.state.materialized&&typeof freshWrapper.____slothletInternal.materializeFunc==="function";this.slothlet.debug("reload",{key:"DEBUG_MODE_RESTORE_ROOT_KEY_INSPECT",rootKey:key,hasFreshWrapper:!!freshWrapper,freshMode:freshWrapper?.____slothletInternal.mode,freshMaterialized:freshWrapper?.____slothletInternal.state?.materialized,hasMaterializeFunc:typeof freshWrapper?.____slothletInternal.materializeFunc==="function",isLazyFresh,existingMaterialized:resolveWrapper(existingAtKey)?.____slothletInternal?.state?.materialized});if(isLazyFresh){resolveWrapper(existingAtKey).___resetLazy(freshWrapper.____slothletInternal.materializeFunc);this._restoreCustomProperties(existingAtKey,customProps);this.slothlet.debug("reload",{key:"DEBUG_MODE_ROOT_KEY_RESET_LAZY",rootKey:key,restoredCustomProps:Object.keys(customProps)})}else{let implForReload;if(freshValue&&resolveWrapper(freshValue)!==null){implForReload=freshWrapper?UnifiedWrapper._extractFullImpl(freshWrapper):freshValue}else{implForReload=freshValue}if(typeof implForReload==="function"){const extracted={};for(const k of Object.keys(implForReload)){extracted[k]=implForReload[k]}implForReload=extracted}const wrapper=resolveWrapper(existingAtKey);const originalCollisionMode=wrapper?wrapper.____slothletInternal.state.collisionMode:null;if(forceReplace&&wrapper){wrapper.____slothletInternal.state.collisionMode="replace"}if(wrapper&&originalCollisionMode!==null){wrapper.____slothletInternal.state.collisionMode=originalCollisionMode}this._restoreCustomProperties(existingAtKey,customProps);this.slothlet.debug("reload",{key:"DEBUG_MODE_ROOT_KEY_UPDATED_SETIMPL",rootKey:key,restoredCustomProps:Object.keys(customProps)})}}else if(existingAtKey===void 0){const cacheManager=this.slothlet.handlers.apiCacheManager;const cacheEntry=cacheManager.get(moduleID);const resolvedFolderPath=cacheEntry?.folderPath||"";await this.setValueAtPath(this.slothlet.api,[key],freshValue,{mutateExisting:true,collisionMode,moduleID,sourceFolder:resolvedFolderPath});if(this.slothlet.boundApi){await this.setValueAtPath(this.slothlet.boundApi,[key],freshValue,{mutateExisting:true,collisionMode,moduleID,sourceFolder:resolvedFolderPath})}}}}else{const existing=this.getValueAtPath(this.slothlet.api,parts);this.slothlet.debug("reload",{key:"DEBUG_MODE_RESTORE_NESTED_PATH",endpoint,moduleID,partsPath:parts.join("."),existingFound:!!existing,hasSetImpl:existing?resolveWrapper(existing)!==null:false,freshApiKeys:Object.keys(freshApi||{})});if(existing&&resolveWrapper(existing)!==null){const customProps=this._collectCustomProperties(existing,freshApi);const wrapper=resolveWrapper(existing);const originalCollisionMode=wrapper?wrapper.____slothletInternal.state.collisionMode:null;if(forceReplace&&wrapper){wrapper.____slothletInternal.state.collisionMode="replace";this.slothlet.debug("reload",{key:"DEBUG_MODE_RESTORE_FORCING_REPLACE",endpoint,originalCollisionMode,wrapperApiPath:wrapper.____slothletInternal.apiPath})}let implForReload;if(resolveWrapper(freshApi)!==null){const freshWrapper=resolveWrapper(freshApi);implForReload=freshWrapper?UnifiedWrapper._extractFullImpl(freshWrapper):freshApi}else if(typeof freshApi==="function"){implForReload={};for(const key of Object.keys(freshApi)){implForReload[key]=freshApi[key]}}else{implForReload=freshApi}if(parts.length>0&&implForReload&&typeof implForReload==="object"){const lastEndpointPart=parts[parts.length-1];if(lastEndpointPart&&Object.prototype.hasOwnProperty.call(implForReload,lastEndpointPart)){const dupValue=implForReload[lastEndpointPart];const dupWrapperForDedup=resolveWrapper(dupValue);if(dupWrapperForDedup){const hoisted={};for(const k of Object.keys(implForReload)){if(k!==lastEndpointPart)hoisted[k]=implForReload[k]}for(const k of Object.keys(dupWrapperForDedup).filter(k2=>!k2.startsWith("_")&&!k2.startsWith("__"))){hoisted[k]=dupWrapperForDedup[k]}implForReload=hoisted}}}if(implForReload&&typeof implForReload==="object"){for(const key of Object.keys(implForReload)){const val=implForReload[key];if(resolveWrapper(val)!==null){const childWrapper=resolveWrapper(val);if(childWrapper.____slothletInternal.state.materialized){implForReload[key]=UnifiedWrapper._extractFullImpl(childWrapper)}}}}resolveWrapper(existing).___setImpl(implForReload,moduleID);if(wrapper&&originalCollisionMode!==null){wrapper.____slothletInternal.state.collisionMode=originalCollisionMode}this._restoreCustomProperties(existing,customProps);this.slothlet.debug("reload",{key:"DEBUG_MODE_UPDATED_WRAPPER_IMPL",endpoint,moduleID,forcedReplaceMode:true,restoredCustomProps:Object.keys(customProps)})}else{const cacheManager=this.slothlet.handlers.apiCacheManager;const cacheEntry=cacheManager.get(moduleID);const resolvedFolderPath=cacheEntry?.folderPath||"";let implForContainer=freshApi;if(typeof freshApi==="function"){implForContainer={};for(const key of Object.keys(freshApi)){implForContainer[key]=freshApi[key]}}const containerWrapper=new UnifiedWrapper(this.slothlet,{apiPath:endpoint,mode:this.____config.mode,moduleID,filePath:resolvedFolderPath,sourceFolder:resolvedFolderPath});containerWrapper.___setImpl(implForContainer,moduleID);const apiToSet=containerWrapper.createProxy();await this.setValueAtPath(this.slothlet.api,parts,apiToSet,{mutateExisting:true,collisionMode,moduleID,sourceFolder:resolvedFolderPath});if(this.slothlet.boundApi){await this.setValueAtPath(this.slothlet.boundApi,parts,apiToSet,{mutateExisting:true,collisionMode,moduleID,sourceFolder:resolvedFolderPath})}this.slothlet.debug("reload",{key:"DEBUG_MODE_CREATED_NEW_WRAPPER_UNEXPECTED",endpoint,moduleID})}}}}export{ApiManager};