@cldmv/slothlet 3.11.1 → 3.12.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. package/README.md +6 -5
  2. package/devcheck.mjs +99 -0
  3. package/dist/lib/builders/api-assignment.mjs +1 -1
  4. package/dist/lib/builders/api_builder.mjs +1 -1
  5. package/dist/lib/builders/builder.mjs +1 -1
  6. package/dist/lib/builders/modes-processor.mjs +1 -1
  7. package/dist/lib/factories/component-base.mjs +1 -1
  8. package/dist/lib/factories/context.mjs +1 -1
  9. package/dist/lib/handlers/api-cache-manager.mjs +1 -1
  10. package/dist/lib/handlers/api-manager.mjs +1 -1
  11. package/dist/lib/handlers/context-async.mjs +1 -1
  12. package/dist/lib/handlers/hook-manager.mjs +1 -1
  13. package/dist/lib/handlers/lifecycle.mjs +1 -1
  14. package/dist/lib/handlers/materialize-manager.mjs +1 -1
  15. package/dist/lib/handlers/metadata.mjs +1 -1
  16. package/dist/lib/handlers/module-manager.mjs +1 -1
  17. package/dist/lib/handlers/ownership.mjs +1 -1
  18. package/dist/lib/handlers/permission-manager.mjs +1 -1
  19. package/dist/lib/handlers/trusted-root.mjs +17 -0
  20. package/dist/lib/handlers/unified-wrapper.mjs +1 -1
  21. package/dist/lib/handlers/version-manager.mjs +1 -1
  22. package/dist/lib/helpers/class-instance-wrapper.mjs +1 -1
  23. package/dist/lib/helpers/config.mjs +1 -1
  24. package/dist/lib/helpers/generate-manifest.mjs +1 -1
  25. package/dist/lib/helpers/hint-detector.mjs +1 -1
  26. package/dist/lib/helpers/modes-utils.mjs +1 -1
  27. package/dist/lib/helpers/resolve-from-caller.mjs +1 -1
  28. package/dist/lib/helpers/sanitize.mjs +1 -1
  29. package/dist/lib/helpers/utilities.mjs +1 -1
  30. package/dist/lib/i18n/languages/en-us.json +6 -1
  31. package/dist/lib/modes/eager.mjs +1 -1
  32. package/dist/lib/modes/lazy.mjs +1 -1
  33. package/dist/lib/processors/flatten.mjs +1 -1
  34. package/dist/lib/processors/loader.mjs +1 -1
  35. package/dist/lib/runtime/runtime-asynclocalstorage.mjs +1 -1
  36. package/dist/lib/runtime/runtime-livebindings.mjs +1 -1
  37. package/dist/lib/runtime/runtime.mjs +1 -1
  38. package/dist/slothlet.mjs +1 -1
  39. package/package.json +35 -32
  40. package/types/stub/lib/factories/component-base.d.mts +0 -3
  41. package/types/stub/lib/factories/context.d.mts +0 -3
  42. package/types/stub/lib/handlers/api-cache-manager.d.mts +0 -3
  43. package/types/stub/lib/handlers/api-manager.d.mts +0 -3
  44. package/types/stub/lib/handlers/context-async.d.mts +0 -3
  45. package/types/stub/lib/handlers/context-live.d.mts +0 -3
  46. package/types/stub/lib/handlers/hook-manager.d.mts +0 -3
  47. package/types/stub/lib/handlers/lifecycle-token.d.mts +0 -3
  48. package/types/stub/lib/handlers/lifecycle.d.mts +0 -3
  49. package/types/stub/lib/handlers/materialize-manager.d.mts +0 -3
  50. package/types/stub/lib/handlers/metadata.d.mts +0 -3
  51. package/types/stub/lib/handlers/module-manager.d.mts +0 -3
  52. package/types/stub/lib/handlers/ownership.d.mts +0 -3
  53. package/types/stub/lib/handlers/permission-manager.d.mts +0 -3
  54. package/types/stub/lib/handlers/unified-wrapper.d.mts +0 -3
  55. package/types/stub/lib/handlers/version-manager.d.mts +0 -3
@@ -14,4 +14,4 @@
14
14
  limitations under the License.
15
15
  */
16
16
 
17
- import{ComponentBase}from"@cldmv/slothlet/factories/component-base";class Sanitize extends ComponentBase{static slothletProperty="sanitize";#compileGlobPattern(pattern,caseSensitive=true){if(pattern.startsWith("**")&&pattern.endsWith("**")&&pattern.length>4){const innerString=pattern.slice(2,-2);const escapedString=innerString.replace(/[.+^${}()|[\]\\*?]/g,"\\$&");const flags2=caseSensitive?"":"i";return new RegExp(`(?<=.)${escapedString}(?=.)`,flags2)}const regexPattern=pattern.replace(/[.+^${}()|[\]\\]/g,"\\$&").replace(/\*/g,".*").replace(/\?/g,".");const flags=caseSensitive?"":"i";return new RegExp(`^${regexPattern}$`,flags)}#matchesAnyPattern(input,patterns,caseSensitive=false){for(const pattern of patterns){if(pattern.includes("*")||pattern.includes("?")){const regex=this.#compileGlobPattern(pattern,caseSensitive);if(regex&&regex.test(input))return true}else{const match=caseSensitive?input===pattern:input.toLowerCase()===pattern.toLowerCase();if(match)return true}}return false}#extractPatternLiterals(pattern){return pattern.split(/[*?]+/).filter(Boolean)}#applySegmentRules(segment,index,originalString,config){const{preserveAllUpper,preserveAllLower,leaveRules,leaveInsensitiveRules,upperRules,lowerRules}=config;if(this.#matchesAnyPattern(segment,leaveRules,true)){return segment}if(this.#matchesAnyPattern(segment,leaveInsensitiveRules,false)){return segment}if(preserveAllUpper&&segment===segment.toUpperCase()&&segment!==segment.toLowerCase()&&/[A-Z]/.test(segment)){return segment}if(preserveAllLower&&segment===segment.toLowerCase()&&segment!==segment.toUpperCase()&&/[a-z]/.test(segment)){return segment}for(const pattern of[...upperRules,...lowerRules]){if(pattern.includes("*")||pattern.includes("?")){const regex=this.#compileGlobPattern(pattern,false);if(regex&&regex.test(originalString)){const literals=this.#extractPatternLiterals(pattern);for(const literal of literals){const cleanLiteral=literal.replace(/[^A-Za-z0-9_$]/g,"").replace(/^_+|_+$/g,"");if(cleanLiteral&&segment.toLowerCase()===cleanLiteral.toLowerCase()){return upperRules.includes(pattern)?segment.toUpperCase():segment.toLowerCase()}}}}else{if(segment.toLowerCase()===pattern.toLowerCase()){return upperRules.includes(pattern)?segment.toUpperCase():segment.toLowerCase()}}}let transformed=this.#applyWithinSegmentPatterns(segment,upperRules,lowerRules);if(transformed!==segment){return transformed}return segment}#applyWithinSegmentPatterns(segment,upperRules,lowerRules){let result=segment;const applyBoundaryPattern=(pattern,toUpper)=>{if(pattern.startsWith("**")&&pattern.endsWith("**")&&pattern.length>4){const innerString=pattern.slice(2,-2);const innerRegex=new RegExp(innerString.replace(/[.+^${}()|[\]\\*?]/g,"\\$&"),"gi");const matches=[...result.matchAll(innerRegex)];for(const match of matches){const startPos=match.index;const endPos=startPos+match[0].length;const hasCharBefore=startPos>0;const hasCharAfter=endPos<result.length;if(hasCharBefore&&hasCharAfter){const replacement=toUpper?innerString.toUpperCase():innerString.toLowerCase();result=result.substring(0,startPos)+replacement+result.substring(endPos);break}}}else if(pattern.includes("*")&&!pattern.startsWith("**")){const literalParts=pattern.split("*").filter(Boolean);for(const literal of literalParts){const literalRegex=new RegExp(literal.replace(/[.+^${}()|[\]\\]/g,"\\$&"),"gi");const replacement=toUpper?literal.toUpperCase():literal.toLowerCase();result=result.replace(literalRegex,replacement)}}};upperRules.forEach(pattern=>applyBoundaryPattern(pattern,true));lowerRules.forEach(pattern=>applyBoundaryPattern(pattern,false));return result}sanitizePropertyName(input,options={}){const{lowerFirst=true,preserveAllUpper=false,preserveAllLower=false,rules={}}=options;const leaveRules=(rules.leave||[]).map(s=>String(s));const leaveInsensitiveRules=(rules.leaveInsensitive||[]).map(s=>String(s));const upperRules=(rules.upper||[]).map(s=>String(s));const lowerRules=(rules.lower||[]).map(s=>String(s));const originalString=String(input).trim();const isAllUpper=originalString===originalString.toUpperCase()&&originalString!==originalString.toLowerCase()&&/[A-Z]/.test(originalString);const isAllLower=originalString===originalString.toLowerCase()&&originalString!==originalString.toUpperCase()&&/[a-z]/.test(originalString);if(preserveAllUpper&&isAllUpper){return originalString}if(preserveAllLower&&isAllLower&&!/-/.test(originalString)){return originalString}let primarySegments=originalString.split(/[-]+|[^A-Za-z0-9_$]+/).filter(Boolean);if(primarySegments.length===0)return"_";while(primarySegments.length&&!/^[A-Za-z_$]/.test(primarySegments[0][0])){primarySegments[0]=primarySegments[0].replace(/^[^A-Za-z_$]+/,"");if(!primarySegments[0])primarySegments.shift()}if(primarySegments.length===0)return"_";const lowerRuleApplied=[];const processedPrimarySegments=primarySegments.map((primarySeg,primaryIdx)=>{const parts=primarySeg.split(/(_+)/);const processedParts=parts.map((part,partIdx)=>{if(partIdx%2===1)return part;if(!part)return part;const cleanSeg=part.replace(/[^A-Za-z0-9_$]/g,"");const config={preserveAllUpper,preserveAllLower,leaveRules,leaveInsensitiveRules,upperRules,lowerRules};const result2=this.#applySegmentRules(cleanSeg,0,originalString,config);const matchesLower=lowerRules.some(pattern=>{if(pattern.includes("*")||pattern.includes("?")){const regex=this.#compileGlobPattern(pattern,false);if(regex&&regex.test(originalString)){const literals=this.#extractPatternLiterals(pattern);for(const literal of literals){const cleanLiteral=literal.replace(/[^A-Za-z0-9_$]/g,"").replace(/^_+|_+$/g,"");if(cleanLiteral&&cleanSeg.toLowerCase()===cleanLiteral.toLowerCase()){return true}}}}else{if(cleanSeg.toLowerCase()===pattern.toLowerCase()){return true}}return false});if(matchesLower&&result2===cleanSeg.toLowerCase()){lowerRuleApplied[primaryIdx]=true}return result2});return processedParts.join("")});const camelCasedSegments=processedPrimarySegments.map((seg,idx)=>{const matchesLeave=this.#matchesAnyPattern(seg,leaveRules,true);const matchesLeaveInsensitive=this.#matchesAnyPattern(seg,leaveInsensitiveRules,false);const matchesUpper=this.#matchesAnyPattern(seg,upperRules,false);const hasUnderscores=seg.includes("_");const isAllUpper2=!hasUnderscores&&preserveAllUpper&&seg===seg.toUpperCase()&&seg!==seg.toLowerCase()&&/[A-Z]/.test(seg);const isAllLower2=!hasUnderscores&&preserveAllLower&&seg===seg.toLowerCase()&&seg!==seg.toUpperCase()&&/[a-z]/.test(seg);if(matchesLeave||matchesLeaveInsensitive||matchesUpper||isAllUpper2||isAllLower2){return seg}let transformed;if(idx===0){transformed=lowerFirst?seg[0].toLowerCase()+seg.slice(1):seg}else{if(lowerRuleApplied[idx]){transformed=seg}else{transformed=seg[0].toUpperCase()+seg.slice(1)}}return transformed});let result=camelCasedSegments.join("");result=result.replace(/[^A-Za-z0-9_$]/g,"");return result}getModuleId(filePath,baseDir){let relative=filePath.replace(baseDir,"").replace(/\\/g,"/");relative=relative.replace(/^\//,"");relative=relative.replace(/\.(mjs|cjs|js)$/,"");return relative}shouldPreserveFunctionCase(name){const preservePatterns=[/^[A-Z]{2,}$/,/[A-Z]{2,}/];return preservePatterns.some(pattern=>pattern.test(name))}}function sanitizePropertyName(input,options={}){const sanitizer=new Sanitize(null);return sanitizer.sanitizePropertyName(input,options)}export{Sanitize,sanitizePropertyName};
17
+ import{ComponentBase}from"#factories/component-base";class Sanitize extends ComponentBase{static slothletProperty="sanitize";#compileGlobPattern(pattern,caseSensitive=true){if(pattern.startsWith("**")&&pattern.endsWith("**")&&pattern.length>4){const innerString=pattern.slice(2,-2);const escapedString=innerString.replace(/[.+^${}()|[\]\\*?]/g,"\\$&");const flags2=caseSensitive?"":"i";return new RegExp(`(?<=.)${escapedString}(?=.)`,flags2)}const regexPattern=pattern.replace(/[.+^${}()|[\]\\]/g,"\\$&").replace(/\*/g,".*").replace(/\?/g,".");const flags=caseSensitive?"":"i";return new RegExp(`^${regexPattern}$`,flags)}#matchesAnyPattern(input,patterns,caseSensitive=false){for(const pattern of patterns){if(pattern.includes("*")||pattern.includes("?")){const regex=this.#compileGlobPattern(pattern,caseSensitive);if(regex&&regex.test(input))return true}else{const match=caseSensitive?input===pattern:input.toLowerCase()===pattern.toLowerCase();if(match)return true}}return false}#extractPatternLiterals(pattern){return pattern.split(/[*?]+/).filter(Boolean)}#applySegmentRules(segment,index,originalString,config){const{preserveAllUpper,preserveAllLower,leaveRules,leaveInsensitiveRules,upperRules,lowerRules}=config;if(this.#matchesAnyPattern(segment,leaveRules,true)){return segment}if(this.#matchesAnyPattern(segment,leaveInsensitiveRules,false)){return segment}if(preserveAllUpper&&segment===segment.toUpperCase()&&segment!==segment.toLowerCase()&&/[A-Z]/.test(segment)){return segment}if(preserveAllLower&&segment===segment.toLowerCase()&&segment!==segment.toUpperCase()&&/[a-z]/.test(segment)){return segment}for(const pattern of[...upperRules,...lowerRules]){if(pattern.includes("*")||pattern.includes("?")){const regex=this.#compileGlobPattern(pattern,false);if(regex&&regex.test(originalString)){const literals=this.#extractPatternLiterals(pattern);for(const literal of literals){const cleanLiteral=literal.replace(/[^A-Za-z0-9_$]/g,"").replace(/^_+|_+$/g,"");if(cleanLiteral&&segment.toLowerCase()===cleanLiteral.toLowerCase()){return upperRules.includes(pattern)?segment.toUpperCase():segment.toLowerCase()}}}}else{if(segment.toLowerCase()===pattern.toLowerCase()){return upperRules.includes(pattern)?segment.toUpperCase():segment.toLowerCase()}}}let transformed=this.#applyWithinSegmentPatterns(segment,upperRules,lowerRules);if(transformed!==segment){return transformed}return segment}#applyWithinSegmentPatterns(segment,upperRules,lowerRules){let result=segment;const applyBoundaryPattern=(pattern,toUpper)=>{if(pattern.startsWith("**")&&pattern.endsWith("**")&&pattern.length>4){const innerString=pattern.slice(2,-2);const innerRegex=new RegExp(innerString.replace(/[.+^${}()|[\]\\*?]/g,"\\$&"),"gi");const matches=[...result.matchAll(innerRegex)];for(const match of matches){const startPos=match.index;const endPos=startPos+match[0].length;const hasCharBefore=startPos>0;const hasCharAfter=endPos<result.length;if(hasCharBefore&&hasCharAfter){const replacement=toUpper?innerString.toUpperCase():innerString.toLowerCase();result=result.substring(0,startPos)+replacement+result.substring(endPos);break}}}else if(pattern.includes("*")&&!pattern.startsWith("**")){const literalParts=pattern.split("*").filter(Boolean);for(const literal of literalParts){const literalRegex=new RegExp(literal.replace(/[.+^${}()|[\]\\]/g,"\\$&"),"gi");const replacement=toUpper?literal.toUpperCase():literal.toLowerCase();result=result.replace(literalRegex,replacement)}}};upperRules.forEach(pattern=>applyBoundaryPattern(pattern,true));lowerRules.forEach(pattern=>applyBoundaryPattern(pattern,false));return result}sanitizePropertyName(input,options={}){const{lowerFirst=true,preserveAllUpper=false,preserveAllLower=false,rules={}}=options;const leaveRules=(rules.leave||[]).map(s=>String(s));const leaveInsensitiveRules=(rules.leaveInsensitive||[]).map(s=>String(s));const upperRules=(rules.upper||[]).map(s=>String(s));const lowerRules=(rules.lower||[]).map(s=>String(s));const originalString=String(input).trim();const isAllUpper=originalString===originalString.toUpperCase()&&originalString!==originalString.toLowerCase()&&/[A-Z]/.test(originalString);const isAllLower=originalString===originalString.toLowerCase()&&originalString!==originalString.toUpperCase()&&/[a-z]/.test(originalString);if(preserveAllUpper&&isAllUpper){return originalString}if(preserveAllLower&&isAllLower&&!/-/.test(originalString)){return originalString}let primarySegments=originalString.split(/[-]+|[^A-Za-z0-9_$]+/).filter(Boolean);if(primarySegments.length===0)return"_";while(primarySegments.length&&!/^[A-Za-z_$]/.test(primarySegments[0][0])){primarySegments[0]=primarySegments[0].replace(/^[^A-Za-z_$]+/,"");if(!primarySegments[0])primarySegments.shift()}if(primarySegments.length===0)return"_";const lowerRuleApplied=[];const processedPrimarySegments=primarySegments.map((primarySeg,primaryIdx)=>{const parts=primarySeg.split(/(_+)/);const processedParts=parts.map((part,partIdx)=>{if(partIdx%2===1)return part;if(!part)return part;const cleanSeg=part.replace(/[^A-Za-z0-9_$]/g,"");const config={preserveAllUpper,preserveAllLower,leaveRules,leaveInsensitiveRules,upperRules,lowerRules};const result2=this.#applySegmentRules(cleanSeg,0,originalString,config);const matchesLower=lowerRules.some(pattern=>{if(pattern.includes("*")||pattern.includes("?")){const regex=this.#compileGlobPattern(pattern,false);if(regex&&regex.test(originalString)){const literals=this.#extractPatternLiterals(pattern);for(const literal of literals){const cleanLiteral=literal.replace(/[^A-Za-z0-9_$]/g,"").replace(/^_+|_+$/g,"");if(cleanLiteral&&cleanSeg.toLowerCase()===cleanLiteral.toLowerCase()){return true}}}}else{if(cleanSeg.toLowerCase()===pattern.toLowerCase()){return true}}return false});if(matchesLower&&result2===cleanSeg.toLowerCase()){lowerRuleApplied[primaryIdx]=true}return result2});return processedParts.join("")});const camelCasedSegments=processedPrimarySegments.map((seg,idx)=>{const matchesLeave=this.#matchesAnyPattern(seg,leaveRules,true);const matchesLeaveInsensitive=this.#matchesAnyPattern(seg,leaveInsensitiveRules,false);const matchesUpper=this.#matchesAnyPattern(seg,upperRules,false);const hasUnderscores=seg.includes("_");const isAllUpper2=!hasUnderscores&&preserveAllUpper&&seg===seg.toUpperCase()&&seg!==seg.toLowerCase()&&/[A-Z]/.test(seg);const isAllLower2=!hasUnderscores&&preserveAllLower&&seg===seg.toLowerCase()&&seg!==seg.toUpperCase()&&/[a-z]/.test(seg);if(matchesLeave||matchesLeaveInsensitive||matchesUpper||isAllUpper2||isAllLower2){return seg}let transformed;if(idx===0){transformed=lowerFirst?seg[0].toLowerCase()+seg.slice(1):seg}else{if(lowerRuleApplied[idx]){transformed=seg}else{transformed=seg[0].toUpperCase()+seg.slice(1)}}return transformed});let result=camelCasedSegments.join("");result=result.replace(/[^A-Za-z0-9_$]/g,"");return result}getModuleId(filePath,baseDir){let relative=filePath.replace(baseDir,"").replace(/\\/g,"/");relative=relative.replace(/^\//,"");relative=relative.replace(/\.(mjs|cjs|js)$/,"");return relative}shouldPreserveFunctionCase(name){const preservePatterns=[/^[A-Z]{2,}$/,/[A-Z]{2,}/];return preservePatterns.some(pattern=>pattern.test(name))}}function sanitizePropertyName(input,options={}){const sanitizer=new Sanitize(null);return sanitizer.sanitizePropertyName(input,options)}export{Sanitize,sanitizePropertyName};
@@ -14,4 +14,4 @@
14
14
  limitations under the License.
15
15
  */
16
16
 
17
- import{ComponentBase}from"@cldmv/slothlet/factories/component-base";class Utilities extends ComponentBase{static slothletProperty="utilities";isPlainObject(obj){if(typeof obj!=="object"||obj===null)return false;const proto=Object.getPrototypeOf(obj);return proto===null||proto===Object.prototype}deepMerge(target,source){if(!this.isPlainObject(target)||!this.isPlainObject(source)){return source}const result={...target};for(const key in source){if(Object.prototype.hasOwnProperty.call(source,key)){if(this.isPlainObject(source[key])){result[key]=this.deepMerge(this.isPlainObject(target[key])?target[key]:{},source[key])}else{result[key]=source[key]}}}return result}deepClone(obj){try{return structuredClone(obj)}catch{const objType=obj?.__type||typeof obj;if(obj===null||objType!=="object"&&objType!=="function")return obj;if(obj instanceof Date)return new Date(obj.getTime());if(Array.isArray(obj))return obj.map(item=>this.deepClone(item));const cloned={};for(const key in obj){try{cloned[key]=this.deepClone(obj[key])}catch{cloned[key]=obj[key]}}return cloned}}generateId(){return`slothlet_${Date.now()}_${Math.random().toString(36).substr(2,9)}`}}export{Utilities};
17
+ import{ComponentBase}from"#factories/component-base";class Utilities extends ComponentBase{static slothletProperty="utilities";isPlainObject(obj){if(typeof obj!=="object"||obj===null)return false;const proto=Object.getPrototypeOf(obj);return proto===null||proto===Object.prototype}deepMerge(target,source){if(!this.isPlainObject(target)||!this.isPlainObject(source)){return source}const result={...target};for(const key in source){if(Object.prototype.hasOwnProperty.call(source,key)){if(this.isPlainObject(source[key])){result[key]=this.deepMerge(this.isPlainObject(target[key])?target[key]:{},source[key])}else{result[key]=source[key]}}}return result}deepClone(obj){try{return structuredClone(obj)}catch{const objType=obj?.__type||typeof obj;if(obj===null||objType!=="object"&&objType!=="function")return obj;if(obj instanceof Date)return new Date(obj.getTime());if(Array.isArray(obj))return obj.map(item=>this.deepClone(item));const cloned={};for(const key in obj){try{cloned[key]=this.deepClone(obj[key])}catch{cloned[key]=obj[key]}}return cloned}}generateId(){return`slothlet_${Date.now()}_${Math.random().toString(36).substr(2,9)}`}}export{Utilities};
@@ -462,7 +462,12 @@
462
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
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
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."
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.",
466
+ "CONTEXT_KEY_PROTECTED": "Context key '{key}' is owner-locked; '{writer}' cannot write it (owner: {owner}).",
467
+ "CONTEXT_KEY_OWNED": "Context key '{key}' is already owned and cannot be re-claimed by a nested scope.",
468
+ "SCOPE_INVALID_PROTECT": "'protect' must be an array of string keys. Received: {received}.",
469
+ "SCOPE_INVALID_OWNERS": "'owners' must be a plain object mapping keys to owner names. Received: {received}.",
470
+ "PERMISSION_SEALED": "The permission control surface is sealed; policy can no longer be modified."
466
471
  },
467
472
  "metadata": {
468
473
  "code": "en-us",
@@ -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,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};
17
+ import{ComponentBase}from"#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};
@@ -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,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};
17
+ import{ComponentBase}from"#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";class Flatten extends ComponentBase{static slothletProperty="flatten";constructor(slothlet){super(slothlet)}#checkSelfReferential(mod,moduleName){if(!mod||typeof mod!=="object")return false;return mod[moduleName]===mod}async#checkMultiDefault(analysis,hasMultipleDefaults,t){if(!hasMultipleDefaults)return null;if(analysis.hasDefault){return{preserveAsNamespace:true,reason:await t("FLATTEN_REASON_MULTI_DEFAULT_WITH_DEFAULT")}}return{flattenToRoot:true,reason:await t("FLATTEN_REASON_MULTI_DEFAULT_WITHOUT_DEFAULT")}}#checkAutoFlatten(mod,moduleName,moduleKeys){if(moduleKeys.length!==1)return false;return moduleKeys[0]===moduleName}async getFlatteningDecision(options){const{mod,moduleName,categoryName,analysis,hasMultipleDefaults,moduleKeys,t}=options;const isAddapiFile=moduleName==="addapi";if(isAddapiFile){if(analysis.hasDefault&&analysis.defaultExportType==="object"&&moduleKeys.length>0){return{flattenToCategory:true,flattenType:"addapi-metadata-default",reason:await t("FLATTEN_REASON_ADDAPI_METADATA_DEFAULT")}}return{flattenToCategory:true,flattenType:"addapi-special-file",reason:await t("FLATTEN_REASON_ADDAPI_SPECIAL_FILE")}}if(this.#checkSelfReferential(mod,moduleName)){return{preserveAsNamespace:true,reason:await t("FLATTEN_REASON_SELF_REFERENTIAL")}}const multiDefaultDecision=await this.#checkMultiDefault(analysis,hasMultipleDefaults,t);if(multiDefaultDecision){if(multiDefaultDecision.preserveAsNamespace){const exportToCheck2=typeof mod==="function"?mod:mod?.default&&typeof mod.default==="function"?mod.default:null;if(exportToCheck2&&exportToCheck2.name&&exportToCheck2.name!=="default"){const normalizedFunctionName=exportToCheck2.name.toLowerCase().replace(/[-_]/g,"");const normalizedModuleName=moduleName.toLowerCase().replace(/[-_]/g,"");if(normalizedFunctionName===normalizedModuleName){multiDefaultDecision.preferredName=exportToCheck2.name}}}return multiDefaultDecision}if(this.#checkAutoFlatten(mod,moduleName,moduleKeys)){return{useAutoFlattening:true,reason:await t("FLATTEN_REASON_SINGLE_EXPORT_MATCHES_FILENAME")}}if(moduleName===categoryName){return{flattenToCategory:true,reason:await t("FLATTEN_REASON_FILENAME_MATCHES_CATEGORY")}}const exportToCheck=typeof mod==="function"?mod:mod?.default&&typeof mod.default==="function"?mod.default:null;if(exportToCheck&&exportToCheck.name&&exportToCheck.name!=="default"){const normalizedFunctionName=exportToCheck.name.toLowerCase().replace(/[-_]/g,"");const normalizedModuleName=moduleName.toLowerCase().replace(/[-_]/g,"");const functionNameMatchesFilename=normalizedFunctionName===normalizedModuleName;if(functionNameMatchesFilename){return{preserveAsNamespace:true,preferredName:exportToCheck.name,reason:await t("FLATTEN_REASON_PRESERVING_FUNCTION_NAME")}}}return{preserveAsNamespace:true,reason:await t("FLATTEN_REASON_DEFAULT_PRESERVE_NAMESPACE")}}processModuleForAPI(options){const{mod,decision,moduleName,propertyName,moduleKeys,analysis,file=null,collisionContext="initial",apiPathPrefix="",isSelfReferential=false}=options;const isAddapiFile=moduleName==="addapi"||file&&file.name==="addapi"||file&&file.fullName&&["addapi.mjs","addapi.cjs","addapi.js","addapi.ts"].includes(file.fullName.toLowerCase());if(isAddapiFile&&analysis.hasDefault&&moduleKeys.length>0){const moduleContent2=mod.default;for(const key of moduleKeys){moduleContent2[key]=mod[key]}return{moduleContent:moduleContent2}}if(decision.useAutoFlattening){return{moduleContent:mod[moduleName]}}if(decision.flattenToRoot||decision.flattenToCategory){if(mod.default&&moduleKeys.length===0){return{moduleContent:mod.default}}if(mod.default&&moduleKeys.length>0){const moduleContent3=typeof mod.default==="function"?mod.default:{...mod.default};for(const key of moduleKeys){moduleContent3[key]=mod[key]}return{moduleContent:moduleContent3}}const moduleContent2={};for(const key of moduleKeys){moduleContent2[key]=mod[key]}return{moduleContent:moduleContent2}}if(isSelfReferential){return{moduleContent:mod[moduleName]||mod}}if(mod.default&&moduleKeys.length>0){if(typeof mod.default==="function"){const moduleContent3=this.slothlet.helpers.modesUtils.ensureNamedExportFunction(mod.default,propertyName);const collisionConfig=this.slothlet.config.api?.collision||this.slothlet.config.collision;const collisionMode=collisionContext==="initial"?collisionConfig.initial:collisionConfig.api;for(const key of moduleKeys){if(!this.shouldAttachNamedExport(key,mod[key],moduleContent3,mod.default)){continue}const hasExisting=Object.prototype.hasOwnProperty.call(moduleContent3,key);if(hasExisting){if(collisionMode==="merge"||collisionMode==="skip"){continue}else if(collisionMode==="error"){throw new this.slothlet.SlothletError("COLLISION_DEFAULT_EXPORT_ERROR",{key,apiPath:`${apiPathPrefix}.${propertyName}`},null,{validationError:true})}else if(collisionMode==="warn"){new this.slothlet.SlothletWarning("WARNING_COLLISION_DEFAULT_EXPORT_OVERWRITE",{key,apiPath:`${apiPathPrefix}.${propertyName}`})}}moduleContent3[key]=mod[key]}return{moduleContent:moduleContent3}}if(typeof mod.default==="object"&&mod.default!==null){const moduleContent3=mod.default;for(const key of moduleKeys){if(key in mod.default){continue}if(!this.shouldAttachNamedExport(key,mod[key],moduleContent3,mod.default)){continue}moduleContent3[key]=mod[key]}return{moduleContent:moduleContent3}}const moduleContent2={default:mod.default};for(const key of moduleKeys){moduleContent2[key]=mod[key]}return{moduleContent:moduleContent2}}if(mod.default&&moduleKeys.length===0){return{moduleContent:this.slothlet.helpers.modesUtils.ensureNamedExportFunction(mod.default,propertyName)}}const moduleContent={};for(const key of moduleKeys){moduleContent[key]=mod[key]}return{moduleContent}}async buildCategoryDecisions(options){const{categoryName,mod,moduleName,fileBaseName,analysis,moduleKeys,currentDepth,moduleFiles=[],t}=options;const decision={shouldFlatten:false,flattenType:"preserve",preferredName:null,reason:await t("FLATTEN_REASON_NO_CONDITIONS_MET")};const isAddapiFile=moduleName==="addapi"||fileBaseName==="addapi"||fileBaseName&&["addapi.mjs","addapi.cjs","addapi.js","addapi.ts"].includes(fileBaseName.toLowerCase());if(isAddapiFile){if(analysis.hasDefault&&analysis.defaultExportType==="object"&&moduleKeys.length>0){return{shouldFlatten:true,flattenType:"addapi-metadata-default",reason:await t("FLATTEN_REASON_ADDAPI_SPECIAL_FILE_PARENT")}}return{shouldFlatten:true,flattenType:"addapi-special-file",reason:await t("FLATTEN_REASON_ADDAPI_SPECIAL_FILE")}}if(moduleName===categoryName&&typeof mod==="function"&&currentDepth>0){return{shouldFlatten:true,flattenType:"function-folder-match",reason:await t("FLATTEN_REASON_FUNCTION_FOLDER_MATCH")}}if(analysis.hasDefault&&analysis.defaultExportType==="object"&&moduleName===categoryName&&currentDepth>0){return{shouldFlatten:true,flattenType:"default-export-flatten",reason:await t("FLATTEN_REASON_DEFAULT_OBJECT_EXPORT_FLATTEN")}}if(moduleName===categoryName&&mod&&typeof mod==="object"&&!Array.isArray(mod)&&currentDepth>0){if(moduleKeys.length===1&&moduleKeys[0]===moduleName){return{shouldFlatten:true,flattenType:"object-auto-flatten",reason:await t("FLATTEN_REASON_SINGLE_EXPORT_MATCHES_FILENAME")}}}if(fileBaseName===categoryName&&moduleKeys.length>0){return{shouldFlatten:true,flattenType:"filename-folder-match-flatten",reason:await t("FLATTEN_REASON_BASENAME_MATCHES_CATEGORY")}}if(moduleFiles.length===1&&currentDepth>0&&mod&&typeof mod==="object"&&!Array.isArray(mod)){const genericFilenames=["singlefile","index","main","default"];const isGenericFilename=genericFilenames.includes(moduleName.toLowerCase());if(moduleKeys.length===1&&isGenericFilename){return{shouldFlatten:true,flattenType:"parent-level-flatten",reason:await t("FLATTEN_REASON_GENERIC_FILENAME_SINGLE_EXPORT")}}}if(typeof mod==="function"&&mod.name&&currentDepth>0){const functionNameMatchesFolder=mod.name.toLowerCase()===categoryName.toLowerCase()||mod.name.toLowerCase().replace(/[-_]/g,"")===categoryName.toLowerCase().replace(/[-_]/g,"");if(functionNameMatchesFolder){return{shouldFlatten:true,flattenType:"function-folder-match",preferredName:mod.name,reason:await t("FLATTEN_REASON_FUNCTION_FOLDER_MATCH")}}}const exportToCheck=typeof mod==="function"?mod:mod?.default&&typeof mod.default==="function"?mod.default:null;if(exportToCheck&&exportToCheck.name&&exportToCheck.name!=="default"){const normalizedFunctionName=exportToCheck.name.toLowerCase().replace(/[-_]/g,"");const normalizedModuleName=moduleName.toLowerCase().replace(/[-_]/g,"");const functionNameMatchesFilename=normalizedFunctionName===normalizedModuleName;if(functionNameMatchesFilename){return{shouldFlatten:false,preferredName:exportToCheck.name,reason:await t("FLATTEN_REASON_PRESERVING_FUNCTION_NAME")}}}if(typeof mod==="function"&&(!mod.name||mod.name==="default"||mod.__slothletDefault===true)&&currentDepth>0){return{shouldFlatten:true,flattenType:"default-function",preferredName:categoryName,reason:await t("FLATTEN_REASON_DEFAULT_FUNCTION_EXPORT")}}if(moduleKeys.length===1&&moduleKeys[0]===moduleName){return{shouldFlatten:true,flattenType:"object-auto-flatten",preferredName:moduleName,reason:await t("FLATTEN_REASON_SINGLE_EXPORT_MATCHES_MODULE")}}return decision}shouldAttachNamedExport(key,value,defaultFunc,originalDefault){if(!key||key==="default"){return false}if(value===defaultFunc||value===originalDefault){return false}if(typeof defaultFunc==="function"&&key===defaultFunc.name){return false}if(typeof originalDefault==="function"&&key===originalDefault.name){return false}return true}}export{Flatten};
17
+ import{ComponentBase}from"#factories/component-base";class Flatten extends ComponentBase{static slothletProperty="flatten";constructor(slothlet){super(slothlet)}#checkSelfReferential(mod,moduleName){if(!mod||typeof mod!=="object")return false;return mod[moduleName]===mod}async#checkMultiDefault(analysis,hasMultipleDefaults,t){if(!hasMultipleDefaults)return null;if(analysis.hasDefault){return{preserveAsNamespace:true,reason:await t("FLATTEN_REASON_MULTI_DEFAULT_WITH_DEFAULT")}}return{flattenToRoot:true,reason:await t("FLATTEN_REASON_MULTI_DEFAULT_WITHOUT_DEFAULT")}}#checkAutoFlatten(mod,moduleName,moduleKeys){if(moduleKeys.length!==1)return false;return moduleKeys[0]===moduleName}async getFlatteningDecision(options){const{mod,moduleName,categoryName,analysis,hasMultipleDefaults,moduleKeys,t}=options;const isAddapiFile=moduleName==="addapi";if(isAddapiFile){if(analysis.hasDefault&&analysis.defaultExportType==="object"&&moduleKeys.length>0){return{flattenToCategory:true,flattenType:"addapi-metadata-default",reason:await t("FLATTEN_REASON_ADDAPI_METADATA_DEFAULT")}}return{flattenToCategory:true,flattenType:"addapi-special-file",reason:await t("FLATTEN_REASON_ADDAPI_SPECIAL_FILE")}}if(this.#checkSelfReferential(mod,moduleName)){return{preserveAsNamespace:true,reason:await t("FLATTEN_REASON_SELF_REFERENTIAL")}}const multiDefaultDecision=await this.#checkMultiDefault(analysis,hasMultipleDefaults,t);if(multiDefaultDecision){if(multiDefaultDecision.preserveAsNamespace){const exportToCheck2=typeof mod==="function"?mod:mod?.default&&typeof mod.default==="function"?mod.default:null;if(exportToCheck2&&exportToCheck2.name&&exportToCheck2.name!=="default"){const normalizedFunctionName=exportToCheck2.name.toLowerCase().replace(/[-_]/g,"");const normalizedModuleName=moduleName.toLowerCase().replace(/[-_]/g,"");if(normalizedFunctionName===normalizedModuleName){multiDefaultDecision.preferredName=exportToCheck2.name}}}return multiDefaultDecision}if(this.#checkAutoFlatten(mod,moduleName,moduleKeys)){return{useAutoFlattening:true,reason:await t("FLATTEN_REASON_SINGLE_EXPORT_MATCHES_FILENAME")}}if(moduleName===categoryName){return{flattenToCategory:true,reason:await t("FLATTEN_REASON_FILENAME_MATCHES_CATEGORY")}}const exportToCheck=typeof mod==="function"?mod:mod?.default&&typeof mod.default==="function"?mod.default:null;if(exportToCheck&&exportToCheck.name&&exportToCheck.name!=="default"){const normalizedFunctionName=exportToCheck.name.toLowerCase().replace(/[-_]/g,"");const normalizedModuleName=moduleName.toLowerCase().replace(/[-_]/g,"");const functionNameMatchesFilename=normalizedFunctionName===normalizedModuleName;if(functionNameMatchesFilename){return{preserveAsNamespace:true,preferredName:exportToCheck.name,reason:await t("FLATTEN_REASON_PRESERVING_FUNCTION_NAME")}}}return{preserveAsNamespace:true,reason:await t("FLATTEN_REASON_DEFAULT_PRESERVE_NAMESPACE")}}processModuleForAPI(options){const{mod,decision,moduleName,propertyName,moduleKeys,analysis,file=null,collisionContext="initial",apiPathPrefix="",isSelfReferential=false}=options;const isAddapiFile=moduleName==="addapi"||file&&file.name==="addapi"||file&&file.fullName&&["addapi.mjs","addapi.cjs","addapi.js","addapi.ts"].includes(file.fullName.toLowerCase());if(isAddapiFile&&analysis.hasDefault&&moduleKeys.length>0){const moduleContent2=mod.default;for(const key of moduleKeys){moduleContent2[key]=mod[key]}return{moduleContent:moduleContent2}}if(decision.useAutoFlattening){return{moduleContent:mod[moduleName]}}if(decision.flattenToRoot||decision.flattenToCategory){if(mod.default&&moduleKeys.length===0){return{moduleContent:mod.default}}if(mod.default&&moduleKeys.length>0){const moduleContent3=typeof mod.default==="function"?mod.default:{...mod.default};for(const key of moduleKeys){moduleContent3[key]=mod[key]}return{moduleContent:moduleContent3}}const moduleContent2={};for(const key of moduleKeys){moduleContent2[key]=mod[key]}return{moduleContent:moduleContent2}}if(isSelfReferential){return{moduleContent:mod[moduleName]||mod}}if(mod.default&&moduleKeys.length>0){if(typeof mod.default==="function"){const moduleContent3=this.slothlet.helpers.modesUtils.ensureNamedExportFunction(mod.default,propertyName);const collisionConfig=this.slothlet.config.api?.collision||this.slothlet.config.collision;const collisionMode=collisionContext==="initial"?collisionConfig.initial:collisionConfig.api;for(const key of moduleKeys){if(!this.shouldAttachNamedExport(key,mod[key],moduleContent3,mod.default)){continue}const hasExisting=Object.prototype.hasOwnProperty.call(moduleContent3,key);if(hasExisting){if(collisionMode==="merge"||collisionMode==="skip"){continue}else if(collisionMode==="error"){throw new this.slothlet.SlothletError("COLLISION_DEFAULT_EXPORT_ERROR",{key,apiPath:`${apiPathPrefix}.${propertyName}`},null,{validationError:true})}else if(collisionMode==="warn"){new this.slothlet.SlothletWarning("WARNING_COLLISION_DEFAULT_EXPORT_OVERWRITE",{key,apiPath:`${apiPathPrefix}.${propertyName}`})}}moduleContent3[key]=mod[key]}return{moduleContent:moduleContent3}}if(typeof mod.default==="object"&&mod.default!==null){const moduleContent3=mod.default;for(const key of moduleKeys){if(key in mod.default){continue}if(!this.shouldAttachNamedExport(key,mod[key],moduleContent3,mod.default)){continue}moduleContent3[key]=mod[key]}return{moduleContent:moduleContent3}}const moduleContent2={default:mod.default};for(const key of moduleKeys){moduleContent2[key]=mod[key]}return{moduleContent:moduleContent2}}if(mod.default&&moduleKeys.length===0){return{moduleContent:this.slothlet.helpers.modesUtils.ensureNamedExportFunction(mod.default,propertyName)}}const moduleContent={};for(const key of moduleKeys){moduleContent[key]=mod[key]}return{moduleContent}}async buildCategoryDecisions(options){const{categoryName,mod,moduleName,fileBaseName,analysis,moduleKeys,currentDepth,moduleFiles=[],t}=options;const decision={shouldFlatten:false,flattenType:"preserve",preferredName:null,reason:await t("FLATTEN_REASON_NO_CONDITIONS_MET")};const isAddapiFile=moduleName==="addapi"||fileBaseName==="addapi"||fileBaseName&&["addapi.mjs","addapi.cjs","addapi.js","addapi.ts"].includes(fileBaseName.toLowerCase());if(isAddapiFile){if(analysis.hasDefault&&analysis.defaultExportType==="object"&&moduleKeys.length>0){return{shouldFlatten:true,flattenType:"addapi-metadata-default",reason:await t("FLATTEN_REASON_ADDAPI_SPECIAL_FILE_PARENT")}}return{shouldFlatten:true,flattenType:"addapi-special-file",reason:await t("FLATTEN_REASON_ADDAPI_SPECIAL_FILE")}}if(moduleName===categoryName&&typeof mod==="function"&&currentDepth>0){return{shouldFlatten:true,flattenType:"function-folder-match",reason:await t("FLATTEN_REASON_FUNCTION_FOLDER_MATCH")}}if(analysis.hasDefault&&analysis.defaultExportType==="object"&&moduleName===categoryName&&currentDepth>0){return{shouldFlatten:true,flattenType:"default-export-flatten",reason:await t("FLATTEN_REASON_DEFAULT_OBJECT_EXPORT_FLATTEN")}}if(moduleName===categoryName&&mod&&typeof mod==="object"&&!Array.isArray(mod)&&currentDepth>0){if(moduleKeys.length===1&&moduleKeys[0]===moduleName){return{shouldFlatten:true,flattenType:"object-auto-flatten",reason:await t("FLATTEN_REASON_SINGLE_EXPORT_MATCHES_FILENAME")}}}if(fileBaseName===categoryName&&moduleKeys.length>0){return{shouldFlatten:true,flattenType:"filename-folder-match-flatten",reason:await t("FLATTEN_REASON_BASENAME_MATCHES_CATEGORY")}}if(moduleFiles.length===1&&currentDepth>0&&mod&&typeof mod==="object"&&!Array.isArray(mod)){const genericFilenames=["singlefile","index","main","default"];const isGenericFilename=genericFilenames.includes(moduleName.toLowerCase());if(moduleKeys.length===1&&isGenericFilename){return{shouldFlatten:true,flattenType:"parent-level-flatten",reason:await t("FLATTEN_REASON_GENERIC_FILENAME_SINGLE_EXPORT")}}}if(typeof mod==="function"&&mod.name&&currentDepth>0){const functionNameMatchesFolder=mod.name.toLowerCase()===categoryName.toLowerCase()||mod.name.toLowerCase().replace(/[-_]/g,"")===categoryName.toLowerCase().replace(/[-_]/g,"");if(functionNameMatchesFolder){return{shouldFlatten:true,flattenType:"function-folder-match",preferredName:mod.name,reason:await t("FLATTEN_REASON_FUNCTION_FOLDER_MATCH")}}}const exportToCheck=typeof mod==="function"?mod:mod?.default&&typeof mod.default==="function"?mod.default:null;if(exportToCheck&&exportToCheck.name&&exportToCheck.name!=="default"){const normalizedFunctionName=exportToCheck.name.toLowerCase().replace(/[-_]/g,"");const normalizedModuleName=moduleName.toLowerCase().replace(/[-_]/g,"");const functionNameMatchesFilename=normalizedFunctionName===normalizedModuleName;if(functionNameMatchesFilename){return{shouldFlatten:false,preferredName:exportToCheck.name,reason:await t("FLATTEN_REASON_PRESERVING_FUNCTION_NAME")}}}if(typeof mod==="function"&&(!mod.name||mod.name==="default"||mod.__slothletDefault===true)&&currentDepth>0){return{shouldFlatten:true,flattenType:"default-function",preferredName:categoryName,reason:await t("FLATTEN_REASON_DEFAULT_FUNCTION_EXPORT")}}if(moduleKeys.length===1&&moduleKeys[0]===moduleName){return{shouldFlatten:true,flattenType:"object-auto-flatten",preferredName:moduleName,reason:await t("FLATTEN_REASON_SINGLE_EXPORT_MATCHES_MODULE")}}return decision}shouldAttachNamedExport(key,value,defaultFunc,originalDefault){if(!key||key==="default"){return false}if(value===defaultFunc||value===originalDefault){return false}if(typeof defaultFunc==="function"&&key===defaultFunc.name){return false}if(typeof originalDefault==="function"&&key===originalDefault.name){return false}return true}}export{Flatten};
@@ -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";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&&currentDepth<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};
17
+ import{ComponentBase}from"#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&&currentDepth<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&&!this.____config?.silent){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};
@@ -14,4 +14,4 @@
14
14
  limitations under the License.
15
15
  */
16
16
 
17
- import{asyncRuntime}from"@cldmv/slothlet/factories/context";import{SlothletError}from"@cldmv/slothlet/errors";function safeGetContext(){try{return asyncRuntime.getContext()}catch{return null}}const self=new Proxy({},{get(_,prop){const ctx=safeGetContext();if(!ctx||!ctx.self){throw new SlothletError("RUNTIME_NO_ACTIVE_CONTEXT_SELF",{},null,{validationError:true})}return ctx.self[prop]},ownKeys(){const ctx=safeGetContext();if(!ctx||!ctx.self)return[];return Reflect.ownKeys(ctx.self)},has(_,prop){const ctx=safeGetContext();if(!ctx||!ctx.self)return false;return prop in ctx.self},getOwnPropertyDescriptor(_,prop){const ctx=safeGetContext();if(!ctx||!ctx.self)return void 0;const desc=Reflect.getOwnPropertyDescriptor(ctx.self,prop);if(desc){return{...desc,configurable:true}}return void 0},set(_,prop,value){const ctx=safeGetContext();if(!ctx||!ctx.self){throw new SlothletError("RUNTIME_NO_ACTIVE_CONTEXT_SELF",{},null,{validationError:true})}if(typeof prop==="symbol"){ctx.self[prop]=value;return true}if(ctx.slothlet?.boundApi&&ctx.self!==ctx.slothlet.boundApi){ctx.self[prop]=value;return true}const apiManager=ctx.slothlet?.handlers?.apiManager;if(apiManager&&typeof apiManager.setOwnedProperty==="function"){apiManager.setOwnedProperty(String(prop),value,ctx.currentWrapper??null)}else{ctx.self[prop]=value}return true}});const context=new Proxy({},{get(_,prop){const ctx=safeGetContext();if(!ctx||!ctx.context){return void 0}return ctx.context[prop]},set(_,prop,value){const ctx=safeGetContext();if(!ctx||!ctx.context){throw new SlothletError("RUNTIME_NO_ACTIVE_CONTEXT_CONTEXT",{},null,{validationError:true})}ctx.context[prop]=value;return true},ownKeys(){const ctx=safeGetContext();if(!ctx||!ctx.context)return[];return Reflect.ownKeys(ctx.context)},has(_,prop){const ctx=safeGetContext();if(!ctx||!ctx.context)return false;return prop in ctx.context},getOwnPropertyDescriptor(_,prop){const ctx=safeGetContext();if(!ctx||!ctx.context)return void 0;return Reflect.getOwnPropertyDescriptor(ctx.context,prop)}});const instanceID=new Proxy({},{get(_,prop){const ctx=safeGetContext();if(!ctx||!ctx.instanceID){return void 0}if(prop===Symbol.toPrimitive||prop==="toString"||prop==="valueOf"){return()=>ctx.instanceID}return ctx.instanceID[prop]},has(_,prop){const ctx=safeGetContext();if(!ctx||!ctx.instanceID)return false;return prop in Object(ctx.instanceID)}});export{context,instanceID,self};
17
+ import{asyncRuntime}from"#factories/context";import{SlothletError}from"@cldmv/slothlet/errors";import{enforceContextKeyWrite,readProtectedContextValue}from"#handlers/trusted-root";function safeGetContext(){try{return asyncRuntime.getContext()}catch{return null}}const self=new Proxy({},{get(_,prop){const ctx=safeGetContext();if(!ctx||!ctx.self){throw new SlothletError("RUNTIME_NO_ACTIVE_CONTEXT_SELF",{},null,{validationError:true})}return ctx.self[prop]},ownKeys(){const ctx=safeGetContext();if(!ctx||!ctx.self)return[];return Reflect.ownKeys(ctx.self)},has(_,prop){const ctx=safeGetContext();if(!ctx||!ctx.self)return false;return prop in ctx.self},getOwnPropertyDescriptor(_,prop){const ctx=safeGetContext();if(!ctx||!ctx.self)return void 0;const desc=Reflect.getOwnPropertyDescriptor(ctx.self,prop);if(desc){return{...desc,configurable:true}}return void 0},set(_,prop,value){const ctx=safeGetContext();if(!ctx||!ctx.self){throw new SlothletError("RUNTIME_NO_ACTIVE_CONTEXT_SELF",{},null,{validationError:true})}if(typeof prop==="symbol"){ctx.self[prop]=value;return true}if(ctx.slothlet?.boundApi&&ctx.self!==ctx.slothlet.boundApi){ctx.self[prop]=value;return true}const apiManager=ctx.slothlet?.handlers?.apiManager;if(apiManager&&typeof apiManager.setOwnedProperty==="function"){apiManager.setOwnedProperty(String(prop),value,ctx.currentWrapper??null)}else{ctx.self[prop]=value}return true}});const context=new Proxy({},{get(_,prop){const ctx=safeGetContext();if(!ctx||!ctx.context){return void 0}return readProtectedContextValue(ctx,prop,safeGetContext)},set(_,prop,value){const ctx=safeGetContext();if(!ctx||!ctx.context){throw new SlothletError("RUNTIME_NO_ACTIVE_CONTEXT_CONTEXT",{},null,{validationError:true})}enforceContextKeyWrite(ctx,prop);ctx.context[prop]=value;return true},ownKeys(){const ctx=safeGetContext();if(!ctx||!ctx.context)return[];return Reflect.ownKeys(ctx.context)},has(_,prop){const ctx=safeGetContext();if(!ctx||!ctx.context)return false;return prop in ctx.context},getOwnPropertyDescriptor(_,prop){const ctx=safeGetContext();if(!ctx||!ctx.context)return void 0;return Reflect.getOwnPropertyDescriptor(ctx.context,prop)}});const instanceID=new Proxy({},{get(_,prop){const ctx=safeGetContext();if(!ctx||!ctx.instanceID){return void 0}if(prop===Symbol.toPrimitive||prop==="toString"||prop==="valueOf"){return()=>ctx.instanceID}return ctx.instanceID[prop]},has(_,prop){const ctx=safeGetContext();if(!ctx||!ctx.instanceID)return false;return prop in Object(ctx.instanceID)}});export{context,instanceID,self};
@@ -14,4 +14,4 @@
14
14
  limitations under the License.
15
15
  */
16
16
 
17
- import{liveRuntime}from"@cldmv/slothlet/factories/context";import{SlothletError}from"@cldmv/slothlet/errors";const self=new Proxy({},{get(_,prop){const ctx=liveRuntime.getContext();if(!ctx||!ctx.self){throw new SlothletError("RUNTIME_NO_ACTIVE_CONTEXT_SELF",{},null,{validationError:true})}return ctx.self[prop]},ownKeys(){const ctx=liveRuntime.getContext();if(!ctx||!ctx.self)return[];return Reflect.ownKeys(ctx.self)},has(_,prop){const ctx=liveRuntime.getContext();if(!ctx||!ctx.self)return false;return prop in ctx.self},getOwnPropertyDescriptor(_,prop){const ctx=liveRuntime.getContext();if(!ctx||!ctx.self)return void 0;const desc=Reflect.getOwnPropertyDescriptor(ctx.self,prop);if(desc){return{...desc,configurable:true}}return void 0},set(_,prop,value){const ctx=liveRuntime.getContext();if(!ctx||!ctx.self){throw new SlothletError("RUNTIME_NO_ACTIVE_CONTEXT_SELF",{},null,{validationError:true})}if(typeof prop==="symbol"){ctx.self[prop]=value;return true}if(ctx.slothlet?.boundApi&&ctx.self!==ctx.slothlet.boundApi){ctx.self[prop]=value;return true}const apiManager=ctx.slothlet?.handlers?.apiManager;if(apiManager&&typeof apiManager.setOwnedProperty==="function"){apiManager.setOwnedProperty(String(prop),value,ctx.currentWrapper??null)}else{ctx.self[prop]=value}return true}});const context=new Proxy({},{get(_,prop){const ctx=liveRuntime.getContext();if(!ctx||!ctx.context){return void 0}return ctx.context[prop]},set(_,prop,value){const ctx=liveRuntime.getContext();if(!ctx||!ctx.context){throw new SlothletError("RUNTIME_NO_ACTIVE_CONTEXT_CONTEXT",{},null,{validationError:true})}ctx.context[prop]=value;return true},ownKeys(){const ctx=liveRuntime.getContext();if(!ctx||!ctx.context)return[];return Reflect.ownKeys(ctx.context)},has(_,prop){const ctx=liveRuntime.getContext();if(!ctx||!ctx.context)return false;return prop in ctx.context},getOwnPropertyDescriptor(_,prop){const ctx=liveRuntime.getContext();if(!ctx||!ctx.context)return void 0;return Reflect.getOwnPropertyDescriptor(ctx.context,prop)}});export{context,self};
17
+ import{liveRuntime}from"#factories/context";import{SlothletError}from"@cldmv/slothlet/errors";import{enforceContextKeyWrite,readProtectedContextValue}from"#handlers/trusted-root";const resolveActiveContext=()=>liveRuntime.getContext();const self=new Proxy({},{get(_,prop){const ctx=liveRuntime.getContext();if(!ctx||!ctx.self){throw new SlothletError("RUNTIME_NO_ACTIVE_CONTEXT_SELF",{},null,{validationError:true})}return ctx.self[prop]},ownKeys(){const ctx=liveRuntime.getContext();if(!ctx||!ctx.self)return[];return Reflect.ownKeys(ctx.self)},has(_,prop){const ctx=liveRuntime.getContext();if(!ctx||!ctx.self)return false;return prop in ctx.self},getOwnPropertyDescriptor(_,prop){const ctx=liveRuntime.getContext();if(!ctx||!ctx.self)return void 0;const desc=Reflect.getOwnPropertyDescriptor(ctx.self,prop);if(desc){return{...desc,configurable:true}}return void 0},set(_,prop,value){const ctx=liveRuntime.getContext();if(!ctx||!ctx.self){throw new SlothletError("RUNTIME_NO_ACTIVE_CONTEXT_SELF",{},null,{validationError:true})}if(typeof prop==="symbol"){ctx.self[prop]=value;return true}if(ctx.slothlet?.boundApi&&ctx.self!==ctx.slothlet.boundApi){ctx.self[prop]=value;return true}const apiManager=ctx.slothlet?.handlers?.apiManager;if(apiManager&&typeof apiManager.setOwnedProperty==="function"){apiManager.setOwnedProperty(String(prop),value,ctx.currentWrapper??null)}else{ctx.self[prop]=value}return true}});const context=new Proxy({},{get(_,prop){const ctx=liveRuntime.getContext();if(!ctx||!ctx.context){return void 0}return readProtectedContextValue(ctx,prop,resolveActiveContext)},set(_,prop,value){const ctx=liveRuntime.getContext();if(!ctx||!ctx.context){throw new SlothletError("RUNTIME_NO_ACTIVE_CONTEXT_CONTEXT",{},null,{validationError:true})}enforceContextKeyWrite(ctx,prop);ctx.context[prop]=value;return true},ownKeys(){const ctx=liveRuntime.getContext();if(!ctx||!ctx.context)return[];return Reflect.ownKeys(ctx.context)},has(_,prop){const ctx=liveRuntime.getContext();if(!ctx||!ctx.context)return false;return prop in ctx.context},getOwnPropertyDescriptor(_,prop){const ctx=liveRuntime.getContext();if(!ctx||!ctx.context)return void 0;return Reflect.getOwnPropertyDescriptor(ctx.context,prop)}});export{context,self};
@@ -14,4 +14,4 @@
14
14
  limitations under the License.
15
15
  */
16
16
 
17
- import{asyncRuntime,liveRuntime}from"@cldmv/slothlet/factories/context";const asyncRuntimeModule=await import("@cldmv/slothlet/runtime/async");const liveRuntimeModule=await import("@cldmv/slothlet/runtime/live");function getCurrentRuntime(){const asyncCtx=asyncRuntime.tryGetContext();if(asyncCtx){return asyncRuntimeModule}const liveCtx=liveRuntime.tryGetContext();if(liveCtx){return liveRuntimeModule}return asyncRuntimeModule}const self=new Proxy({},{get(_,prop){const runtime=getCurrentRuntime();return runtime.self[prop]},ownKeys(){const runtime=getCurrentRuntime();return Reflect.ownKeys(runtime.self)},has(_,prop){const runtime=getCurrentRuntime();return prop in runtime.self},getOwnPropertyDescriptor(_,prop){const runtime=getCurrentRuntime();const desc=Reflect.getOwnPropertyDescriptor(runtime.self,prop);if(desc){return{...desc,configurable:true}}return void 0},set(_,prop,value){const runtime=getCurrentRuntime();runtime.self[prop]=value;return true}});const context=new Proxy({},{get(_,prop){const runtime=getCurrentRuntime();return runtime.context[prop]},ownKeys(){const runtime=getCurrentRuntime();return Reflect.ownKeys(runtime.context)},has(_,prop){const runtime=getCurrentRuntime();return prop in runtime.context},getOwnPropertyDescriptor(_,prop){const runtime=getCurrentRuntime();return Reflect.getOwnPropertyDescriptor(runtime.context,prop)},set(_,prop,value){const runtime=getCurrentRuntime();runtime.context[prop]=value;return true}});const instanceID=new Proxy({},{get(_,prop){const runtime=getCurrentRuntime();return runtime.instanceID?runtime.instanceID[prop]:void 0},has(_,prop){const runtime=getCurrentRuntime();return runtime.instanceID?prop in runtime.instanceID:false}});export{context,instanceID,self};
17
+ import{asyncRuntime,liveRuntime}from"#factories/context";const asyncRuntimeModule=await import("@cldmv/slothlet/runtime/async");const liveRuntimeModule=await import("@cldmv/slothlet/runtime/live");function getCurrentRuntime(){const asyncCtx=asyncRuntime.tryGetContext();if(asyncCtx){return asyncRuntimeModule}const liveCtx=liveRuntime.tryGetContext();if(liveCtx){return liveRuntimeModule}return asyncRuntimeModule}const self=new Proxy({},{get(_,prop){const runtime=getCurrentRuntime();return runtime.self[prop]},ownKeys(){const runtime=getCurrentRuntime();return Reflect.ownKeys(runtime.self)},has(_,prop){const runtime=getCurrentRuntime();return prop in runtime.self},getOwnPropertyDescriptor(_,prop){const runtime=getCurrentRuntime();const desc=Reflect.getOwnPropertyDescriptor(runtime.self,prop);if(desc){return{...desc,configurable:true}}return void 0},set(_,prop,value){const runtime=getCurrentRuntime();runtime.self[prop]=value;return true}});const context=new Proxy({},{get(_,prop){const runtime=getCurrentRuntime();return runtime.context[prop]},ownKeys(){const runtime=getCurrentRuntime();return Reflect.ownKeys(runtime.context)},has(_,prop){const runtime=getCurrentRuntime();return prop in runtime.context},getOwnPropertyDescriptor(_,prop){const runtime=getCurrentRuntime();return Reflect.getOwnPropertyDescriptor(runtime.context,prop)},set(_,prop,value){const runtime=getCurrentRuntime();runtime.context[prop]=value;return true}});const instanceID=new Proxy({},{get(_,prop){const runtime=getCurrentRuntime();return runtime.instanceID?runtime.instanceID[prop]:void 0},has(_,prop){const runtime=getCurrentRuntime();return runtime.instanceID?prop in runtime.instanceID:false}});export{context,instanceID,self};
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)}`;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};
17
+ import{isNode,fs,fsp,path,url,createRequire}from"@cldmv/slothlet/helpers/platform";import{getContextManager}from"#factories/context";import{SlothletError,SlothletWarning,SlothletDebug}from"@cldmv/slothlet/errors";import{registerInstance}from"#handlers/lifecycle-token";import{resolveWrapper}from"#handlers/unified-wrapper";import{TRUSTED_ROOT}from"#handlers/trusted-root";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","#handlers/api-cache-manager","#handlers/api-manager","#handlers/hook-manager","#handlers/lifecycle","#handlers/materialize-manager","#handlers/metadata","#handlers/module-manager","#handlers/ownership","#handlers/permission-manager","#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=specifier.startsWith("#")?parts[0].slice(1):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)}}}_setupConfigLifecycleSubscribers(){const map=this.config.lifecycle;if(!map){return}const lifecycle=this.handlers.lifecycle;for(const[event,handler]of Object.entries(map)){const handlers=Array.isArray(handler)?handler:[handler];for(const fn of handlers){lifecycle.subscribe(event,fn)}}}_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);this._setupConfigLifecycleSubscribers();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)}Object.defineProperty(store,TRUSTED_ROOT,{value:true,configurable:true});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?.();const wasSealed=this.handlers.permissionManager?.isSealed?.()===true;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)}}}}if(wasSealed)this.handlers.permissionManager?.seal?.();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 _collectLifecycleHooks(kind){if(!this.api)return[];const hooks=[];const seen=new Set;const collect=async(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){if(wrapper.____slothletInternal.mode==="lazy"&&!wrapper.____slothletInternal.state.materialized){try{await wrapper._materialize()}catch{return}}if(wrapper.____slothletInternal.mode!=="lazy"||wrapper.____slothletInternal.state.materialized){const hook=obj[kind];if(typeof hook==="function"){hooks.push({apiPath:wrapper.____slothletInternal.apiPath,fn:hook,receiver:obj})}}for(const key of Object.keys(wrapper)){if(!key.startsWith("____"))await collect(wrapper[key],depth+1)}return}for(const key of Object.keys(obj)){await collect(obj[key],depth+1)}}catch{}};for(const key of Object.keys(this.api)){if(key==="slothlet"||key==="shutdown"||key==="destroy"||key.startsWith("____"))continue;await collect(this.api[key])}return hooks}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};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cldmv/slothlet",
3
- "version": "3.11.1",
3
+ "version": "3.12.1",
4
4
  "moduleVersions": {
5
5
  "lazy": "3.0.0",
6
6
  "eager": "3.0.0",
@@ -97,14 +97,6 @@
97
97
  "types": "./types/stub/lib/builders/*.d.mts",
98
98
  "import": "./dist/lib/builders/*.mjs"
99
99
  },
100
- "./handlers/*": {
101
- "slothlet-dev": {
102
- "types": "./types/src/lib/handlers/*.d.mts",
103
- "import": "./src/lib/handlers/*.mjs"
104
- },
105
- "types": "./types/stub/lib/handlers/*.d.mts",
106
- "import": "./dist/lib/handlers/*.mjs"
107
- },
108
100
  "./processors/*": {
109
101
  "slothlet-dev": {
110
102
  "types": "./types/src/lib/processors/*.d.mts",
@@ -113,14 +105,6 @@
113
105
  "types": "./types/stub/lib/processors/*.d.mts",
114
106
  "import": "./dist/lib/processors/*.mjs"
115
107
  },
116
- "./factories/*": {
117
- "slothlet-dev": {
118
- "types": "./types/src/lib/factories/*.d.mts",
119
- "import": "./src/lib/factories/*.mjs"
120
- },
121
- "types": "./types/stub/lib/factories/*.d.mts",
122
- "import": "./dist/lib/factories/*.mjs"
123
- },
124
108
  "./errors": {
125
109
  "slothlet-dev": {
126
110
  "types": "./types/src/lib/errors.d.mts",
@@ -143,6 +127,24 @@
143
127
  },
144
128
  "./schemas/slothlet.module.schema.json": "./schemas/slothlet.module.schema.json"
145
129
  },
130
+ "imports": {
131
+ "#handlers/*": {
132
+ "slothlet-dev": {
133
+ "types": "./types/src/lib/handlers/*.d.mts",
134
+ "import": "./src/lib/handlers/*.mjs"
135
+ },
136
+ "types": "./types/stub/lib/handlers/*.d.mts",
137
+ "import": "./dist/lib/handlers/*.mjs"
138
+ },
139
+ "#factories/*": {
140
+ "slothlet-dev": {
141
+ "types": "./types/src/lib/factories/*.d.mts",
142
+ "import": "./src/lib/factories/*.mjs"
143
+ },
144
+ "types": "./types/stub/lib/factories/*.d.mts",
145
+ "import": "./dist/lib/factories/*.mjs"
146
+ }
147
+ },
146
148
  "types": "./types/stub/index.d.mts",
147
149
  "scripts": {
148
150
  "precommit": "node tools/dev/precommit-validation.mjs",
@@ -311,32 +313,32 @@
311
313
  },
312
314
  "devDependencies": {
313
315
  "@cldmv/fix-headers": "^1.3.0",
314
- "@cldmv/vitest-runner": "^1.1.0",
315
- "@eslint/css": "^1.1.0",
316
+ "@cldmv/vitest-runner": "^1.2.0",
317
+ "@eslint/css": "^1.4.0",
316
318
  "@eslint/js": "^10.0.1",
317
- "@eslint/json": "^2.0.0",
318
- "@eslint/markdown": "^8.0.1",
319
- "@types/node": "^25.6.0",
320
- "@vitest/browser": "^4.1.8",
321
- "@vitest/browser-playwright": "^4.1.8",
322
- "@vitest/coverage-v8": "^4.1.8",
323
- "acorn": "^8.16.0",
319
+ "@eslint/json": "^2.0.1",
320
+ "@eslint/markdown": "^8.0.3",
321
+ "@types/node": "^26.1.1",
322
+ "@vitest/browser": "^4.1.10",
323
+ "@vitest/browser-playwright": "^4.1.10",
324
+ "@vitest/coverage-v8": "^4.1.10",
325
+ "acorn": "^8.17.0",
324
326
  "chalk": "^5.6.2",
325
327
  "chokidar": "^5.0.0",
326
328
  "dmd": "^7.1.1",
327
- "esbuild": "^0.28.0",
328
- "eslint": "^10.2.1",
329
+ "esbuild": "^0.28.1",
330
+ "eslint": "^10.7.0",
329
331
  "estree-walker": "^3.0.3",
330
- "globals": "^17.5.0",
332
+ "globals": "^17.7.0",
331
333
  "jsdoc": "^4.0.5",
332
334
  "jsdoc-to-markdown": "^9.1.3",
333
335
  "jsdoc2md": "^1.0.0",
334
336
  "jsonc-parser": "^3.3.1",
335
- "playwright": "^1.60.0",
336
- "prettier": "^3.8.3",
337
+ "playwright": "^1.61.1",
338
+ "prettier": "^3.9.5",
337
339
  "shx": "^0.4.0",
338
340
  "typescript": "^6.0.3",
339
- "vitest": "^4.1.8"
341
+ "vitest": "^4.1.10"
340
342
  },
341
343
  "optionalDependencies": {
342
344
  "@rolldown/binding-linux-x64-gnu": "1.0.3"
@@ -355,6 +357,7 @@
355
357
  "files": [
356
358
  "index.mjs",
357
359
  "index.cjs",
360
+ "devcheck.mjs",
358
361
  "README.md",
359
362
  "REFERENCE.md",
360
363
  "LICENSE",
@@ -1,3 +0,0 @@
1
- // AUTO-GENERATED by tools/build/build-typestubs.mjs — do not edit.
2
- // Re-exports the real declarations from @cldmv/slothlet-types (install it for TypeScript support).
3
- export * from "@cldmv/slothlet-types/factories/component-base";
@@ -1,3 +0,0 @@
1
- // AUTO-GENERATED by tools/build/build-typestubs.mjs — do not edit.
2
- // Re-exports the real declarations from @cldmv/slothlet-types (install it for TypeScript support).
3
- export * from "@cldmv/slothlet-types/factories/context";
@@ -1,3 +0,0 @@
1
- // AUTO-GENERATED by tools/build/build-typestubs.mjs — do not edit.
2
- // Re-exports the real declarations from @cldmv/slothlet-types (install it for TypeScript support).
3
- export * from "@cldmv/slothlet-types/handlers/api-cache-manager";
@@ -1,3 +0,0 @@
1
- // AUTO-GENERATED by tools/build/build-typestubs.mjs — do not edit.
2
- // Re-exports the real declarations from @cldmv/slothlet-types (install it for TypeScript support).
3
- export * from "@cldmv/slothlet-types/handlers/api-manager";
@@ -1,3 +0,0 @@
1
- // AUTO-GENERATED by tools/build/build-typestubs.mjs — do not edit.
2
- // Re-exports the real declarations from @cldmv/slothlet-types (install it for TypeScript support).
3
- export * from "@cldmv/slothlet-types/handlers/context-async";
@@ -1,3 +0,0 @@
1
- // AUTO-GENERATED by tools/build/build-typestubs.mjs — do not edit.
2
- // Re-exports the real declarations from @cldmv/slothlet-types (install it for TypeScript support).
3
- export * from "@cldmv/slothlet-types/handlers/context-live";
@@ -1,3 +0,0 @@
1
- // AUTO-GENERATED by tools/build/build-typestubs.mjs — do not edit.
2
- // Re-exports the real declarations from @cldmv/slothlet-types (install it for TypeScript support).
3
- export * from "@cldmv/slothlet-types/handlers/hook-manager";
@@ -1,3 +0,0 @@
1
- // AUTO-GENERATED by tools/build/build-typestubs.mjs — do not edit.
2
- // Re-exports the real declarations from @cldmv/slothlet-types (install it for TypeScript support).
3
- export * from "@cldmv/slothlet-types/handlers/lifecycle-token";
@@ -1,3 +0,0 @@
1
- // AUTO-GENERATED by tools/build/build-typestubs.mjs — do not edit.
2
- // Re-exports the real declarations from @cldmv/slothlet-types (install it for TypeScript support).
3
- export * from "@cldmv/slothlet-types/handlers/lifecycle";
@@ -1,3 +0,0 @@
1
- // AUTO-GENERATED by tools/build/build-typestubs.mjs — do not edit.
2
- // Re-exports the real declarations from @cldmv/slothlet-types (install it for TypeScript support).
3
- export * from "@cldmv/slothlet-types/handlers/materialize-manager";
@@ -1,3 +0,0 @@
1
- // AUTO-GENERATED by tools/build/build-typestubs.mjs — do not edit.
2
- // Re-exports the real declarations from @cldmv/slothlet-types (install it for TypeScript support).
3
- export * from "@cldmv/slothlet-types/handlers/metadata";
@@ -1,3 +0,0 @@
1
- // AUTO-GENERATED by tools/build/build-typestubs.mjs — do not edit.
2
- // Re-exports the real declarations from @cldmv/slothlet-types (install it for TypeScript support).
3
- export * from "@cldmv/slothlet-types/handlers/module-manager";
@@ -1,3 +0,0 @@
1
- // AUTO-GENERATED by tools/build/build-typestubs.mjs — do not edit.
2
- // Re-exports the real declarations from @cldmv/slothlet-types (install it for TypeScript support).
3
- export * from "@cldmv/slothlet-types/handlers/ownership";
@@ -1,3 +0,0 @@
1
- // AUTO-GENERATED by tools/build/build-typestubs.mjs — do not edit.
2
- // Re-exports the real declarations from @cldmv/slothlet-types (install it for TypeScript support).
3
- export * from "@cldmv/slothlet-types/handlers/permission-manager";
@@ -1,3 +0,0 @@
1
- // AUTO-GENERATED by tools/build/build-typestubs.mjs — do not edit.
2
- // Re-exports the real declarations from @cldmv/slothlet-types (install it for TypeScript support).
3
- export * from "@cldmv/slothlet-types/handlers/unified-wrapper";
@@ -1,3 +0,0 @@
1
- // AUTO-GENERATED by tools/build/build-typestubs.mjs — do not edit.
2
- // Re-exports the real declarations from @cldmv/slothlet-types (install it for TypeScript support).
3
- export * from "@cldmv/slothlet-types/handlers/version-manager";