@aigne/afs 1.11.0-beta.12 → 1.11.0-beta.13
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.cts +2 -2
- package/dist/index.d.mts +2 -2
- package/dist/program/index.d.mts +1 -1
- package/dist/program/program-afs.cjs +14 -10
- package/dist/program/program-afs.d.cts +19 -1
- package/dist/program/program-afs.d.cts.map +1 -1
- package/dist/program/program-afs.d.mts +19 -1
- package/dist/program/program-afs.d.mts.map +1 -1
- package/dist/program/program-afs.mjs +14 -10
- package/dist/program/program-afs.mjs.map +1 -1
- package/dist/registry.cjs +8 -4
- package/dist/registry.d.cts.map +1 -1
- package/dist/registry.d.mts.map +1 -1
- package/dist/registry.mjs +8 -4
- package/dist/registry.mjs.map +1 -1
- package/dist/utils/schema.cjs +3 -1
- package/dist/utils/schema.d.cts.map +1 -1
- package/dist/utils/schema.d.mts.map +1 -1
- package/dist/utils/schema.mjs +3 -1
- package/dist/utils/schema.mjs.map +1 -1
- package/package.json +4 -4
package/dist/index.d.cts
CHANGED
|
@@ -15,7 +15,7 @@ import { AFSPathError, ParsedCanonicalPath, isCanonicalPath, normalizePath, pars
|
|
|
15
15
|
import { resolveEffectivePolicy } from "./policy.cjs";
|
|
16
16
|
import { MountDeclaration, ProgramManifest } from "./program/types.cjs";
|
|
17
17
|
import { parseProgramManifest } from "./program/parse-manifest.cjs";
|
|
18
|
-
import { CreateProgramAFSOptions, createProgramAFS, findMountByURI } from "./program/program-afs.cjs";
|
|
18
|
+
import { CreateProgramAFSOptions, MountOverride, createProgramAFS, findMountByURI } from "./program/program-afs.cjs";
|
|
19
19
|
import { ProjectionProvider, ProjectionProviderOptions } from "./program/projection-provider.cjs";
|
|
20
20
|
import { DeleteRouteHandler, ExecRouteHandler, ExplainRouteHandler, ListDecoratorOptions, ListHandlerResult, ListRouteHandler, ReadRouteHandler, RenameRouteHandler, RouteContext, RouteDefinition, RouteHandler, RouteMatch, RouteMetadata, RouteOperation, SearchRouteHandler, StatRouteHandler, WriteRouteHandler } from "./provider/types.cjs";
|
|
21
21
|
import { ProviderRouter } from "./provider/router.cjs";
|
|
@@ -23,4 +23,4 @@ import { AFSBaseProvider } from "./provider/base.cjs";
|
|
|
23
23
|
import { Actions, Delete, Exec, Explain, List, Meta, Read, Rename, Search, Stat, Write, clearRoutes, getRoutes } from "./provider/decorators.cjs";
|
|
24
24
|
import { ProviderFactory, ProviderRegistry } from "./registry.cjs";
|
|
25
25
|
import { SecretAuditSink, createCompositeAuditSink, createFileAuditSink, createMemoryAuditSink, createSecretCapability, resolveVaultURIs } from "./secret-capability.cjs";
|
|
26
|
-
export { AFS, AFSAccessMode, AFSAccessModeError, AFSActionResult, AFSAlreadyExistsError, AFSBaseProvider, AFSCategory, AFSChangeListener, AFSChangeRecord, AFSContext, AFSDeleteOptions, AFSDeleteResult, AFSEntry, AFSEntryMetadata, AFSError, AFSEvent, AFSEventCallback, AFSEventDeclaration, AFSEventFilter, AFSEventSink, AFSExecOptions, AFSExecResult, AFSExplainOptions, AFSExplainResult, AFSListOptions, AFSListResult, AFSModule, AFSModuleClass, AFSModuleLoadParams, AFSMountError, AFSNotFoundError, AFSOperationOptions, AFSOptions, AFSPatch, AFSPatchError, AFSPathError, AFSReadOptions, AFSReadResult, AFSReadonlyError, AFSRenameOptions, AFSRenameResult, AFSRoot, AFSSearchOptions, AFSSearchResult, AFSSeverityError, AFSStatOptions, AFSStatResult, AFSUnsubscribe, AFSValidationError, AFSVisibility, AFSWorldMappingCapable, AFSWriteEntryPayload, AFSWriteOptions, AFSWriteResult, AFS_CATEGORIES, ActionCatalog, ActionDefinition, ActionPolicy, ActionSeverity, ActionSummary, Actions, AggregatedCapabilities, AuthContext, CAPABILITY_TAGS, CallbackServer, CapabilitiesManifest, CapabilityCheckResult, CapabilityEnforcer, CapabilityEnforcerOptions, CapabilityEvent, CapabilityEventHandler, CapabilityTag, CreateProgramAFSOptions, DataSensitivity, Delete, DeleteRouteHandler, EventBus, Exec, ExecRouteHandler, Explain, ExplainRouteHandler, ExternalDependency, ExternalRef, IsolationConfig, IsolationLevel, JSONSchema7, KINDS_SEGMENT, Kind, KindDefinition, KindError, KindResolver, KindSchema, List, ListDecoratorOptions, ListHandlerResult, ListRouteHandler, META_SEGMENT, MappingStatus, Meta, MetaPathInfo, MountConfig, MountDeclaration, MountInfo, MountOptions, MutateAction, MutateResult, NodeConstraint, NodesConstraints, OperationPricing, OperationsDeclaration, ParsedCanonicalPath, ProgramManifest, ProjectionContext, ProjectionProvider, ProjectionProviderOptions, ProviderCap, ProviderCapabilityManifest, ProviderFactory, ProviderLimits, ProviderManifest, ProviderPricing, ProviderRegistry, ProviderResources, ProviderRouter, ProviderSecurityDeclaration, ProviderTreeSchema, Read, ReadRouteHandler, Rename, RenameRouteHandler, ResourceAccess, RouteContext, RouteDefinition, RouteHandler, RouteMatch, RouteMetadata, RouteOperation, Search, SearchRouteHandler, SecretAuditEntry, SecretAuditSink, SecretCapability, SecurityConfig, SecurityProfile, Stat, StatRouteHandler, TokenUsage, ToolDefinition, TreeNodeSchema, UsageMetadata, ValidationError, ValidationResult, WELL_KNOWN_KINDS, WELL_KNOWN_KINDS_MAP, Write, WriteRouteHandler, accessModeSchema, actionSummarySchema, afsDocument, afsEntrySchema, afsExecutable, afsImage, afsLink, afsNode, afsProgram, clearRoutes, combineValidationResults, commonMetaSchema, createCompositeAuditSink, createEventSink, createFileAuditSink, createKindResolver, createMemoryAuditSink, createProgramAFS, createScopedAFSProxy, createSecretCapability, defaultKindResolver, defineKind, findMountByURI, getInheritanceChain, getNodePathFromMetaPath, getRoutes, getWellKnownKind, isCanonicalPath, isKindsPath, isMetaPath, isWellKnownKind, isWorldMappingCapable, normalizePath, parseCanonicalPath, parseMetaPath, parseProgramManifest, resolveEffectivePolicy, resolveKindSchema, resolveVaultURIs, toCanonicalPath, validateModuleName, validateNodes, validatePath };
|
|
26
|
+
export { AFS, AFSAccessMode, AFSAccessModeError, AFSActionResult, AFSAlreadyExistsError, AFSBaseProvider, AFSCategory, AFSChangeListener, AFSChangeRecord, AFSContext, AFSDeleteOptions, AFSDeleteResult, AFSEntry, AFSEntryMetadata, AFSError, AFSEvent, AFSEventCallback, AFSEventDeclaration, AFSEventFilter, AFSEventSink, AFSExecOptions, AFSExecResult, AFSExplainOptions, AFSExplainResult, AFSListOptions, AFSListResult, AFSModule, AFSModuleClass, AFSModuleLoadParams, AFSMountError, AFSNotFoundError, AFSOperationOptions, AFSOptions, AFSPatch, AFSPatchError, AFSPathError, AFSReadOptions, AFSReadResult, AFSReadonlyError, AFSRenameOptions, AFSRenameResult, AFSRoot, AFSSearchOptions, AFSSearchResult, AFSSeverityError, AFSStatOptions, AFSStatResult, AFSUnsubscribe, AFSValidationError, AFSVisibility, AFSWorldMappingCapable, AFSWriteEntryPayload, AFSWriteOptions, AFSWriteResult, AFS_CATEGORIES, ActionCatalog, ActionDefinition, ActionPolicy, ActionSeverity, ActionSummary, Actions, AggregatedCapabilities, AuthContext, CAPABILITY_TAGS, CallbackServer, CapabilitiesManifest, CapabilityCheckResult, CapabilityEnforcer, CapabilityEnforcerOptions, CapabilityEvent, CapabilityEventHandler, CapabilityTag, CreateProgramAFSOptions, DataSensitivity, Delete, DeleteRouteHandler, EventBus, Exec, ExecRouteHandler, Explain, ExplainRouteHandler, ExternalDependency, ExternalRef, IsolationConfig, IsolationLevel, JSONSchema7, KINDS_SEGMENT, Kind, KindDefinition, KindError, KindResolver, KindSchema, List, ListDecoratorOptions, ListHandlerResult, ListRouteHandler, META_SEGMENT, MappingStatus, Meta, MetaPathInfo, MountConfig, MountDeclaration, MountInfo, MountOptions, MountOverride, MutateAction, MutateResult, NodeConstraint, NodesConstraints, OperationPricing, OperationsDeclaration, ParsedCanonicalPath, ProgramManifest, ProjectionContext, ProjectionProvider, ProjectionProviderOptions, ProviderCap, ProviderCapabilityManifest, ProviderFactory, ProviderLimits, ProviderManifest, ProviderPricing, ProviderRegistry, ProviderResources, ProviderRouter, ProviderSecurityDeclaration, ProviderTreeSchema, Read, ReadRouteHandler, Rename, RenameRouteHandler, ResourceAccess, RouteContext, RouteDefinition, RouteHandler, RouteMatch, RouteMetadata, RouteOperation, Search, SearchRouteHandler, SecretAuditEntry, SecretAuditSink, SecretCapability, SecurityConfig, SecurityProfile, Stat, StatRouteHandler, TokenUsage, ToolDefinition, TreeNodeSchema, UsageMetadata, ValidationError, ValidationResult, WELL_KNOWN_KINDS, WELL_KNOWN_KINDS_MAP, Write, WriteRouteHandler, accessModeSchema, actionSummarySchema, afsDocument, afsEntrySchema, afsExecutable, afsImage, afsLink, afsNode, afsProgram, clearRoutes, combineValidationResults, commonMetaSchema, createCompositeAuditSink, createEventSink, createFileAuditSink, createKindResolver, createMemoryAuditSink, createProgramAFS, createScopedAFSProxy, createSecretCapability, defaultKindResolver, defineKind, findMountByURI, getInheritanceChain, getNodePathFromMetaPath, getRoutes, getWellKnownKind, isCanonicalPath, isKindsPath, isMetaPath, isWellKnownKind, isWorldMappingCapable, normalizePath, parseCanonicalPath, parseMetaPath, parseProgramManifest, resolveEffectivePolicy, resolveKindSchema, resolveVaultURIs, toCanonicalPath, validateModuleName, validateNodes, validatePath };
|
package/dist/index.d.mts
CHANGED
|
@@ -16,7 +16,7 @@ import { AFSPathError, ParsedCanonicalPath, isCanonicalPath, normalizePath, pars
|
|
|
16
16
|
import { resolveEffectivePolicy } from "./policy.mjs";
|
|
17
17
|
import { MountDeclaration, ProgramManifest } from "./program/types.mjs";
|
|
18
18
|
import { parseProgramManifest } from "./program/parse-manifest.mjs";
|
|
19
|
-
import { CreateProgramAFSOptions, createProgramAFS, findMountByURI } from "./program/program-afs.mjs";
|
|
19
|
+
import { CreateProgramAFSOptions, MountOverride, createProgramAFS, findMountByURI } from "./program/program-afs.mjs";
|
|
20
20
|
import { ProjectionProvider, ProjectionProviderOptions } from "./program/projection-provider.mjs";
|
|
21
21
|
import "./program/index.mjs";
|
|
22
22
|
import { DeleteRouteHandler, ExecRouteHandler, ExplainRouteHandler, ListDecoratorOptions, ListHandlerResult, ListRouteHandler, ReadRouteHandler, RenameRouteHandler, RouteContext, RouteDefinition, RouteHandler, RouteMatch, RouteMetadata, RouteOperation, SearchRouteHandler, StatRouteHandler, WriteRouteHandler } from "./provider/types.mjs";
|
|
@@ -26,4 +26,4 @@ import { Actions, Delete, Exec, Explain, List, Meta, Read, Rename, Search, Stat,
|
|
|
26
26
|
import "./provider/index.mjs";
|
|
27
27
|
import { ProviderFactory, ProviderRegistry } from "./registry.mjs";
|
|
28
28
|
import { SecretAuditSink, createCompositeAuditSink, createFileAuditSink, createMemoryAuditSink, createSecretCapability, resolveVaultURIs } from "./secret-capability.mjs";
|
|
29
|
-
export { AFS, AFSAccessMode, AFSAccessModeError, AFSActionResult, AFSAlreadyExistsError, AFSBaseProvider, AFSCategory, AFSChangeListener, AFSChangeRecord, AFSContext, AFSDeleteOptions, AFSDeleteResult, AFSEntry, AFSEntryMetadata, AFSError, AFSEvent, AFSEventCallback, AFSEventDeclaration, AFSEventFilter, AFSEventSink, AFSExecOptions, AFSExecResult, AFSExplainOptions, AFSExplainResult, AFSListOptions, AFSListResult, AFSModule, AFSModuleClass, AFSModuleLoadParams, AFSMountError, AFSNotFoundError, AFSOperationOptions, AFSOptions, AFSPatch, AFSPatchError, AFSPathError, AFSReadOptions, AFSReadResult, AFSReadonlyError, AFSRenameOptions, AFSRenameResult, AFSRoot, AFSSearchOptions, AFSSearchResult, AFSSeverityError, AFSStatOptions, AFSStatResult, AFSUnsubscribe, AFSValidationError, AFSVisibility, AFSWorldMappingCapable, AFSWriteEntryPayload, AFSWriteOptions, AFSWriteResult, AFS_CATEGORIES, ActionCatalog, ActionDefinition, ActionPolicy, ActionSeverity, ActionSummary, Actions, AggregatedCapabilities, AuthContext, CAPABILITY_TAGS, CallbackServer, CapabilitiesManifest, CapabilityCheckResult, CapabilityEnforcer, CapabilityEnforcerOptions, CapabilityEvent, CapabilityEventHandler, CapabilityTag, CreateProgramAFSOptions, DataSensitivity, Delete, DeleteRouteHandler, EventBus, Exec, ExecRouteHandler, Explain, ExplainRouteHandler, ExternalDependency, ExternalRef, IsolationConfig, IsolationLevel, JSONSchema7, KINDS_SEGMENT, Kind, KindDefinition, KindError, KindResolver, KindSchema, List, ListDecoratorOptions, ListHandlerResult, ListRouteHandler, META_SEGMENT, MappingStatus, Meta, MetaPathInfo, MountConfig, MountDeclaration, MountInfo, MountOptions, MutateAction, MutateResult, NodeConstraint, NodesConstraints, OperationPricing, OperationsDeclaration, ParsedCanonicalPath, ProgramManifest, ProjectionContext, ProjectionProvider, ProjectionProviderOptions, ProviderCap, ProviderCapabilityManifest, ProviderFactory, ProviderLimits, ProviderManifest, ProviderPricing, ProviderRegistry, ProviderResources, ProviderRouter, ProviderSecurityDeclaration, ProviderTreeSchema, Read, ReadRouteHandler, Rename, RenameRouteHandler, ResourceAccess, RouteContext, RouteDefinition, RouteHandler, RouteMatch, RouteMetadata, RouteOperation, Search, SearchRouteHandler, SecretAuditEntry, SecretAuditSink, SecretCapability, SecurityConfig, SecurityProfile, Stat, StatRouteHandler, TokenUsage, ToolDefinition, TreeNodeSchema, UsageMetadata, ValidationError, ValidationResult, WELL_KNOWN_KINDS, WELL_KNOWN_KINDS_MAP, Write, WriteRouteHandler, accessModeSchema, actionSummarySchema, afsDocument, afsEntrySchema, afsExecutable, afsImage, afsLink, afsNode, afsProgram, clearRoutes, combineValidationResults, commonMetaSchema, createCompositeAuditSink, createEventSink, createFileAuditSink, createKindResolver, createMemoryAuditSink, createProgramAFS, createScopedAFSProxy, createSecretCapability, defaultKindResolver, defineKind, findMountByURI, getInheritanceChain, getNodePathFromMetaPath, getRoutes, getWellKnownKind, isCanonicalPath, isKindsPath, isMetaPath, isWellKnownKind, isWorldMappingCapable, normalizePath, parseCanonicalPath, parseMetaPath, parseProgramManifest, resolveEffectivePolicy, resolveKindSchema, resolveVaultURIs, toCanonicalPath, validateModuleName, validateNodes, validatePath };
|
|
29
|
+
export { AFS, AFSAccessMode, AFSAccessModeError, AFSActionResult, AFSAlreadyExistsError, AFSBaseProvider, AFSCategory, AFSChangeListener, AFSChangeRecord, AFSContext, AFSDeleteOptions, AFSDeleteResult, AFSEntry, AFSEntryMetadata, AFSError, AFSEvent, AFSEventCallback, AFSEventDeclaration, AFSEventFilter, AFSEventSink, AFSExecOptions, AFSExecResult, AFSExplainOptions, AFSExplainResult, AFSListOptions, AFSListResult, AFSModule, AFSModuleClass, AFSModuleLoadParams, AFSMountError, AFSNotFoundError, AFSOperationOptions, AFSOptions, AFSPatch, AFSPatchError, AFSPathError, AFSReadOptions, AFSReadResult, AFSReadonlyError, AFSRenameOptions, AFSRenameResult, AFSRoot, AFSSearchOptions, AFSSearchResult, AFSSeverityError, AFSStatOptions, AFSStatResult, AFSUnsubscribe, AFSValidationError, AFSVisibility, AFSWorldMappingCapable, AFSWriteEntryPayload, AFSWriteOptions, AFSWriteResult, AFS_CATEGORIES, ActionCatalog, ActionDefinition, ActionPolicy, ActionSeverity, ActionSummary, Actions, AggregatedCapabilities, AuthContext, CAPABILITY_TAGS, CallbackServer, CapabilitiesManifest, CapabilityCheckResult, CapabilityEnforcer, CapabilityEnforcerOptions, CapabilityEvent, CapabilityEventHandler, CapabilityTag, CreateProgramAFSOptions, DataSensitivity, Delete, DeleteRouteHandler, EventBus, Exec, ExecRouteHandler, Explain, ExplainRouteHandler, ExternalDependency, ExternalRef, IsolationConfig, IsolationLevel, JSONSchema7, KINDS_SEGMENT, Kind, KindDefinition, KindError, KindResolver, KindSchema, List, ListDecoratorOptions, ListHandlerResult, ListRouteHandler, META_SEGMENT, MappingStatus, Meta, MetaPathInfo, MountConfig, MountDeclaration, MountInfo, MountOptions, MountOverride, MutateAction, MutateResult, NodeConstraint, NodesConstraints, OperationPricing, OperationsDeclaration, ParsedCanonicalPath, ProgramManifest, ProjectionContext, ProjectionProvider, ProjectionProviderOptions, ProviderCap, ProviderCapabilityManifest, ProviderFactory, ProviderLimits, ProviderManifest, ProviderPricing, ProviderRegistry, ProviderResources, ProviderRouter, ProviderSecurityDeclaration, ProviderTreeSchema, Read, ReadRouteHandler, Rename, RenameRouteHandler, ResourceAccess, RouteContext, RouteDefinition, RouteHandler, RouteMatch, RouteMetadata, RouteOperation, Search, SearchRouteHandler, SecretAuditEntry, SecretAuditSink, SecretCapability, SecurityConfig, SecurityProfile, Stat, StatRouteHandler, TokenUsage, ToolDefinition, TreeNodeSchema, UsageMetadata, ValidationError, ValidationResult, WELL_KNOWN_KINDS, WELL_KNOWN_KINDS_MAP, Write, WriteRouteHandler, accessModeSchema, actionSummarySchema, afsDocument, afsEntrySchema, afsExecutable, afsImage, afsLink, afsNode, afsProgram, clearRoutes, combineValidationResults, commonMetaSchema, createCompositeAuditSink, createEventSink, createFileAuditSink, createKindResolver, createMemoryAuditSink, createProgramAFS, createScopedAFSProxy, createSecretCapability, defaultKindResolver, defineKind, findMountByURI, getInheritanceChain, getNodePathFromMetaPath, getRoutes, getWellKnownKind, isCanonicalPath, isKindsPath, isMetaPath, isWellKnownKind, isWorldMappingCapable, normalizePath, parseCanonicalPath, parseMetaPath, parseProgramManifest, resolveEffectivePolicy, resolveKindSchema, resolveVaultURIs, toCanonicalPath, validateModuleName, validateNodes, validatePath };
|
package/dist/program/index.d.mts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import { MountDeclaration, ProgramManifest } from "./types.mjs";
|
|
2
2
|
import { parseProgramManifest } from "./parse-manifest.mjs";
|
|
3
|
-
import { CreateProgramAFSOptions, createProgramAFS, findMountByURI } from "./program-afs.mjs";
|
|
3
|
+
import { CreateProgramAFSOptions, MountOverride, createProgramAFS, findMountByURI } from "./program-afs.mjs";
|
|
4
4
|
import { ProjectionProvider, ProjectionProviderOptions } from "./projection-provider.mjs";
|
|
@@ -64,37 +64,41 @@ async function createProgramAFS(programPath, dataPath, globalAFS, options) {
|
|
|
64
64
|
sourcePath: dataPath
|
|
65
65
|
});
|
|
66
66
|
await programAFS.mount(dataProvider, "/data", { lenient: true });
|
|
67
|
-
const createOwned = async (mountDecl) => {
|
|
67
|
+
const createOwned = async (mountDecl, effectiveUri, extraOptions) => {
|
|
68
68
|
if (!options?.createProvider) {
|
|
69
|
-
if (mountDecl.required) throw new Error(`Mount "${mountDecl.target}" (URI: ${safeURI(
|
|
69
|
+
if (mountDecl.required) throw new Error(`Mount "${mountDecl.target}" (URI: ${safeURI(effectiveUri)}) requires a provider factory, but none was provided.`);
|
|
70
70
|
return false;
|
|
71
71
|
}
|
|
72
|
-
const
|
|
72
|
+
const mountConfig = {
|
|
73
73
|
path: mountDecl.target,
|
|
74
|
-
uri:
|
|
75
|
-
}
|
|
74
|
+
uri: effectiveUri
|
|
75
|
+
};
|
|
76
|
+
if (extraOptions && Object.keys(extraOptions).length > 0) mountConfig.options = extraOptions;
|
|
77
|
+
const provider = await options.createProvider(mountConfig);
|
|
76
78
|
ownedProviders.push(provider);
|
|
77
79
|
await programAFS.mount(provider, mountDecl.target, { lenient: true });
|
|
78
80
|
return true;
|
|
79
81
|
};
|
|
80
82
|
for (const mountDecl of manifest.mounts) {
|
|
81
83
|
const isOwned = mountDecl.shared === false;
|
|
84
|
+
const override = options?.mountOverrides?.find((o) => o.target === mountDecl.target);
|
|
85
|
+
const effectiveUri = override?.uri || mountDecl.uri;
|
|
82
86
|
try {
|
|
83
|
-
if (isOwned) await createOwned(mountDecl);
|
|
87
|
+
if (isOwned) await createOwned(mountDecl, effectiveUri, override?.options);
|
|
84
88
|
else {
|
|
85
|
-
const matches = findMountByURI(globalAFS,
|
|
89
|
+
const matches = findMountByURI(globalAFS, effectiveUri);
|
|
86
90
|
if (matches.length === 0) {
|
|
87
91
|
let fallbackOk = false;
|
|
88
92
|
if (options?.createProvider) try {
|
|
89
|
-
await createOwned(mountDecl);
|
|
93
|
+
await createOwned(mountDecl, effectiveUri, override?.options);
|
|
90
94
|
fallbackOk = true;
|
|
91
95
|
} catch {}
|
|
92
96
|
if (!fallbackOk) {
|
|
93
|
-
if (mountDecl.required) throw new Error(`Required mount URI "${safeURI(
|
|
97
|
+
if (mountDecl.required) throw new Error(`Required mount URI "${safeURI(effectiveUri)}" not found in host AFS. No provider is mounted with this URI.`);
|
|
94
98
|
}
|
|
95
99
|
continue;
|
|
96
100
|
}
|
|
97
|
-
if (matches.length > 1) throw new Error(`Mount conflict: URI "${safeURI(
|
|
101
|
+
if (matches.length > 1) throw new Error(`Mount conflict: URI "${safeURI(effectiveUri)}" matches ${matches.length} providers in host AFS. Expected exactly 1.`);
|
|
98
102
|
const hostMount = matches[0];
|
|
99
103
|
const projection = new require_projection_provider.ProjectionProvider({
|
|
100
104
|
name: `projection:${mountDecl.target.replace(/^\//, "").replace(/\//g, "-")}`,
|
|
@@ -3,6 +3,18 @@ import { AFS, MountInfo } from "../afs.cjs";
|
|
|
3
3
|
import { ProgramManifest } from "./types.cjs";
|
|
4
4
|
|
|
5
5
|
//#region src/program/program-afs.d.ts
|
|
6
|
+
/**
|
|
7
|
+
* A user-side mount override from mounts.toml.
|
|
8
|
+
* Provides a complete URI and optional extra options for a mount target.
|
|
9
|
+
*/
|
|
10
|
+
interface MountOverride {
|
|
11
|
+
/** Mount target path — must match a mount declaration's target in program.yaml */
|
|
12
|
+
target: string;
|
|
13
|
+
/** Complete URI (overrides the placeholder URI in program.yaml) */
|
|
14
|
+
uri: string;
|
|
15
|
+
/** Additional provider options to merge into mount config */
|
|
16
|
+
options?: Record<string, unknown>;
|
|
17
|
+
}
|
|
6
18
|
/**
|
|
7
19
|
* Options for createProgramAFS.
|
|
8
20
|
*/
|
|
@@ -14,6 +26,12 @@ interface CreateProgramAFSOptions {
|
|
|
14
26
|
* whose URI isn't found in the host AFS.
|
|
15
27
|
*/
|
|
16
28
|
createProvider?: (mount: MountConfig) => Promise<AFSModule>;
|
|
29
|
+
/**
|
|
30
|
+
* User-side mount overrides from mounts.toml.
|
|
31
|
+
* Each override replaces the URI (and optionally adds options) for a matching
|
|
32
|
+
* mount target declared in program.yaml.
|
|
33
|
+
*/
|
|
34
|
+
mountOverrides?: MountOverride[];
|
|
17
35
|
}
|
|
18
36
|
/**
|
|
19
37
|
* Find mounts in an AFS instance whose module.uri matches the given URI exactly.
|
|
@@ -41,5 +59,5 @@ declare function createProgramAFS(programPath: string, dataPath: string, globalA
|
|
|
41
59
|
ownedProviders: AFSModule[];
|
|
42
60
|
}>;
|
|
43
61
|
//#endregion
|
|
44
|
-
export { CreateProgramAFSOptions, createProgramAFS, findMountByURI };
|
|
62
|
+
export { CreateProgramAFSOptions, MountOverride, createProgramAFS, findMountByURI };
|
|
45
63
|
//# sourceMappingURL=program-afs.d.cts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"program-afs.d.cts","names":[],"sources":["../../src/program/program-afs.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"program-afs.d.cts","names":[],"sources":["../../src/program/program-afs.ts"],"mappings":";;;;;;;;;UAeiB,aAAA;EAMf;EAJA,MAAA;EAIgB;EAFhB,GAAA;EAQe;EANf,OAAA,GAAU,MAAA;AAAA;;;;UAMK,uBAAA;EAae;;;;;;EAN9B,cAAA,IAAkB,KAAA,EAAO,WAAA,KAAgB,OAAA,CAAQ,SAAA;EAMjD;;;;AAOF;EAPE,cAAA,GAAiB,aAAA;AAAA;;;;;iBAOH,cAAA,CAAe,GAAA,EAAK,OAAA,GAAU,GAAA,EAAK,GAAA,WAAc,SAAA;;;;;;;;AA6BjE;;;;;;;;iBAAsB,gBAAA,CACpB,WAAA,UACA,QAAA,UACA,SAAA,EAAW,GAAA,EACX,OAAA,GAAU,uBAAA,GACT,OAAA;EAAU,GAAA,EAAK,OAAA;EAAS,QAAA,EAAU,eAAA;EAAiB,cAAA,EAAgB,SAAA;AAAA"}
|
|
@@ -3,6 +3,18 @@ import { AFS, MountInfo } from "../afs.mjs";
|
|
|
3
3
|
import { ProgramManifest } from "./types.mjs";
|
|
4
4
|
|
|
5
5
|
//#region src/program/program-afs.d.ts
|
|
6
|
+
/**
|
|
7
|
+
* A user-side mount override from mounts.toml.
|
|
8
|
+
* Provides a complete URI and optional extra options for a mount target.
|
|
9
|
+
*/
|
|
10
|
+
interface MountOverride {
|
|
11
|
+
/** Mount target path — must match a mount declaration's target in program.yaml */
|
|
12
|
+
target: string;
|
|
13
|
+
/** Complete URI (overrides the placeholder URI in program.yaml) */
|
|
14
|
+
uri: string;
|
|
15
|
+
/** Additional provider options to merge into mount config */
|
|
16
|
+
options?: Record<string, unknown>;
|
|
17
|
+
}
|
|
6
18
|
/**
|
|
7
19
|
* Options for createProgramAFS.
|
|
8
20
|
*/
|
|
@@ -14,6 +26,12 @@ interface CreateProgramAFSOptions {
|
|
|
14
26
|
* whose URI isn't found in the host AFS.
|
|
15
27
|
*/
|
|
16
28
|
createProvider?: (mount: MountConfig) => Promise<AFSModule>;
|
|
29
|
+
/**
|
|
30
|
+
* User-side mount overrides from mounts.toml.
|
|
31
|
+
* Each override replaces the URI (and optionally adds options) for a matching
|
|
32
|
+
* mount target declared in program.yaml.
|
|
33
|
+
*/
|
|
34
|
+
mountOverrides?: MountOverride[];
|
|
17
35
|
}
|
|
18
36
|
/**
|
|
19
37
|
* Find mounts in an AFS instance whose module.uri matches the given URI exactly.
|
|
@@ -41,5 +59,5 @@ declare function createProgramAFS(programPath: string, dataPath: string, globalA
|
|
|
41
59
|
ownedProviders: AFSModule[];
|
|
42
60
|
}>;
|
|
43
61
|
//#endregion
|
|
44
|
-
export { CreateProgramAFSOptions, createProgramAFS, findMountByURI };
|
|
62
|
+
export { CreateProgramAFSOptions, MountOverride, createProgramAFS, findMountByURI };
|
|
45
63
|
//# sourceMappingURL=program-afs.d.mts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"program-afs.d.mts","names":[],"sources":["../../src/program/program-afs.ts"],"mappings":"
|
|
1
|
+
{"version":3,"file":"program-afs.d.mts","names":[],"sources":["../../src/program/program-afs.ts"],"mappings":";;;;;;;;;UAeiB,aAAA;EAMf;EAJA,MAAA;EAIgB;EAFhB,GAAA;EAQe;EANf,OAAA,GAAU,MAAA;AAAA;;;;UAMK,uBAAA;EAae;;;;;;EAN9B,cAAA,IAAkB,KAAA,EAAO,WAAA,KAAgB,OAAA,CAAQ,SAAA;EAMjD;;;;AAOF;EAPE,cAAA,GAAiB,aAAA;AAAA;;;;;iBAOH,cAAA,CAAe,GAAA,EAAK,OAAA,GAAU,GAAA,EAAK,GAAA,WAAc,SAAA;;;;;;;;AA6BjE;;;;;;;;iBAAsB,gBAAA,CACpB,WAAA,UACA,QAAA,UACA,SAAA,EAAW,GAAA,EACX,OAAA,GAAU,uBAAA,GACT,OAAA;EAAU,GAAA,EAAK,OAAA;EAAS,QAAA,EAAU,eAAA;EAAiB,cAAA,EAAgB,SAAA;AAAA"}
|
|
@@ -64,37 +64,41 @@ async function createProgramAFS(programPath, dataPath, globalAFS, options) {
|
|
|
64
64
|
sourcePath: dataPath
|
|
65
65
|
});
|
|
66
66
|
await programAFS.mount(dataProvider, "/data", { lenient: true });
|
|
67
|
-
const createOwned = async (mountDecl) => {
|
|
67
|
+
const createOwned = async (mountDecl, effectiveUri, extraOptions) => {
|
|
68
68
|
if (!options?.createProvider) {
|
|
69
|
-
if (mountDecl.required) throw new Error(`Mount "${mountDecl.target}" (URI: ${safeURI(
|
|
69
|
+
if (mountDecl.required) throw new Error(`Mount "${mountDecl.target}" (URI: ${safeURI(effectiveUri)}) requires a provider factory, but none was provided.`);
|
|
70
70
|
return false;
|
|
71
71
|
}
|
|
72
|
-
const
|
|
72
|
+
const mountConfig = {
|
|
73
73
|
path: mountDecl.target,
|
|
74
|
-
uri:
|
|
75
|
-
}
|
|
74
|
+
uri: effectiveUri
|
|
75
|
+
};
|
|
76
|
+
if (extraOptions && Object.keys(extraOptions).length > 0) mountConfig.options = extraOptions;
|
|
77
|
+
const provider = await options.createProvider(mountConfig);
|
|
76
78
|
ownedProviders.push(provider);
|
|
77
79
|
await programAFS.mount(provider, mountDecl.target, { lenient: true });
|
|
78
80
|
return true;
|
|
79
81
|
};
|
|
80
82
|
for (const mountDecl of manifest.mounts) {
|
|
81
83
|
const isOwned = mountDecl.shared === false;
|
|
84
|
+
const override = options?.mountOverrides?.find((o) => o.target === mountDecl.target);
|
|
85
|
+
const effectiveUri = override?.uri || mountDecl.uri;
|
|
82
86
|
try {
|
|
83
|
-
if (isOwned) await createOwned(mountDecl);
|
|
87
|
+
if (isOwned) await createOwned(mountDecl, effectiveUri, override?.options);
|
|
84
88
|
else {
|
|
85
|
-
const matches = findMountByURI(globalAFS,
|
|
89
|
+
const matches = findMountByURI(globalAFS, effectiveUri);
|
|
86
90
|
if (matches.length === 0) {
|
|
87
91
|
let fallbackOk = false;
|
|
88
92
|
if (options?.createProvider) try {
|
|
89
|
-
await createOwned(mountDecl);
|
|
93
|
+
await createOwned(mountDecl, effectiveUri, override?.options);
|
|
90
94
|
fallbackOk = true;
|
|
91
95
|
} catch {}
|
|
92
96
|
if (!fallbackOk) {
|
|
93
|
-
if (mountDecl.required) throw new Error(`Required mount URI "${safeURI(
|
|
97
|
+
if (mountDecl.required) throw new Error(`Required mount URI "${safeURI(effectiveUri)}" not found in host AFS. No provider is mounted with this URI.`);
|
|
94
98
|
}
|
|
95
99
|
continue;
|
|
96
100
|
}
|
|
97
|
-
if (matches.length > 1) throw new Error(`Mount conflict: URI "${safeURI(
|
|
101
|
+
if (matches.length > 1) throw new Error(`Mount conflict: URI "${safeURI(effectiveUri)}" matches ${matches.length} providers in host AFS. Expected exactly 1.`);
|
|
98
102
|
const hostMount = matches[0];
|
|
99
103
|
const projection = new ProjectionProvider({
|
|
100
104
|
name: `projection:${mountDecl.target.replace(/^\//, "").replace(/\//g, "-")}`,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"program-afs.mjs","names":[],"sources":["../../src/program/program-afs.ts"],"sourcesContent":["/**\n * Program AFS — factory for creating isolated Runtime AFS namespaces.\n */\n\nimport { joinURL } from \"ufo\";\nimport { AFS, type MountInfo } from \"../afs.js\";\nimport type { AFSModule, AFSRoot, MountConfig } from \"../type.js\";\nimport { parseProgramManifest } from \"./parse-manifest.js\";\nimport { ProjectionProvider } from \"./projection-provider.js\";\nimport type { ProgramManifest } from \"./types.js\";\n\n/**\n * Options for createProgramAFS.\n */\nexport interface CreateProgramAFSOptions {\n /**\n * Factory function for creating providers from mount configs.\n * Handles credential resolution + provider instantiation.\n * Used for owned mounts (shared: false) and as fallback for shared mounts\n * whose URI isn't found in the host AFS.\n */\n createProvider?: (mount: MountConfig) => Promise<AFSModule>;\n}\n\n/**\n * Find mounts in an AFS instance whose module.uri matches the given URI exactly.\n * Accepts AFS class or any AFSRoot with getMounts() (duck-typed).\n */\nexport function findMountByURI(afs: AFSRoot | AFS, uri: string): MountInfo[] {\n const getMounts = (afs as AFS).getMounts;\n if (typeof getMounts !== \"function\") {\n return [];\n }\n return getMounts.call(afs).filter((m: MountInfo) => m.module.uri === uri);\n}\n\n/** Strip query params from a URI for safe error messages. */\nfunction safeURI(uri: string): string {\n const qIdx = uri.indexOf(\"?\");\n return qIdx >= 0 ? uri.slice(0, qIdx) : uri;\n}\n\n/**\n * Create an isolated Runtime AFS namespace for a program.\n *\n * Mounts:\n * - `/program` → programPath (readonly via allowedOps)\n * - `/data` → dataPath (readwrite, no restriction)\n * - `/{target}` → shared: ProjectionProvider wrapping host AFS provider matched by URI\n * owned (shared: false): independent provider via createProvider factory\n *\n * @param programPath - Path to the program definition directory in the host AFS\n * @param dataPath - Path to the program runtime data directory in the host AFS\n * @param globalAFS - The host AFS instance (must be an AFS class instance for getMounts)\n * @param options - Optional: createProvider factory for owned/fallback mount creation\n * @returns The isolated Runtime AFS, parsed manifest, and owned providers for lifecycle management\n */\nexport async function createProgramAFS(\n programPath: string,\n dataPath: string,\n globalAFS: AFS,\n options?: CreateProgramAFSOptions,\n): Promise<{ afs: AFSRoot; manifest: ProgramManifest; ownedProviders: AFSModule[] }> {\n // 1. Read and parse program.yaml\n const manifestPath = joinURL(programPath, \"program.yaml\");\n const readResult = await globalAFS.read!(manifestPath);\n const yamlContent = String(readResult.data?.content ?? \"\");\n if (!yamlContent.trim()) {\n throw new Error(`program.yaml at ${manifestPath} is empty or not readable`);\n }\n const manifest = parseProgramManifest(yamlContent);\n\n // 2. Create new AFS instance\n const programAFS = new AFS();\n const ownedProviders: AFSModule[] = [];\n\n // 3. Mount /program → programPath (readonly)\n const programProvider = new ProjectionProvider({\n name: \"program\",\n globalAFS,\n sourcePath: programPath,\n allowedOps: new Set([\"read\", \"list\", \"search\", \"stat\", \"explain\", \"exec\"]),\n });\n await programAFS.mount(programProvider, \"/program\", { lenient: true });\n\n // 4. Mount /data → dataPath (readwrite, no restriction)\n const dataProvider = new ProjectionProvider({\n name: \"data\",\n globalAFS,\n sourcePath: dataPath,\n });\n await programAFS.mount(dataProvider, \"/data\", { lenient: true });\n\n // Helper: create owned provider via factory\n const createOwned = async (mountDecl: ProgramManifest[\"mounts\"][0]) => {\n if (!options?.createProvider) {\n if (mountDecl.required) {\n throw new Error(\n `Mount \"${mountDecl.target}\" (URI: ${safeURI(mountDecl.uri)}) requires a provider factory, but none was provided.`,\n );\n }\n return false;\n }\n const provider = await options.createProvider({\n path: mountDecl.target,\n uri: mountDecl.uri,\n });\n ownedProviders.push(provider);\n await programAFS.mount(provider, mountDecl.target, { lenient: true });\n return true;\n };\n\n // 5. Mount dependencies — shared via ProjectionProvider, owned via factory\n for (const mountDecl of manifest.mounts) {\n const isOwned = mountDecl.shared === false;\n\n try {\n if (isOwned) {\n // ── Owned mount: create independent provider via factory ──\n await createOwned(mountDecl);\n } else {\n // ── Shared mount: ProjectionProvider wrapping global AFS ──\n const matches = findMountByURI(globalAFS, mountDecl.uri);\n\n if (matches.length === 0) {\n // Fallback: try creating via factory as an owned provider\n let fallbackOk = false;\n if (options?.createProvider) {\n try {\n await createOwned(mountDecl);\n fallbackOk = true;\n } catch {\n // Factory fallback failed — fall through to error/skip\n }\n }\n if (!fallbackOk) {\n if (mountDecl.required) {\n throw new Error(\n `Required mount URI \"${safeURI(mountDecl.uri)}\" not found in host AFS. No provider is mounted with this URI.`,\n );\n }\n }\n continue;\n }\n\n if (matches.length > 1) {\n throw new Error(\n `Mount conflict: URI \"${safeURI(mountDecl.uri)}\" matches ${matches.length} providers in host AFS. Expected exactly 1.`,\n );\n }\n\n const hostMount = matches[0]!;\n const projection = new ProjectionProvider({\n name: `projection:${mountDecl.target.replace(/^\\//, \"\").replace(/\\//g, \"-\")}`,\n globalAFS,\n sourcePath: hostMount.path,\n // Always include \"stat\" and \"list\" — needed by AFS mount system (checkProviderOnMount\n // validates childrenCount via list when stat reports children)\n allowedOps: mountDecl.ops ? new Set([...mountDecl.ops, \"stat\", \"list\"]) : undefined,\n });\n await programAFS.mount(projection, mountDecl.target, { lenient: true });\n }\n } catch (err) {\n if (mountDecl.required) {\n // Clean up already-created owned providers before re-throwing\n await cleanupOwnedProviders(ownedProviders);\n throw err;\n }\n // optional mount failed, continue\n }\n }\n\n return { afs: programAFS, manifest, ownedProviders };\n}\n\n/**\n * Close all owned providers, swallowing individual errors.\n */\nasync function cleanupOwnedProviders(providers: AFSModule[]): Promise<void> {\n for (const provider of providers) {\n try {\n await provider.close?.();\n } catch {\n // Swallow individual close errors — best-effort cleanup\n }\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"program-afs.mjs","names":[],"sources":["../../src/program/program-afs.ts"],"sourcesContent":["/**\n * Program AFS — factory for creating isolated Runtime AFS namespaces.\n */\n\nimport { joinURL } from \"ufo\";\nimport { AFS, type MountInfo } from \"../afs.js\";\nimport type { AFSModule, AFSRoot, MountConfig } from \"../type.js\";\nimport { parseProgramManifest } from \"./parse-manifest.js\";\nimport { ProjectionProvider } from \"./projection-provider.js\";\nimport type { ProgramManifest } from \"./types.js\";\n\n/**\n * A user-side mount override from mounts.toml.\n * Provides a complete URI and optional extra options for a mount target.\n */\nexport interface MountOverride {\n /** Mount target path — must match a mount declaration's target in program.yaml */\n target: string;\n /** Complete URI (overrides the placeholder URI in program.yaml) */\n uri: string;\n /** Additional provider options to merge into mount config */\n options?: Record<string, unknown>;\n}\n\n/**\n * Options for createProgramAFS.\n */\nexport interface CreateProgramAFSOptions {\n /**\n * Factory function for creating providers from mount configs.\n * Handles credential resolution + provider instantiation.\n * Used for owned mounts (shared: false) and as fallback for shared mounts\n * whose URI isn't found in the host AFS.\n */\n createProvider?: (mount: MountConfig) => Promise<AFSModule>;\n /**\n * User-side mount overrides from mounts.toml.\n * Each override replaces the URI (and optionally adds options) for a matching\n * mount target declared in program.yaml.\n */\n mountOverrides?: MountOverride[];\n}\n\n/**\n * Find mounts in an AFS instance whose module.uri matches the given URI exactly.\n * Accepts AFS class or any AFSRoot with getMounts() (duck-typed).\n */\nexport function findMountByURI(afs: AFSRoot | AFS, uri: string): MountInfo[] {\n const getMounts = (afs as AFS).getMounts;\n if (typeof getMounts !== \"function\") {\n return [];\n }\n return getMounts.call(afs).filter((m: MountInfo) => m.module.uri === uri);\n}\n\n/** Strip query params from a URI for safe error messages. */\nfunction safeURI(uri: string): string {\n const qIdx = uri.indexOf(\"?\");\n return qIdx >= 0 ? uri.slice(0, qIdx) : uri;\n}\n\n/**\n * Create an isolated Runtime AFS namespace for a program.\n *\n * Mounts:\n * - `/program` → programPath (readonly via allowedOps)\n * - `/data` → dataPath (readwrite, no restriction)\n * - `/{target}` → shared: ProjectionProvider wrapping host AFS provider matched by URI\n * owned (shared: false): independent provider via createProvider factory\n *\n * @param programPath - Path to the program definition directory in the host AFS\n * @param dataPath - Path to the program runtime data directory in the host AFS\n * @param globalAFS - The host AFS instance (must be an AFS class instance for getMounts)\n * @param options - Optional: createProvider factory for owned/fallback mount creation\n * @returns The isolated Runtime AFS, parsed manifest, and owned providers for lifecycle management\n */\nexport async function createProgramAFS(\n programPath: string,\n dataPath: string,\n globalAFS: AFS,\n options?: CreateProgramAFSOptions,\n): Promise<{ afs: AFSRoot; manifest: ProgramManifest; ownedProviders: AFSModule[] }> {\n // 1. Read and parse program.yaml\n const manifestPath = joinURL(programPath, \"program.yaml\");\n const readResult = await globalAFS.read!(manifestPath);\n const yamlContent = String(readResult.data?.content ?? \"\");\n if (!yamlContent.trim()) {\n throw new Error(`program.yaml at ${manifestPath} is empty or not readable`);\n }\n const manifest = parseProgramManifest(yamlContent);\n\n // 2. Create new AFS instance\n const programAFS = new AFS();\n const ownedProviders: AFSModule[] = [];\n\n // 3. Mount /program → programPath (readonly)\n const programProvider = new ProjectionProvider({\n name: \"program\",\n globalAFS,\n sourcePath: programPath,\n allowedOps: new Set([\"read\", \"list\", \"search\", \"stat\", \"explain\", \"exec\"]),\n });\n await programAFS.mount(programProvider, \"/program\", { lenient: true });\n\n // 4. Mount /data → dataPath (readwrite, no restriction)\n const dataProvider = new ProjectionProvider({\n name: \"data\",\n globalAFS,\n sourcePath: dataPath,\n });\n await programAFS.mount(dataProvider, \"/data\", { lenient: true });\n\n // Helper: create owned provider via factory\n const createOwned = async (\n mountDecl: ProgramManifest[\"mounts\"][0],\n effectiveUri: string,\n extraOptions?: Record<string, unknown>,\n ) => {\n if (!options?.createProvider) {\n if (mountDecl.required) {\n throw new Error(\n `Mount \"${mountDecl.target}\" (URI: ${safeURI(effectiveUri)}) requires a provider factory, but none was provided.`,\n );\n }\n return false;\n }\n const mountConfig: MountConfig = {\n path: mountDecl.target,\n uri: effectiveUri,\n };\n if (extraOptions && Object.keys(extraOptions).length > 0) {\n mountConfig.options = extraOptions;\n }\n const provider = await options.createProvider(mountConfig);\n ownedProviders.push(provider);\n await programAFS.mount(provider, mountDecl.target, { lenient: true });\n return true;\n };\n\n // 5. Mount dependencies — shared via ProjectionProvider, owned via factory\n for (const mountDecl of manifest.mounts) {\n const isOwned = mountDecl.shared === false;\n\n // Apply user-side mount override (from mounts.toml) if available\n const override = options?.mountOverrides?.find((o) => o.target === mountDecl.target);\n const effectiveUri = override?.uri || mountDecl.uri;\n\n try {\n if (isOwned) {\n // ── Owned mount: create independent provider via factory ──\n await createOwned(mountDecl, effectiveUri, override?.options);\n } else {\n // ── Shared mount: ProjectionProvider wrapping global AFS ──\n const matches = findMountByURI(globalAFS, effectiveUri);\n\n if (matches.length === 0) {\n // Fallback: try creating via factory as an owned provider\n let fallbackOk = false;\n if (options?.createProvider) {\n try {\n await createOwned(mountDecl, effectiveUri, override?.options);\n fallbackOk = true;\n } catch {\n // Factory fallback failed — fall through to error/skip\n }\n }\n if (!fallbackOk) {\n if (mountDecl.required) {\n throw new Error(\n `Required mount URI \"${safeURI(effectiveUri)}\" not found in host AFS. No provider is mounted with this URI.`,\n );\n }\n }\n continue;\n }\n\n if (matches.length > 1) {\n throw new Error(\n `Mount conflict: URI \"${safeURI(effectiveUri)}\" matches ${matches.length} providers in host AFS. Expected exactly 1.`,\n );\n }\n\n const hostMount = matches[0]!;\n const projection = new ProjectionProvider({\n name: `projection:${mountDecl.target.replace(/^\\//, \"\").replace(/\\//g, \"-\")}`,\n globalAFS,\n sourcePath: hostMount.path,\n // Always include \"stat\" and \"list\" — needed by AFS mount system (checkProviderOnMount\n // validates childrenCount via list when stat reports children)\n allowedOps: mountDecl.ops ? new Set([...mountDecl.ops, \"stat\", \"list\"]) : undefined,\n });\n await programAFS.mount(projection, mountDecl.target, { lenient: true });\n }\n } catch (err) {\n if (mountDecl.required) {\n // Clean up already-created owned providers before re-throwing\n await cleanupOwnedProviders(ownedProviders);\n throw err;\n }\n // optional mount failed, continue\n }\n }\n\n return { afs: programAFS, manifest, ownedProviders };\n}\n\n/**\n * Close all owned providers, swallowing individual errors.\n */\nasync function cleanupOwnedProviders(providers: AFSModule[]): Promise<void> {\n for (const provider of providers) {\n try {\n await provider.close?.();\n } catch {\n // Swallow individual close errors — best-effort cleanup\n }\n }\n}\n"],"mappings":"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"}
|
package/dist/registry.cjs
CHANGED
|
@@ -249,10 +249,14 @@ var ProviderRegistry = class {
|
|
|
249
249
|
manifest = this.matchManifest(manifests, parsed.scheme, packageName);
|
|
250
250
|
}
|
|
251
251
|
let schema = null;
|
|
252
|
-
if (manifest?.schema)
|
|
253
|
-
const
|
|
254
|
-
|
|
255
|
-
|
|
252
|
+
if (manifest?.schema) {
|
|
253
|
+
const ms = manifest.schema;
|
|
254
|
+
if (ms.type && ms.properties && typeof ms.properties === "object") schema = ms;
|
|
255
|
+
else try {
|
|
256
|
+
const { z } = await import("zod");
|
|
257
|
+
schema = z.toJSONSchema(ms);
|
|
258
|
+
} catch {}
|
|
259
|
+
}
|
|
256
260
|
if (!schema && ProviderClass.schema) try {
|
|
257
261
|
const zodSchema = ProviderClass.schema();
|
|
258
262
|
const { z } = await import("zod");
|
package/dist/registry.d.cts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"registry.d.cts","names":[],"sources":["../src/registry.ts"],"mappings":";;;;;;AAUA;KAAY,eAAA,IAAmB,KAAA,EAAO,WAAA,EAAa,MAAA,EAAQ,SAAA,KAAc,OAAA,CAAQ,SAAA;;;;;;;;;;;;;;;cA2QpE,gBAAA;EAAA,QACH,SAAA;EADmB;EAI3B,QAAA,CAAS,MAAA,UAAgB,OAAA,EAAS,eAAA;EAAA;EAKlC,GAAA,CAAI,MAAA;EAcuB;;;;;;;;EAFrB,eAAA,CAAgB,GAAA,WAAc,OAAA;IAClC,MAAA;IACA,IAAA,IAAQ,OAAA,UAAiB,OAAA,CAAQ,MAAA;IACjC,QAAA,EAAU,gBAAA;EAAA;EAfZ;;;;;;
|
|
1
|
+
{"version":3,"file":"registry.d.cts","names":[],"sources":["../src/registry.ts"],"mappings":";;;;;;AAUA;KAAY,eAAA,IAAmB,KAAA,EAAO,WAAA,EAAa,MAAA,EAAQ,SAAA,KAAc,OAAA,CAAQ,SAAA;;;;;;;;;;;;;;;cA2QpE,gBAAA;EAAA,QACH,SAAA;EADmB;EAI3B,QAAA,CAAS,MAAA,UAAgB,OAAA,EAAS,eAAA;EAAA;EAKlC,GAAA,CAAI,MAAA;EAcuB;;;;;;;;EAFrB,eAAA,CAAgB,GAAA,WAAc,OAAA;IAClC,MAAA;IACA,IAAA,IAAQ,OAAA,UAAiB,OAAA,CAAQ,MAAA;IACjC,QAAA,EAAU,gBAAA;EAAA;EAfZ;;;;;;EA8EM,cAAA,CAAe,KAAA,EAAO,WAAA,GAAc,OAAA,CAAQ,SAAA;EAhExC;;;EAAA,QAoFI,gBAAA;EAnFF;;;;;;;EAAA,QAkHE,mBAAA;EAwEN;;;EAAA,QAAA,YAAA;EAoIM;;;;;EAAA,QAnHN,aAAA;;;;;UAiCA,YAAA;;;;UAgCM,iBAAA;;;;;;;;UAkDA,gBAAA;;;;;UAiCN,gBAAA;AAAA"}
|
package/dist/registry.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"registry.d.mts","names":[],"sources":["../src/registry.ts"],"mappings":";;;;;;AAUA;KAAY,eAAA,IAAmB,KAAA,EAAO,WAAA,EAAa,MAAA,EAAQ,SAAA,KAAc,OAAA,CAAQ,SAAA;;;;;;;;;;;;;;;cA2QpE,gBAAA;EAAA,QACH,SAAA;EADmB;EAI3B,QAAA,CAAS,MAAA,UAAgB,OAAA,EAAS,eAAA;EAAA;EAKlC,GAAA,CAAI,MAAA;EAcuB;;;;;;;;EAFrB,eAAA,CAAgB,GAAA,WAAc,OAAA;IAClC,MAAA;IACA,IAAA,IAAQ,OAAA,UAAiB,OAAA,CAAQ,MAAA;IACjC,QAAA,EAAU,gBAAA;EAAA;EAfZ;;;;;;
|
|
1
|
+
{"version":3,"file":"registry.d.mts","names":[],"sources":["../src/registry.ts"],"mappings":";;;;;;AAUA;KAAY,eAAA,IAAmB,KAAA,EAAO,WAAA,EAAa,MAAA,EAAQ,SAAA,KAAc,OAAA,CAAQ,SAAA;;;;;;;;;;;;;;;cA2QpE,gBAAA;EAAA,QACH,SAAA;EADmB;EAI3B,QAAA,CAAS,MAAA,UAAgB,OAAA,EAAS,eAAA;EAAA;EAKlC,GAAA,CAAI,MAAA;EAcuB;;;;;;;;EAFrB,eAAA,CAAgB,GAAA,WAAc,OAAA;IAClC,MAAA;IACA,IAAA,IAAQ,OAAA,UAAiB,OAAA,CAAQ,MAAA;IACjC,QAAA,EAAU,gBAAA;EAAA;EAfZ;;;;;;EA8EM,cAAA,CAAe,KAAA,EAAO,WAAA,GAAc,OAAA,CAAQ,SAAA;EAhExC;;;EAAA,QAoFI,gBAAA;EAnFF;;;;;;;EAAA,QAkHE,mBAAA;EAwEN;;;EAAA,QAAA,YAAA;EAoIM;;;;;EAAA,QAnHN,aAAA;;;;;UAiCA,YAAA;;;;UAgCM,iBAAA;;;;;;;;UAkDA,gBAAA;;;;;UAiCN,gBAAA;AAAA"}
|
package/dist/registry.mjs
CHANGED
|
@@ -250,10 +250,14 @@ var ProviderRegistry = class {
|
|
|
250
250
|
manifest = this.matchManifest(manifests, parsed.scheme, packageName);
|
|
251
251
|
}
|
|
252
252
|
let schema = null;
|
|
253
|
-
if (manifest?.schema)
|
|
254
|
-
const
|
|
255
|
-
|
|
256
|
-
|
|
253
|
+
if (manifest?.schema) {
|
|
254
|
+
const ms = manifest.schema;
|
|
255
|
+
if (ms.type && ms.properties && typeof ms.properties === "object") schema = ms;
|
|
256
|
+
else try {
|
|
257
|
+
const { z } = await import("zod");
|
|
258
|
+
schema = z.toJSONSchema(ms);
|
|
259
|
+
} catch {}
|
|
260
|
+
}
|
|
257
261
|
if (!schema && ProviderClass.schema) try {
|
|
258
262
|
const zodSchema = ProviderClass.schema();
|
|
259
263
|
const { z } = await import("zod");
|
package/dist/registry.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"registry.mjs","names":["provider"],"sources":["../src/registry.ts"],"sourcesContent":["import { existsSync, readdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\nimport type { AFSModule, MountConfig, ProviderManifest } from \"./type.js\";\nimport { resolveEnvFromSchema } from \"./utils/schema.js\";\nimport { type ParsedURI, parseURI } from \"./utils/uri.js\";\nimport { extractSchemeFromTemplate, parseTemplate } from \"./utils/uri-template.js\";\n\n/**\n * Factory function that creates a provider from a mount config and pre-parsed URI.\n */\nexport type ProviderFactory = (mount: MountConfig, parsed: ParsedURI) => Promise<AFSModule>;\n\n/**\n * Resolve a package specifier to an importable path.\n * If the specifier is a directory path (e.g. from npm install),\n * read its package.json to find the ESM entry point.\n */\nfunction resolveImportPath(specifier: string): string {\n if (!specifier.startsWith(\"/\")) return specifier;\n\n const pkgJsonPath = join(specifier, \"package.json\");\n if (!existsSync(pkgJsonPath)) return specifier;\n\n try {\n const pkg = JSON.parse(readFileSync(pkgJsonPath, \"utf-8\"));\n const esmEntry = (typeof pkg.exports === \"object\" && pkg.exports[\".\"]?.import) || pkg.module;\n if (esmEntry) return join(specifier, esmEntry);\n if (pkg.main) return join(specifier, pkg.main);\n } catch {\n // Fall through to use original specifier\n }\n return specifier;\n}\n\n/** Mutex for npm install operations to prevent concurrent installs */\nconst npmInstallLocks = new Map<string, Promise<void>>();\n\n/**\n * Validate npm package name format.\n * Rejects path traversal and shell metacharacters.\n */\nfunction isValidNpmPackageName(name: string): boolean {\n if (!name || name.length > 214) return false;\n if (name.includes(\"..\") || name.startsWith(\"/\") || name.startsWith(\"\\\\\")) return false;\n const dangerous = [\";\", \"|\", \"&\", \"`\", \"$\", \"(\", \")\", \">\", \"<\", \"\\n\", \"\\r\", \"\\t\", \"\\x00\"];\n for (const char of dangerous) {\n if (name.includes(char)) return false;\n }\n if (name.startsWith(\"@\")) {\n const parts = name.slice(1).split(\"/\");\n if (parts.length !== 2 || !parts[0] || !parts[1]) return false;\n }\n return true;\n}\n\n/**\n * Install an npm package if not already present.\n * Uses per-package mutex to prevent concurrent installs.\n */\nasync function npmInstall(packageName: string, packagesDir: string): Promise<void> {\n const existing = npmInstallLocks.get(packageName);\n if (existing) {\n await existing;\n return;\n }\n\n const { mkdir } = await import(\"node:fs/promises\");\n const installPromise = (async () => {\n await mkdir(packagesDir, { recursive: true });\n const { execSync } = await import(\"node:child_process\");\n try {\n execSync(\n `npm install --prefix ${JSON.stringify(packagesDir)} ${JSON.stringify(packageName)}`,\n { stdio: \"pipe\", timeout: 120_000 },\n );\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n throw new Error(`Failed to install npm package \"${packageName}\": ${message}`);\n }\n })();\n\n npmInstallLocks.set(packageName, installPromise);\n try {\n await installPromise;\n } finally {\n npmInstallLocks.delete(packageName);\n }\n}\n\n/**\n * Get the npm packages install directory (~/.afs-config/packages/).\n */\nfunction getNpmPackagesDir(): string {\n const os = require(\"node:os\") as typeof import(\"node:os\");\n const { resolve } = require(\"node:path\") as typeof import(\"node:path\");\n return resolve(os.homedir(), \".afs-config\", \"packages\");\n}\n\n/** How often to check for package updates (24 hours). */\nconst UPDATE_CHECK_STALE_MS = 24 * 60 * 60 * 1000;\n\n/**\n * Trigger a background npm update if the package hasn't been checked recently.\n * Completely silent — never blocks, never throws, never produces output.\n */\nfunction npmUpdateIfStale(packageName: string, packagesDir: string): void {\n const checkFile = join(packagesDir, \".update-check.json\");\n const now = Date.now();\n\n let checks: Record<string, number> = {};\n try {\n checks = JSON.parse(readFileSync(checkFile, \"utf-8\"));\n } catch {\n /* file missing or corrupt — treat all packages as stale */\n }\n\n const lastCheck = checks[packageName] ?? 0;\n if (now - lastCheck < UPDATE_CHECK_STALE_MS) return;\n\n // Record check time immediately to prevent duplicate triggers\n checks[packageName] = now;\n try {\n writeFileSync(checkFile, JSON.stringify(checks, null, 2));\n } catch {\n /* write failure is non-fatal */\n }\n\n // Fire-and-forget background update\n npmUpdateBackground(packageName, packagesDir).catch(() => {});\n}\n\n/**\n * Run `npm update` for a single package in the background.\n * Errors are silently swallowed (e.g. no network).\n */\nasync function npmUpdateBackground(packageName: string, packagesDir: string): Promise<void> {\n const { execSync } = await import(\"node:child_process\");\n try {\n execSync(`npm update --prefix ${JSON.stringify(packagesDir)} ${JSON.stringify(packageName)}`, {\n stdio: \"ignore\",\n timeout: 120_000,\n });\n } catch {\n // Silent — no network, npm error, etc.\n }\n}\n\n// ─── pnpm workspace resolution ──────────────────────────────────────────────\n\n/** Cached workspace package map: package name → absolute directory path. */\nlet workspacePackageMap: Map<string, string> | undefined;\n\n/**\n * Walk up from `startDir` looking for `pnpm-workspace.yaml`.\n * Returns the workspace root directory, or undefined if not found.\n */\nfunction findWorkspaceRoot(startDir: string): string | undefined {\n let dir = startDir;\n for (;;) {\n if (existsSync(join(dir, \"pnpm-workspace.yaml\"))) return dir;\n const parent = dirname(dir);\n if (parent === dir) break;\n dir = parent;\n }\n return undefined;\n}\n\n/**\n * Build a map of package name → directory for all packages in the pnpm workspace.\n * Result is cached for the lifetime of the process.\n */\nfunction buildWorkspacePackageMap(workspaceRoot: string): Map<string, string> {\n if (workspacePackageMap) return workspacePackageMap;\n\n const yamlContent = readFileSync(join(workspaceRoot, \"pnpm-workspace.yaml\"), \"utf-8\");\n\n // Parse `packages:` globs — the format is simple enough for regex\n const globs: string[] = [];\n let inPackages = false;\n for (const line of yamlContent.split(\"\\n\")) {\n if (/^packages:\\s*$/.test(line)) {\n inPackages = true;\n continue;\n }\n if (inPackages) {\n const match = line.match(/^\\s+-\\s+(.+)$/);\n if (match) {\n globs.push(match[1]!.trim().replace(/['\"]/g, \"\"));\n } else if (/^\\S/.test(line)) {\n break; // next top-level key\n }\n }\n }\n\n const map = new Map<string, string>();\n\n for (const glob of globs) {\n if (glob.includes(\"*\")) {\n // Expand \"packages/*\" → list subdirs of \"packages/\"\n const baseDir = join(workspaceRoot, glob.split(\"*\")[0]!);\n if (!existsSync(baseDir)) continue;\n try {\n for (const entry of readdirSync(baseDir, { withFileTypes: true })) {\n if (!entry.isDirectory()) continue;\n const pkgDir = join(baseDir, entry.name);\n readPackageNameInto(map, pkgDir);\n }\n } catch {\n // baseDir unreadable — skip\n }\n } else {\n // Non-glob entry (e.g. \"scripts\", \"benchmarks\")\n readPackageNameInto(map, join(workspaceRoot, glob));\n }\n }\n\n workspacePackageMap = map;\n return map;\n}\n\n/** Read package.json in `dir` and add `name → dir` to the map. */\nfunction readPackageNameInto(map: Map<string, string>, dir: string): void {\n const pkgJsonPath = join(dir, \"package.json\");\n if (!existsSync(pkgJsonPath)) return;\n try {\n const pkg = JSON.parse(readFileSync(pkgJsonPath, \"utf-8\"));\n if (pkg.name) map.set(pkg.name, dir);\n } catch {\n // corrupt package.json — skip\n }\n}\n\n/**\n * Try to find a package inside the pnpm workspace.\n * Returns the package directory path, or undefined if not in a workspace or not found.\n */\nfunction locateInWorkspace(packageName: string): string | undefined {\n const root = findWorkspaceRoot(process.cwd());\n if (!root) return undefined;\n return buildWorkspacePackageMap(root).get(packageName);\n}\n\n// ─── Built-in provider package mapping ─────────────────────────────────────\n// Maps base scheme → npm package name for providers that don't follow\n// the @aigne/afs-{scheme} convention, or need explicit class name mapping.\n\n/**\n * Package name overrides for schemes that don't follow the @aigne/afs-{scheme} convention.\n * Class discovery uses the .manifest() static method — no class name mapping needed.\n */\nconst PACKAGE_OVERRIDES: Record<string, string> = {\n https: \"@aigne/afs-http\",\n};\n\n/**\n * Derive the base scheme for compound schemes.\n * e.g. \"mcp+stdio\" → \"mcp\", \"mcp+http\" → \"mcp\"\n */\nfunction baseScheme(scheme: string): string {\n const plusIdx = scheme.indexOf(\"+\");\n return plusIdx >= 0 ? scheme.slice(0, plusIdx) : scheme;\n}\n\n/**\n * Registry of provider factories with unified manifest-driven loading.\n *\n * Loading flow:\n * 1. parseURI → get scheme\n * 2. Check registered factories (workspace, custom) → use directly\n * 3. Resolve package: mount.provider or @aigne/afs-{baseScheme}\n * 4. Import package → get ProviderClass\n * 5. Get manifest from ProviderClass.manifest()\n * 6. Match manifest by scheme (for multi-manifest providers)\n * 7. parseTemplate(uriTemplate, body) → extract path variables\n * 8. Merge params: body vars > query > mount.options\n * 9. Construct provider with merged options\n */\nexport class ProviderRegistry {\n private factories = new Map<string, ProviderFactory>();\n\n /** Register a scheme → factory mapping. Overwrites any existing registration. */\n register(scheme: string, factory: ProviderFactory): void {\n this.factories.set(scheme.toLowerCase(), factory);\n }\n\n /** Check if a scheme has a registered factory. */\n has(scheme: string): boolean {\n return this.factories.has(scheme.toLowerCase());\n }\n\n /**\n * Get provider metadata (schema, auth, manifest) for a URI.\n *\n * Used by CLI credential resolution to get schema and auth method\n * without constructing the provider.\n *\n * Returns null if the provider class can't be loaded (e.g., unknown scheme).\n */\n async getProviderInfo(uri: string): Promise<{\n schema: any | null;\n auth: ((context: any) => Promise<Record<string, unknown> | null>) | undefined;\n manifest: ProviderManifest | null;\n } | null> {\n try {\n const parsed = parseURI(uri);\n const base = baseScheme(parsed.scheme);\n const packageName = PACKAGE_OVERRIDES[base] ?? `@aigne/afs-${base}`;\n\n const ProviderClass = await this.importProviderClass(packageName, base);\n\n // Get auth method\n const auth = ProviderClass.auth ? ProviderClass.auth.bind(ProviderClass) : undefined;\n\n // Get manifest\n let manifest: ProviderManifest | null = null;\n if (ProviderClass.manifest) {\n const manifests = this.getManifests(ProviderClass, packageName);\n manifest = this.matchManifest(manifests, parsed.scheme, packageName);\n }\n\n // Get schema: prefer manifest.schema (user-facing fields only),\n // fall back to deprecated static schema() (full constructor schema)\n let schema: any = null;\n if (manifest?.schema) {\n try {\n const { z } = await import(\"zod\");\n schema = (z as unknown as { toJSONSchema: (s: unknown) => unknown }).toJSONSchema(\n manifest.schema,\n );\n } catch {\n // Schema conversion failed — fall through\n }\n }\n if (!schema && ProviderClass.schema) {\n try {\n const zodSchema = ProviderClass.schema();\n const { z } = await import(\"zod\");\n schema = (z as unknown as { toJSONSchema: (s: unknown) => unknown }).toJSONSchema(\n zodSchema,\n );\n } catch {\n // Schema conversion failed — fall through\n }\n }\n\n return { schema, auth, manifest };\n } catch {\n return null;\n }\n }\n\n /**\n * Create a provider from a mount config.\n *\n * Uses registered factory if available, otherwise auto-loads\n * via manifest-driven resolution.\n */\n async createProvider(mount: MountConfig): Promise<AFSModule> {\n const parsed = parseURI(mount.uri);\n\n // Step 1: Check registered factories (workspace, custom providers)\n const factory = this.factories.get(parsed.scheme);\n if (factory) {\n const provider = await factory(mount, parsed);\n (provider as { uri?: string }).uri = mount.uri;\n return provider;\n }\n\n // Step 2: Auto-load via manifest-driven resolution\n const provider = await this.autoLoadProvider(mount, parsed);\n (provider as { uri?: string }).uri = mount.uri;\n return provider;\n }\n\n /**\n * Auto-load a provider using the manifest-driven unified flow.\n */\n private async autoLoadProvider(mount: MountConfig, parsed: ParsedURI): Promise<AFSModule> {\n // Step 3: Resolve package name\n const base = baseScheme(parsed.scheme);\n const packageName = PACKAGE_OVERRIDES[base] ?? `@aigne/afs-${base}`;\n\n // Step 4: Import the provider package\n const ProviderClass = await this.importProviderClass(packageName, base);\n\n // Step 5: Get manifest(s)\n const manifests = this.getManifests(ProviderClass, packageName);\n\n // Step 6: Match manifest by scheme\n const manifest = this.matchManifest(manifests, parsed.scheme, packageName);\n\n // Step 7: Parse template — extract path variables from URI body\n const templateVars = parseTemplate(manifest.uriTemplate, parsed.body);\n\n // Step 8: Merge params (body vars > query > mount.options)\n const mergedOptions = this.mergeOptions(templateVars, parsed.query, mount);\n\n // Step 9: Construct provider\n return this.constructProvider(ProviderClass, mount, parsed, mergedOptions, manifest);\n }\n\n /**\n * Import a provider class from a package name.\n * Resolution order:\n * 1. Direct import (works when package is a dependency of the importing module)\n * 2. createRequire from process.cwd() (works in monorepo dev environments)\n * 3. npm auto-install to ~/.afs-config/packages/\n */\n private async importProviderClass(\n packageName: string,\n scheme: string,\n explicitClassName?: string,\n ): Promise<ProviderClassLike> {\n let mod: Record<string, unknown>;\n\n try {\n mod = await this.resolveAndImport(packageName);\n } catch {\n // Package not found locally — try npm auto-install.\n // This covers both @aigne/* packages (e.g. used from core without CLI)\n // and third-party packages.\n if (!isValidNpmPackageName(packageName)) {\n throw new Error(\n `Unknown URI scheme \"${scheme}\": package \"${packageName}\" not found and name is invalid.`,\n );\n }\n\n const packagesDir = getNpmPackagesDir();\n const { resolve } = await import(\"node:path\");\n const nodeModulesPath = resolve(packagesDir, \"node_modules\", ...packageName.split(\"/\"));\n\n if (!existsSync(nodeModulesPath)) {\n await npmInstall(packageName, packagesDir);\n } else {\n // Package exists — check for stale version and update in background\n npmUpdateIfStale(packageName, packagesDir);\n }\n\n const importPath = resolveImportPath(nodeModulesPath);\n try {\n mod = (await import(importPath)) as Record<string, unknown>;\n } catch (error) {\n const msg = error instanceof Error ? error.message : String(error);\n throw new Error(\n `Failed to import provider package \"${packageName}\" for scheme \"${scheme}\": ${msg}`,\n );\n }\n }\n\n // Find the provider class in the module\n if (explicitClassName && mod[explicitClassName]) {\n return mod[explicitClassName] as ProviderClassLike;\n }\n\n // Convention: try common export patterns\n // 1. Named export matching AFS{PascalCase}\n const conventionName = `AFS${scheme.charAt(0).toUpperCase()}${scheme.slice(1).toUpperCase()}`;\n if (mod[conventionName]) return mod[conventionName] as ProviderClassLike;\n\n // 2. Try common naming patterns for the scheme\n for (const key of Object.keys(mod)) {\n const val = mod[key];\n if (typeof val === \"function\" && key !== \"default\" && \"manifest\" in val) {\n return val as ProviderClassLike;\n }\n }\n\n // 3. Default export\n if (mod.default && typeof mod.default === \"function\") {\n return mod.default as ProviderClassLike;\n }\n\n throw new Error(\n `Package \"${packageName}\" does not export a valid AFS Provider class for scheme \"${scheme}\".`,\n );\n }\n\n /**\n * Get manifest(s) from a provider class.\n */\n private getManifests(ProviderClass: ProviderClassLike, packageName: string): ProviderManifest[] {\n if (!ProviderClass.manifest) {\n throw new Error(\n `Provider class from \"${packageName}\" does not implement static manifest(). ` +\n `Please add a static manifest() method to the provider class.`,\n );\n }\n\n const result = ProviderClass.manifest();\n return Array.isArray(result) ? result : [result];\n }\n\n /**\n * Find the matching manifest for a given scheme.\n * For multi-manifest providers (e.g., MCP with mcp+stdio, mcp+http, mcp+sse),\n * match by the full scheme from the URI template.\n */\n private matchManifest(\n manifests: ProviderManifest[],\n scheme: string,\n packageName: string,\n ): ProviderManifest {\n if (manifests.length === 1) {\n return manifests[0]!;\n }\n\n // Match by extracting scheme from each manifest's uriTemplate\n for (const m of manifests) {\n try {\n const templateScheme = extractSchemeFromTemplate(m.uriTemplate);\n if (templateScheme === scheme) return m;\n } catch {\n // Skip invalid templates\n }\n }\n\n // Fallback: use first manifest\n if (manifests.length > 0) {\n return manifests[0]!;\n }\n\n throw new Error(\n `No matching manifest found for scheme \"${scheme}\" in package \"${packageName}\".`,\n );\n }\n\n /**\n * Merge parameters from multiple sources.\n * Priority: template vars (from URI body) > query params > mount.options\n */\n private mergeOptions(\n templateVars: Record<string, string | undefined>,\n query: Record<string, string | string[]>,\n mount: MountConfig,\n ): Record<string, unknown> {\n const result: Record<string, unknown> = {};\n\n // Start with mount.options (lowest priority)\n if (mount.options) {\n Object.assign(result, mount.options);\n }\n\n // Layer on query params (medium priority)\n for (const [key, value] of Object.entries(query)) {\n if (value !== \"\") {\n result[key] = value;\n }\n }\n\n // Layer on template vars (highest priority)\n for (const [key, value] of Object.entries(templateVars)) {\n if (value !== undefined) {\n result[key] = value;\n }\n }\n\n return result;\n }\n\n /**\n * Construct a provider instance with merged options.\n */\n private async constructProvider(\n ProviderClass: ProviderClassLike,\n mount: MountConfig,\n _parsed: ParsedURI,\n mergedOptions: Record<string, unknown>,\n manifest: ProviderManifest,\n ): Promise<AFSModule> {\n // Resolve env vars declared in manifest schema (e.g. AIGNE_HUB_API_KEY → apiKey)\n const envResolved = manifest.schema ? resolveEnvFromSchema(manifest.schema as any) : {};\n\n const constructorOptions: Record<string, unknown> = {\n ...envResolved,\n ...mergedOptions,\n name: mount.path.slice(1).replace(/\\//g, \"-\") || manifest.name,\n description: mount.description,\n accessMode: mount.access_mode,\n uri: mount.uri,\n };\n\n // Only inject registry when the provider schema declares it (e.g. workspace).\n // Providers with .strict() schemas reject unknown keys, so unconditional injection breaks them.\n const schema = ProviderClass.schema?.();\n if (schema?.shape?.registry) {\n constructorOptions.registry = this;\n }\n\n // Mount-level auth/token passthrough\n if (mount.auth !== undefined) constructorOptions.auth = mount.auth;\n if (mount.token !== undefined) constructorOptions.token = mount.token;\n\n // Construct the provider — all normalization is handled by the provider itself\n const provider = new ProviderClass(constructorOptions);\n\n // Set registry on the provider after construction (not in constructor options)\n // to avoid strict Zod schema rejection of unknown keys\n (provider as { registry?: ProviderRegistry }).registry = this;\n\n // Generic post-construction initialization\n await provider.ready?.();\n\n return provider;\n }\n\n /**\n * Resolve and import a package, trying multiple resolution strategies.\n *\n * In a monorepo (pnpm workspace), `import(\"@aigne/afs-fs\")` inside packages/core\n * won't find packages/cli's dependencies. We locate the package directory via\n * createRequire, then use resolveImportPath to find the correct ESM entry.\n */\n private async resolveAndImport(packageName: string): Promise<Record<string, unknown>> {\n // Strategy 1: Direct import (works if package is a direct/transitive dependency)\n try {\n const importPath = resolveImportPath(packageName);\n return (await import(importPath)) as Record<string, unknown>;\n } catch {\n // Fall through to next strategy\n }\n\n // Strategy 2+3: Locate the package directory via createRequire,\n // then use resolveImportPath to find the correct ESM entry point.\n const packageDir = this.locatePackageDir(packageName);\n if (packageDir) {\n const importPath = resolveImportPath(packageDir);\n return (await import(importPath)) as Record<string, unknown>;\n }\n\n // Strategy 4: pnpm workspace scan — packages in providers/* and packages/*\n // aren't hoisted to root node_modules, so createRequire can't find them.\n const workspaceDir = locateInWorkspace(packageName);\n if (workspaceDir) {\n const importPath = resolveImportPath(workspaceDir);\n return (await import(importPath)) as Record<string, unknown>;\n }\n\n // All strategies failed\n throw new Error(`Cannot resolve module \"${packageName}\"`);\n }\n\n /**\n * Locate a package directory using createRequire from various contexts.\n * Returns the package directory path, or undefined if not found.\n */\n private locatePackageDir(packageName: string): string | undefined {\n const { createRequire } = require(\"node:module\") as typeof import(\"node:module\");\n\n // Try resolving the package's package.json to find its directory\n const contexts = [\n join(process.cwd(), \"__resolve__.js\"),\n ...(process.argv[1] ? [join(dirname(process.argv[1]), \"__resolve__.js\")] : []),\n ];\n\n for (const context of contexts) {\n try {\n const req = createRequire(context);\n // Resolve package.json to get the package directory reliably\n const pkgJsonPath = req.resolve(join(packageName, \"package.json\"));\n return dirname(pkgJsonPath);\n } catch {\n // Try resolving the main entry and walking up to find package.json\n try {\n const req = createRequire(context);\n const resolvedEntry = req.resolve(packageName);\n // Walk up from the resolved entry to find the package root\n let dir = dirname(resolvedEntry);\n for (let i = 0; i < 5; i++) {\n if (existsSync(join(dir, \"package.json\"))) {\n return dir;\n }\n const parent = dirname(dir);\n if (parent === dir) break;\n dir = parent;\n }\n } catch {\n // Continue to next context\n }\n }\n }\n\n return undefined;\n }\n}\n\n/**\n * Provider class shape (what we expect from importing a provider package).\n */\ntype ProviderClassLike = {\n manifest?(): ProviderManifest | ProviderManifest[];\n schema?(): any;\n auth?(context: any): Promise<Record<string, unknown> | null>;\n new (options: any): AFSModule;\n};\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"registry.mjs","names":["provider"],"sources":["../src/registry.ts"],"sourcesContent":["import { existsSync, readdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { dirname, join } from \"node:path\";\nimport type { AFSModule, MountConfig, ProviderManifest } from \"./type.js\";\nimport { resolveEnvFromSchema } from \"./utils/schema.js\";\nimport { type ParsedURI, parseURI } from \"./utils/uri.js\";\nimport { extractSchemeFromTemplate, parseTemplate } from \"./utils/uri-template.js\";\n\n/**\n * Factory function that creates a provider from a mount config and pre-parsed URI.\n */\nexport type ProviderFactory = (mount: MountConfig, parsed: ParsedURI) => Promise<AFSModule>;\n\n/**\n * Resolve a package specifier to an importable path.\n * If the specifier is a directory path (e.g. from npm install),\n * read its package.json to find the ESM entry point.\n */\nfunction resolveImportPath(specifier: string): string {\n if (!specifier.startsWith(\"/\")) return specifier;\n\n const pkgJsonPath = join(specifier, \"package.json\");\n if (!existsSync(pkgJsonPath)) return specifier;\n\n try {\n const pkg = JSON.parse(readFileSync(pkgJsonPath, \"utf-8\"));\n const esmEntry = (typeof pkg.exports === \"object\" && pkg.exports[\".\"]?.import) || pkg.module;\n if (esmEntry) return join(specifier, esmEntry);\n if (pkg.main) return join(specifier, pkg.main);\n } catch {\n // Fall through to use original specifier\n }\n return specifier;\n}\n\n/** Mutex for npm install operations to prevent concurrent installs */\nconst npmInstallLocks = new Map<string, Promise<void>>();\n\n/**\n * Validate npm package name format.\n * Rejects path traversal and shell metacharacters.\n */\nfunction isValidNpmPackageName(name: string): boolean {\n if (!name || name.length > 214) return false;\n if (name.includes(\"..\") || name.startsWith(\"/\") || name.startsWith(\"\\\\\")) return false;\n const dangerous = [\";\", \"|\", \"&\", \"`\", \"$\", \"(\", \")\", \">\", \"<\", \"\\n\", \"\\r\", \"\\t\", \"\\x00\"];\n for (const char of dangerous) {\n if (name.includes(char)) return false;\n }\n if (name.startsWith(\"@\")) {\n const parts = name.slice(1).split(\"/\");\n if (parts.length !== 2 || !parts[0] || !parts[1]) return false;\n }\n return true;\n}\n\n/**\n * Install an npm package if not already present.\n * Uses per-package mutex to prevent concurrent installs.\n */\nasync function npmInstall(packageName: string, packagesDir: string): Promise<void> {\n const existing = npmInstallLocks.get(packageName);\n if (existing) {\n await existing;\n return;\n }\n\n const { mkdir } = await import(\"node:fs/promises\");\n const installPromise = (async () => {\n await mkdir(packagesDir, { recursive: true });\n const { execSync } = await import(\"node:child_process\");\n try {\n execSync(\n `npm install --prefix ${JSON.stringify(packagesDir)} ${JSON.stringify(packageName)}`,\n { stdio: \"pipe\", timeout: 120_000 },\n );\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n throw new Error(`Failed to install npm package \"${packageName}\": ${message}`);\n }\n })();\n\n npmInstallLocks.set(packageName, installPromise);\n try {\n await installPromise;\n } finally {\n npmInstallLocks.delete(packageName);\n }\n}\n\n/**\n * Get the npm packages install directory (~/.afs-config/packages/).\n */\nfunction getNpmPackagesDir(): string {\n const os = require(\"node:os\") as typeof import(\"node:os\");\n const { resolve } = require(\"node:path\") as typeof import(\"node:path\");\n return resolve(os.homedir(), \".afs-config\", \"packages\");\n}\n\n/** How often to check for package updates (24 hours). */\nconst UPDATE_CHECK_STALE_MS = 24 * 60 * 60 * 1000;\n\n/**\n * Trigger a background npm update if the package hasn't been checked recently.\n * Completely silent — never blocks, never throws, never produces output.\n */\nfunction npmUpdateIfStale(packageName: string, packagesDir: string): void {\n const checkFile = join(packagesDir, \".update-check.json\");\n const now = Date.now();\n\n let checks: Record<string, number> = {};\n try {\n checks = JSON.parse(readFileSync(checkFile, \"utf-8\"));\n } catch {\n /* file missing or corrupt — treat all packages as stale */\n }\n\n const lastCheck = checks[packageName] ?? 0;\n if (now - lastCheck < UPDATE_CHECK_STALE_MS) return;\n\n // Record check time immediately to prevent duplicate triggers\n checks[packageName] = now;\n try {\n writeFileSync(checkFile, JSON.stringify(checks, null, 2));\n } catch {\n /* write failure is non-fatal */\n }\n\n // Fire-and-forget background update\n npmUpdateBackground(packageName, packagesDir).catch(() => {});\n}\n\n/**\n * Run `npm update` for a single package in the background.\n * Errors are silently swallowed (e.g. no network).\n */\nasync function npmUpdateBackground(packageName: string, packagesDir: string): Promise<void> {\n const { execSync } = await import(\"node:child_process\");\n try {\n execSync(`npm update --prefix ${JSON.stringify(packagesDir)} ${JSON.stringify(packageName)}`, {\n stdio: \"ignore\",\n timeout: 120_000,\n });\n } catch {\n // Silent — no network, npm error, etc.\n }\n}\n\n// ─── pnpm workspace resolution ──────────────────────────────────────────────\n\n/** Cached workspace package map: package name → absolute directory path. */\nlet workspacePackageMap: Map<string, string> | undefined;\n\n/**\n * Walk up from `startDir` looking for `pnpm-workspace.yaml`.\n * Returns the workspace root directory, or undefined if not found.\n */\nfunction findWorkspaceRoot(startDir: string): string | undefined {\n let dir = startDir;\n for (;;) {\n if (existsSync(join(dir, \"pnpm-workspace.yaml\"))) return dir;\n const parent = dirname(dir);\n if (parent === dir) break;\n dir = parent;\n }\n return undefined;\n}\n\n/**\n * Build a map of package name → directory for all packages in the pnpm workspace.\n * Result is cached for the lifetime of the process.\n */\nfunction buildWorkspacePackageMap(workspaceRoot: string): Map<string, string> {\n if (workspacePackageMap) return workspacePackageMap;\n\n const yamlContent = readFileSync(join(workspaceRoot, \"pnpm-workspace.yaml\"), \"utf-8\");\n\n // Parse `packages:` globs — the format is simple enough for regex\n const globs: string[] = [];\n let inPackages = false;\n for (const line of yamlContent.split(\"\\n\")) {\n if (/^packages:\\s*$/.test(line)) {\n inPackages = true;\n continue;\n }\n if (inPackages) {\n const match = line.match(/^\\s+-\\s+(.+)$/);\n if (match) {\n globs.push(match[1]!.trim().replace(/['\"]/g, \"\"));\n } else if (/^\\S/.test(line)) {\n break; // next top-level key\n }\n }\n }\n\n const map = new Map<string, string>();\n\n for (const glob of globs) {\n if (glob.includes(\"*\")) {\n // Expand \"packages/*\" → list subdirs of \"packages/\"\n const baseDir = join(workspaceRoot, glob.split(\"*\")[0]!);\n if (!existsSync(baseDir)) continue;\n try {\n for (const entry of readdirSync(baseDir, { withFileTypes: true })) {\n if (!entry.isDirectory()) continue;\n const pkgDir = join(baseDir, entry.name);\n readPackageNameInto(map, pkgDir);\n }\n } catch {\n // baseDir unreadable — skip\n }\n } else {\n // Non-glob entry (e.g. \"scripts\", \"benchmarks\")\n readPackageNameInto(map, join(workspaceRoot, glob));\n }\n }\n\n workspacePackageMap = map;\n return map;\n}\n\n/** Read package.json in `dir` and add `name → dir` to the map. */\nfunction readPackageNameInto(map: Map<string, string>, dir: string): void {\n const pkgJsonPath = join(dir, \"package.json\");\n if (!existsSync(pkgJsonPath)) return;\n try {\n const pkg = JSON.parse(readFileSync(pkgJsonPath, \"utf-8\"));\n if (pkg.name) map.set(pkg.name, dir);\n } catch {\n // corrupt package.json — skip\n }\n}\n\n/**\n * Try to find a package inside the pnpm workspace.\n * Returns the package directory path, or undefined if not in a workspace or not found.\n */\nfunction locateInWorkspace(packageName: string): string | undefined {\n const root = findWorkspaceRoot(process.cwd());\n if (!root) return undefined;\n return buildWorkspacePackageMap(root).get(packageName);\n}\n\n// ─── Built-in provider package mapping ─────────────────────────────────────\n// Maps base scheme → npm package name for providers that don't follow\n// the @aigne/afs-{scheme} convention, or need explicit class name mapping.\n\n/**\n * Package name overrides for schemes that don't follow the @aigne/afs-{scheme} convention.\n * Class discovery uses the .manifest() static method — no class name mapping needed.\n */\nconst PACKAGE_OVERRIDES: Record<string, string> = {\n https: \"@aigne/afs-http\",\n};\n\n/**\n * Derive the base scheme for compound schemes.\n * e.g. \"mcp+stdio\" → \"mcp\", \"mcp+http\" → \"mcp\"\n */\nfunction baseScheme(scheme: string): string {\n const plusIdx = scheme.indexOf(\"+\");\n return plusIdx >= 0 ? scheme.slice(0, plusIdx) : scheme;\n}\n\n/**\n * Registry of provider factories with unified manifest-driven loading.\n *\n * Loading flow:\n * 1. parseURI → get scheme\n * 2. Check registered factories (workspace, custom) → use directly\n * 3. Resolve package: mount.provider or @aigne/afs-{baseScheme}\n * 4. Import package → get ProviderClass\n * 5. Get manifest from ProviderClass.manifest()\n * 6. Match manifest by scheme (for multi-manifest providers)\n * 7. parseTemplate(uriTemplate, body) → extract path variables\n * 8. Merge params: body vars > query > mount.options\n * 9. Construct provider with merged options\n */\nexport class ProviderRegistry {\n private factories = new Map<string, ProviderFactory>();\n\n /** Register a scheme → factory mapping. Overwrites any existing registration. */\n register(scheme: string, factory: ProviderFactory): void {\n this.factories.set(scheme.toLowerCase(), factory);\n }\n\n /** Check if a scheme has a registered factory. */\n has(scheme: string): boolean {\n return this.factories.has(scheme.toLowerCase());\n }\n\n /**\n * Get provider metadata (schema, auth, manifest) for a URI.\n *\n * Used by CLI credential resolution to get schema and auth method\n * without constructing the provider.\n *\n * Returns null if the provider class can't be loaded (e.g., unknown scheme).\n */\n async getProviderInfo(uri: string): Promise<{\n schema: any | null;\n auth: ((context: any) => Promise<Record<string, unknown> | null>) | undefined;\n manifest: ProviderManifest | null;\n } | null> {\n try {\n const parsed = parseURI(uri);\n const base = baseScheme(parsed.scheme);\n const packageName = PACKAGE_OVERRIDES[base] ?? `@aigne/afs-${base}`;\n\n const ProviderClass = await this.importProviderClass(packageName, base);\n\n // Get auth method\n const auth = ProviderClass.auth ? ProviderClass.auth.bind(ProviderClass) : undefined;\n\n // Get manifest\n let manifest: ProviderManifest | null = null;\n if (ProviderClass.manifest) {\n const manifests = this.getManifests(ProviderClass, packageName);\n manifest = this.matchManifest(manifests, parsed.scheme, packageName);\n }\n\n // Get schema: prefer manifest.schema (user-facing fields only),\n // fall back to deprecated static schema() (full constructor schema).\n // manifest.schema can be either a Zod schema (needs toJSONSchema) or\n // a plain JSON Schema object (used directly).\n let schema: any = null;\n if (manifest?.schema) {\n const ms = manifest.schema as any;\n if (ms.type && ms.properties && typeof ms.properties === \"object\") {\n // Already a plain JSON Schema object — use directly\n schema = ms;\n } else {\n // Assume Zod schema — convert to JSON Schema\n try {\n const { z } = await import(\"zod\");\n schema = (z as unknown as { toJSONSchema: (s: unknown) => unknown }).toJSONSchema(ms);\n } catch {\n // Schema conversion failed — fall through\n }\n }\n }\n if (!schema && ProviderClass.schema) {\n try {\n const zodSchema = ProviderClass.schema();\n const { z } = await import(\"zod\");\n schema = (z as unknown as { toJSONSchema: (s: unknown) => unknown }).toJSONSchema(\n zodSchema,\n );\n } catch {\n // Schema conversion failed — fall through\n }\n }\n\n return { schema, auth, manifest };\n } catch {\n return null;\n }\n }\n\n /**\n * Create a provider from a mount config.\n *\n * Uses registered factory if available, otherwise auto-loads\n * via manifest-driven resolution.\n */\n async createProvider(mount: MountConfig): Promise<AFSModule> {\n const parsed = parseURI(mount.uri);\n\n // Step 1: Check registered factories (workspace, custom providers)\n const factory = this.factories.get(parsed.scheme);\n if (factory) {\n const provider = await factory(mount, parsed);\n (provider as { uri?: string }).uri = mount.uri;\n return provider;\n }\n\n // Step 2: Auto-load via manifest-driven resolution\n const provider = await this.autoLoadProvider(mount, parsed);\n (provider as { uri?: string }).uri = mount.uri;\n return provider;\n }\n\n /**\n * Auto-load a provider using the manifest-driven unified flow.\n */\n private async autoLoadProvider(mount: MountConfig, parsed: ParsedURI): Promise<AFSModule> {\n // Step 3: Resolve package name\n const base = baseScheme(parsed.scheme);\n const packageName = PACKAGE_OVERRIDES[base] ?? `@aigne/afs-${base}`;\n\n // Step 4: Import the provider package\n const ProviderClass = await this.importProviderClass(packageName, base);\n\n // Step 5: Get manifest(s)\n const manifests = this.getManifests(ProviderClass, packageName);\n\n // Step 6: Match manifest by scheme\n const manifest = this.matchManifest(manifests, parsed.scheme, packageName);\n\n // Step 7: Parse template — extract path variables from URI body\n const templateVars = parseTemplate(manifest.uriTemplate, parsed.body);\n\n // Step 8: Merge params (body vars > query > mount.options)\n const mergedOptions = this.mergeOptions(templateVars, parsed.query, mount);\n\n // Step 9: Construct provider\n return this.constructProvider(ProviderClass, mount, parsed, mergedOptions, manifest);\n }\n\n /**\n * Import a provider class from a package name.\n * Resolution order:\n * 1. Direct import (works when package is a dependency of the importing module)\n * 2. createRequire from process.cwd() (works in monorepo dev environments)\n * 3. npm auto-install to ~/.afs-config/packages/\n */\n private async importProviderClass(\n packageName: string,\n scheme: string,\n explicitClassName?: string,\n ): Promise<ProviderClassLike> {\n let mod: Record<string, unknown>;\n\n try {\n mod = await this.resolveAndImport(packageName);\n } catch {\n // Package not found locally — try npm auto-install.\n // This covers both @aigne/* packages (e.g. used from core without CLI)\n // and third-party packages.\n if (!isValidNpmPackageName(packageName)) {\n throw new Error(\n `Unknown URI scheme \"${scheme}\": package \"${packageName}\" not found and name is invalid.`,\n );\n }\n\n const packagesDir = getNpmPackagesDir();\n const { resolve } = await import(\"node:path\");\n const nodeModulesPath = resolve(packagesDir, \"node_modules\", ...packageName.split(\"/\"));\n\n if (!existsSync(nodeModulesPath)) {\n await npmInstall(packageName, packagesDir);\n } else {\n // Package exists — check for stale version and update in background\n npmUpdateIfStale(packageName, packagesDir);\n }\n\n const importPath = resolveImportPath(nodeModulesPath);\n try {\n mod = (await import(importPath)) as Record<string, unknown>;\n } catch (error) {\n const msg = error instanceof Error ? error.message : String(error);\n throw new Error(\n `Failed to import provider package \"${packageName}\" for scheme \"${scheme}\": ${msg}`,\n );\n }\n }\n\n // Find the provider class in the module\n if (explicitClassName && mod[explicitClassName]) {\n return mod[explicitClassName] as ProviderClassLike;\n }\n\n // Convention: try common export patterns\n // 1. Named export matching AFS{PascalCase}\n const conventionName = `AFS${scheme.charAt(0).toUpperCase()}${scheme.slice(1).toUpperCase()}`;\n if (mod[conventionName]) return mod[conventionName] as ProviderClassLike;\n\n // 2. Try common naming patterns for the scheme\n for (const key of Object.keys(mod)) {\n const val = mod[key];\n if (typeof val === \"function\" && key !== \"default\" && \"manifest\" in val) {\n return val as ProviderClassLike;\n }\n }\n\n // 3. Default export\n if (mod.default && typeof mod.default === \"function\") {\n return mod.default as ProviderClassLike;\n }\n\n throw new Error(\n `Package \"${packageName}\" does not export a valid AFS Provider class for scheme \"${scheme}\".`,\n );\n }\n\n /**\n * Get manifest(s) from a provider class.\n */\n private getManifests(ProviderClass: ProviderClassLike, packageName: string): ProviderManifest[] {\n if (!ProviderClass.manifest) {\n throw new Error(\n `Provider class from \"${packageName}\" does not implement static manifest(). ` +\n `Please add a static manifest() method to the provider class.`,\n );\n }\n\n const result = ProviderClass.manifest();\n return Array.isArray(result) ? result : [result];\n }\n\n /**\n * Find the matching manifest for a given scheme.\n * For multi-manifest providers (e.g., MCP with mcp+stdio, mcp+http, mcp+sse),\n * match by the full scheme from the URI template.\n */\n private matchManifest(\n manifests: ProviderManifest[],\n scheme: string,\n packageName: string,\n ): ProviderManifest {\n if (manifests.length === 1) {\n return manifests[0]!;\n }\n\n // Match by extracting scheme from each manifest's uriTemplate\n for (const m of manifests) {\n try {\n const templateScheme = extractSchemeFromTemplate(m.uriTemplate);\n if (templateScheme === scheme) return m;\n } catch {\n // Skip invalid templates\n }\n }\n\n // Fallback: use first manifest\n if (manifests.length > 0) {\n return manifests[0]!;\n }\n\n throw new Error(\n `No matching manifest found for scheme \"${scheme}\" in package \"${packageName}\".`,\n );\n }\n\n /**\n * Merge parameters from multiple sources.\n * Priority: template vars (from URI body) > query params > mount.options\n */\n private mergeOptions(\n templateVars: Record<string, string | undefined>,\n query: Record<string, string | string[]>,\n mount: MountConfig,\n ): Record<string, unknown> {\n const result: Record<string, unknown> = {};\n\n // Start with mount.options (lowest priority)\n if (mount.options) {\n Object.assign(result, mount.options);\n }\n\n // Layer on query params (medium priority)\n for (const [key, value] of Object.entries(query)) {\n if (value !== \"\") {\n result[key] = value;\n }\n }\n\n // Layer on template vars (highest priority)\n for (const [key, value] of Object.entries(templateVars)) {\n if (value !== undefined) {\n result[key] = value;\n }\n }\n\n return result;\n }\n\n /**\n * Construct a provider instance with merged options.\n */\n private async constructProvider(\n ProviderClass: ProviderClassLike,\n mount: MountConfig,\n _parsed: ParsedURI,\n mergedOptions: Record<string, unknown>,\n manifest: ProviderManifest,\n ): Promise<AFSModule> {\n // Resolve env vars declared in manifest schema (e.g. AIGNE_HUB_API_KEY → apiKey)\n const envResolved = manifest.schema ? resolveEnvFromSchema(manifest.schema as any) : {};\n\n const constructorOptions: Record<string, unknown> = {\n ...envResolved,\n ...mergedOptions,\n name: mount.path.slice(1).replace(/\\//g, \"-\") || manifest.name,\n description: mount.description,\n accessMode: mount.access_mode,\n uri: mount.uri,\n };\n\n // Only inject registry when the provider schema declares it (e.g. workspace).\n // Providers with .strict() schemas reject unknown keys, so unconditional injection breaks them.\n const schema = ProviderClass.schema?.();\n if (schema?.shape?.registry) {\n constructorOptions.registry = this;\n }\n\n // Mount-level auth/token passthrough\n if (mount.auth !== undefined) constructorOptions.auth = mount.auth;\n if (mount.token !== undefined) constructorOptions.token = mount.token;\n\n // Construct the provider — all normalization is handled by the provider itself\n const provider = new ProviderClass(constructorOptions);\n\n // Set registry on the provider after construction (not in constructor options)\n // to avoid strict Zod schema rejection of unknown keys\n (provider as { registry?: ProviderRegistry }).registry = this;\n\n // Generic post-construction initialization\n await provider.ready?.();\n\n return provider;\n }\n\n /**\n * Resolve and import a package, trying multiple resolution strategies.\n *\n * In a monorepo (pnpm workspace), `import(\"@aigne/afs-fs\")` inside packages/core\n * won't find packages/cli's dependencies. We locate the package directory via\n * createRequire, then use resolveImportPath to find the correct ESM entry.\n */\n private async resolveAndImport(packageName: string): Promise<Record<string, unknown>> {\n // Strategy 1: Direct import (works if package is a direct/transitive dependency)\n try {\n const importPath = resolveImportPath(packageName);\n return (await import(importPath)) as Record<string, unknown>;\n } catch {\n // Fall through to next strategy\n }\n\n // Strategy 2+3: Locate the package directory via createRequire,\n // then use resolveImportPath to find the correct ESM entry point.\n const packageDir = this.locatePackageDir(packageName);\n if (packageDir) {\n const importPath = resolveImportPath(packageDir);\n return (await import(importPath)) as Record<string, unknown>;\n }\n\n // Strategy 4: pnpm workspace scan — packages in providers/* and packages/*\n // aren't hoisted to root node_modules, so createRequire can't find them.\n const workspaceDir = locateInWorkspace(packageName);\n if (workspaceDir) {\n const importPath = resolveImportPath(workspaceDir);\n return (await import(importPath)) as Record<string, unknown>;\n }\n\n // All strategies failed\n throw new Error(`Cannot resolve module \"${packageName}\"`);\n }\n\n /**\n * Locate a package directory using createRequire from various contexts.\n * Returns the package directory path, or undefined if not found.\n */\n private locatePackageDir(packageName: string): string | undefined {\n const { createRequire } = require(\"node:module\") as typeof import(\"node:module\");\n\n // Try resolving the package's package.json to find its directory\n const contexts = [\n join(process.cwd(), \"__resolve__.js\"),\n ...(process.argv[1] ? [join(dirname(process.argv[1]), \"__resolve__.js\")] : []),\n ];\n\n for (const context of contexts) {\n try {\n const req = createRequire(context);\n // Resolve package.json to get the package directory reliably\n const pkgJsonPath = req.resolve(join(packageName, \"package.json\"));\n return dirname(pkgJsonPath);\n } catch {\n // Try resolving the main entry and walking up to find package.json\n try {\n const req = createRequire(context);\n const resolvedEntry = req.resolve(packageName);\n // Walk up from the resolved entry to find the package root\n let dir = dirname(resolvedEntry);\n for (let i = 0; i < 5; i++) {\n if (existsSync(join(dir, \"package.json\"))) {\n return dir;\n }\n const parent = dirname(dir);\n if (parent === dir) break;\n dir = parent;\n }\n } catch {\n // Continue to next context\n }\n }\n }\n\n return undefined;\n }\n}\n\n/**\n * Provider class shape (what we expect from importing a provider package).\n */\ntype ProviderClassLike = {\n manifest?(): ProviderManifest | ProviderManifest[];\n schema?(): any;\n auth?(context: any): Promise<Record<string, unknown> | null>;\n new (options: any): AFSModule;\n};\n"],"mappings":"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"}
|
package/dist/utils/schema.cjs
CHANGED
|
@@ -96,9 +96,11 @@ function buildAdHocSchema(values, sensitiveArgs = []) {
|
|
|
96
96
|
if (sensitiveSet.has(key)) prop.sensitive = true;
|
|
97
97
|
properties[key] = prop;
|
|
98
98
|
}
|
|
99
|
+
const required = Object.keys(values);
|
|
99
100
|
return {
|
|
100
101
|
type: "object",
|
|
101
|
-
properties
|
|
102
|
+
properties,
|
|
103
|
+
...required.length > 0 ? { required } : {}
|
|
102
104
|
};
|
|
103
105
|
}
|
|
104
106
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schema.d.cts","names":[],"sources":["../../src/utils/schema.ts"],"mappings":";;;AAiEA;;;;;;;;;AAAA,iBApCgB,kBAAA,CAAmB,MAAA,EAAQ,WAAA;;;;;;;;;;iBAoC3B,cAAA,CAAe,MAAA,EAAQ,WAAA,GAAc,MAAA;;;;;AAkErD;;;;;AAYA;iBArCgB,oBAAA,CACd,MAAA,EAAQ,WAAA,EACR,GAAA,GAAK,MAAA,+BACJ,MAAA;;;;;;cAsBU,kBAAA;;;
|
|
1
|
+
{"version":3,"file":"schema.d.cts","names":[],"sources":["../../src/utils/schema.ts"],"mappings":";;;AAiEA;;;;;;;;;AAAA,iBApCgB,kBAAA,CAAmB,MAAA,EAAQ,WAAA;;;;;;;;;;iBAoC3B,cAAA,CAAe,MAAA,EAAQ,WAAA,GAAc,MAAA;;;;;AAkErD;;;;;AAYA;iBArCgB,oBAAA,CACd,MAAA,EAAQ,WAAA,EACR,GAAA,GAAK,MAAA,+BACJ,MAAA;;;;;;cAsBU,kBAAA;;;AA8Cb;;;;;;;;iBAlCgB,gBAAA,CACd,MAAA,EAAQ,MAAA,mBACR,aAAA,cACC,WAAA;;;;;;;;iBA+Ba,uBAAA,CACd,MAAA,EAAQ,WAAA,EACR,MAAA,EAAQ,MAAA;EACL,SAAA,EAAW,MAAA;EAAwB,YAAA,EAAc,MAAA;AAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schema.d.mts","names":[],"sources":["../../src/utils/schema.ts"],"mappings":";;;AAiEA;;;;;;;;;AAAA,iBApCgB,kBAAA,CAAmB,MAAA,EAAQ,WAAA;;;;;;;;;;iBAoC3B,cAAA,CAAe,MAAA,EAAQ,WAAA,GAAc,MAAA;;;;;AAkErD;;;;;AAYA;iBArCgB,oBAAA,CACd,MAAA,EAAQ,WAAA,EACR,GAAA,GAAK,MAAA,+BACJ,MAAA;;;;;;cAsBU,kBAAA;;;
|
|
1
|
+
{"version":3,"file":"schema.d.mts","names":[],"sources":["../../src/utils/schema.ts"],"mappings":";;;AAiEA;;;;;;;;;AAAA,iBApCgB,kBAAA,CAAmB,MAAA,EAAQ,WAAA;;;;;;;;;;iBAoC3B,cAAA,CAAe,MAAA,EAAQ,WAAA,GAAc,MAAA;;;;;AAkErD;;;;;AAYA;iBArCgB,oBAAA,CACd,MAAA,EAAQ,WAAA,EACR,GAAA,GAAK,MAAA,+BACJ,MAAA;;;;;;cAsBU,kBAAA;;;AA8Cb;;;;;;;;iBAlCgB,gBAAA,CACd,MAAA,EAAQ,MAAA,mBACR,aAAA,cACC,WAAA;;;;;;;;iBA+Ba,uBAAA,CACd,MAAA,EAAQ,WAAA,EACR,MAAA,EAAQ,MAAA;EACL,SAAA,EAAW,MAAA;EAAwB,YAAA,EAAc,MAAA;AAAA"}
|
package/dist/utils/schema.mjs
CHANGED
|
@@ -95,9 +95,11 @@ function buildAdHocSchema(values, sensitiveArgs = []) {
|
|
|
95
95
|
if (sensitiveSet.has(key)) prop.sensitive = true;
|
|
96
96
|
properties[key] = prop;
|
|
97
97
|
}
|
|
98
|
+
const required = Object.keys(values);
|
|
98
99
|
return {
|
|
99
100
|
type: "object",
|
|
100
|
-
properties
|
|
101
|
+
properties,
|
|
102
|
+
...required.length > 0 ? { required } : {}
|
|
101
103
|
};
|
|
102
104
|
}
|
|
103
105
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"schema.mjs","names":[],"sources":["../../src/utils/schema.ts"],"sourcesContent":["/**\n * Schema utilities for extracting sensitive field metadata and env mappings\n * from JSON Schema output (produced by z.toJSONSchema()).\n *\n * Zod 4's .meta() transparently passes custom fields through to JSON Schema output.\n * These utilities read those fields to identify sensitive fields and environment variable bindings.\n */\n\nimport type { JSONSchema7 } from \"../meta/type.js\";\n\n/**\n * Extended JSON Schema property with AFS credential metadata.\n * Fields are passed through from Zod 4's .meta({ sensitive, env }).\n */\ninterface SchemaPropertyWithMeta {\n sensitive?: boolean;\n env?: string[];\n [key: string]: unknown;\n}\n\n/**\n * Extract the list of top-level property names marked as sensitive.\n *\n * Works with both flat schemas and nested schemas (e.g. credentials.accessKeyId).\n * For nested objects, returns dot-notation paths (e.g. \"credentials.accessKeyId\").\n *\n * @param schema - JSON Schema (from z.toJSONSchema() or manifest schema)\n * @returns array of sensitive field paths\n */\nexport function getSensitiveFields(schema: JSONSchema7): string[] {\n const result: string[] = [];\n collectSensitiveFields(schema, \"\", result);\n return result;\n}\n\nfunction collectSensitiveFields(schema: JSONSchema7, prefix: string, result: string[]): void {\n if (typeof schema !== \"object\" || schema === null) return;\n\n const properties = (schema as Record<string, any>).properties;\n if (!properties || typeof properties !== \"object\") return;\n\n for (const [key, propSchema] of Object.entries(properties)) {\n const prop = propSchema as SchemaPropertyWithMeta;\n const fieldPath = prefix ? `${prefix}.${key}` : key;\n\n if (prop.sensitive === true) {\n result.push(fieldPath);\n }\n\n // Recurse into nested objects\n if (prop.type === \"object\" && prop.properties) {\n collectSensitiveFields(prop as JSONSchema7, fieldPath, result);\n }\n }\n}\n\n/**\n * Extract environment variable mappings from a JSON Schema.\n *\n * Returns a map from field path to array of env variable names.\n * Only includes fields that have `env` metadata set.\n *\n * @param schema - JSON Schema (from z.toJSONSchema() or manifest schema)\n * @returns map of field path → env variable names\n */\nexport function getEnvMappings(schema: JSONSchema7): Record<string, string[]> {\n const result: Record<string, string[]> = {};\n collectEnvMappings(schema, \"\", result);\n return result;\n}\n\nfunction collectEnvMappings(\n schema: JSONSchema7,\n prefix: string,\n result: Record<string, string[]>,\n): void {\n if (typeof schema !== \"object\" || schema === null) return;\n\n const properties = (schema as Record<string, any>).properties;\n if (!properties || typeof properties !== \"object\") return;\n\n for (const [key, propSchema] of Object.entries(properties)) {\n const prop = propSchema as SchemaPropertyWithMeta;\n const fieldPath = prefix ? `${prefix}.${key}` : key;\n\n if (Array.isArray(prop.env) && prop.env.length > 0) {\n result[fieldPath] = prop.env;\n }\n\n // Recurse into nested objects\n if (prop.type === \"object\" && prop.properties) {\n collectEnvMappings(prop as JSONSchema7, fieldPath, result);\n }\n }\n}\n\n/**\n * Resolve environment variables for schema fields that declare `env` metadata.\n *\n * For each field with env mapping, checks process.env for the first matching variable.\n * Only returns fields where an env variable was found.\n *\n * @param schema - JSON Schema with env metadata\n * @param env - Environment variables (defaults to process.env)\n * @returns resolved field values from environment\n */\nexport function resolveEnvFromSchema(\n schema: JSONSchema7,\n env: Record<string, string | undefined> = process.env,\n): Record<string, string> {\n const mappings = getEnvMappings(schema);\n const resolved: Record<string, string> = {};\n\n for (const [field, envVars] of Object.entries(mappings)) {\n for (const envVar of envVars) {\n const value = env[envVar];\n if (value !== undefined && value !== \"\") {\n resolved[field] = value;\n break;\n }\n }\n }\n\n return resolved;\n}\n\n/**\n * Reserved key for passing sensitiveArgs annotations through mount.options.\n * Used by CLI --sensitive-args and exec mount actions to annotate which\n * user-provided options are sensitive (for ad-hoc schema construction).\n */\nexport const SENSITIVE_ARGS_KEY = \"_sensitiveArgs\";\n\n/**\n * Build an ad-hoc JSON Schema from user-provided key-value pairs and sensitiveArgs.\n *\n * Used when a provider has no native schema() and no registry manifest schema,\n * e.g., generic MCP servers mounted via direct URI with extra options.\n *\n * @param values - Key-value pairs provided by the user\n * @param sensitiveArgs - Field names that should be marked as sensitive\n * @returns JSON Schema with properties derived from values\n */\nexport function buildAdHocSchema(\n values: Record<string, unknown>,\n sensitiveArgs: string[] = [],\n): JSONSchema7 {\n const sensitiveSet = new Set(sensitiveArgs);\n const properties: Record<string, unknown> = {};\n\n for (const [key, value] of Object.entries(values)) {\n const prop: Record<string, unknown> = {\n type:\n typeof value === \"number\" ? \"number\" : typeof value === \"boolean\" ? \"boolean\" : \"string\",\n };\n if (sensitiveSet.has(key)) {\n prop.sensitive = true;\n }\n properties[key] = prop;\n }\n\n return {\n type: \"object\",\n properties,\n } as JSONSchema7;\n}\n\n/**\n * Separate values into sensitive and non-sensitive groups based on schema metadata.\n *\n * @param schema - JSON Schema with sensitive metadata\n * @param values - Values to separate\n * @returns object with `sensitive` and `nonSensitive` value groups\n */\nexport function separateSensitiveValues(\n schema: JSONSchema7,\n values: Record<string, unknown>,\n): { sensitive: Record<string, string>; nonSensitive: Record<string, unknown> } {\n const sensitiveFields = new Set(getSensitiveFields(schema));\n const sensitive: Record<string, string> = {};\n const nonSensitive: Record<string, unknown> = {};\n\n for (const [key, value] of Object.entries(values)) {\n if (sensitiveFields.has(key)) {\n sensitive[key] = String(value);\n } else {\n nonSensitive[key] = value;\n }\n }\n\n return { sensitive, nonSensitive };\n}\n"],"mappings":";;;;;;;;;;AA6BA,SAAgB,mBAAmB,QAA+B;CAChE,MAAM,SAAmB,EAAE;AAC3B,wBAAuB,QAAQ,IAAI,OAAO;AAC1C,QAAO;;AAGT,SAAS,uBAAuB,QAAqB,QAAgB,QAAwB;AAC3F,KAAI,OAAO,WAAW,YAAY,WAAW,KAAM;CAEnD,MAAM,aAAc,OAA+B;AACnD,KAAI,CAAC,cAAc,OAAO,eAAe,SAAU;AAEnD,MAAK,MAAM,CAAC,KAAK,eAAe,OAAO,QAAQ,WAAW,EAAE;EAC1D,MAAM,OAAO;EACb,MAAM,YAAY,SAAS,GAAG,OAAO,GAAG,QAAQ;AAEhD,MAAI,KAAK,cAAc,KACrB,QAAO,KAAK,UAAU;AAIxB,MAAI,KAAK,SAAS,YAAY,KAAK,WACjC,wBAAuB,MAAqB,WAAW,OAAO;;;;;;;;;;;;AAcpE,SAAgB,eAAe,QAA+C;CAC5E,MAAM,SAAmC,EAAE;AAC3C,oBAAmB,QAAQ,IAAI,OAAO;AACtC,QAAO;;AAGT,SAAS,mBACP,QACA,QACA,QACM;AACN,KAAI,OAAO,WAAW,YAAY,WAAW,KAAM;CAEnD,MAAM,aAAc,OAA+B;AACnD,KAAI,CAAC,cAAc,OAAO,eAAe,SAAU;AAEnD,MAAK,MAAM,CAAC,KAAK,eAAe,OAAO,QAAQ,WAAW,EAAE;EAC1D,MAAM,OAAO;EACb,MAAM,YAAY,SAAS,GAAG,OAAO,GAAG,QAAQ;AAEhD,MAAI,MAAM,QAAQ,KAAK,IAAI,IAAI,KAAK,IAAI,SAAS,EAC/C,QAAO,aAAa,KAAK;AAI3B,MAAI,KAAK,SAAS,YAAY,KAAK,WACjC,oBAAmB,MAAqB,WAAW,OAAO;;;;;;;;;;;;;AAehE,SAAgB,qBACd,QACA,MAA0C,QAAQ,KAC1B;CACxB,MAAM,WAAW,eAAe,OAAO;CACvC,MAAM,WAAmC,EAAE;AAE3C,MAAK,MAAM,CAAC,OAAO,YAAY,OAAO,QAAQ,SAAS,CACrD,MAAK,MAAM,UAAU,SAAS;EAC5B,MAAM,QAAQ,IAAI;AAClB,MAAI,UAAU,UAAa,UAAU,IAAI;AACvC,YAAS,SAAS;AAClB;;;AAKN,QAAO;;;;;;;AAQT,MAAa,qBAAqB;;;;;;;;;;;AAYlC,SAAgB,iBACd,QACA,gBAA0B,EAAE,EACf;CACb,MAAM,eAAe,IAAI,IAAI,cAAc;CAC3C,MAAM,aAAsC,EAAE;AAE9C,MAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,OAAO,EAAE;EACjD,MAAM,OAAgC,EACpC,MACE,OAAO,UAAU,WAAW,WAAW,OAAO,UAAU,YAAY,YAAY,UACnF;AACD,MAAI,aAAa,IAAI,IAAI,CACvB,MAAK,YAAY;AAEnB,aAAW,OAAO;;
|
|
1
|
+
{"version":3,"file":"schema.mjs","names":[],"sources":["../../src/utils/schema.ts"],"sourcesContent":["/**\n * Schema utilities for extracting sensitive field metadata and env mappings\n * from JSON Schema output (produced by z.toJSONSchema()).\n *\n * Zod 4's .meta() transparently passes custom fields through to JSON Schema output.\n * These utilities read those fields to identify sensitive fields and environment variable bindings.\n */\n\nimport type { JSONSchema7 } from \"../meta/type.js\";\n\n/**\n * Extended JSON Schema property with AFS credential metadata.\n * Fields are passed through from Zod 4's .meta({ sensitive, env }).\n */\ninterface SchemaPropertyWithMeta {\n sensitive?: boolean;\n env?: string[];\n [key: string]: unknown;\n}\n\n/**\n * Extract the list of top-level property names marked as sensitive.\n *\n * Works with both flat schemas and nested schemas (e.g. credentials.accessKeyId).\n * For nested objects, returns dot-notation paths (e.g. \"credentials.accessKeyId\").\n *\n * @param schema - JSON Schema (from z.toJSONSchema() or manifest schema)\n * @returns array of sensitive field paths\n */\nexport function getSensitiveFields(schema: JSONSchema7): string[] {\n const result: string[] = [];\n collectSensitiveFields(schema, \"\", result);\n return result;\n}\n\nfunction collectSensitiveFields(schema: JSONSchema7, prefix: string, result: string[]): void {\n if (typeof schema !== \"object\" || schema === null) return;\n\n const properties = (schema as Record<string, any>).properties;\n if (!properties || typeof properties !== \"object\") return;\n\n for (const [key, propSchema] of Object.entries(properties)) {\n const prop = propSchema as SchemaPropertyWithMeta;\n const fieldPath = prefix ? `${prefix}.${key}` : key;\n\n if (prop.sensitive === true) {\n result.push(fieldPath);\n }\n\n // Recurse into nested objects\n if (prop.type === \"object\" && prop.properties) {\n collectSensitiveFields(prop as JSONSchema7, fieldPath, result);\n }\n }\n}\n\n/**\n * Extract environment variable mappings from a JSON Schema.\n *\n * Returns a map from field path to array of env variable names.\n * Only includes fields that have `env` metadata set.\n *\n * @param schema - JSON Schema (from z.toJSONSchema() or manifest schema)\n * @returns map of field path → env variable names\n */\nexport function getEnvMappings(schema: JSONSchema7): Record<string, string[]> {\n const result: Record<string, string[]> = {};\n collectEnvMappings(schema, \"\", result);\n return result;\n}\n\nfunction collectEnvMappings(\n schema: JSONSchema7,\n prefix: string,\n result: Record<string, string[]>,\n): void {\n if (typeof schema !== \"object\" || schema === null) return;\n\n const properties = (schema as Record<string, any>).properties;\n if (!properties || typeof properties !== \"object\") return;\n\n for (const [key, propSchema] of Object.entries(properties)) {\n const prop = propSchema as SchemaPropertyWithMeta;\n const fieldPath = prefix ? `${prefix}.${key}` : key;\n\n if (Array.isArray(prop.env) && prop.env.length > 0) {\n result[fieldPath] = prop.env;\n }\n\n // Recurse into nested objects\n if (prop.type === \"object\" && prop.properties) {\n collectEnvMappings(prop as JSONSchema7, fieldPath, result);\n }\n }\n}\n\n/**\n * Resolve environment variables for schema fields that declare `env` metadata.\n *\n * For each field with env mapping, checks process.env for the first matching variable.\n * Only returns fields where an env variable was found.\n *\n * @param schema - JSON Schema with env metadata\n * @param env - Environment variables (defaults to process.env)\n * @returns resolved field values from environment\n */\nexport function resolveEnvFromSchema(\n schema: JSONSchema7,\n env: Record<string, string | undefined> = process.env,\n): Record<string, string> {\n const mappings = getEnvMappings(schema);\n const resolved: Record<string, string> = {};\n\n for (const [field, envVars] of Object.entries(mappings)) {\n for (const envVar of envVars) {\n const value = env[envVar];\n if (value !== undefined && value !== \"\") {\n resolved[field] = value;\n break;\n }\n }\n }\n\n return resolved;\n}\n\n/**\n * Reserved key for passing sensitiveArgs annotations through mount.options.\n * Used by CLI --sensitive-args and exec mount actions to annotate which\n * user-provided options are sensitive (for ad-hoc schema construction).\n */\nexport const SENSITIVE_ARGS_KEY = \"_sensitiveArgs\";\n\n/**\n * Build an ad-hoc JSON Schema from user-provided key-value pairs and sensitiveArgs.\n *\n * Used when a provider has no native schema() and no registry manifest schema,\n * e.g., generic MCP servers mounted via direct URI with extra options.\n *\n * @param values - Key-value pairs provided by the user\n * @param sensitiveArgs - Field names that should be marked as sensitive\n * @returns JSON Schema with properties derived from values\n */\nexport function buildAdHocSchema(\n values: Record<string, unknown>,\n sensitiveArgs: string[] = [],\n): JSONSchema7 {\n const sensitiveSet = new Set(sensitiveArgs);\n const properties: Record<string, unknown> = {};\n\n for (const [key, value] of Object.entries(values)) {\n const prop: Record<string, unknown> = {\n type:\n typeof value === \"number\" ? \"number\" : typeof value === \"boolean\" ? \"boolean\" : \"string\",\n };\n if (sensitiveSet.has(key)) {\n prop.sensitive = true;\n }\n properties[key] = prop;\n }\n\n const required = Object.keys(values);\n\n return {\n type: \"object\",\n properties,\n ...(required.length > 0 ? { required } : {}),\n } as JSONSchema7;\n}\n\n/**\n * Separate values into sensitive and non-sensitive groups based on schema metadata.\n *\n * @param schema - JSON Schema with sensitive metadata\n * @param values - Values to separate\n * @returns object with `sensitive` and `nonSensitive` value groups\n */\nexport function separateSensitiveValues(\n schema: JSONSchema7,\n values: Record<string, unknown>,\n): { sensitive: Record<string, string>; nonSensitive: Record<string, unknown> } {\n const sensitiveFields = new Set(getSensitiveFields(schema));\n const sensitive: Record<string, string> = {};\n const nonSensitive: Record<string, unknown> = {};\n\n for (const [key, value] of Object.entries(values)) {\n if (sensitiveFields.has(key)) {\n sensitive[key] = String(value);\n } else {\n nonSensitive[key] = value;\n }\n }\n\n return { sensitive, nonSensitive };\n}\n"],"mappings":";;;;;;;;;;AA6BA,SAAgB,mBAAmB,QAA+B;CAChE,MAAM,SAAmB,EAAE;AAC3B,wBAAuB,QAAQ,IAAI,OAAO;AAC1C,QAAO;;AAGT,SAAS,uBAAuB,QAAqB,QAAgB,QAAwB;AAC3F,KAAI,OAAO,WAAW,YAAY,WAAW,KAAM;CAEnD,MAAM,aAAc,OAA+B;AACnD,KAAI,CAAC,cAAc,OAAO,eAAe,SAAU;AAEnD,MAAK,MAAM,CAAC,KAAK,eAAe,OAAO,QAAQ,WAAW,EAAE;EAC1D,MAAM,OAAO;EACb,MAAM,YAAY,SAAS,GAAG,OAAO,GAAG,QAAQ;AAEhD,MAAI,KAAK,cAAc,KACrB,QAAO,KAAK,UAAU;AAIxB,MAAI,KAAK,SAAS,YAAY,KAAK,WACjC,wBAAuB,MAAqB,WAAW,OAAO;;;;;;;;;;;;AAcpE,SAAgB,eAAe,QAA+C;CAC5E,MAAM,SAAmC,EAAE;AAC3C,oBAAmB,QAAQ,IAAI,OAAO;AACtC,QAAO;;AAGT,SAAS,mBACP,QACA,QACA,QACM;AACN,KAAI,OAAO,WAAW,YAAY,WAAW,KAAM;CAEnD,MAAM,aAAc,OAA+B;AACnD,KAAI,CAAC,cAAc,OAAO,eAAe,SAAU;AAEnD,MAAK,MAAM,CAAC,KAAK,eAAe,OAAO,QAAQ,WAAW,EAAE;EAC1D,MAAM,OAAO;EACb,MAAM,YAAY,SAAS,GAAG,OAAO,GAAG,QAAQ;AAEhD,MAAI,MAAM,QAAQ,KAAK,IAAI,IAAI,KAAK,IAAI,SAAS,EAC/C,QAAO,aAAa,KAAK;AAI3B,MAAI,KAAK,SAAS,YAAY,KAAK,WACjC,oBAAmB,MAAqB,WAAW,OAAO;;;;;;;;;;;;;AAehE,SAAgB,qBACd,QACA,MAA0C,QAAQ,KAC1B;CACxB,MAAM,WAAW,eAAe,OAAO;CACvC,MAAM,WAAmC,EAAE;AAE3C,MAAK,MAAM,CAAC,OAAO,YAAY,OAAO,QAAQ,SAAS,CACrD,MAAK,MAAM,UAAU,SAAS;EAC5B,MAAM,QAAQ,IAAI;AAClB,MAAI,UAAU,UAAa,UAAU,IAAI;AACvC,YAAS,SAAS;AAClB;;;AAKN,QAAO;;;;;;;AAQT,MAAa,qBAAqB;;;;;;;;;;;AAYlC,SAAgB,iBACd,QACA,gBAA0B,EAAE,EACf;CACb,MAAM,eAAe,IAAI,IAAI,cAAc;CAC3C,MAAM,aAAsC,EAAE;AAE9C,MAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,OAAO,EAAE;EACjD,MAAM,OAAgC,EACpC,MACE,OAAO,UAAU,WAAW,WAAW,OAAO,UAAU,YAAY,YAAY,UACnF;AACD,MAAI,aAAa,IAAI,IAAI,CACvB,MAAK,YAAY;AAEnB,aAAW,OAAO;;CAGpB,MAAM,WAAW,OAAO,KAAK,OAAO;AAEpC,QAAO;EACL,MAAM;EACN;EACA,GAAI,SAAS,SAAS,IAAI,EAAE,UAAU,GAAG,EAAE;EAC5C;;;;;;;;;AAUH,SAAgB,wBACd,QACA,QAC8E;CAC9E,MAAM,kBAAkB,IAAI,IAAI,mBAAmB,OAAO,CAAC;CAC3D,MAAM,YAAoC,EAAE;CAC5C,MAAM,eAAwC,EAAE;AAEhD,MAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,OAAO,CAC/C,KAAI,gBAAgB,IAAI,IAAI,CAC1B,WAAU,OAAO,OAAO,MAAM;KAE9B,cAAa,OAAO;AAIxB,QAAO;EAAE;EAAW;EAAc"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aigne/afs",
|
|
3
|
-
"version": "1.11.0-beta.
|
|
3
|
+
"version": "1.11.0-beta.13",
|
|
4
4
|
"description": "Agentic File System (AFS) is a virtual file system that supports various storage backends and provides a unified API for file operations.",
|
|
5
5
|
"license": "UNLICENSED",
|
|
6
6
|
"publishConfig": {
|
|
@@ -72,7 +72,7 @@
|
|
|
72
72
|
"@aigne/uuid": "^13.0.1",
|
|
73
73
|
"@types/json-schema": "^7.0.15",
|
|
74
74
|
"@types/node": "^25.0.9",
|
|
75
|
-
"minimatch": "^10.2.
|
|
75
|
+
"minimatch": "^10.2.3",
|
|
76
76
|
"strict-event-emitter": "^0.5.1",
|
|
77
77
|
"ufo": "^1.6.3",
|
|
78
78
|
"yaml": "^2.8.2",
|
|
@@ -86,8 +86,8 @@
|
|
|
86
86
|
"rimraf": "^6.1.2",
|
|
87
87
|
"tsdown": "0.20.0-beta.3",
|
|
88
88
|
"typescript": "5.9.2",
|
|
89
|
-
"@aigne/
|
|
90
|
-
"@aigne/
|
|
89
|
+
"@aigne/scripts": "0.0.0",
|
|
90
|
+
"@aigne/typescript-config": "0.0.0"
|
|
91
91
|
},
|
|
92
92
|
"scripts": {
|
|
93
93
|
"build": "tsdown",
|