@cldmv/slothlet 3.9.2 → 3.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +21 -21
- package/REFERENCE.md +19 -19
- package/dist/lib/builders/api_builder.mjs +1 -1
- package/dist/lib/builders/builder.mjs +1 -1
- package/dist/lib/builders/modes-processor.mjs +1 -1
- package/dist/lib/handlers/api-cache-manager.mjs +1 -1
- package/dist/lib/handlers/api-manager.mjs +1 -1
- package/dist/lib/handlers/hook-manager.mjs +1 -1
- package/dist/lib/handlers/permission-manager.mjs +1 -1
- package/dist/lib/handlers/unified-wrapper.mjs +1 -1
- package/dist/lib/helpers/config.mjs +1 -1
- package/dist/lib/helpers/generate-manifest.mjs +1 -1
- package/dist/lib/helpers/module-discovery.mjs +1 -1
- package/dist/lib/helpers/module-manifest-validator.mjs +1 -1
- package/dist/lib/helpers/platform.mjs +1 -1
- package/dist/lib/i18n/languages/en-us.json +92 -64
- package/dist/lib/i18n/translations.mjs +1 -1
- package/dist/lib/modes/eager.mjs +1 -1
- package/dist/lib/modes/lazy.mjs +1 -1
- package/dist/lib/processors/loader.mjs +1 -1
- package/dist/slothlet.mjs +1 -1
- package/package.json +64 -34
- package/types/stub/devcheck.d.mts +3 -0
- package/types/stub/index.d.mts +4 -0
- package/types/stub/lib/builders/api-assignment.d.mts +3 -0
- package/types/stub/lib/builders/api_builder.d.mts +3 -0
- package/types/stub/lib/builders/builder.d.mts +3 -0
- package/types/stub/lib/builders/modes-processor.d.mts +3 -0
- package/types/stub/lib/errors.d.mts +3 -0
- package/types/stub/lib/factories/component-base.d.mts +3 -0
- package/types/stub/lib/factories/context.d.mts +3 -0
- package/types/stub/lib/handlers/api-cache-manager.d.mts +3 -0
- package/types/stub/lib/handlers/api-manager.d.mts +3 -0
- package/types/stub/lib/handlers/context-async.d.mts +3 -0
- package/types/stub/lib/handlers/context-live.d.mts +3 -0
- package/types/stub/lib/handlers/hook-manager.d.mts +3 -0
- package/types/stub/lib/handlers/lifecycle-token.d.mts +3 -0
- package/types/stub/lib/handlers/lifecycle.d.mts +3 -0
- package/types/stub/lib/handlers/materialize-manager.d.mts +3 -0
- package/types/stub/lib/handlers/metadata.d.mts +3 -0
- package/types/stub/lib/handlers/module-manager.d.mts +3 -0
- package/types/stub/lib/handlers/ownership.d.mts +3 -0
- package/types/stub/lib/handlers/permission-manager.d.mts +3 -0
- package/types/stub/lib/handlers/unified-wrapper.d.mts +3 -0
- package/types/stub/lib/handlers/version-manager.d.mts +3 -0
- package/types/stub/lib/helpers/class-instance-wrapper.d.mts +3 -0
- package/types/stub/lib/helpers/config.d.mts +3 -0
- package/types/stub/lib/helpers/eventemitter-context.d.mts +3 -0
- package/types/stub/lib/helpers/generate-manifest.d.mts +3 -0
- package/types/stub/lib/helpers/hint-detector.d.mts +3 -0
- package/types/stub/lib/helpers/manifest-resolver.d.mts +3 -0
- package/types/stub/lib/helpers/modes-utils.d.mts +3 -0
- package/types/stub/lib/helpers/module-discovery.d.mts +3 -0
- package/types/stub/lib/helpers/module-manifest-validator.d.mts +3 -0
- package/types/stub/lib/helpers/module-sort.d.mts +3 -0
- package/types/stub/lib/helpers/pattern-matcher.d.mts +3 -0
- package/types/stub/lib/helpers/platform.d.mts +3 -0
- package/types/stub/lib/helpers/resolve-from-caller.d.mts +3 -0
- package/types/stub/lib/helpers/sanitize.d.mts +3 -0
- package/types/stub/lib/helpers/utilities.d.mts +3 -0
- package/types/stub/lib/i18n/translations.d.mts +3 -0
- package/types/stub/lib/modes/eager.d.mts +3 -0
- package/types/stub/lib/modes/lazy.d.mts +3 -0
- package/types/stub/lib/processors/flatten.d.mts +3 -0
- package/types/stub/lib/processors/loader.d.mts +3 -0
- package/types/stub/lib/processors/type-generator.d.mts +3 -0
- package/types/stub/lib/processors/typescript.d.mts +3 -0
- package/types/stub/lib/runtime/runtime-asynclocalstorage.d.mts +3 -0
- package/types/stub/lib/runtime/runtime-livebindings.d.mts +3 -0
- package/types/stub/lib/runtime/runtime.d.mts +3 -0
- package/types/stub/lib/typegen/typegen.d.mts +3 -0
- package/types/stub/slothlet.d.mts +4 -0
- package/dist/lib/i18n/languages/de-de.json +0 -444
- package/dist/lib/i18n/languages/en-gb.json +0 -444
- package/dist/lib/i18n/languages/es-es.json +0 -444
- package/dist/lib/i18n/languages/es-mx.json +0 -444
- package/dist/lib/i18n/languages/fr-fr.json +0 -444
- package/dist/lib/i18n/languages/hi-in.json +0 -444
- package/dist/lib/i18n/languages/ja-jp.json +0 -444
- package/dist/lib/i18n/languages/ko-kr.json +0 -444
- package/dist/lib/i18n/languages/pt-br.json +0 -444
- package/dist/lib/i18n/languages/ru-ru.json +0 -444
- package/dist/lib/i18n/languages/zh-cn.json +0 -444
- package/types/dist/lib/builders/api-assignment.d.mts +0 -8
- package/types/dist/lib/builders/api-assignment.d.mts.map +0 -1
- package/types/dist/lib/builders/api_builder.d.mts +0 -12
- package/types/dist/lib/builders/api_builder.d.mts.map +0 -1
- package/types/dist/lib/builders/builder.d.mts +0 -6
- package/types/dist/lib/builders/builder.d.mts.map +0 -1
- package/types/dist/lib/builders/modes-processor.d.mts +0 -8
- package/types/dist/lib/builders/modes-processor.d.mts.map +0 -1
- package/types/dist/lib/errors.d.mts +0 -28
- package/types/dist/lib/errors.d.mts.map +0 -1
- package/types/dist/lib/factories/component-base.d.mts +0 -12
- package/types/dist/lib/factories/component-base.d.mts.map +0 -1
- package/types/dist/lib/factories/context.d.mts +0 -8
- package/types/dist/lib/factories/context.d.mts.map +0 -1
- package/types/dist/lib/handlers/api-cache-manager.d.mts +0 -25
- package/types/dist/lib/handlers/api-cache-manager.d.mts.map +0 -1
- package/types/dist/lib/handlers/api-manager.d.mts +0 -47
- package/types/dist/lib/handlers/api-manager.d.mts.map +0 -1
- package/types/dist/lib/handlers/context-async.d.mts +0 -28
- package/types/dist/lib/handlers/context-async.d.mts.map +0 -1
- package/types/dist/lib/handlers/context-live.d.mts +0 -28
- package/types/dist/lib/handlers/context-live.d.mts.map +0 -1
- package/types/dist/lib/handlers/hook-manager.d.mts +0 -65
- package/types/dist/lib/handlers/hook-manager.d.mts.map +0 -1
- package/types/dist/lib/handlers/lifecycle-token.d.mts +0 -4
- package/types/dist/lib/handlers/lifecycle-token.d.mts.map +0 -1
- package/types/dist/lib/handlers/lifecycle.d.mts +0 -13
- package/types/dist/lib/handlers/lifecycle.d.mts.map +0 -1
- package/types/dist/lib/handlers/materialize-manager.d.mts +0 -13
- package/types/dist/lib/handlers/materialize-manager.d.mts.map +0 -1
- package/types/dist/lib/handlers/metadata.d.mts +0 -26
- package/types/dist/lib/handlers/metadata.d.mts.map +0 -1
- package/types/dist/lib/handlers/module-manager.d.mts +0 -29
- package/types/dist/lib/handlers/module-manager.d.mts.map +0 -1
- package/types/dist/lib/handlers/ownership.d.mts +0 -57
- package/types/dist/lib/handlers/ownership.d.mts.map +0 -1
- package/types/dist/lib/handlers/permission-manager.d.mts +0 -54
- package/types/dist/lib/handlers/permission-manager.d.mts.map +0 -1
- package/types/dist/lib/handlers/unified-wrapper.d.mts +0 -37
- package/types/dist/lib/handlers/unified-wrapper.d.mts.map +0 -1
- package/types/dist/lib/handlers/version-manager.d.mts +0 -37
- package/types/dist/lib/handlers/version-manager.d.mts.map +0 -1
- package/types/dist/lib/helpers/class-instance-wrapper.d.mts +0 -4
- package/types/dist/lib/helpers/class-instance-wrapper.d.mts.map +0 -1
- package/types/dist/lib/helpers/config.d.mts +0 -150
- package/types/dist/lib/helpers/config.d.mts.map +0 -1
- package/types/dist/lib/helpers/eventemitter-context.d.mts +0 -5
- package/types/dist/lib/helpers/eventemitter-context.d.mts.map +0 -1
- package/types/dist/lib/helpers/generate-manifest.d.mts +0 -11
- package/types/dist/lib/helpers/generate-manifest.d.mts.map +0 -1
- package/types/dist/lib/helpers/hint-detector.d.mts +0 -7
- package/types/dist/lib/helpers/hint-detector.d.mts.map +0 -1
- package/types/dist/lib/helpers/manifest-resolver.d.mts +0 -2
- package/types/dist/lib/helpers/manifest-resolver.d.mts.map +0 -1
- package/types/dist/lib/helpers/modes-utils.d.mts +0 -8
- package/types/dist/lib/helpers/modes-utils.d.mts.map +0 -1
- package/types/dist/lib/helpers/module-discovery.d.mts +0 -8
- package/types/dist/lib/helpers/module-discovery.d.mts.map +0 -1
- package/types/dist/lib/helpers/module-manifest-validator.d.mts +0 -14
- package/types/dist/lib/helpers/module-manifest-validator.d.mts.map +0 -1
- package/types/dist/lib/helpers/module-sort.d.mts +0 -2
- package/types/dist/lib/helpers/module-sort.d.mts.map +0 -1
- package/types/dist/lib/helpers/pattern-matcher.d.mts +0 -4
- package/types/dist/lib/helpers/pattern-matcher.d.mts.map +0 -1
- package/types/dist/lib/helpers/platform.d.mts +0 -12
- package/types/dist/lib/helpers/platform.d.mts.map +0 -1
- package/types/dist/lib/helpers/resolve-from-caller.d.mts +0 -9
- package/types/dist/lib/helpers/resolve-from-caller.d.mts.map +0 -1
- package/types/dist/lib/helpers/sanitize.d.mts +0 -10
- package/types/dist/lib/helpers/sanitize.d.mts.map +0 -1
- package/types/dist/lib/helpers/utilities.d.mts +0 -9
- package/types/dist/lib/helpers/utilities.d.mts.map +0 -1
- package/types/dist/lib/i18n/translations.d.mts +0 -7
- package/types/dist/lib/i18n/translations.d.mts.map +0 -1
- package/types/dist/lib/modes/eager.d.mts +0 -14
- package/types/dist/lib/modes/eager.d.mts.map +0 -1
- package/types/dist/lib/modes/lazy.d.mts +0 -16
- package/types/dist/lib/modes/lazy.d.mts.map +0 -1
- package/types/dist/lib/processors/flatten.d.mts +0 -63
- package/types/dist/lib/processors/flatten.d.mts.map +0 -1
- package/types/dist/lib/processors/loader.d.mts +0 -12
- package/types/dist/lib/processors/loader.d.mts.map +0 -1
- package/types/dist/lib/processors/type-generator.d.mts +0 -5
- package/types/dist/lib/processors/type-generator.d.mts.map +0 -1
- package/types/dist/lib/processors/typescript.d.mts +0 -18
- package/types/dist/lib/processors/typescript.d.mts.map +0 -1
- package/types/dist/lib/runtime/runtime-asynclocalstorage.d.mts +0 -4
- package/types/dist/lib/runtime/runtime-asynclocalstorage.d.mts.map +0 -1
- package/types/dist/lib/runtime/runtime-livebindings.d.mts +0 -3
- package/types/dist/lib/runtime/runtime-livebindings.d.mts.map +0 -1
- package/types/dist/lib/runtime/runtime.d.mts +0 -4
- package/types/dist/lib/runtime/runtime.d.mts.map +0 -1
- package/types/dist/lib/typegen/typegen.d.mts +0 -5
- package/types/dist/lib/typegen/typegen.d.mts.map +0 -1
- package/types/dist/slothlet.d.mts +0 -4
- package/types/dist/slothlet.d.mts.map +0 -1
- package/types/index.d.mts +0 -18
- package/types/index.d.mts.map +0 -1
|
@@ -1,54 +1,110 @@
|
|
|
1
1
|
{
|
|
2
2
|
"translations": {
|
|
3
3
|
"INVALID_CONFIG": "Invalid configuration: {option} is {value}, expected {expected}. {hint}",
|
|
4
|
+
"HINT_INVALID_CONFIG": "Check the configuration value and ensure it matches the expected type and format.",
|
|
5
|
+
"INVALID_CONFIG_SYNTHETIC_EXPORTS_SHAPE": "Configuration error: inline exports must be a plain export-map object (a default and/or named exports), received {received}.",
|
|
6
|
+
"HINT_INVALID_CONFIG_SYNTHETIC_EXPORTS_SHAPE": "Pass exports as a plain object, e.g. { default: fn } or { name: fn } — or a { exports: { default?, ...named } } wrapper, or a bare function.",
|
|
7
|
+
"INVALID_CONFIG_SYNTHETIC_INPUT": "Configuration error: inline content must be a plain export-map object, an exports-wrapper object, or a bare function, received {received}.",
|
|
8
|
+
"HINT_INVALID_CONFIG_SYNTHETIC_INPUT": "Pass inline exports as a plain object or a bare function; a filesystem mount needs a string path.",
|
|
9
|
+
"INVALID_CONFIG_SYNTHETIC_NAME": "Configuration error: syntheticName must be a non-empty string, received {received}.",
|
|
10
|
+
"HINT_INVALID_CONFIG_SYNTHETIC_NAME": "Provide a string key name for the synthetic build, e.g. \"synthetic\".",
|
|
11
|
+
"INVALID_CONFIG_PRELOADED_STRUCTURE": "Configuration error: preloadedStructure must be a plain object with files and directories arrays, received {received}.",
|
|
12
|
+
"HINT_INVALID_CONFIG_PRELOADED_STRUCTURE": "preloadedStructure is built internally; pass an object with files and directories arrays, or omit it to scan a directory.",
|
|
4
13
|
"INVALID_CONFIG_DIR_MISSING": "Configuration error: 'dir' option is required. Provide a directory path to load API from.",
|
|
14
|
+
"HINT_INVALID_CONFIG_DIR_MISSING": "The directory path is required but was not provided.",
|
|
5
15
|
"INVALID_CONFIG_DIR_INVALID": "Configuration error: 'dir' must be a non-empty string path. Received: {dir}",
|
|
16
|
+
"HINT_INVALID_CONFIG_DIR_INVALID": "Ensure the directory path is a valid string and points to an existing directory.",
|
|
6
17
|
"INVALID_CONFIG_BROWSER_REQUIRES_MANIFEST": "Configuration error: 'manifest' is required when env is 'browser'. Provide a pre-generated manifest object with 'files' and 'directories' arrays.",
|
|
7
18
|
"INVALID_CONFIG_BROWSER_MANIFEST_INVALID": "Configuration error: 'manifest' must be a plain object with 'files' and 'directories' arrays. Received: {received}",
|
|
8
19
|
"INVALID_CONFIG_BROWSER_RESOLVE_SPECIFIER_INVALID": "Configuration error: 'resolveModuleSpecifier' must be a function when env is 'browser'. Received: {received}",
|
|
9
20
|
"INVALID_CONFIG_MODE_INVALID": "Configuration error: 'mode' must be either 'eager' or 'lazy'. Received: {value}",
|
|
21
|
+
"HINT_INVALID_CONFIG_MODE_INVALID": "Mode must be either 'eager' or 'lazy'.",
|
|
10
22
|
"INVALID_CONFIG_NOT_LOADED": "Cannot perform operation '{operation}' - instance not loaded. Call load() first.",
|
|
23
|
+
"HINT_INVALID_CONFIG_NOT_LOADED": "The instance must be loaded before performing this operation. Call load() first.",
|
|
11
24
|
"INVALID_CONFIG_LAZY_MATERIALIZATION_FAILED": "Failed to materialize lazy proxy for '{apiPath}'. Check that the module loads correctly.",
|
|
12
25
|
"INVALID_CONFIG_NOT_A_FUNCTION": "Cannot call '{apiPath}' - not a function (got {actualType}). Check that the module exports a callable function.",
|
|
13
26
|
"INVALID_CONFIG_API_PATH_INVALID": "Invalid API path '{apiPath}': {reason}. API paths must be non-empty, properly formatted dot-notation strings that don't conflict with reserved names. Segment at index {index}: '{segment}'.",
|
|
27
|
+
"HINT_INVALID_CONFIG_API_PATH_INVALID": "Ensure the API path is a valid dot-notation string (e.g., 'plugins.tools') without empty segments or reserved names (slothlet, shutdown, destroy).",
|
|
14
28
|
"INVALID_CONFIG_FORCE_OVERWRITE_REQUIRES_MODULE_ID": "Configuration error: forceOverwrite/allowOverwrite requires a moduleID. Provide a unique moduleID when using overwrite options for API path '{apiPath}'.",
|
|
29
|
+
"HINT_INVALID_CONFIG_FORCE_OVERWRITE_REQUIRES_MODULE_ID": "When using forceOverwrite or allowOverwrite, you must provide a unique moduleID to track ownership of the overwritten path.",
|
|
15
30
|
"INVALID_METADATA_TARGET": "Invalid metadata target: expected {expected}, received {target}. Metadata operations require a function or object reference.",
|
|
31
|
+
"HINT_INVALID_METADATA_TARGET": "The target must be a function or object that was loaded through Slothlet. Pass the actual function/object reference, not a string or primitive value.",
|
|
16
32
|
"METADATA_NO_MODULE_ID": "Cannot set user metadata: no moduleID found in system metadata. Ensure the target function/object was loaded through Slothlet.",
|
|
33
|
+
"HINT_METADATA_NO_MODULE_ID": "Ensure the function/object was loaded through Slothlet's module system. Only Slothlet-managed functions have associated metadata.",
|
|
17
34
|
"METADATA_LIFECYCLE_BYPASS": "tagSystemMetadata() must be called through the lifecycle system. Use lifecycle.emit('impl:created') or lifecycle.emit('impl:changed') instead of a direct call.",
|
|
35
|
+
"HINT_METADATA_LIFECYCLE_BYPASS": "Never call tagSystemMetadata() directly. Trigger the 'impl:created' or 'impl:changed' lifecycle events instead, which will invoke tagSystemMetadata() through the proper channel.",
|
|
18
36
|
"INVALID_METADATA_KEY": "Invalid metadata key: expected {expected}, received {type} for key '{key}'. Metadata keys must be properly formatted.",
|
|
37
|
+
"HINT_INVALID_METADATA_KEY": "Metadata keys must be strings, string arrays, or objects with array values. Check the key format matches one of these types.",
|
|
19
38
|
"WARNING_METADATA_MISMATCH": "Security warning: Metadata file path mismatch for '{apiPath}'. Stack trace shows '{stackFile}' but metadata shows '{metadataFile}'. This may indicate hot reload or tampering.",
|
|
39
|
+
"HINT_WARNING_METADATA_MISMATCH": "This warning indicates the function's execution location doesn't match its registered metadata path. This can occur during hot reload or if the function was tampered with. In most cases, this is expected during development with hot reload enabled.",
|
|
20
40
|
"COLLISION_ERROR": "Collision error at '{key}' (context: {collisionContext}, mode: {collisionMode}). Set collision mode to 'merge', 'replace', 'warn', or 'skip' to handle collisions.",
|
|
41
|
+
"HINT_COLLISION_ERROR": "Collision mode is set to 'error' which prevents any overwrites. Use collision: 'merge' (combine properties), 'replace' (overwrite completely), 'warn' (warn but keep existing), or 'skip' (silently ignore) instead.",
|
|
21
42
|
"COLLISION_DEFAULT_EXPORT_ERROR": "Collision detected: property '{key}' already exists on default export at '{apiPath}'. Collision mode is 'error'.",
|
|
43
|
+
"HINT_COLLISION_DEFAULT_EXPORT_ERROR": "A named export conflicts with a property already present on the default export object at this path. Change the collision mode to 'merge', 'replace', 'warn', or 'skip', or rename the conflicting property.",
|
|
22
44
|
"INVALID_ARGUMENT": "Invalid argument '{argument}': expected {expected}, received {received}.",
|
|
45
|
+
"HINT_INVALID_ARGUMENT": "Path must be a dot-notation string (e.g., 'math.add').",
|
|
23
46
|
"RUNTIME_NO_ACTIVE_CONTEXT": "No active context found. This operation requires being called from within a slothlet API function.",
|
|
47
|
+
"HINT_RUNTIME_NO_ACTIVE_CONTEXT": "metadata.self() must be called from within a slothlet API function.",
|
|
24
48
|
"INVALID_CONFIG_MUTATIONS_DISABLED": "Cannot perform '{operation}' - mutation is disabled. Set allowMutation: true to enable API modification operations (add/remove/reload).",
|
|
49
|
+
"HINT_INVALID_CONFIG_MUTATIONS_DISABLED": "API mutation operations require allowMutation: true in the configuration. Use diagnostics: true to access these methods for testing without enabling actual mutations.",
|
|
25
50
|
"CACHE_MODULEID_MISMATCH": "Cache entry moduleID mismatch: expected '{cacheKey}', but entry has '{entryModuleID}'. This indicates an internal cache inconsistency.",
|
|
51
|
+
"HINT_CACHE_MODULEID_MISMATCH": "This is an internal error indicating cache corruption. Please report this issue with steps to reproduce.",
|
|
26
52
|
"CACHE_NOT_FOUND": "Cache entry not found for moduleID '{moduleID}' during '{operation}' operation. The module may not be loaded or the cache may have been cleared.",
|
|
53
|
+
"HINT_CACHE_NOT_FOUND": "Ensure the module has been loaded before attempting to reload or rebuild its cache. Check that the moduleID is correct.",
|
|
27
54
|
"CACHE_MANAGER_NOT_AVAILABLE": "Cache manager is not available. Cannot perform '{operation}' operation. Ensure the cache manager is initialized.",
|
|
55
|
+
"HINT_CACHE_MANAGER_NOT_AVAILABLE": "The cache manager should be initialized automatically. If you see this error, it may indicate an internal initialization issue.",
|
|
28
56
|
"MODULE_LOAD_FAILED": "Failed to load module '{modulePath}' (ID: {moduleID}): {error}",
|
|
57
|
+
"HINT_MODULE_LOAD_FAILED": "Check the module file for errors. Ensure it has valid JavaScript syntax and exports.",
|
|
29
58
|
"MODULE_NOT_FOUND": "Module not found: {modulePath}. {hint}",
|
|
59
|
+
"HINT_MODULE_NOT_FOUND": "Ensure the module exists and the path is correct. Check for typos in the import statement.",
|
|
30
60
|
"MODULE_IMPORT_FAILED": "Failed to import module '{modulePath}': {error}. Check that the file exists and has valid syntax.",
|
|
61
|
+
"HINT_MODULE_IMPORT_FAILED": "Ensure the module file exists and can be imported. Check for syntax errors or missing dependencies.",
|
|
31
62
|
"CONTEXT_ALREADY_EXISTS": "Context for instance '{instanceID}' already exists. Cannot initialize twice.",
|
|
63
|
+
"HINT_CONTEXT_ALREADY_EXISTS": "This context already exists. Check if you're trying to initialize the same instance twice.",
|
|
32
64
|
"CONTEXT_NOT_FOUND": "Context not found for instance '{instanceID}'. Instance may have been shut down. Available instances: {availableInstances}",
|
|
65
|
+
"HINT_CONTEXT_NOT_FOUND": "Ensure the slothlet instance is initialized and the context is created before accessing it. Check that you're using the correct instance ID.",
|
|
33
66
|
"CONTEXT_EXECUTION_FAILED": "Failed to execute in context for instance '{instanceID}': {error}",
|
|
67
|
+
"HINT_CONTEXT_EXECUTION_FAILED": "An error occurred while executing the function. Check the error details for more information.",
|
|
34
68
|
"NO_ACTIVE_CONTEXT_LIVE": "No active context - no instance is currently active in live bindings mode.",
|
|
69
|
+
"HINT_NO_ACTIVE_CONTEXT_LIVE": "No active context found. Ensure you're calling this function from within a slothlet live context.",
|
|
35
70
|
"NO_ACTIVE_CONTEXT_ASYNC": "No active context - function must be called within slothlet API context.",
|
|
71
|
+
"HINT_NO_ACTIVE_CONTEXT_ASYNC": "No active context found. Ensure you're calling this function from within a slothlet async context.",
|
|
36
72
|
"RUNTIME_NO_ACTIVE_CONTEXT_SELF": "No active context - cannot access 'self'. Ensure you're calling from within a Slothlet API function.",
|
|
73
|
+
"HINT_RUNTIME_NO_ACTIVE_CONTEXT_SELF": "Cannot access 'self' outside of a slothlet API function context.",
|
|
37
74
|
"RUNTIME_NO_ACTIVE_CONTEXT_CONTEXT": "No active context - 'context' can only be modified within slothlet API calls.",
|
|
75
|
+
"HINT_RUNTIME_NO_ACTIVE_CONTEXT_CONTEXT": "Cannot access 'context' outside of a slothlet API function. Context can only be modified within slothlet API calls.",
|
|
38
76
|
"OWNERSHIP_INVALID_MODULE_ID": "Invalid ownership registration: moduleID '{moduleID}' is invalid.",
|
|
77
|
+
"HINT_OWNERSHIP_INVALID_MODULE_ID": "The module ID is invalid. Ensure the module was loaded properly and the ID is correct.",
|
|
39
78
|
"OWNERSHIP_INVALID_API_PATH": "Invalid ownership registration: apiPath '{apiPath}' is invalid.",
|
|
79
|
+
"HINT_OWNERSHIP_INVALID_API_PATH": "The API path is invalid. Ensure the path format is correct.",
|
|
40
80
|
"OWNERSHIP_CONFLICT": "Ownership conflict: Path '{apiPath}' is already owned by module '{existingModuleId}', cannot assign to '{newModuleId}'. Use forceOverwrite: true or removeApi first.",
|
|
81
|
+
"HINT_OWNERSHIP_CONFLICT": "Path is already owned by another module. Options: (1) Use forceOverwrite: true in api.add() options, (2) Set collision config to 'merge' or 'replace', (3) Call api.slothlet.api.remove() first to clear the path.",
|
|
41
82
|
"LOOSE_SET_NOT_OWNED": "Module {callerApiPath} is not allowed to write to {apiPath}. A module may only write under its own apiPath; use api.slothlet.api.add() to register at a different path.",
|
|
83
|
+
"HINT_LOOSE_SET_NOT_OWNED": "A module owning apiPath \"P\" may write only under \"P.*\". To register code at a different namespace, call api.slothlet.api.add() instead.",
|
|
42
84
|
"LOOSE_SET_RESERVED_KEY": "Cannot assign to reserved key segment '{segment}' in apiPath '{apiPath}'. Names like __proto__, prototype, and constructor are blocked to prevent prototype pollution of the API tree.",
|
|
85
|
+
"HINT_LOOSE_SET_RESERVED_KEY": "The segments __proto__, prototype, and constructor cannot be used as apiPath names because writing to them would mutate the JavaScript prototype chain. Choose a different name.",
|
|
43
86
|
"INVALID_DIRECTORY": "Invalid directory '{dir}': {error}. Ensure the directory exists and is accessible.",
|
|
87
|
+
"HINT_INVALID_DIRECTORY": "Ensure the directory path is correct and the directory exists and is accessible.",
|
|
44
88
|
"WARN_DIRECTORY_EMPTY": "Directory '{dir}' (resolved: '{resolvedPath}') is empty or contains no loadable modules (.mjs, .cjs, .js files). This is valid for add-api workflows but may indicate a misconfigured path.",
|
|
89
|
+
"HINT_WARN_DIRECTORY_EMPTY": "Check that the directory path is correct. Empty directories are valid for add-api workflows where modules will be added dynamically.",
|
|
90
|
+
"WARN_SYNTHETIC_ROOT_EMPTY": "Synthetic add at api path '{apiPath}' contributed no leaves; nothing was mounted.",
|
|
91
|
+
"HINT_WARN_SYNTHETIC_ROOT_EMPTY": "Provide at least one export — a named function default or named exports — so the synthetic add has something to mount.",
|
|
92
|
+
"WARN_SYNTHETIC_ROOT_UNNAMED": "Synthetic add at the API root has an anonymous default export; it cannot be keyed onto the root and was skipped.",
|
|
93
|
+
"HINT_WARN_SYNTHETIC_ROOT_UNNAMED": "Name the default function (its name becomes the root key), provide named exports, or mount the leaf at a named apiPath.",
|
|
94
|
+
"WARN_SYNTHETIC_ROOT_COLLISION": "Synthetic add at the API root re-keys its default to '{name}', but a named export already uses '{name}'; the named export takes precedence.",
|
|
95
|
+
"HINT_WARN_SYNTHETIC_ROOT_COLLISION": "Rename the default function or the conflicting named export so each lands on a distinct root key.",
|
|
45
96
|
"INTERNAL_HOOK_STATE_CORRUPT": "[INTERNAL ERROR] HookManager state is corrupt: hook \"{hookId}\" ({type}/{subset}/{pattern}) — {detail}. This is a bug in Slothlet — please report it.",
|
|
97
|
+
"HINT_INTERNAL_HOOK_STATE_CORRUPT": "HookManager internal state is inconsistent. This should never happen through normal usage — please file a bug report including how you called hook.on() and hook.remove().",
|
|
46
98
|
"WARNING_RESERVED_PROPERTY_CONFLICT": "User API conflicts with reserved properties: {properties}",
|
|
99
|
+
"HINT_WARNING_RESERVED_PROPERTY_CONFLICT": "The 'slothlet' property name is reserved for built-in API methods. Rename your API module or property to avoid conflicts with slothlet.shutdown(), slothlet.api.*, etc.",
|
|
47
100
|
"WARNING_LANGUAGE_LOAD_FAILED": "Failed to load language '{lang}', falling back to English.",
|
|
48
101
|
"WARNING_LANGUAGE_UNAVAILABLE": "Language '{lang}' is not available, using English.",
|
|
49
102
|
"WARNING_OWNERSHIP_CONFLICT": "Ownership conflict at '{apiPath}': already owned by '{existingModuleId}', cannot register '{newModuleId}'. Keeping existing.",
|
|
103
|
+
"HINT_WARNING_OWNERSHIP_CONFLICT": "The path is already owned by another module. To force overwrite, use forceOverwrite: true in api.add() options, or call api.slothlet.api.remove() first to clear the path.",
|
|
50
104
|
"WARNING_HOT_RELOAD_PATH_COLLISION": "Path collision at {apiPath} - keeping existing value (collision mode: warn).",
|
|
105
|
+
"HINT_WARNING_HOT_RELOAD_PATH_COLLISION": "A collision occurred during hot reload at the specified path. The existing value is being kept. To force replacement, use collision mode 'replace' instead of 'warn'.",
|
|
51
106
|
"WARNING_HOT_RELOAD_MERGE_PRIMITIVES": "Cannot merge primitive values at {apiPath} - keeping existing value. Use collision mode 'replace' to overwrite or ensure both values are objects.",
|
|
107
|
+
"HINT_WARNING_HOT_RELOAD_MERGE_PRIMITIVES": "Cannot merge primitive values (strings, numbers, booleans). To replace the value, use collision mode 'replace'. To keep the existing value, continue using 'warn' mode.",
|
|
52
108
|
"WARNING_COLLISION_FILE_FOLDER_MERGE": "Collision detected at '{key}' - merging file and folder exports (collision mode: 'warn').",
|
|
53
109
|
"HINT_WARNING_COLLISION_FILE_FOLDER_MERGE": "A file and a folder share the same name at '{key}'. Their exports are being merged. Rename one to avoid ambiguity, or set collisionMode to 'replace' or 'error' if merging is not intended.",
|
|
54
110
|
"WARNING_COLLISION_DEFAULT_EXPORT_OVERWRITE": "Collision warning: property '{key}' already exists on default export function at {apiPath}. Named export will overwrite.",
|
|
@@ -58,8 +114,13 @@
|
|
|
58
114
|
"WARNING_LIFECYCLE_HANDLER_ERROR": "Lifecycle event handler threw an error for event '{event}'. Other handlers for this event continued executing.",
|
|
59
115
|
"HINT_WARNING_LIFECYCLE_HANDLER_ERROR": "A lifecycle handler registered for the '{event}' event threw an error. Check your lifecycle.on('{event}', ...) handler for bugs. Other handlers in the same event are not affected.",
|
|
60
116
|
"WARNING_MULTIPLE_ROOT_CONTRIBUTORS": "Multiple root-level default function exports detected: {rootContributors}. Each has been namespaced by filename (e.g., api.{firstContributor}()). Consider using a single root-level default export or moving files to subdirectories.",
|
|
117
|
+
"HINT_WARNING_MULTIPLE_ROOT_CONTRIBUTORS": "Multiple files export default functions at the root level. Each has been namespaced (e.g., api.filename()). Consider consolidating into one root export or moving files to subdirectories for clearer organization.",
|
|
61
118
|
"V3_CONFIG_DEPRECATED": "Configuration option '{option}' is deprecated and will be removed in v4. Use '{replacement}' instead.",
|
|
119
|
+
"HINT_V3_CONFIG_DEPRECATED": "This configuration option has been renamed for clarity. Update your code to use the new option name to ensure forward compatibility with v4.",
|
|
120
|
+
"CONFIG_SCAN_HIDDEN_FOLDERS_DEPRECATED": "Configuration option '{option}' is deprecated and will be removed in v4. Hidden folders (names starting with '.' or '__') are excluded from the API by default.",
|
|
121
|
+
"HINT_CONFIG_SCAN_HIDDEN_FOLDERS_DEPRECATED": "This option is a temporary backward-compatibility escape hatch. Move non-API content out of the API directory so hidden folders no longer need to be scanned.",
|
|
62
122
|
"V2_CONFIG_UNSUPPORTED": "Configuration option '{option}' from v2 is not supported in v3. {hint} Use '{replacement}' instead.",
|
|
123
|
+
"HINT_V2_CONFIG_UNSUPPORTED": "This configuration option from v2 is not supported in v3. Update your configuration to use the v3 equivalent for better control and clarity.",
|
|
63
124
|
"WARN_SUPPRESS_FIX_ACTIVE": "Rule fix '{rule}' is suppressed via 'suppressFixes'. See {url} for details. This is a temporary override and will be removed in v4. The corrected '{rule}' behavior will be enforced permanently.",
|
|
64
125
|
"HINT_WARN_SUPPRESS_FIX_ACTIVE": "Remove '{rule}' from 'suppressFixes' and update your API directory structure to accommodate the corrected behavior before upgrading to v4.",
|
|
65
126
|
"DEBUG_MODE_ROOT_CONTRIBUTOR": "[{mode}] Root contributor detected: {functionName}",
|
|
@@ -230,72 +291,15 @@
|
|
|
230
291
|
"DEBUG_MODE_LAZY_WRAPPER_MATERIALIZED": "Lazy wrapper materialized",
|
|
231
292
|
"DEBUG_MODE_ALL_LAZY_WRAPPERS_MATERIALIZED": "All lazy wrappers materialized",
|
|
232
293
|
"HINT_REFERENCE_REMOVED": "The 'reference' export has been removed from '@cldmv/slothlet/runtime'. Reference objects are now merged directly into the API. Access them via 'self.*' instead (e.g., 'self.myRefProperty').",
|
|
233
|
-
"HINT_MODULE_NOT_FOUND": "Ensure the module exists and the path is correct. Check for typos in the import statement.",
|
|
234
294
|
"HINT_SYNTAX_ERROR": "Check for syntax errors in the module file. Common issues: missing brackets, unclosed strings, or invalid JavaScript syntax.",
|
|
235
|
-
"HINT_CONTEXT_NOT_FOUND": "Ensure the slothlet instance is initialized and the context is created before accessing it. Check that you're using the correct instance ID.",
|
|
236
|
-
"HINT_CONTEXT_ALREADY_EXISTS": "This context already exists. Check if you're trying to initialize the same instance twice.",
|
|
237
|
-
"HINT_CONTEXT_EXECUTION_FAILED": "An error occurred while executing the function. Check the error details for more information.",
|
|
238
|
-
"HINT_NO_ACTIVE_CONTEXT": "No active context found. Ensure you're calling this function from within a slothlet context (async or live mode).",
|
|
239
|
-
"HINT_NO_ACTIVE_CONTEXT_ASYNC": "No active context found. Ensure you're calling this function from within a slothlet async context.",
|
|
240
|
-
"HINT_NO_ACTIVE_CONTEXT_LIVE": "No active context found. Ensure you're calling this function from within a slothlet live context.",
|
|
241
|
-
"HINT_OWNERSHIP_INVALID_MODULE_ID": "The module ID is invalid. Ensure the module was loaded properly and the ID is correct.",
|
|
242
|
-
"HINT_OWNERSHIP_INVALID_API_PATH": "The API path is invalid. Ensure the path format is correct.",
|
|
243
|
-
"HINT_OWNERSHIP_CONFLICT": "Path is already owned by another module. Options: (1) Use forceOverwrite: true in api.add() options, (2) Set collision config to 'merge' or 'replace', (3) Call api.slothlet.api.remove() first to clear the path.",
|
|
244
|
-
"HINT_INVALID_CONFIG": "Check the configuration value and ensure it matches the expected type and format.",
|
|
245
|
-
"HINT_INVALID_CONFIG_DIR_INVALID": "Ensure the directory path is a valid string and points to an existing directory.",
|
|
246
|
-
"HINT_INVALID_CONFIG_FORCE_OVERWRITE_REQUIRES_MODULE_ID": "When using forceOverwrite or allowOverwrite, you must provide a unique moduleID to track ownership of the overwritten path.",
|
|
247
|
-
"HINT_COLLISION_ERROR": "Collision mode is set to 'error' which prevents any overwrites. Use collision: 'merge' (combine properties), 'replace' (overwrite completely), 'warn' (warn but keep existing), or 'skip' (silently ignore) instead.",
|
|
248
|
-
"HINT_COLLISION_DEFAULT_EXPORT_ERROR": "A named export conflicts with a property already present on the default export object at this path. Change the collision mode to 'merge', 'replace', 'warn', or 'skip', or rename the conflicting property.",
|
|
249
|
-
"HINT_INVALID_ARGUMENT": "Path must be a dot-notation string (e.g., 'math.add').",
|
|
250
|
-
"HINT_RUNTIME_NO_ACTIVE_CONTEXT": "metadata.self() must be called from within a slothlet API function.",
|
|
251
|
-
"HINT_INVALID_CONFIG_MODE_INVALID": "Mode must be either 'eager' or 'lazy'.",
|
|
252
|
-
"HINT_INVALID_CONFIG_MODE_UNKNOWN": "Unknown mode specified. Use 'eager' or 'lazy'.",
|
|
253
|
-
"HINT_INVALID_CONFIG_DIR_MISSING": "The directory path is required but was not provided.",
|
|
254
|
-
"HINT_INVALID_CONFIG_API_PATH_INVALID": "Ensure the API path is a valid dot-notation string (e.g., 'plugins.tools') without empty segments or reserved names (slothlet, shutdown, destroy).",
|
|
255
|
-
"HINT_INVALID_CONFIG_MUTATIONS_DISABLED": "API mutation operations require allowMutation: true in the configuration. Use diagnostics: true to access these methods for testing without enabling actual mutations.",
|
|
256
|
-
"HINT_CACHE_MODULEID_MISMATCH": "This is an internal error indicating cache corruption. Please report this issue with steps to reproduce.",
|
|
257
|
-
"HINT_CACHE_NOT_FOUND": "Ensure the module has been loaded before attempting to reload or rebuild its cache. Check that the moduleID is correct.",
|
|
258
|
-
"HINT_CACHE_MANAGER_NOT_AVAILABLE": "The cache manager should be initialized automatically. If you see this error, it may indicate an internal initialization issue.",
|
|
259
|
-
"HINT_INVALID_METADATA_TARGET": "The target must be a function or object that was loaded through Slothlet. Pass the actual function/object reference, not a string or primitive value.",
|
|
260
|
-
"HINT_METADATA_NO_MODULE_ID": "Ensure the function/object was loaded through Slothlet's module system. Only Slothlet-managed functions have associated metadata.",
|
|
261
|
-
"HINT_METADATA_LIFECYCLE_BYPASS": "Never call tagSystemMetadata() directly. Trigger the 'impl:created' or 'impl:changed' lifecycle events instead, which will invoke tagSystemMetadata() through the proper channel.",
|
|
262
|
-
"HINT_INVALID_METADATA_KEY": "Metadata keys must be strings, string arrays, or objects with array values. Check the key format matches one of these types.",
|
|
263
|
-
"HINT_WARNING_METADATA_MISMATCH": "This warning indicates the function's execution location doesn't match its registered metadata path. This can occur during hot reload or if the function was tampered with. In most cases, this is expected during development with hot reload enabled.",
|
|
264
|
-
"HINT_WARNING_INIT_COMPONENT_SKIPPED": "Component files that fail to import will be skipped. This is normal for optional components. Check the error message for details if the component should have loaded.",
|
|
265
|
-
"HINT_WARNING_MULTIPLE_ROOT_CONTRIBUTORS": "Multiple files export default functions at the root level. Each has been namespaced (e.g., api.filename()). Consider consolidating into one root export or moving files to subdirectories for clearer organization.",
|
|
266
|
-
"HINT_WARNING_HOT_RELOAD_PATH_COLLISION": "A collision occurred during hot reload at the specified path. The existing value is being kept. To force replacement, use collision mode 'replace' instead of 'warn'.",
|
|
267
|
-
"HINT_WARNING_HOT_RELOAD_MERGE_PRIMITIVES": "Cannot merge primitive values (strings, numbers, booleans). To replace the value, use collision mode 'replace'. To keep the existing value, continue using 'warn' mode.",
|
|
268
|
-
"HINT_WARNING_OWNERSHIP_CONFLICT": "The path is already owned by another module. To force overwrite, use forceOverwrite: true in api.add() options, or call api.slothlet.api.remove() first to clear the path.",
|
|
269
|
-
"HINT_V2_CONFIG_UNSUPPORTED": "This configuration option from v2 is not supported in v3. Update your configuration to use the v3 equivalent for better control and clarity.",
|
|
270
|
-
"HINT_V3_CONFIG_DEPRECATED": "This configuration option has been renamed for clarity. Update your code to use the new option name to ensure forward compatibility with v4.",
|
|
271
|
-
"HINT_MODULE_LOAD_FAILED": "Check the module file for errors. Ensure it has valid JavaScript syntax and exports.",
|
|
272
|
-
"HINT_MODULE_IMPORT_FAILED": "Ensure the module file exists and can be imported. Check for syntax errors or missing dependencies.",
|
|
273
|
-
"HINT_MODULE_NO_EXPORTS": "The module must export at least one function or object.",
|
|
274
|
-
"HINT_INVALID_DIRECTORY": "Ensure the directory path is correct and the directory exists and is accessible.",
|
|
275
|
-
"HINT_WARN_DIRECTORY_EMPTY": "Check that the directory path is correct. Empty directories are valid for add-api workflows where modules will be added dynamically.",
|
|
276
|
-
"HINT_INVALID_CONFIG_LAZY_NOT_READY": "In lazy mode, access properties to trigger materialization before calling functions.",
|
|
277
|
-
"HINT_INTERNAL_INVALID_STATE": "An internal state error occurred. This is likely a bug - please report it with details.",
|
|
278
|
-
"HINT_INTERNAL_HOOK_STATE_CORRUPT": "HookManager internal state is inconsistent. This should never happen through normal usage — please file a bug report including how you called hook.on() and hook.remove().",
|
|
279
|
-
"HINT_INVALID_CONFIG_LAZY_ASYNC_REQUIRED": "Lazy mode requires async operations. Use eager mode or implement proper async patterns.",
|
|
280
|
-
"HINT_RUNTIME_NO_ACTIVE_CONTEXT_SELF": "Cannot access 'self' outside of a slothlet API function context.",
|
|
281
|
-
"HINT_RUNTIME_NO_ACTIVE_CONTEXT_CONTEXT": "Cannot access 'context' outside of a slothlet API function. Context can only be modified within slothlet API calls.",
|
|
282
|
-
"HINT_LOOSE_SET_NOT_OWNED": "A module owning apiPath \"P\" may write only under \"P.*\". To register code at a different namespace, call api.slothlet.api.add() instead.",
|
|
283
|
-
"HINT_LOOSE_SET_RESERVED_KEY": "The segments __proto__, prototype, and constructor cannot be used as apiPath names because writing to them would mutate the JavaScript prototype chain. Choose a different name.",
|
|
284
|
-
"HINT_INVALID_CONFIG_NOT_LOADED": "The instance must be loaded before performing this operation. Call load() first.",
|
|
285
|
-
"HINT_INVALID_CONFIG_RELOAD_NOT_IMPL": "Reload functionality is not yet implemented. This will be added in a future iteration.",
|
|
286
|
-
"HINT_WARNING_RESERVED_PROPERTY_CONFLICT": "The 'slothlet' property name is reserved for built-in API methods. Rename your API module or property to avoid conflicts with slothlet.shutdown(), slothlet.api.*, etc.",
|
|
287
|
-
"HINT_DEPRECATED_CONFIG_OPTION": "This configuration option is deprecated and will be removed in a future version. Update your configuration to use the recommended replacement.",
|
|
288
|
-
"HINT_ERROR_RUNTIME_IMPORT_FAILED": "The runtime module could not be loaded. This may occur if @cldmv/slothlet/runtime export is unavailable or there's a circular dependency. Some features requiring runtime access may be limited.",
|
|
289
|
-
"INVALID_HOOK_TYPE": "Invalid hook type \"{type}\". Must be one of: {validTypes}.",
|
|
290
295
|
"INVALID_HOOK_HANDLER": "Hook handler must be a function. Received type: {receivedType}.",
|
|
291
|
-
"DUPLICATE_HOOK_ID": "A hook with ID \"{id}\" already exists. Use a unique ID or omit the id option to auto-generate one.",
|
|
292
|
-
"INVALID_HOOK_SUBSET": "Invalid hook subset \"{subset}\". Must be \"before\", \"primary\", or \"after\". Valid subsets: {validSubsets}.",
|
|
293
|
-
"INVALID_TYPE_PATTERN": "Invalid type pattern \"{typePattern}\". {expected}",
|
|
294
|
-
"HINT_INVALID_HOOK_TYPE": "Use one of the valid hook types: before, after, always, or error.",
|
|
295
296
|
"HINT_INVALID_HOOK_HANDLER": "Provide a function as the hook handler, not a string or other type.",
|
|
297
|
+
"DUPLICATE_HOOK_ID": "A hook with ID \"{id}\" already exists. Use a unique ID or omit the id option to auto-generate one.",
|
|
296
298
|
"HINT_DUPLICATE_HOOK_ID": "Either use a different id value or remove the id option to let Slothlet auto-generate a unique ID.",
|
|
299
|
+
"INVALID_HOOK_SUBSET": "Invalid hook subset \"{subset}\". Must be \"before\", \"primary\", or \"after\". Valid subsets: {validSubsets}.",
|
|
297
300
|
"HINT_INVALID_HOOK_SUBSET": "Subsets control execution order. Use 'before' for pre-processing, 'primary' (default) for main hooks, or 'after' for post-processing.",
|
|
298
|
-
"
|
|
301
|
+
"INVALID_TYPE_PATTERN": "Invalid type pattern \"{typePattern}\". {expected}",
|
|
302
|
+
"HINT_INVALID_TYPE_PATTERN": "Hook patterns use the form 'pattern:type', such as 'math.*:before' or '**:error'. The legacy 'type:pattern' form still works but is deprecated.",
|
|
299
303
|
"HOOK_BEFORE_RETURNED_PROMISE": "Before hook '{id}' for path '{path}' returned a Promise. Before hooks must be synchronous.",
|
|
300
304
|
"HINT_HOOK_BEFORE_RETURNED_PROMISE": "Before hooks execute synchronously before the API call. Remove async/await or Promise usage from this hook, or change it to an 'after' hook if async processing is needed.",
|
|
301
305
|
"HOOK_BRACE_EXPANSION_MAX_DEPTH": "Brace expansion in hook pattern exceeds the maximum nesting depth of {maxDepth}.",
|
|
@@ -383,11 +387,11 @@
|
|
|
383
387
|
"INVALID_CONFIG_VERSION_DISPATCHER": "config.versionDispatcher must be a string (metadata key) or a function, received {received}",
|
|
384
388
|
"INVALID_CONFIG_VERSION_TAG": "versionConfig.version must be a non-empty string, received {received}",
|
|
385
389
|
"VERSION_NOT_FOUND": "Version '{version}' is not registered at path '{apiPath}'",
|
|
390
|
+
"HINT_VERSION_NOT_FOUND": "Call api.slothlet.versioning.list('{apiPath}') to see which version tags are currently registered at that path.",
|
|
386
391
|
"VERSION_NO_DEFAULT": "No default version configured for path '{apiPath}' and no version could be resolved from caller metadata",
|
|
387
392
|
"VERSION_DISPATCH_NOT_CALLABLE": "The versioned dispatcher at '{apiPath}' is a namespace, not a callable function",
|
|
388
393
|
"VERSION_REGISTER_DUPLICATE": "Version '{version}' is already registered at path '{apiPath}'. Use collisionMode 'replace' to overwrite",
|
|
389
394
|
"HINT_VERSION_REGISTER_DUPLICATE": "Call api.slothlet.versioning.unregister('{apiPath}', '{version}') first, or register with a different version tag.",
|
|
390
|
-
"HINT_VERSION_NOT_FOUND": "Call api.slothlet.versioning.list('{apiPath}') to see which version tags are currently registered at that path.",
|
|
391
395
|
"VERSION_DISCRIMINATOR_INVALID_RETURN": "versionDispatcher function returned '{returned}' which is not a registered version tag for path '{apiPath}'",
|
|
392
396
|
"DEBUG_VERSION_RESOLVED": "Version resolved: {version} for path {apiPath} (caller: {callerModule})",
|
|
393
397
|
"DEBUG_VERSION_DEFAULT_USED": "No discriminator match for path {apiPath}; using default version {version}",
|
|
@@ -417,7 +421,27 @@
|
|
|
417
421
|
"HINT_MODULE_MANIFEST_NOT_FOUND": "Plugin modules must ship a 'slothlet.module.json' at the package root (or the file/key specified via the `manifest` override). Check that the file exists in the package and that the override locator is correct.",
|
|
418
422
|
"MODULE_MANIFEST_INVALID": "Module manifest is invalid for package '{packageName}' at '{manifestPath}': {reason}.",
|
|
419
423
|
"HINT_MODULE_MANIFEST_INVALID": "Open the manifest and ensure it is valid JSON and matches the slothlet module schema (see schemas/slothlet.module.schema.json). Required fields: schemaVersion, mountPath, apiDir.",
|
|
420
|
-
"
|
|
424
|
+
"MODULE_MANIFEST_REASON_NOT_OBJECT": "manifest must be a JSON object",
|
|
425
|
+
"MODULE_MANIFEST_REASON_MISSING_FIELD": "missing required field '{field}'",
|
|
426
|
+
"MODULE_MANIFEST_REASON_FIELD_TYPE": "field '{field}' must be {expected}",
|
|
427
|
+
"EXPECTED_NON_EMPTY_STRING": "a non-empty string",
|
|
428
|
+
"EXPECTED_STRING": "a string",
|
|
429
|
+
"EXPECTED_FINITE_NUMBER": "a finite number",
|
|
430
|
+
"EXPECTED_PLAIN_OBJECT": "a plain object",
|
|
431
|
+
"EXPECTED_ARRAY_OF_RULE_OBJECTS": "an array of rule objects",
|
|
432
|
+
"MODULE_MANIFEST_REASON_MOUNTPATH_SHAPE": "field 'mountPath' must be a non-empty string or non-empty array of non-empty strings",
|
|
433
|
+
"MODULE_MANIFEST_REASON_MOUNTPATH_ENTRIES": "field 'mountPath' array entries must all be non-empty strings",
|
|
434
|
+
"MODULE_MANIFEST_REASON_DEPENDENCY_TYPE": "dependency '{dependency}' must be a string version range",
|
|
435
|
+
"MODULE_MANIFEST_REASON_PERMISSION_RULE": "permissions[{index}] must be a rule object",
|
|
436
|
+
"MODULE_MANIFEST_REASON_PERMISSION_CALLER": "permissions[{index}].caller must be a non-empty string",
|
|
437
|
+
"MODULE_MANIFEST_REASON_PERMISSION_TARGET": "permissions[{index}].target must be a non-empty string",
|
|
438
|
+
"MODULE_MANIFEST_REASON_PERMISSION_EFFECT": "permissions[{index}].effect must be \"allow\" or \"deny\"",
|
|
439
|
+
"MODULE_MANIFEST_REASON_JSON_PARSE": "JSON parse error: {error}",
|
|
440
|
+
"GENERATE_MANIFEST_DIR_INVALID": "generateManifest: dir must be a non-empty string, received {received}",
|
|
441
|
+
"GENERATE_MANIFEST_DIR_UNREADABLE": "generateManifest: cannot read directory \"{dir}\": {reason}",
|
|
442
|
+
"GENERATE_MANIFEST_NOT_DIRECTORY": "generateManifest: \"{dir}\" is not a directory",
|
|
443
|
+
"GENERATE_BROWSER_ASSETS_SLOTHLET_BASE_INVALID": "generateBrowserAssets: options.slothletBase must be a string (where @cldmv/slothlet is served in the browser), received {received}",
|
|
444
|
+
"MODULE_MANIFEST_UNKNOWN_FIELD": "Module manifest for package '{packageName}' at '{manifestPath}' contains unrecognized top-level field '{field}'. Unknown fields are rejected; use the dedicated 'metadata' block for developer-defined extras.",
|
|
421
445
|
"HINT_MODULE_MANIFEST_UNKNOWN_FIELD": "If '{field}' is a typo, fix it. If it is intentional developer metadata, move it inside the 'metadata' object.",
|
|
422
446
|
"MODULE_MANIFEST_NAME_MISMATCH": "Module manifest for package '{packageName}' declares name '{manifestName}' which does not match package.json name '{packageName}'.",
|
|
423
447
|
"HINT_MODULE_MANIFEST_NAME_MISMATCH": "The 'name' field in slothlet.module.json is optional but must match package.json when present. Either remove the manifest 'name' field or align it with package.json.",
|
|
@@ -434,7 +458,11 @@
|
|
|
434
458
|
"MODULE_DUPLICATE_NAME_VERSION_MISMATCH": "Module package '{packageName}' version '{version}' was found at multiple distinct real paths: {paths}.",
|
|
435
459
|
"HINT_MODULE_DUPLICATE_NAME_VERSION_MISMATCH": "This is almost certainly a misconfiguration — the same package at the same version installed in two unrelated locations. Investigate which install is intended and remove the other.",
|
|
436
460
|
"MODULE_MOUNT_COLLISION": "Module package '{packageName}' cannot mount at '{mountPath}': path is already occupied by module '{existingModuleID}' and collisionMode is '{collisionMode}'.",
|
|
437
|
-
"HINT_MODULE_MOUNT_COLLISION": "Either change the manifest's mountPath, pass `collisionMode: \"merge\"` to `addModule()` / `addModules()` to allow coexistence, or call `removeModule()` on the existing module first."
|
|
461
|
+
"HINT_MODULE_MOUNT_COLLISION": "Either change the manifest's mountPath, pass `collisionMode: \"merge\"` to `addModule()` / `addModules()` to allow coexistence, or call `removeModule()` on the existing module first.",
|
|
462
|
+
"HOOK_TYPEPATTERN_PREFIX_DEPRECATED": "Hook registration form '{given}' is deprecated and will be removed in v4. Use the path-first form '{suggested}' instead (e.g. 'math.*:before').",
|
|
463
|
+
"HINT_HOOK_TYPEPATTERN_PREFIX_DEPRECATED": "Move the hook type to the end as a suffix: rewrite a type-first selector like 'before:math.add' as the path-first form 'math.add:before'.",
|
|
464
|
+
"HOOK_UNPINNED_IGNORED": "lockCaller:false was ignored for hook '{pattern}'; hooks are pinned to their registering module. Set hook.pin:false (init) or call api.slothlet.hook.pin.disable() to permit unpinned hooks.",
|
|
465
|
+
"HINT_HOOK_UNPINNED_IGNORED": "Module-registered hooks are always pinned to their owner for security. To allow unpinned hooks, set hook.pin:false in the slothlet config, or call api.slothlet.hook.pin.disable() at runtime."
|
|
438
466
|
},
|
|
439
467
|
"metadata": {
|
|
440
468
|
"code": "en-us",
|
|
@@ -14,4 +14,4 @@
|
|
|
14
14
|
limitations under the License.
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
|
-
import defaultTranslations from"./languages/en-us.json"with{type:"json"};import{isNode,fs,path,url,loadJson}from"@cldmv/slothlet/helpers/platform";const translations_dirname=isNode?path.dirname(url.fileURLToPath(import.meta.url)):null;let currentTranslations=defaultTranslations.translations;let currentLanguage="en-us";const i18n_languageFallbacks={en:"en-us",es:"es-mx",de:"de-de",fr:"fr-fr",hi:"hi-in",ja:"ja-jp",ko:"ko-kr",pt:"pt-br",ru:"ru-ru",zh:"zh-cn"};const KNOWN_LOCALES=new Set(["de-de","en-gb","en-us","es-es","es-mx","fr-fr","hi-in","ja-jp","ko-kr","pt-br","ru-ru","zh-cn"]);function
|
|
17
|
+
import defaultTranslations from"./languages/en-us.json"with{type:"json"};import{isNode,fs,path,url,loadJson}from"@cldmv/slothlet/helpers/platform";const translations_dirname=isNode?path.dirname(url.fileURLToPath(import.meta.url)):null;let currentTranslations=defaultTranslations.translations;let currentLanguage="en-us";const i18n_languageFallbacks={en:"en-us",es:"es-mx",de:"de-de",fr:"fr-fr",hi:"hi-in",ja:"ja-jp",ko:"ko-kr",pt:"pt-br",ru:"ru-ru",zh:"zh-cn"};const KNOWN_LOCALES=new Set(["de-de","en-gb","en-us","es-es","es-mx","fr-fr","hi-in","ja-jp","ko-kr","pt-br","ru-ru","zh-cn"]);const BASE_LOCALES=new Set(["en-us"]);function i18n_resolvePackPath(lang){try{const packPath=url.fileURLToPath(import.meta.resolve(`@cldmv/slothlet-i18n/language/${lang}.json`));return fs.existsSync(packPath)?packPath:null}catch{return null}}function i18n_localeRefs(lang){if(!isNode){const specs=[`@cldmv/slothlet-i18n/language/${lang}.json`,`@cldmv/slothlet/i18n/language/${lang}.json`];if(typeof import.meta.resolve!=="function")return specs;return specs.filter(s=>{try{return Boolean(import.meta.resolve(s))}catch{return false}})}const refs=[];const packPath=i18n_resolvePackPath(lang);if(packPath)refs.push(packPath);const internal=path.join(translations_dirname,"languages",`${lang}.json`);if(fs.existsSync(internal))refs.push(internal);return refs}function i18n_languageFileExists(lang){if(!isNode)return KNOWN_LOCALES.has(lang);const isBaseLocale=BASE_LOCALES.has(lang);if(isBaseLocale){return fs.existsSync(path.join(translations_dirname,"languages",`${lang}.json`))}return i18n_localeRefs(lang).length>0}function i18n_normalizeEnvLanguage(envLang){const normalized=String(envLang).split(".")[0].split("@")[0].replace(/_/g,"-").toLowerCase();if(normalized==="c"||normalized==="posix")return"en-us";const fullLocaleExists=i18n_languageFileExists(normalized);if(fullLocaleExists)return normalized;const base=normalized.split("-")[0];if(!base)return"en-us";if(i18n_languageFileExists(base))return base;return i18n_languageFallbacks[base]||base}function i18n_detectLanguage(){if(!isNode){const navLang=typeof navigator!=="undefined"?navigator.languages?.[0]||navigator.language:null;return navLang?i18n_normalizeEnvLanguage(navLang):"en-us"}const envLang=process.env.LANG||process.env.LANGUAGE||process.env.LC_ALL;if(envLang){return i18n_normalizeEnvLanguage(envLang)}return"en-us"}function i18n_loadLanguageSync(lang){if(!isNode)return null;for(const ref of i18n_localeRefs(lang)){const langData=loadJson(ref);if(langData?.translations)return langData.translations}return null}function setLanguage(lang){currentTranslations={...defaultTranslations.translations};if(lang==="en-us"){currentLanguage="en-us";return}if(!isNode){void setLanguageAsync(lang);return}const langTranslations=i18n_loadLanguageSync(lang);if(langTranslations){currentTranslations={...currentTranslations,...langTranslations};currentLanguage=lang}else{console.warn(`Failed to load language '${lang}', falling back to English.`);currentLanguage="en-us"}}async function setLanguageAsync(lang){currentTranslations={...defaultTranslations.translations};if(lang==="en-us"){currentLanguage="en-us";return}currentLanguage="en-us";let langData=null;for(const ref of i18n_localeRefs(lang)){const data=await loadJson(ref);if(data?.translations){langData=data;break}}if(langData?.translations){currentTranslations={...currentTranslations,...langData.translations};currentLanguage=lang}else{console.warn(`Failed to load language '${lang}', falling back to English.`);currentLanguage="en-us"}}function getLanguage(){return currentLanguage}function translate(errorCode,params={}){let template=currentTranslations[errorCode];if(!template&&errorCode.startsWith("INVALID_CONFIG_")){template=currentTranslations.INVALID_CONFIG_generic}let message=template||`Error: ${errorCode}`;for(const[key,value]of Object.entries(params)){message=message.replace(new RegExp(`\\{${key}\\}`,"g"),value!==void 0?String(value):"")}message=message.replace(/\{\w+\}/g,"").replace(/\s+/g," ").trim();return message}function initI18n(options={}){try{const lang=options.language||i18n_detectLanguage();if(!isNode){currentLanguage="en-us";if(lang&&lang!=="en-us")void setLanguageAsync(lang);return}setLanguage(lang)}catch(___error){console.warn("i18n initialization failed, using English:",___error.message);currentLanguage="en-us";currentTranslations=defaultTranslations.translations}}initI18n();const t=translate;export{getLanguage,initI18n,setLanguage,setLanguageAsync,t,translate};
|
package/dist/lib/modes/eager.mjs
CHANGED
|
@@ -14,4 +14,4 @@
|
|
|
14
14
|
limitations under the License.
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
|
-
import{ComponentBase}from"@cldmv/slothlet/factories/component-base";class EagerMode extends ComponentBase{static slothletProperty="eager";constructor(slothlet){super(slothlet)}async buildAPI({dir,apiPathPrefix="",collisionContext="initial",moduleID,apiDepth=Infinity,cacheBust=null,fileFilter=null}){const api={};const{modesProcessor}=this.slothlet.builders;const{loader}=this.slothlet.processors;const structure=await loader.scanDirectory(dir,{maxDepth:apiDepth,fileFilter});const rootDirectory={name:".",path:dir,children:{files:structure.files,directories:structure.directories}};const rootDefaultFunction=await modesProcessor.processFiles(api,structure.files,rootDirectory,0,"eager",true,true,false,apiPathPrefix,collisionContext,moduleID,dir,cacheBust);return modesProcessor.applyRootContributor(api,rootDefaultFunction,"eager")}}export{EagerMode};
|
|
17
|
+
import{ComponentBase}from"@cldmv/slothlet/factories/component-base";class EagerMode extends ComponentBase{static slothletProperty="eager";constructor(slothlet){super(slothlet)}async buildAPI({dir,apiPathPrefix="",collisionContext="initial",moduleID,apiDepth=Infinity,cacheBust=null,fileFilter=null,hidden=null,scanHiddenFolders=false,preloadedStructure=null}){const api={};const{modesProcessor}=this.slothlet.builders;const{loader}=this.slothlet.processors;if(preloadedStructure!=null&&(!Array.isArray(preloadedStructure.files)||!Array.isArray(preloadedStructure.directories))){const filesType=Array.isArray(preloadedStructure.files)?"array":typeof preloadedStructure.files;const directoriesType=Array.isArray(preloadedStructure.directories)?"array":typeof preloadedStructure.directories;const received=`{ files: ${filesType}, directories: ${directoriesType} }`;throw new this.SlothletError("INVALID_CONFIG_PRELOADED_STRUCTURE",{received},null,{validationError:true})}const structure=preloadedStructure??await loader.scanDirectory(dir,{maxDepth:apiDepth,fileFilter,hidden,scanHiddenFolders});const rootDirectory={name:".",path:dir,children:{files:structure.files,directories:structure.directories}};const rootDefaultFunction=await modesProcessor.processFiles(api,structure.files,rootDirectory,0,"eager",true,true,false,apiPathPrefix,collisionContext,moduleID,dir,cacheBust);return modesProcessor.applyRootContributor(api,rootDefaultFunction,"eager")}}export{EagerMode};
|
package/dist/lib/modes/lazy.mjs
CHANGED
|
@@ -14,4 +14,4 @@
|
|
|
14
14
|
limitations under the License.
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
|
-
import{ComponentBase}from"@cldmv/slothlet/factories/component-base";class LazyMode extends ComponentBase{static slothletProperty="lazy";constructor(slothlet){super(slothlet)}createNamedMaterializeFunc(apiPath,handler){const safePath=String(apiPath||"api").replace(/\./g,"__").replace(/[^A-Za-z0-9_$]/g,"_");const normalized=/^[A-Za-z_$]/.test(safePath[0])?safePath:`_${safePath}`;const funcName=`${normalized}__lazy_materializeFunc`;return{[funcName]:async function(...args){return handler(...args)}}[funcName]}async buildAPI({dir,apiPathPrefix="",collisionContext="initial",collisionMode=null,moduleID,apiDepth=Infinity,cacheBust=null,fileFilter=null}){this.slothlet.debug("modes",{key:"DEBUG_MODE_BUILD_LAZY_API_CALLED",apiPathPrefix,collisionMode,collisionContext});const api={};const{modesProcessor}=this.slothlet.builders;const{loader}=this.slothlet.processors;const structure=await loader.scanDirectory(dir,{maxDepth:apiDepth,fileFilter});const rootDirectory={name:".",path:dir,children:{files:structure.files,directories:structure.directories}};const rootDefaultFunction=await modesProcessor.processFiles(api,structure.files,rootDirectory,0,"lazy",true,false,false,apiPathPrefix,collisionContext,moduleID,dir,cacheBust,collisionMode);return modesProcessor.applyRootContributor(api,rootDefaultFunction,"lazy")}}export{LazyMode};
|
|
17
|
+
import{ComponentBase}from"@cldmv/slothlet/factories/component-base";class LazyMode extends ComponentBase{static slothletProperty="lazy";constructor(slothlet){super(slothlet)}createNamedMaterializeFunc(apiPath,handler){const safePath=String(apiPath||"api").replace(/\./g,"__").replace(/[^A-Za-z0-9_$]/g,"_");const normalized=/^[A-Za-z_$]/.test(safePath[0])?safePath:`_${safePath}`;const funcName=`${normalized}__lazy_materializeFunc`;return{[funcName]:async function(...args){return handler(...args)}}[funcName]}async buildAPI({dir,apiPathPrefix="",collisionContext="initial",collisionMode=null,moduleID,apiDepth=Infinity,cacheBust=null,fileFilter=null,hidden=null,scanHiddenFolders=false,preloadedStructure=null}){this.slothlet.debug("modes",{key:"DEBUG_MODE_BUILD_LAZY_API_CALLED",apiPathPrefix,collisionMode,collisionContext});const api={};const{modesProcessor}=this.slothlet.builders;const{loader}=this.slothlet.processors;if(preloadedStructure!=null&&(!Array.isArray(preloadedStructure.files)||!Array.isArray(preloadedStructure.directories))){const filesType=Array.isArray(preloadedStructure.files)?"array":typeof preloadedStructure.files;const directoriesType=Array.isArray(preloadedStructure.directories)?"array":typeof preloadedStructure.directories;const received=`{ files: ${filesType}, directories: ${directoriesType} }`;throw new this.SlothletError("INVALID_CONFIG_PRELOADED_STRUCTURE",{received},null,{validationError:true})}const structure=preloadedStructure??await loader.scanDirectory(dir,{maxDepth:apiDepth,fileFilter,hidden,scanHiddenFolders});const rootDirectory={name:".",path:dir,children:{files:structure.files,directories:structure.directories}};const rootDefaultFunction=await modesProcessor.processFiles(api,structure.files,rootDirectory,0,"lazy",true,false,false,apiPathPrefix,collisionContext,moduleID,dir,cacheBust,collisionMode);return modesProcessor.applyRootContributor(api,rootDefaultFunction,"lazy")}}export{LazyMode};
|
|
@@ -14,4 +14,4 @@
|
|
|
14
14
|
limitations under the License.
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
|
-
import{ComponentBase}from"@cldmv/slothlet/factories/component-base";import{fsp,path,url,createRequire}from"@cldmv/slothlet/helpers/platform";class Loader extends ComponentBase{static slothletProperty="loader";constructor(slothlet){super(slothlet)}async loadModule(filePath,instanceID,moduleID,cacheBust=null){try{if(this.slothlet.envTarget==="browser"){return this.#loadModuleBrowser(filePath)}if(filePath.endsWith(".cjs")){return this.#loadCJSIsolated(filePath)}const isTypeScript=filePath.endsWith(".ts")||filePath.endsWith(".mts");const typescriptConfig=this.slothlet.config?.typescript;let moduleUrl;if(isTypeScript&&typescriptConfig?.enabled){const mode=typescriptConfig.mode;if(mode==="strict"){if(!typescriptConfig.types?.output){throw new this.SlothletError("TS_STRICT_REQUIRES_OUTPUT",{},null,{validationError:true})}if(!typescriptConfig.types?.interfaceName){throw new this.SlothletError("TS_STRICT_REQUIRES_INTERFACE_NAME",{},null,{validationError:true})}if(!this.slothlet._typesGenerated){const{fork}=await import("child_process");const path2=await import("path");const{fileURLToPath}=await import("url");const __dirname=path2.dirname(fileURLToPath(import.meta.url));const scriptPath=path2.resolve(__dirname,"../../../tools/build/generate-types-worker.mjs");const childConfig=JSON.stringify({dir:this.slothlet.config.root||this.slothlet.config.dir,mode:"eager",typescript:{enabled:true,mode:"fast"},types:typescriptConfig.types});await new Promise((resolve,reject)=>{const child=fork(scriptPath,[],{stdio:["pipe","pipe","pipe","ipc"],env:{...process.env,SLOTHLET_CONFIG:childConfig}});let errorOutput="";child.stderr?.on("data",data=>{errorOutput+=data.toString()});child.on("message",msg=>{if(msg.type==="success"){this.slothlet._typesGenerated=true;resolve()}else if(msg.type==="error"){reject(new this.SlothletError("TS_TYPE_GENERATION_FAILED",{},{message:msg.error}))}});child.on("error",error=>{reject(new this.SlothletError("TS_TYPE_GENERATION_FORK_FAILED",{},error))});child.on("exit",code=>{if(code!==0&&!this.slothlet._typesGenerated){reject(new this.SlothletError("TS_TYPE_GENERATION_PROCESS_EXITED",{code,output:errorOutput},null,{validationError:true}))}})})}const{transformTypeScriptStrict,writeTransformedToCache,formatDiagnostics}=await import("@cldmv/slothlet/processors/typescript");const strictTransform=async tsPath=>{const result=await transformTypeScriptStrict(tsPath,{target:typescriptConfig.target,module:typescriptConfig.module,strict:typescriptConfig.strict,typeDefinitionPath:typescriptConfig.types.output,compilerOptions:typescriptConfig.compilerOptions});if(result.diagnostics&&result.diagnostics.length>0){const ts=await import("typescript");const errors=formatDiagnostics(result.diagnostics,ts.default);const error=new this.SlothletError("TS_TYPE_CHECK_ERRORS",{filePath:tsPath,errors:errors.join("\n")},null,{validationError:true});error.diagnostics=result.diagnostics;throw error}return result.code};const entryCode=await strictTransform(filePath);moduleUrl=await this.#buildTypescriptModuleUrl(writeTransformedToCache,filePath,entryCode,instanceID,moduleID,cacheBust,strictTransform)}else{const{transformTypeScript,writeTransformedToCache}=await import("@cldmv/slothlet/processors/typescript");const transformOptions={target:typescriptConfig.target,sourcemap:typescriptConfig.sourcemap};const transformedCode=await transformTypeScript(filePath,transformOptions);const transform=tsPath=>transformTypeScript(tsPath,transformOptions);moduleUrl=await this.#buildTypescriptModuleUrl(writeTransformedToCache,filePath,transformedCode,instanceID,moduleID,cacheBust,transform)}}else{const fileUrl=url.pathToFileURL(filePath).href;moduleUrl=`${fileUrl}?slothlet_instance=${instanceID}`;if(moduleID){moduleUrl+=`&module=${moduleID}`}if(cacheBust){moduleUrl+=`&_reload=${cacheBust}`}}const module=await import(moduleUrl);return module}catch(error){throw new this.SlothletError("MODULE_IMPORT_FAILED",{modulePath:filePath},error)}}#loadCJSIsolated(filePath){const requireFn=createRequire(filePath);const resolved=requireFn.resolve(filePath);delete requireFn.cache[resolved];const exports=requireFn(resolved);delete requireFn.cache[resolved];const namespace={default:exports};if(exports!==null&&typeof exports==="object"){for(const key of Object.keys(exports)){if(key!=="default"){namespace[key]=exports[key]}}}return namespace}async#buildTypescriptModuleUrl(writeTransformedToCache,filePath,code,instanceID,moduleID,cacheBust,transform){const{url:url2,cacheDir}=await writeTransformedToCache(filePath,code,instanceID,transform);(this.slothlet._typescriptCacheDirs??=new Set).add(cacheDir);let moduleUrl=`${url2}?slothlet_instance=${instanceID}`;if(moduleID){moduleUrl+=`&module=${moduleID}`}if(cacheBust){moduleUrl+=`&_reload=${cacheBust}`}return moduleUrl}async scanDirectory(dir,options={}){if(this.slothlet.envTarget==="browser"){return this.#scanDirectoryBrowser(dir,options)}const typescriptConfig=this.slothlet.config?.typescript;const defaultExtensions=[".mjs",".cjs",".js"];const typescriptExtensions=typescriptConfig?.enabled?[".ts",".mts"]:[];const allExtensions=[...defaultExtensions,...typescriptExtensions];const{recursive=true,extensions=allExtensions,isRootScan=true,currentDepth=0,maxDepth=Infinity,fileFilter=null}=options;try{await fsp.stat(dir)}catch(error){throw new this.SlothletError("INVALID_DIRECTORY",{dir},error)}const structure={files:[],directories:[]};const entries=await fsp.readdir(dir,{withFileTypes:true});for(const entry of entries){const fullPath=path.join(dir,entry.name);if(entry.isDirectory()){if(fileFilter){continue}if(recursive&¤tDepth<maxDepth){const subStructure=await this.scanDirectory(fullPath,{...options,isRootScan:false,currentDepth:currentDepth+1});structure.directories.push({path:fullPath,name:entry.name,children:subStructure})}}else if(entry.isFile()){const ext=path.extname(entry.name);if(extensions.includes(ext)){if(entry.name.startsWith("__")){continue}if(fileFilter&&!fileFilter(entry.name)){continue}const nameWithoutExt=path.basename(entry.name,ext);structure.files.push({path:fullPath,name:nameWithoutExt,fullName:entry.name,moduleID:this.slothlet.helpers.sanitize.getModuleId(fullPath,dir)})}}}if(isRootScan&&structure.files.length===0&&structure.directories.length===0){new this.SlothletWarning("WARN_DIRECTORY_EMPTY",{dir,resolvedPath:path.resolve(dir)})}return structure}#scanDirectoryBrowser(dir,options={}){const manifest=this.slothlet.config?.manifest;if(!manifest){throw new this.SlothletError("INVALID_CONFIG_BROWSER_REQUIRES_MANIFEST",{},null,{validationError:true})}const configBase=(this.slothlet.config?.dir||"").replace(/\/$/,"");let relativePath=(dir||"").replace(/\/$/,"");if(configBase&&relativePath.startsWith(configBase)){relativePath=relativePath.slice(configBase.length).replace(/^\/|\/$/g,"")}const isRoot=!relativePath||relativePath==="/"||relativePath===".";const node=isRoot?manifest:this.#findManifestNode(manifest,relativePath);if(!node){throw new this.SlothletError("INVALID_DIRECTORY",{dir},null)}return this.#manifestNodeToStructure(node,dir,options)}#findManifestNode(node,targetPath){const normalised=targetPath.replace(/\\/g,"/").replace(/^\/|\/$/g,"");for(const dir of node.directories||[]){const dirPath=(dir.path||dir.name||"").replace(/\\/g,"/").replace(/^\/|\/$/g,"");if(dirPath===normalised)return dir.children||dir;const found=this.#findManifestNode(dir.children||dir,normalised);if(found)return found}return null}#manifestNodeToStructure(node,rootPath,options={}){const{fileFilter=null}=options;const ALLOWED_EXTS=[".mjs",".cjs",".js"];const structure={files:[],directories:[]};for(const file of node.files||[]){const filePath=file.path||file.relativePath||"";const fullName=file.fullName||filePath.split("/").pop();const lastDot=fullName.lastIndexOf(".");const ext=lastDot>=0?fullName.slice(lastDot):"";if(!ALLOWED_EXTS.includes(ext))continue;if(fullName.startsWith("__"))continue;if(fileFilter&&!fileFilter(fullName))continue;const name=file.name||(lastDot>=0?fullName.slice(0,lastDot):fullName);structure.files.push({path:filePath,name,fullName,moduleID:this.slothlet.helpers.sanitize.getModuleId(filePath,rootPath)})}if(!fileFilter){for(const dir of node.directories||[]){const dirPath=dir.path||dir.name||"";structure.directories.push({path:dirPath,name:dir.name||dirPath.split("/").pop(),children:this.#manifestNodeToStructure(dir.children||dir,dirPath,options)})}}return structure}async#loadModuleBrowser(filePath){const resolveModuleSpecifier=this.slothlet.config?.resolveModuleSpecifier??(({path:p})=>{const base=this.slothlet.config?.base??this.slothlet.config?.dir??"";const leadingSlash=base.startsWith("/")?"":"/";const baseUrl=/^[a-zA-Z][\w+\-.]*:\/\//.test(base)?base.endsWith("/")?base:base+"/":"file://"+leadingSlash+base.replace(/\/?$/,"/");return new URL(p,baseUrl).href});const fullName=filePath.split("/").pop();const lastDot=fullName.lastIndexOf(".");const name=lastDot>=0?fullName.slice(0,lastDot):fullName;const specifier=resolveModuleSpecifier({path:filePath,name,fullName});const module=await import(specifier);return module}extractExports(module){const exports={};if(module.default!==void 0){exports.default=module.default}for(const key of Object.keys(module)){if(key!=="default"&&key!=="module.exports"&&typeof key==="string"){exports[key]=module[key]}}if(exports.default&&typeof exports.default==="object"&&exports.default!==null&&"default"in exports.default){const rootNamedKeys=Object.keys(exports).filter(k=>k!=="default"&&k!=="module.exports");const defaultKeys=Object.keys(exports.default).filter(k=>k!=="default");const isCJSPattern=rootNamedKeys.every(k=>k in exports.default);if(isCJSPattern&&defaultKeys.length>0){exports.default=exports.default.default}}return exports}}export{Loader};
|
|
17
|
+
import{ComponentBase}from"@cldmv/slothlet/factories/component-base";import{fsp,path,url,createRequire}from"@cldmv/slothlet/helpers/platform";import{compilePattern}from"@cldmv/slothlet/helpers/pattern-matcher";function compileHidden(globs){if(!globs)return null;const list=Array.isArray(globs)?globs:[globs];const rules=[];for(const g of list){if(typeof g!=="string"||g.length===0)continue;const negated=g.startsWith("!");const body=(negated?g.slice(1):g).replace(/\//g,".");if(body.length===0)continue;rules.push({negated,match:compilePattern(body)})}if(!rules.length)return null;return relDotted=>{let hidden=false;for(const rule of rules){if(rule.match(relDotted))hidden=!rule.negated}return hidden}}class Loader extends ComponentBase{static slothletProperty="loader";constructor(slothlet){super(slothlet)}async loadModule(filePath,instanceID,moduleID,cacheBust=null){try{if(this.slothlet.envTarget==="browser"){return this.#loadModuleBrowser(filePath)}if(filePath.endsWith(".cjs")){return this.#loadCJSIsolated(filePath)}const isTypeScript=filePath.endsWith(".ts")||filePath.endsWith(".mts");const typescriptConfig=this.slothlet.config?.typescript;let moduleUrl;if(isTypeScript&&typescriptConfig?.enabled){const mode=typescriptConfig.mode;if(mode==="strict"){if(!typescriptConfig.types?.output){throw new this.SlothletError("TS_STRICT_REQUIRES_OUTPUT",{},null,{validationError:true})}if(!typescriptConfig.types?.interfaceName){throw new this.SlothletError("TS_STRICT_REQUIRES_INTERFACE_NAME",{},null,{validationError:true})}if(!this.slothlet._typesGenerated){const{fork}=await import("child_process");const path2=await import("path");const{fileURLToPath}=await import("url");const __dirname=path2.dirname(fileURLToPath(import.meta.url));const scriptPath=path2.resolve(__dirname,"../../../tools/build/generate-types-worker.mjs");const childConfig=JSON.stringify({dir:this.slothlet.config.root||this.slothlet.config.dir,mode:"eager",typescript:{enabled:true,mode:"fast"},types:typescriptConfig.types});await new Promise((resolve,reject)=>{const child=fork(scriptPath,[],{stdio:["pipe","pipe","pipe","ipc"],env:{...process.env,SLOTHLET_CONFIG:childConfig}});let errorOutput="";child.stderr?.on("data",data=>{errorOutput+=data.toString()});child.on("message",msg=>{if(msg.type==="success"){this.slothlet._typesGenerated=true;resolve()}else if(msg.type==="error"){reject(new this.SlothletError("TS_TYPE_GENERATION_FAILED",{},{message:msg.error}))}});child.on("error",error=>{reject(new this.SlothletError("TS_TYPE_GENERATION_FORK_FAILED",{},error))});child.on("exit",code=>{if(code!==0&&!this.slothlet._typesGenerated){reject(new this.SlothletError("TS_TYPE_GENERATION_PROCESS_EXITED",{code,output:errorOutput},null,{validationError:true}))}})})}const{transformTypeScriptStrict,writeTransformedToCache,formatDiagnostics}=await import("@cldmv/slothlet/processors/typescript");const strictTransform=async tsPath=>{const result=await transformTypeScriptStrict(tsPath,{target:typescriptConfig.target,module:typescriptConfig.module,strict:typescriptConfig.strict,typeDefinitionPath:typescriptConfig.types.output,compilerOptions:typescriptConfig.compilerOptions});if(result.diagnostics&&result.diagnostics.length>0){const ts=await import("typescript");const errors=formatDiagnostics(result.diagnostics,ts.default);const error=new this.SlothletError("TS_TYPE_CHECK_ERRORS",{filePath:tsPath,errors:errors.join("\n")},null,{validationError:true});error.diagnostics=result.diagnostics;throw error}return result.code};const entryCode=await strictTransform(filePath);moduleUrl=await this.#buildTypescriptModuleUrl(writeTransformedToCache,filePath,entryCode,instanceID,moduleID,cacheBust,strictTransform)}else{const{transformTypeScript,writeTransformedToCache}=await import("@cldmv/slothlet/processors/typescript");const transformOptions={target:typescriptConfig.target,sourcemap:typescriptConfig.sourcemap};const transformedCode=await transformTypeScript(filePath,transformOptions);const transform=tsPath=>transformTypeScript(tsPath,transformOptions);moduleUrl=await this.#buildTypescriptModuleUrl(writeTransformedToCache,filePath,transformedCode,instanceID,moduleID,cacheBust,transform)}}else{const fileUrl=url.pathToFileURL(filePath).href;moduleUrl=`${fileUrl}?slothlet_instance=${instanceID}`;if(moduleID){moduleUrl+=`&module=${moduleID}`}if(cacheBust){moduleUrl+=`&_reload=${cacheBust}`}}const module=await import(moduleUrl);return module}catch(error){throw new this.SlothletError("MODULE_IMPORT_FAILED",{modulePath:filePath},error)}}#loadCJSIsolated(filePath){const requireFn=createRequire(filePath);const resolved=requireFn.resolve(filePath);delete requireFn.cache[resolved];const exports=requireFn(resolved);delete requireFn.cache[resolved];const namespace={default:exports};if(exports!==null&&typeof exports==="object"){for(const key of Object.keys(exports)){if(key!=="default"){namespace[key]=exports[key]}}}return namespace}async#buildTypescriptModuleUrl(writeTransformedToCache,filePath,code,instanceID,moduleID,cacheBust,transform){const{url:url2,cacheDir}=await writeTransformedToCache(filePath,code,instanceID,transform);(this.slothlet._typescriptCacheDirs??=new Set).add(cacheDir);let moduleUrl=`${url2}?slothlet_instance=${instanceID}`;if(moduleID){moduleUrl+=`&module=${moduleID}`}if(cacheBust){moduleUrl+=`&_reload=${cacheBust}`}return moduleUrl}async scanDirectory(dir,options={}){if(this.slothlet.envTarget==="browser"){return this.#scanDirectoryBrowser(dir,options)}const typescriptConfig=this.slothlet.config?.typescript;const defaultExtensions=[".mjs",".cjs",".js"];const typescriptExtensions=typescriptConfig?.enabled?[".ts",".mts"]:[];const allExtensions=[...defaultExtensions,...typescriptExtensions];const{recursive=true,extensions=allExtensions,isRootScan=true,currentDepth=0,maxDepth=Infinity,fileFilter=null,hidden=null,scanHiddenFolders=false,rootDir=dir}=options;const hiddenMatcher=typeof hidden==="function"?hidden:compileHidden(hidden);const apiRel=p=>path.relative(rootDir,p).split(path.sep).join(".");const hasHiddenPrefix=name=>name.startsWith(".")||name.startsWith("__");try{await fsp.stat(dir)}catch(error){throw new this.SlothletError("INVALID_DIRECTORY",{dir},error)}const structure={files:[],directories:[]};const entries=await fsp.readdir(dir,{withFileTypes:true});for(const entry of entries){const fullPath=path.join(dir,entry.name);if(entry.isDirectory()){if(fileFilter){continue}if(!scanHiddenFolders&&hasHiddenPrefix(entry.name)){continue}if(hiddenMatcher&&hiddenMatcher(apiRel(fullPath))){continue}if(recursive&¤tDepth<maxDepth){const subStructure=await this.scanDirectory(fullPath,{...options,isRootScan:false,currentDepth:currentDepth+1,hidden:hiddenMatcher,scanHiddenFolders,rootDir});if(subStructure.files.length===0&&subStructure.directories.length===0){continue}structure.directories.push({path:fullPath,name:entry.name,children:subStructure})}}else if(entry.isFile()){const ext=path.extname(entry.name);if(extensions.includes(ext)){if(hasHiddenPrefix(entry.name)){continue}if(fileFilter&&!fileFilter(entry.name)){continue}const nameWithoutExt=path.basename(entry.name,ext);if(hiddenMatcher&&hiddenMatcher(apiRel(path.join(dir,nameWithoutExt)))){continue}structure.files.push({path:fullPath,name:nameWithoutExt,fullName:entry.name,moduleID:this.slothlet.helpers.sanitize.getModuleId(fullPath,dir)})}}}if(isRootScan&&structure.files.length===0&&structure.directories.length===0){new this.SlothletWarning("WARN_DIRECTORY_EMPTY",{dir,resolvedPath:path.resolve(dir)})}return structure}#scanDirectoryBrowser(dir,options={}){const manifest=this.slothlet.config?.manifest;if(!manifest){throw new this.SlothletError("INVALID_CONFIG_BROWSER_REQUIRES_MANIFEST",{},null,{validationError:true})}const configBase=(this.slothlet.config?.dir||"").replace(/\/$/,"");let relativePath=(dir||"").replace(/\/$/,"");if(configBase&&relativePath.startsWith(configBase)){relativePath=relativePath.slice(configBase.length).replace(/^\/|\/$/g,"")}const isRoot=!relativePath||relativePath==="/"||relativePath===".";const node=isRoot?manifest:this.#findManifestNode(manifest,relativePath);if(!node){throw new this.SlothletError("INVALID_DIRECTORY",{dir},null)}return this.#manifestNodeToStructure(node,dir,options)}#findManifestNode(node,targetPath){const normalised=targetPath.replace(/\\/g,"/").replace(/^\/|\/$/g,"");for(const dir of node.directories||[]){const dirPath=(dir.path||dir.name||"").replace(/\\/g,"/").replace(/^\/|\/$/g,"");if(dirPath===normalised)return dir.children||dir;const found=this.#findManifestNode(dir.children||dir,normalised);if(found)return found}return null}#manifestNodeToStructure(node,rootPath,options={}){const{fileFilter=null}=options;const ALLOWED_EXTS=[".mjs",".cjs",".js"];const structure={files:[],directories:[]};for(const file of node.files||[]){const filePath=file.path||file.relativePath||"";const fullName=file.fullName||filePath.split("/").pop();const lastDot=fullName.lastIndexOf(".");const ext=lastDot>=0?fullName.slice(lastDot):"";if(!ALLOWED_EXTS.includes(ext))continue;if(fullName.startsWith("__"))continue;if(fileFilter&&!fileFilter(fullName))continue;const name=file.name||(lastDot>=0?fullName.slice(0,lastDot):fullName);structure.files.push({path:filePath,name,fullName,moduleID:this.slothlet.helpers.sanitize.getModuleId(filePath,rootPath)})}if(!fileFilter){for(const dir of node.directories||[]){const dirPath=dir.path||dir.name||"";structure.directories.push({path:dirPath,name:dir.name||dirPath.split("/").pop(),children:this.#manifestNodeToStructure(dir.children||dir,dirPath,options)})}}return structure}async#loadModuleBrowser(filePath){const resolveModuleSpecifier=this.slothlet.config?.resolveModuleSpecifier??(({path:p})=>{const base=this.slothlet.config?.base??this.slothlet.config?.dir??"";const leadingSlash=base.startsWith("/")?"":"/";const baseUrl=/^[a-zA-Z][\w+\-.]*:\/\//.test(base)?base.endsWith("/")?base:base+"/":"file://"+leadingSlash+base.replace(/\/?$/,"/");return new URL(p,baseUrl).href});const fullName=filePath.split("/").pop();const lastDot=fullName.lastIndexOf(".");const name=lastDot>=0?fullName.slice(0,lastDot):fullName;const specifier=resolveModuleSpecifier({path:filePath,name,fullName});const module=await import(specifier);return module}extractExports(module){const exports={};if(module.default!==void 0){exports.default=module.default}for(const key of Object.keys(module)){if(key!=="default"&&key!=="module.exports"&&typeof key==="string"){exports[key]=module[key]}}if(exports.default&&typeof exports.default==="object"&&exports.default!==null&&"default"in exports.default){const rootNamedKeys=Object.keys(exports).filter(k=>k!=="default"&&k!=="module.exports");const defaultKeys=Object.keys(exports.default).filter(k=>k!=="default");const isCJSPattern=rootNamedKeys.every(k=>k in exports.default);if(isCJSPattern&&defaultKeys.length>0){exports.default=exports.default.default}}return exports}}export{Loader};
|
package/dist/slothlet.mjs
CHANGED
|
@@ -14,4 +14,4 @@
|
|
|
14
14
|
limitations under the License.
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
|
-
import{isNode,fs,fsp,path,url,createRequire}from"@cldmv/slothlet/helpers/platform";import{getContextManager}from"@cldmv/slothlet/factories/context";import{SlothletError,SlothletWarning,SlothletDebug}from"@cldmv/slothlet/errors";import{registerInstance}from"@cldmv/slothlet/handlers/lifecycle-token";import{resolveWrapper}from"@cldmv/slothlet/handlers/unified-wrapper";import{initI18n}from"@cldmv/slothlet/i18n";import{enableEventEmitterPatching,disableEventEmitterPatching,cleanupEventEmitterResources,setApiContextChecker}from"@cldmv/slothlet/helpers/eventemitter-context";class Slothlet{static RESERVED_ROOT_KEYS=["slothlet","shutdown","destroy"];static SKIP_PROPS=["__metadata","__type","_materialize","_impl","____slothletInternal"];constructor(){this.SlothletError=SlothletError;this.SlothletWarning=SlothletWarning;this.debugLogger=null;this.instanceID=null;this.config=null;this.envTarget="node";this.api=null;this.boundApi=null;this.contextManager=null;this.isLoaded=false;this.reference=null;this.context=null;this.envSnapshot=null;this._totalLazyCount=0;this._unmaterializedLazyCount=0;this._materializationComplete=false;this._materializationWaiters=[];this._materializationCompleteEmitted=false;this.componentCategories=["helpers","handlers","builders","processors","modes"];for(const category of this.componentCategories){this[category]={}}}async _initializeComponents(){if(this.envTarget==="browser"){await this._initializeComponentsBrowser();return}const baseDir=path.join(path.dirname(url.fileURLToPath(import.meta.url)),"lib");for(const category of this.componentCategories){const categoryDir=path.join(baseDir,category);const files=fs.readdirSync(categoryDir).filter(f=>f.endsWith(".mjs"));for(const file of files){const filePath=path.join(categoryDir,file);try{const module=await import(url.pathToFileURL(filePath).href);const classExports=Object.values(module).filter(exp=>typeof exp==="function"&&exp.slothletProperty);for(const ClassExport of classExports){const propName=ClassExport.slothletProperty;this[category][propName]=new ClassExport(this);if(this.config?.debug?.initialization){this.debug("initialization",{key:"DEBUG_MODE_COMPONENT_INITIALIZED",component:ClassExport.name,category,propertyName:propName})}}}catch(error){throw new this.SlothletError("MODULE_IMPORT_FAILED",{modulePath:filePath},error)}}}}async _initializeComponentsBrowser(){const BROWSER_COMPONENT_SPECIFIERS=["@cldmv/slothlet/builders/api-assignment","@cldmv/slothlet/builders/api_builder","@cldmv/slothlet/builders/builder","@cldmv/slothlet/builders/modes-processor","@cldmv/slothlet/handlers/api-cache-manager","@cldmv/slothlet/handlers/api-manager","@cldmv/slothlet/handlers/hook-manager","@cldmv/slothlet/handlers/lifecycle","@cldmv/slothlet/handlers/materialize-manager","@cldmv/slothlet/handlers/metadata","@cldmv/slothlet/handlers/module-manager","@cldmv/slothlet/handlers/ownership","@cldmv/slothlet/handlers/permission-manager","@cldmv/slothlet/handlers/version-manager","@cldmv/slothlet/helpers/config","@cldmv/slothlet/helpers/hint-detector","@cldmv/slothlet/helpers/modes-utils","@cldmv/slothlet/helpers/resolve-from-caller","@cldmv/slothlet/helpers/sanitize","@cldmv/slothlet/helpers/utilities","@cldmv/slothlet/modes/eager","@cldmv/slothlet/modes/lazy","@cldmv/slothlet/processors/flatten","@cldmv/slothlet/processors/loader"];for(const specifier of BROWSER_COMPONENT_SPECIFIERS){const parts=specifier.split("/");const category=parts[2];const module=await import(specifier);const classExports=Object.values(module).filter(exp=>typeof exp==="function"&&exp.slothletProperty);for(const ClassExport of classExports){const propName=ClassExport.slothletProperty;this[category][propName]=new ClassExport(this)}}}_setupLifecycleSubscribers(){if(!this.handlers.lifecycle){return}if(this.handlers.metadata){this.handlers.lifecycle.subscribe("impl:created",(data,token)=>{this.handlers.metadata.tagSystemMetadata(data.impl,{filePath:data.filePath,apiPath:data.apiPath,moduleID:data.moduleID,sourceFolder:data.sourceFolder},token)});this.handlers.lifecycle.subscribe("impl:changed",(data,token)=>{this.handlers.metadata.tagSystemMetadata(data.impl,{filePath:data.filePath,apiPath:data.apiPath,moduleID:data.moduleID,sourceFolder:data.sourceFolder},token)});this.handlers.lifecycle.subscribe("impl:removed",data=>{if(data.apiPath){const rootSegment=data.apiPath.split(".")[0];this.handlers.metadata.removeUserMetadataByApiPath(rootSegment)}})}if(this.handlers.ownership){this.handlers.lifecycle.subscribe("impl:created",data=>{const collisionMode=this.config?.collision?.api||"merge";const implValue=data.wrapper?.__impl??data.impl;this.handlers.ownership.register({moduleID:data.moduleID,apiPath:data.apiPath,value:implValue,source:data.source,filePath:data.filePath,collisionMode})});this.handlers.lifecycle.subscribe("impl:changed",data=>{const collisionMode=this.config?.collision?.api||"merge";const implValue=data.wrapper?.__impl??data.impl;const currentOwner=this.handlers.ownership.getCurrentOwner(data.apiPath);if(currentOwner?.moduleID!==data.moduleID){this.handlers.ownership.register({moduleID:data.moduleID,apiPath:data.apiPath,value:implValue,source:data.source,filePath:data.filePath,collisionMode})}})}}_registerLazyWrapper(){this._totalLazyCount++;this._unmaterializedLazyCount++;if(this.config?.debug?.materialize){this.debug("materialize",{key:"DEBUG_MODE_LAZY_WRAPPER_REGISTERED",total:this._totalLazyCount,unmaterialized:this._unmaterializedLazyCount})}}_onWrapperMaterialized(){this._unmaterializedLazyCount--;if(this.config?.debug?.materialize){this.debug("materialize",{key:"DEBUG_MODE_LAZY_WRAPPER_MATERIALIZED",total:this._totalLazyCount,unmaterialized:this._unmaterializedLazyCount,percentage:this._totalLazyCount>0?(this._totalLazyCount-this._unmaterializedLazyCount)/this._totalLazyCount*100:100})}if(this._unmaterializedLazyCount===0&&!this._materializationComplete){this._materializationComplete=true;if(this.config?.debug?.materialize){this.debug("materialize",{key:"DEBUG_MODE_ALL_LAZY_WRAPPERS_MATERIALIZED",total:this._totalLazyCount})}const waiters=this._materializationWaiters.splice(0);for(const resolve of waiters){resolve()}if(this.config?.tracking?.materialization&&!this._materializationCompleteEmitted){this._materializationCompleteEmitted=true;if(this.handlers?.lifecycle){this.handlers.lifecycle.emit("materialized:complete",{total:this._totalLazyCount,timestamp:Date.now()})}}}}_captureEnvSnapshot(envConfig){const rawInclude=envConfig?.include;const include=Array.isArray(rawInclude)?rawInclude.filter(key=>typeof key==="string"):null;const useAllowlist=include!==null&&include.length>0;const raw=useAllowlist?include.reduce((acc,key)=>{if(Object.prototype.hasOwnProperty.call(process.env,key)){acc[key]=process.env[key]}return acc},Object.create(null)):{...process.env};return Object.freeze(raw)}async load(config={},preservedInstanceID=null){this.config=config;this.envTarget=config.platform==="browser"||config.platform!=="node"&&config.manifest!=null?"browser":"node";if(!this.envSnapshot){this.envSnapshot=this.envTarget==="browser"?Object.freeze(Object.create(null)):this._captureEnvSnapshot(config.env)}this.debugLogger=new SlothletDebug(config);await this._initializeComponents();registerInstance(this);this._setupLifecycleSubscribers();this.config=this.helpers.config.transformConfig(config);if(this.config?.i18n?.language){initI18n({language:this.config.i18n.language})}this.debugLogger=new SlothletDebug(this.config);this.instanceID=preservedInstanceID||this.helpers.utilities.generateId();this.reference=this.config.reference;this.context=this.config.context;this.contextManager=getContextManager(this.envTarget==="browser"?"live":this.config.runtime);setApiContextChecker(()=>{const ctx=this.contextManager.tryGetContext();return!!(ctx&&ctx.self)});let store;if(preservedInstanceID&&this.contextManager.instances.has(preservedInstanceID)){this.contextManager.cleanup(preservedInstanceID);store=this.contextManager.initialize(this.instanceID,this.config)}else{store=this.contextManager.initialize(this.instanceID,this.config)}enableEventEmitterPatching();if(typeof this.contextManager.registerEventEmitterContextChecker==="function"){this.contextManager.registerEventEmitterContextChecker()}const baseModuleId=`base_${this.helpers.utilities.generateId().substring(0,8)}`;const baseApi=await this.builders.builder.buildAPI({dir:this.config.dir,mode:this.config.mode,moduleID:baseModuleId});this.api=baseApi;const apiWithBuiltins=await this.buildFinalAPI(this.api);if(this.handlers.apiCacheManager){this.handlers.apiCacheManager.set(baseModuleId,{endpoint:".",moduleID:baseModuleId,api:this.api,folderPath:this.config.dir,mode:this.config.mode,sanitizeOptions:this.config.sanitize||{},collisionMode:this.config.collision?.api||"merge",config:{...this.config},timestamp:Date.now()})}this.injectRuntimeMetadataFunctions(apiWithBuiltins);if(this.config.metadata&&typeof this.config.metadata==="object"){for(const[key,value]of Object.entries(this.config.metadata)){this.handlers.metadata.setGlobalMetadata(key,value)}this.handlers.metadata.registerUserMetadata(baseModuleId,this.config.metadata)}if(this.handlers.ownership){this.handlers.ownership.registerSubtree(apiWithBuiltins,baseModuleId,"");this.handlers.ownership.setModuleEndpoint(baseModuleId,".")}if(!this.boundApi){const isCallable=typeof this.api==="function"||this.api&&typeof this.api.default==="function";const proxyTarget=isCallable?function(){}:{};this.boundApi=new Proxy(proxyTarget,{get:(target,prop)=>this.api?this.api[prop]:void 0,set:(target,prop,value)=>{if(this.api){this.api[prop]=value}return true},has:(target,prop)=>this.api?prop in this.api:false,ownKeys:____target=>this.api?Reflect.ownKeys(this.api):[],deleteProperty:(target,prop)=>this.api?delete this.api[prop]:true,apply:(target,thisArg,args)=>this.api?Reflect.apply(this.api,thisArg,args):void 0,construct:(target,args)=>this.api?Reflect.construct(this.api,args):{},getOwnPropertyDescriptor:(target,prop)=>{if(isCallable&&prop==="prototype"){return Object.getOwnPropertyDescriptor(target,prop)}if(this.api&&prop in this.api){const desc=Object.getOwnPropertyDescriptor(this.api,prop);if(desc){return{...desc,configurable:true}}}return void 0}})}store.self=this.boundApi;store.context=this.context||{};store.slothlet=this;if(this.reference&&typeof this.reference==="object"){Object.assign(this.boundApi,this.reference)}this.isLoaded=true;return this.boundApi}async reload(options={}){const{keepInstanceID=false}=options;if(!this.config?.dir){throw new SlothletError("INVALID_CONFIG_NOT_LOADED",{operation:"reload",validationError:true})}const operationHistory=this.handlers.apiManager?.state?.operationHistory?[...this.handlers.apiManager.state.operationHistory]:[];await this._clearModuleCaches();const oldInstanceID=this.instanceID;if(!keepInstanceID){this.instanceID=`${oldInstanceID}_reload_${Date.now()}`;if(isNode&&this._typescriptCacheDirs?.size){await Promise.allSettled([...this._typescriptCacheDirs].map(dir=>fsp.rm(dir,{recursive:true,force:true})));this._typescriptCacheDirs.clear()}}const savedMetadataState=this.handlers.metadata?.exportUserState?.();const savedHooks=this.handlers.hookManager?.exportHooks?.();await this.load(this.config,this.instanceID);if(savedMetadataState&&this.handlers.metadata){this.handlers.metadata.importUserState(savedMetadataState)}if(savedHooks?.length&&this.handlers.hookManager){this.handlers.hookManager.importHooks(savedHooks)}for(const[,store]of this.contextManager.instances){if(store.parentInstanceID===oldInstanceID){store.parentInstanceID=this.instanceID}}if(oldInstanceID&&oldInstanceID!==this.instanceID&&this.contextManager.instances?.has(oldInstanceID)){this.contextManager.cleanup(oldInstanceID)}for(const operation of operationHistory){if(operation.type==="add"){await this.handlers.apiManager.addApiComponent({apiPath:operation.apiPath,folderPath:operation.folderPath,options:{...operation.options||{},recordHistory:false},moduleID:`replay_${this.helpers.utilities.generateId().substring(0,8)}`,versionConfig:operation.versionConfig||null})}else if(operation.type==="remove"){await this.handlers.apiManager.removeApiComponent(operation.apiPath,{recordHistory:false})}else if(operation.type==="addPermissionRule"){if(this.handlers.permissionManager){this.handlers.permissionManager.addRule(operation.rule,operation.ownerModuleID,operation.ruleId)}}else if(operation.type==="removePermissionRule"){if(this.handlers.permissionManager){this.handlers.permissionManager.removeRule(operation.ruleId,operation.callerModuleID)}}}return this.boundApi}async _clearModuleCaches(){if(!isNode)return;const targetDir=this.config.dir;const require2=createRequire(import.meta.url);const absoluteTargetDir=path.resolve(targetDir);for(const key of Object.keys(require2.cache)){if(key.startsWith(absoluteTargetDir)){delete require2.cache[key]}}}injectRuntimeMetadataFunctions(api){if(!api.slothlet?.metadata){return}const metadataHandler=this.handlers.metadata;api.slothlet.metadata.get=async function slothlet_metadata_get_runtime(path2){return metadataHandler.get(path2)};api.slothlet.metadata.self=function slothlet_metadata_self_runtime(){return metadataHandler.self()};api.slothlet.metadata.caller=function slothlet_metadata_caller_runtime(){return metadataHandler.caller()}}async _drainInFlightLoads(){if(!this.api)return;const pending=[];const seen=new Set;const collect=(obj,depth=0)=>{const objType=typeof obj;if(!obj||objType!=="object"&&objType!=="function"||depth>15||seen.has(obj))return;seen.add(obj);try{if(obj.__isVersionDispatcher===true)return;const wrapper=resolveWrapper(obj);if(wrapper){const mat=wrapper.____slothletInternal.materializationPromise;if(mat)pending.push(mat);for(const key of Object.keys(wrapper)){if(!key.startsWith("____"))collect(wrapper[key],depth+1)}return}for(const key of Object.keys(obj)){collect(obj[key],depth+1)}}catch{}};for(const key of Object.keys(this.api)){collect(this.api[key])}if(pending.length>0){await Promise.allSettled(pending)}}async shutdown(){if(!this.isLoaded){return}await this._drainInFlightLoads();disableEventEmitterPatching();cleanupEventEmitterResources();if(this.instanceID&&this.contextManager){this.contextManager.cleanup(this.instanceID)}if(this.handlers.ownership){this.handlers.ownership.clear()}this.handlers.versionManager?.shutdown();await this.handlers.permissionManager?.shutdown();if(isNode&&this._typescriptCacheDirs?.size){await Promise.allSettled([...this._typescriptCacheDirs].map(dir=>fsp.rm(dir,{recursive:true,force:true})));this._typescriptCacheDirs.clear()}this.isLoaded=false}debug(code,context={}){if(this.debugLogger){this.debugLogger.log(code,context)}}getAPI(){if(!this.isLoaded){throw new SlothletError("INVALID_CONFIG_NOT_LOADED",{operation:"getAPI"},null,{validationError:true})}return this.boundApi}getDiagnostics(){return{instanceID:this.instanceID,isLoaded:this.isLoaded,config:this.config,context:this.contextManager?.getDiagnostics()||null,ownership:this.handlers.ownership?.getDiagnostics()||null}}getOwnership(){if(!this.handlers.ownership){return null}return this.handlers.ownership.getDiagnostics()}buildFinalAPI(userApi){return this.builders.apiBuilder.buildFinalAPI(userApi)}}async function slothlet(config){const instance=new Slothlet;const api=await instance.load(config);return api}var stdin_default=slothlet;export{stdin_default as default,slothlet};
|
|
17
|
+
import{isNode,fs,fsp,path,url,createRequire}from"@cldmv/slothlet/helpers/platform";import{getContextManager}from"@cldmv/slothlet/factories/context";import{SlothletError,SlothletWarning,SlothletDebug}from"@cldmv/slothlet/errors";import{registerInstance}from"@cldmv/slothlet/handlers/lifecycle-token";import{resolveWrapper}from"@cldmv/slothlet/handlers/unified-wrapper";import{initI18n}from"@cldmv/slothlet/i18n";import{enableEventEmitterPatching,disableEventEmitterPatching,cleanupEventEmitterResources,setApiContextChecker}from"@cldmv/slothlet/helpers/eventemitter-context";class Slothlet{static RESERVED_ROOT_KEYS=["slothlet","shutdown","destroy"];static SKIP_PROPS=["__metadata","__type","_materialize","_impl","____slothletInternal"];constructor(){this.SlothletError=SlothletError;this.SlothletWarning=SlothletWarning;this.debugLogger=null;this.instanceID=null;this.config=null;this.envTarget="node";this.api=null;this.boundApi=null;this.contextManager=null;this.isLoaded=false;this.reference=null;this.context=null;this.envSnapshot=null;this._totalLazyCount=0;this._unmaterializedLazyCount=0;this._materializationComplete=false;this._materializationWaiters=[];this._materializationCompleteEmitted=false;this.componentCategories=["helpers","handlers","builders","processors","modes"];for(const category of this.componentCategories){this[category]={}}}async _initializeComponents(){if(this.envTarget==="browser"){await this._initializeComponentsBrowser();return}const baseDir=path.join(path.dirname(url.fileURLToPath(import.meta.url)),"lib");for(const category of this.componentCategories){const categoryDir=path.join(baseDir,category);const files=fs.readdirSync(categoryDir).filter(f=>f.endsWith(".mjs"));for(const file of files){const filePath=path.join(categoryDir,file);try{const module=await import(url.pathToFileURL(filePath).href);const classExports=Object.values(module).filter(exp=>typeof exp==="function"&&exp.slothletProperty);for(const ClassExport of classExports){const propName=ClassExport.slothletProperty;this[category][propName]=new ClassExport(this);if(this.config?.debug?.initialization){this.debug("initialization",{key:"DEBUG_MODE_COMPONENT_INITIALIZED",component:ClassExport.name,category,propertyName:propName})}}}catch(error){throw new this.SlothletError("MODULE_IMPORT_FAILED",{modulePath:filePath},error)}}}}async _initializeComponentsBrowser(){const BROWSER_COMPONENT_SPECIFIERS=["@cldmv/slothlet/builders/api-assignment","@cldmv/slothlet/builders/api_builder","@cldmv/slothlet/builders/builder","@cldmv/slothlet/builders/modes-processor","@cldmv/slothlet/handlers/api-cache-manager","@cldmv/slothlet/handlers/api-manager","@cldmv/slothlet/handlers/hook-manager","@cldmv/slothlet/handlers/lifecycle","@cldmv/slothlet/handlers/materialize-manager","@cldmv/slothlet/handlers/metadata","@cldmv/slothlet/handlers/module-manager","@cldmv/slothlet/handlers/ownership","@cldmv/slothlet/handlers/permission-manager","@cldmv/slothlet/handlers/version-manager","@cldmv/slothlet/helpers/config","@cldmv/slothlet/helpers/hint-detector","@cldmv/slothlet/helpers/modes-utils","@cldmv/slothlet/helpers/resolve-from-caller","@cldmv/slothlet/helpers/sanitize","@cldmv/slothlet/helpers/utilities","@cldmv/slothlet/modes/eager","@cldmv/slothlet/modes/lazy","@cldmv/slothlet/processors/flatten","@cldmv/slothlet/processors/loader"];for(const specifier of BROWSER_COMPONENT_SPECIFIERS){const parts=specifier.split("/");const category=parts[2];const module=await import(specifier);const classExports=Object.values(module).filter(exp=>typeof exp==="function"&&exp.slothletProperty);for(const ClassExport of classExports){const propName=ClassExport.slothletProperty;this[category][propName]=new ClassExport(this)}}}_setupLifecycleSubscribers(){if(!this.handlers.lifecycle){return}if(this.handlers.metadata){this.handlers.lifecycle.subscribe("impl:created",(data,token)=>{this.handlers.metadata.tagSystemMetadata(data.impl,{filePath:data.filePath,apiPath:data.apiPath,moduleID:data.moduleID,sourceFolder:data.sourceFolder},token)});this.handlers.lifecycle.subscribe("impl:changed",(data,token)=>{this.handlers.metadata.tagSystemMetadata(data.impl,{filePath:data.filePath,apiPath:data.apiPath,moduleID:data.moduleID,sourceFolder:data.sourceFolder},token)});this.handlers.lifecycle.subscribe("impl:removed",data=>{if(data.apiPath){const rootSegment=data.apiPath.split(".")[0];this.handlers.metadata.removeUserMetadataByApiPath(rootSegment)}})}if(this.handlers.ownership){this.handlers.lifecycle.subscribe("impl:created",data=>{const collisionMode=this.config?.collision?.api||"merge";const implValue=data.wrapper?.__impl??data.impl;this.handlers.ownership.register({moduleID:data.moduleID,apiPath:data.apiPath,value:implValue,source:data.source,filePath:data.filePath,collisionMode})});this.handlers.lifecycle.subscribe("impl:changed",data=>{const collisionMode=this.config?.collision?.api||"merge";const implValue=data.wrapper?.__impl??data.impl;const currentOwner=this.handlers.ownership.getCurrentOwner(data.apiPath);if(currentOwner?.moduleID!==data.moduleID){this.handlers.ownership.register({moduleID:data.moduleID,apiPath:data.apiPath,value:implValue,source:data.source,filePath:data.filePath,collisionMode})}})}}_registerLazyWrapper(){this._totalLazyCount++;this._unmaterializedLazyCount++;if(this.config?.debug?.materialize){this.debug("materialize",{key:"DEBUG_MODE_LAZY_WRAPPER_REGISTERED",total:this._totalLazyCount,unmaterialized:this._unmaterializedLazyCount})}}_onWrapperMaterialized(){this._unmaterializedLazyCount--;if(this.config?.debug?.materialize){this.debug("materialize",{key:"DEBUG_MODE_LAZY_WRAPPER_MATERIALIZED",total:this._totalLazyCount,unmaterialized:this._unmaterializedLazyCount,percentage:this._totalLazyCount>0?(this._totalLazyCount-this._unmaterializedLazyCount)/this._totalLazyCount*100:100})}if(this._unmaterializedLazyCount===0&&!this._materializationComplete){this._materializationComplete=true;if(this.config?.debug?.materialize){this.debug("materialize",{key:"DEBUG_MODE_ALL_LAZY_WRAPPERS_MATERIALIZED",total:this._totalLazyCount})}const waiters=this._materializationWaiters.splice(0);for(const resolve of waiters){resolve()}if(this.config?.tracking?.materialization&&!this._materializationCompleteEmitted){this._materializationCompleteEmitted=true;if(this.handlers?.lifecycle){this.handlers.lifecycle.emit("materialized:complete",{total:this._totalLazyCount,timestamp:Date.now()})}}}}_captureEnvSnapshot(envConfig){const rawInclude=envConfig?.include;const include=Array.isArray(rawInclude)?rawInclude.filter(key=>typeof key==="string"):null;const useAllowlist=include!==null&&include.length>0;const raw=useAllowlist?include.reduce((acc,key)=>{if(Object.prototype.hasOwnProperty.call(process.env,key)){acc[key]=process.env[key]}return acc},Object.create(null)):{...process.env};return Object.freeze(raw)}async load(config={},preservedInstanceID=null){this.config=config;this.envTarget=config.platform==="browser"||config.platform!=="node"&&config.manifest!=null?"browser":"node";if(!this.envSnapshot){this.envSnapshot=this.envTarget==="browser"?Object.freeze(Object.create(null)):this._captureEnvSnapshot(config.env)}this.debugLogger=new SlothletDebug(config);await this._initializeComponents();registerInstance(this);this._setupLifecycleSubscribers();this.config=this.helpers.config.transformConfig(config);if(this.config?.i18n?.language){initI18n({language:this.config.i18n.language})}this.debugLogger=new SlothletDebug(this.config);this.instanceID=preservedInstanceID||this.helpers.utilities.generateId();this.reference=this.config.reference;this.context=this.config.context;this.contextManager=getContextManager(this.envTarget==="browser"?"live":this.config.runtime);setApiContextChecker(()=>{const ctx=this.contextManager.tryGetContext();return!!(ctx&&ctx.self)});let store;if(preservedInstanceID&&this.contextManager.instances.has(preservedInstanceID)){this.contextManager.cleanup(preservedInstanceID);store=this.contextManager.initialize(this.instanceID,this.config)}else{store=this.contextManager.initialize(this.instanceID,this.config)}enableEventEmitterPatching();if(typeof this.contextManager.registerEventEmitterContextChecker==="function"){this.contextManager.registerEventEmitterContextChecker()}const baseModuleId=`base_${this.helpers.utilities.generateId().substring(0,8)}`;if(this.config.scanHiddenFolders!==void 0&&!this.config.silent){new this.SlothletWarning("CONFIG_SCAN_HIDDEN_FOLDERS_DEPRECATED",{option:"scanHiddenFolders"})}const baseApi=await this.builders.builder.buildAPI({dir:this.config.dir,mode:this.config.mode,moduleID:baseModuleId,hidden:this.config.hidden??null,scanHiddenFolders:this.config.scanHiddenFolders===true});this.api=baseApi;const apiWithBuiltins=await this.buildFinalAPI(this.api);if(this.handlers.apiCacheManager){this.handlers.apiCacheManager.set(baseModuleId,{endpoint:".",moduleID:baseModuleId,api:this.api,folderPath:this.config.dir,mode:this.config.mode,sanitizeOptions:this.config.sanitize||{},collisionMode:this.config.collision?.api||"merge",config:{...this.config},timestamp:Date.now()})}this.injectRuntimeMetadataFunctions(apiWithBuiltins);if(this.config.metadata&&typeof this.config.metadata==="object"){for(const[key,value]of Object.entries(this.config.metadata)){this.handlers.metadata.setGlobalMetadata(key,value)}this.handlers.metadata.registerUserMetadata(baseModuleId,this.config.metadata)}if(this.handlers.ownership){this.handlers.ownership.registerSubtree(apiWithBuiltins,baseModuleId,"");this.handlers.ownership.setModuleEndpoint(baseModuleId,".")}if(!this.boundApi){const isCallable=typeof this.api==="function"||this.api&&typeof this.api.default==="function";const proxyTarget=isCallable?function(){}:{};this.boundApi=new Proxy(proxyTarget,{get:(target,prop)=>this.api?this.api[prop]:void 0,set:(target,prop,value)=>{if(this.api){this.api[prop]=value}return true},has:(target,prop)=>this.api?prop in this.api:false,ownKeys:____target=>this.api?Reflect.ownKeys(this.api):[],deleteProperty:(target,prop)=>this.api?delete this.api[prop]:true,apply:(target,thisArg,args)=>this.api?Reflect.apply(this.api,thisArg,args):void 0,construct:(target,args)=>this.api?Reflect.construct(this.api,args):{},getOwnPropertyDescriptor:(target,prop)=>{if(isCallable&&prop==="prototype"){return Object.getOwnPropertyDescriptor(target,prop)}if(this.api&&prop in this.api){const desc=Object.getOwnPropertyDescriptor(this.api,prop);if(desc){return{...desc,configurable:true}}}return void 0}})}store.self=this.boundApi;store.context=this.context||{};store.slothlet=this;if(this.reference&&typeof this.reference==="object"){Object.assign(this.boundApi,this.reference)}this.isLoaded=true;return this.boundApi}async reload(options={}){const{keepInstanceID=false}=options;if(!this.config?.dir){throw new SlothletError("INVALID_CONFIG_NOT_LOADED",{operation:"reload",validationError:true})}const operationHistory=this.handlers.apiManager?.state?.operationHistory?[...this.handlers.apiManager.state.operationHistory]:[];await this._clearModuleCaches();const oldInstanceID=this.instanceID;if(!keepInstanceID){this.instanceID=`${oldInstanceID}_reload_${Date.now()}`;if(isNode&&this._typescriptCacheDirs?.size){await Promise.allSettled([...this._typescriptCacheDirs].map(dir=>fsp.rm(dir,{recursive:true,force:true})));this._typescriptCacheDirs.clear()}}const savedMetadataState=this.handlers.metadata?.exportUserState?.();const savedHooks=this.handlers.hookManager?.exportHooks?.();await this.load(this.config,this.instanceID);if(savedMetadataState&&this.handlers.metadata){this.handlers.metadata.importUserState(savedMetadataState)}if(savedHooks?.length&&this.handlers.hookManager){this.handlers.hookManager.importHooks(savedHooks)}for(const[,store]of this.contextManager.instances){if(store.parentInstanceID===oldInstanceID){store.parentInstanceID=this.instanceID}}if(oldInstanceID&&oldInstanceID!==this.instanceID&&this.contextManager.instances?.has(oldInstanceID)){this.contextManager.cleanup(oldInstanceID)}for(const operation of operationHistory){if(operation.type==="add"){await this.handlers.apiManager.addApiComponent({apiPath:operation.apiPath,folderPath:operation.folderPath,options:{...operation.options||{},recordHistory:false},moduleID:`replay_${this.helpers.utilities.generateId().substring(0,8)}`,versionConfig:operation.versionConfig||null})}else if(operation.type==="remove"){await this.handlers.apiManager.removeApiComponent(operation.apiPath,{recordHistory:false})}else if(operation.type==="addPermissionRule"){if(this.handlers.permissionManager){this.handlers.permissionManager.addRule(operation.rule,operation.ownerModuleID,operation.ruleId)}}else{if(operation.type==="removePermissionRule"){if(this.handlers.permissionManager){this.handlers.permissionManager.removeRule(operation.ruleId,operation.callerModuleID)}}}}return this.boundApi}async _clearModuleCaches(){if(!isNode)return;const targetDir=this.config.dir;const require2=createRequire(import.meta.url);const absoluteTargetDir=path.resolve(targetDir);for(const key of Object.keys(require2.cache)){if(key.startsWith(absoluteTargetDir)){delete require2.cache[key]}}}injectRuntimeMetadataFunctions(api){if(!api.slothlet?.metadata){return}const metadataHandler=this.handlers.metadata;api.slothlet.metadata.get=async function slothlet_metadata_get_runtime(path2){return metadataHandler.get(path2)};api.slothlet.metadata.self=function slothlet_metadata_self_runtime(){return metadataHandler.self()};api.slothlet.metadata.caller=function slothlet_metadata_caller_runtime(){return metadataHandler.caller()}}async _drainInFlightLoads(){if(!this.api)return;const pending=[];const seen=new Set;const collect=(obj,depth=0)=>{const objType=typeof obj;if(!obj||objType!=="object"&&objType!=="function"||depth>15||seen.has(obj))return;seen.add(obj);try{if(obj.__isVersionDispatcher===true)return;const wrapper=resolveWrapper(obj);if(wrapper){const mat=wrapper.____slothletInternal.materializationPromise;if(mat)pending.push(mat);for(const key of Object.keys(wrapper)){if(!key.startsWith("____"))collect(wrapper[key],depth+1)}return}for(const key of Object.keys(obj)){collect(obj[key],depth+1)}}catch{}};for(const key of Object.keys(this.api)){collect(this.api[key])}if(pending.length>0){await Promise.allSettled(pending)}}async shutdown(){if(!this.isLoaded){return}await this._drainInFlightLoads();disableEventEmitterPatching();cleanupEventEmitterResources();if(this.instanceID&&this.contextManager){this.contextManager.cleanup(this.instanceID)}if(this.handlers.ownership){this.handlers.ownership.clear()}this.handlers.versionManager?.shutdown();await this.handlers.permissionManager?.shutdown();if(isNode&&this._typescriptCacheDirs?.size){await Promise.allSettled([...this._typescriptCacheDirs].map(dir=>fsp.rm(dir,{recursive:true,force:true})));this._typescriptCacheDirs.clear()}this.isLoaded=false}debug(code,context={}){if(this.debugLogger){this.debugLogger.log(code,context)}}getAPI(){if(!this.isLoaded){throw new SlothletError("INVALID_CONFIG_NOT_LOADED",{operation:"getAPI"},null,{validationError:true})}return this.boundApi}getDiagnostics(){return{instanceID:this.instanceID,isLoaded:this.isLoaded,config:this.config,context:this.contextManager?.getDiagnostics()||null,ownership:this.handlers.ownership?.getDiagnostics()||null}}getOwnership(){if(!this.handlers.ownership){return null}return this.handlers.ownership.getDiagnostics()}buildFinalAPI(userApi){return this.builders.apiBuilder.buildFinalAPI(userApi)}}async function slothlet(config){const instance=new Slothlet;const api=await instance.load(config);return api}var stdin_default=slothlet;export{stdin_default as default,slothlet};
|