@cldmv/slothlet 3.12.1 → 3.12.3

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.
@@ -0,0 +1,17 @@
1
+ /*
2
+ Copyright 2026 CLDMV/Shinrai
3
+
4
+ Licensed under the Apache License, Version 2.0 (the "License");
5
+ you may not use this file except in compliance with the License.
6
+ You may obtain a copy of the License at
7
+
8
+ http://www.apache.org/licenses/LICENSE-2.0
9
+
10
+ Unless required by applicable law or agreed to in writing, software
11
+ distributed under the License is distributed on an "AS IS" BASIS,
12
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ See the License for the specific language governing permissions and
14
+ limitations under the License.
15
+ */
16
+
17
+ import{pinToCurrentCaller}from"@cldmv/slothlet/helpers/caller-pinning";const patched=[];let isPatchingEnabled=false;function runtime_carryOwnExtras(wrapper,original){for(const key of Object.getOwnPropertySymbols(original)){const descriptor=Object.getOwnPropertyDescriptor(original,key);if(!descriptor)continue;Object.defineProperty(wrapper,key,descriptor)}for(const key of Object.keys(original)){wrapper[key]=original[key]}}function runtime_patchScheduler(host,name){const original=host?.[name];if(typeof original!=="function")return;const wrapper=function(callback,...rest){if(typeof callback!=="function")return original.call(host,callback,...rest);return original.call(host,pinToCurrentCaller(callback),...rest)};runtime_carryOwnExtras(wrapper,original);host[name]=wrapper;patched.push({host,name,original,wrapper})}function enableSchedulerPatching(){if(isPatchingEnabled)return;runtime_patchScheduler(globalThis,"setTimeout");runtime_patchScheduler(globalThis,"setInterval");runtime_patchScheduler(globalThis,"setImmediate");runtime_patchScheduler(globalThis,"queueMicrotask");runtime_patchScheduler(globalThis.process,"nextTick");isPatchingEnabled=true}function disableSchedulerPatching(){if(!isPatchingEnabled)return;for(const{host,name,original,wrapper}of patched){if(host[name]===wrapper)host[name]=original}patched.length=0;isPatchingEnabled=false}export{disableSchedulerPatching,enableSchedulerPatching};
@@ -14,4 +14,4 @@
14
14
  limitations under the License.
15
15
  */
16
16
 
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};
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,rootUnwrap=false}){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,null,rootUnwrap);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"#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,rootUnwrap=false}){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,rootUnwrap);return modesProcessor.applyRootContributor(api,rootDefaultFunction,"lazy")}}export{LazyMode};
@@ -14,4 +14,4 @@
14
14
  limitations under the License.
15
15
  */
16
16
 
17
- import fs from"fs";import path from"path";import{SlothletError}from"@cldmv/slothlet/errors";let typescriptInstance=null;async function getTypeScript(){if(!typescriptInstance){try{typescriptInstance=await import("typescript")}catch(error){throw new SlothletError("TYPESCRIPT_NOT_INSTALLED",{feature:"type-generation"},error)}}return typescriptInstance}async function generateTypes(api,options){const ts=await getTypeScript();if(!options.output){throw new SlothletError("INVALID_CONFIG",{option:"types.output",expected:"a string output path",value:options.output,hint:"Provide a string output path for the generated .d.ts file, e.g. './types/api.d.ts'.",validationError:true})}if(!options.interfaceName){throw new SlothletError("INVALID_CONFIG",{option:"types.interfaceName",expected:"a string interface name",value:options.interfaceName,hint:"Provide a string interface name for the generated TypeScript interface, e.g. 'SlothletAPI'.",validationError:true})}const nodes=traverseAPI(api);for(const node of nodes){if(node.metadata?.filePath){node.typeInfo=await extractTypesFromFile(node.metadata.filePath,ts)}}const declaration=generateDeclaration(nodes,options);const outputPath=path.resolve(options.output);const outputDir=path.dirname(outputPath);fs.mkdirSync(outputDir,{recursive:true});fs.writeFileSync(outputPath,declaration,"utf8");return{output:declaration,filePath:outputPath}}function traverseAPI(api,currentPath=[],visited=new Set){const nodes=[];if(!api||typeof api!=="object"){return nodes}if(visited.has(api)){return nodes}visited.add(api);for(const[key,value]of Object.entries(api)){if(key.startsWith("_")||key.startsWith("__")||key==="slothlet"||key==="shutdown"||key==="destroy"){continue}const nodePath=[...currentPath,key];const metadata=value?.__metadata;if(typeof value==="function"){nodes.push({type:"function",path:nodePath,value,metadata})}else if(typeof value==="object"&&value!==null){nodes.push({type:"object",path:nodePath,value,metadata});const childNodes=traverseAPI(value,nodePath,visited);nodes.push(...childNodes)}}return nodes}async function extractTypesFromFile(filePath,ts){try{let visit=function(node){if(ts.isFunctionDeclaration(node)&&node.name){const hasExport=node.modifiers?.some(m=>m.kind===ts.SyntaxKind.ExportKeyword);if(hasExport){exports.push({name:node.name.text,type:"function",signature:extractFunctionSignature(node,source,ts)})}}if(ts.isVariableStatement(node)){const hasExport=node.modifiers?.some(m=>m.kind===ts.SyntaxKind.ExportKeyword);if(hasExport){for(const decl of node.declarationList.declarations){if(!decl.name||!ts.isIdentifier(decl.name))continue;const init=decl.initializer;if(!init)continue;if(ts.isArrowFunction(init)||ts.isFunctionExpression(init)){exports.push({name:decl.name.text,type:"function",signature:extractFunctionSignature(init,source,ts)})}}}}ts.forEachChild(node,visit)};const source=fs.readFileSync(filePath,"utf8");const sourceFile=ts.createSourceFile(filePath,source,ts.ScriptTarget.Latest,true);const exports=[];visit(sourceFile);return{exports,sourceFile}}catch(____error){return{exports:[]}}}function extractFunctionSignature(node,____source,____ts){const params=node.parameters.map(p=>{const name=p.name.getText(node.getSourceFile());const type=p.type?p.type.getText(node.getSourceFile()):"any";return`${name}: ${type}`}).join(", ");const returnType=node.type?node.type.getText(node.getSourceFile()):"any";return`(${params}): ${returnType}`}function generateDeclaration(nodes,options){const interfaceName=options.interfaceName;const lines=[];lines.push("/**");lines.push(` * Generated TypeScript declarations for Slothlet API`);lines.push(` * @generated ${new Date().toISOString()}`);lines.push(" */");lines.push("");const structure={};for(const node of nodes){if(node.type==="function"){const fnName=node.path[node.path.length-1];const exportInfo=node.typeInfo?.exports?.find(e=>e.name===fnName);const signature=exportInfo?.signature??"(...args: any[]): any";setNestedProperty(structure,node.path,{type:"function",signature})}}lines.push(`export interface ${interfaceName} {`);generateInterfaceContent(structure,lines,1);lines.push("}");lines.push("");lines.push(`declare const self: ${interfaceName};`);lines.push("");return lines.join("\n")}function setNestedProperty(obj,path2,value){let current=obj;for(let i=0;i<path2.length-1;i++){const key=path2[i];if(!current[key]){current[key]={}}current=current[key]}const lastKey=path2[path2.length-1];current[lastKey]=value}function generateInterfaceContent(structure,lines,indent){const indentation=" ".repeat(indent);for(const[key,value]of Object.entries(structure)){if(value.type==="function"){lines.push(`${indentation}${key}${value.signature};`)}else if(typeof value==="object"&&value!==null){lines.push(`${indentation}${key}: {`);generateInterfaceContent(value,lines,indent+1);lines.push(`${indentation}};`)}else{}}}export{generateTypes};
17
+ import fs from"fs";import path from"path";import{SlothletError}from"@cldmv/slothlet/errors";let typescriptInstance=null;async function getTypeScript(){if(!typescriptInstance){try{typescriptInstance=await import("typescript")}catch(error){throw new SlothletError("TYPESCRIPT_NOT_INSTALLED",{feature:"type-generation"},error)}}return typescriptInstance}async function generateTypes(api,options){const ts=await getTypeScript();if(!options.output){throw new SlothletError("INVALID_CONFIG",{option:"types.output",expected:"a string output path",value:options.output,hint:"Provide a string output path for the generated .d.ts file, e.g. './types/api.d.ts'.",validationError:true})}if(!options.interfaceName){throw new SlothletError("INVALID_CONFIG",{option:"types.interfaceName",expected:"a string interface name",value:options.interfaceName,hint:"Provide a string interface name for the generated TypeScript interface, e.g. 'SlothletAPI'.",validationError:true})}const nodes=traverseAPI(api);const filePaths=[...new Set(nodes.map(node=>node.metadata?.filePath).filter(Boolean))];const{byFile:exportsByFile,localTypes}=extractTypeInfo(filePaths,ts);for(const node of nodes){if(node.metadata?.filePath){node.typeInfo=exportsByFile.get(node.metadata.filePath)}}const declaration=generateDeclaration(nodes,options,localTypes);const outputPath=path.resolve(options.output);const outputDir=path.dirname(outputPath);fs.mkdirSync(outputDir,{recursive:true});fs.writeFileSync(outputPath,declaration,"utf8");return{output:declaration,filePath:outputPath}}function traverseAPI(api,currentPath=[],visited=new Set){const nodes=[];if(!api||typeof api!=="object"){return nodes}if(visited.has(api)){return nodes}visited.add(api);for(const[key,value]of Object.entries(api)){if(key.startsWith("_")||key.startsWith("__")||key==="slothlet"||key==="shutdown"||key==="destroy"){continue}const nodePath=[...currentPath,key];const metadata=value?.__metadata;if(typeof value==="function"){nodes.push({type:"function",path:nodePath,value,metadata})}else if(typeof value==="object"&&value!==null){nodes.push({type:"object",path:nodePath,value,metadata});const childNodes=traverseAPI(value,nodePath,visited);nodes.push(...childNodes)}}return nodes}function extractTypeInfo(filePaths,ts){const byFile=new Map;const program=ts.createProgram(filePaths,{allowJs:true,checkJs:false,declaration:true,emitDeclarationOnly:true,skipLibCheck:true,target:ts.ScriptTarget.Latest,module:ts.ModuleKind.ESNext,moduleResolution:ts.ModuleResolutionKind.Bundler});const checker=program.getTypeChecker();const isExported=node=>node.modifiers?.some(m=>m.kind===ts.SyntaxKind.ExportKeyword);const candidates=new Map;program.emit(void 0,(____fileName,text)=>{const dts=ts.createSourceFile("emitted.d.ts",text,ts.ScriptTarget.Latest,false,ts.ScriptKind.TS);for(const stmt of dts.statements){if(ts.isInterfaceDeclaration(stmt)||ts.isTypeAliasDeclaration(stmt)||ts.isEnumDeclaration(stmt)){candidates.set(stmt.name.text,stmt.getText(dts))}}},void 0,true);for(const filePath of filePaths){const exportsForFile=[];try{const visit=node=>{if(ts.isFunctionDeclaration(node)&&node.name&&isExported(node)){exportsForFile.push({name:node.name.text,type:"function",signature:signatureText(node,checker,ts)})}else if(ts.isVariableStatement(node)&&isExported(node)){for(const decl of node.declarationList.declarations){const init=decl.initializer;if(ts.isIdentifier(decl.name)&&init&&(ts.isArrowFunction(init)||ts.isFunctionExpression(init))){exportsForFile.push({name:decl.name.text,type:"function",signature:signatureText(init,checker,ts)})}}}ts.forEachChild(node,visit)};const sourceFile=program.getSourceFile(filePath);if(sourceFile){visit(sourceFile)}}catch(____error){}byFile.set(filePath,{exports:exportsForFile})}const localTypes=collectReferencedLocalTypes(candidates,byFile);return{byFile,localTypes}}function collectReferencedLocalTypes(candidates,byFile){const referenced=new Map;if(candidates.size===0)return referenced;const wholeWord=name=>new RegExp(`\\b${name.replace(/[.*+?^${}()|[\]\\]/g,"\\$&")}\\b`);const signatureBlob=[];for(const{exports}of byFile.values()){for(const e of exports)signatureBlob.push(e.signature)}const haystack=signatureBlob.join("\n");const consider=name=>{if(referenced.has(name))return;const text=candidates.get(name);referenced.set(name,text);for(const other of candidates.keys()){if(wholeWord(other).test(text))consider(other)}};for(const name of candidates.keys()){if(wholeWord(name).test(haystack))consider(name)}return referenced}function signatureText(fnNode,checker,ts){const signature=checker.getSignatureFromDeclaration(fnNode);return checker.signatureToString(signature,fnNode,ts.TypeFormatFlags.NoTruncation)}function generateDeclaration(nodes,options,localTypes){const interfaceName=options.interfaceName;const lines=[];lines.push("/**");lines.push(` * Generated TypeScript declarations for Slothlet API`);lines.push(` * @generated ${new Date().toISOString()}`);lines.push(" */");lines.push("");if(localTypes.size>0){for(const text of localTypes.values()){lines.push(text)}lines.push("")}const structure={};for(const node of nodes){if(node.type==="function"){const fnName=node.path[node.path.length-1];const exportInfo=node.typeInfo?.exports?.find(e=>e.name===fnName);const signature=exportInfo?.signature??"(...args: any[]): any";setNestedProperty(structure,node.path,{type:"function",signature})}}lines.push(`export interface ${interfaceName} {`);generateInterfaceContent(structure,lines,1);lines.push("}");lines.push("");lines.push(`declare const self: ${interfaceName};`);lines.push("");return lines.join("\n")}function setNestedProperty(obj,path2,value){let current=obj;for(let i=0;i<path2.length-1;i++){const key=path2[i];if(!current[key]){current[key]={}}current=current[key]}const lastKey=path2[path2.length-1];current[lastKey]=value}function generateInterfaceContent(structure,lines,indent){const indentation=" ".repeat(indent);for(const[key,value]of Object.entries(structure)){if(value.type==="function"){lines.push(`${indentation}${key}${value.signature};`)}else if(typeof value==="object"&&value!==null){lines.push(`${indentation}${key}: {`);generateInterfaceContent(value,lines,indent+1);lines.push(`${indentation}};`)}else{}}}export{generateTypes};
@@ -14,4 +14,4 @@
14
14
  limitations under the License.
15
15
  */
16
16
 
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};
17
+ import{liveRuntime}from"#factories/context";import{SlothletError}from"@cldmv/slothlet/errors";import{enforceContextKeyWrite,readProtectedContextValue,TRUSTED_ROOT}from"#handlers/trusted-root";const resolveActiveContext=()=>liveRuntime.getContext();function runtime_resolveExecutingContext(){const ctx=liveRuntime.getContext();if(!ctx||!ctx.self)return null;const identity=liveRuntime.getCallerIdentity?.();const executing=identity?identity.currentWrapper:ctx.currentWrapper;if(executing)return ctx;if(ctx.parentInstanceID&&ctx[TRUSTED_ROOT]===true)return ctx;return null}const self=new Proxy({},{get(_,prop){const ctx=runtime_resolveExecutingContext();if(!ctx){throw new SlothletError("RUNTIME_NO_ACTIVE_CONTEXT_SELF",{},null,{validationError:true})}return ctx.self[prop]},ownKeys(){const ctx=runtime_resolveExecutingContext();if(!ctx)return[];return Reflect.ownKeys(ctx.self)},has(_,prop){const ctx=runtime_resolveExecutingContext();if(!ctx)return false;return prop in ctx.self},getOwnPropertyDescriptor(_,prop){const ctx=runtime_resolveExecutingContext();if(!ctx)return void 0;const desc=Reflect.getOwnPropertyDescriptor(ctx.self,prop);if(desc){return{...desc,configurable:true}}return void 0},set(_,prop,value){const ctx=runtime_resolveExecutingContext();if(!ctx){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,liveRuntime.getCallerIdentity?.()?.currentWrapper??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};
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"#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};
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";import{enableSchedulerPatching,disableSchedulerPatching}from"@cldmv/slothlet/helpers/scheduler-context";import{enableEventTargetPatching,disableEventTargetPatching}from"@cldmv/slothlet/helpers/eventtarget-context";const boundaryPatchHolders=new Set;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();enableSchedulerPatching();enableEventTargetPatching();boundaryPatchHolders.add(this.instanceID);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();boundaryPatchHolders.delete(this.instanceID);if(boundaryPatchHolders.size===0){disableEventEmitterPatching();disableSchedulerPatching();disableEventTargetPatching();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.12.1",
3
+ "version": "3.12.3",
4
4
  "moduleVersions": {
5
5
  "lazy": "3.0.0",
6
6
  "eager": "3.0.0",
@@ -312,7 +312,7 @@
312
312
  }
313
313
  },
314
314
  "devDependencies": {
315
- "@cldmv/fix-headers": "^1.3.0",
315
+ "@cldmv/fix-headers": "^1.3.7",
316
316
  "@cldmv/vitest-runner": "^1.2.0",
317
317
  "@eslint/css": "^1.4.0",
318
318
  "@eslint/js": "^10.0.1",
@@ -322,8 +322,8 @@
322
322
  "@vitest/browser": "^4.1.10",
323
323
  "@vitest/browser-playwright": "^4.1.10",
324
324
  "@vitest/coverage-v8": "^4.1.10",
325
- "acorn": "^8.17.0",
326
- "chalk": "^5.6.2",
325
+ "acorn": "^8.18.0",
326
+ "chalk": "^6.0.0",
327
327
  "chokidar": "^5.0.0",
328
328
  "dmd": "^7.1.1",
329
329
  "esbuild": "^0.28.1",
@@ -334,14 +334,14 @@
334
334
  "jsdoc-to-markdown": "^9.1.3",
335
335
  "jsdoc2md": "^1.0.0",
336
336
  "jsonc-parser": "^3.3.1",
337
- "playwright": "^1.61.1",
337
+ "playwright": "^1.62.1",
338
338
  "prettier": "^3.9.5",
339
339
  "shx": "^0.4.0",
340
340
  "typescript": "^6.0.3",
341
341
  "vitest": "^4.1.10"
342
342
  },
343
343
  "optionalDependencies": {
344
- "@rolldown/binding-linux-x64-gnu": "1.0.3"
344
+ "@rolldown/binding-linux-x64-gnu": "1.1.3"
345
345
  },
346
346
  "repository": {
347
347
  "type": "git",
@@ -0,0 +1,3 @@
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/helpers/caller-pinning";
@@ -0,0 +1,3 @@
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/helpers/eventtarget-context";
@@ -0,0 +1,3 @@
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/helpers/scheduler-context";