@aigne/afs 1.11.0-beta → 1.11.0-beta.10
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/LICENSE.md +17 -84
- package/README.md +4 -13
- package/dist/_virtual/rolldown_runtime.mjs +7 -0
- package/dist/afs.cjs +1330 -0
- package/dist/afs.d.cts +275 -0
- package/dist/afs.d.cts.map +1 -0
- package/dist/afs.d.mts +275 -0
- package/dist/afs.d.mts.map +1 -0
- package/dist/afs.mjs +1331 -0
- package/dist/afs.mjs.map +1 -0
- package/dist/capabilities/index.d.mts +2 -0
- package/dist/capabilities/types.d.cts +100 -0
- package/dist/capabilities/types.d.cts.map +1 -0
- package/dist/capabilities/types.d.mts +100 -0
- package/dist/capabilities/types.d.mts.map +1 -0
- package/dist/capabilities/world-mapping.cjs +20 -0
- package/dist/capabilities/world-mapping.d.cts +139 -0
- package/dist/capabilities/world-mapping.d.cts.map +1 -0
- package/dist/capabilities/world-mapping.d.mts +139 -0
- package/dist/capabilities/world-mapping.d.mts.map +1 -0
- package/dist/capabilities/world-mapping.mjs +20 -0
- package/dist/capabilities/world-mapping.mjs.map +1 -0
- package/dist/error.cjs +63 -0
- package/dist/error.d.cts +39 -0
- package/dist/error.d.cts.map +1 -0
- package/dist/error.d.mts +39 -0
- package/dist/error.d.mts.map +1 -0
- package/dist/error.mjs +59 -0
- package/dist/error.mjs.map +1 -0
- package/dist/index.cjs +72 -345
- package/dist/index.d.cts +18 -300
- package/dist/index.d.mts +20 -300
- package/dist/index.mjs +16 -342
- package/dist/loader/index.cjs +110 -0
- package/dist/loader/index.d.cts +48 -0
- package/dist/loader/index.d.cts.map +1 -0
- package/dist/loader/index.d.mts +48 -0
- package/dist/loader/index.d.mts.map +1 -0
- package/dist/loader/index.mjs +110 -0
- package/dist/loader/index.mjs.map +1 -0
- package/dist/meta/index.cjs +4 -0
- package/dist/meta/index.mjs +6 -0
- package/dist/meta/kind.cjs +161 -0
- package/dist/meta/kind.d.cts +134 -0
- package/dist/meta/kind.d.cts.map +1 -0
- package/dist/meta/kind.d.mts +134 -0
- package/dist/meta/kind.d.mts.map +1 -0
- package/dist/meta/kind.mjs +157 -0
- package/dist/meta/kind.mjs.map +1 -0
- package/dist/meta/path.cjs +116 -0
- package/dist/meta/path.d.cts +43 -0
- package/dist/meta/path.d.cts.map +1 -0
- package/dist/meta/path.d.mts +43 -0
- package/dist/meta/path.d.mts.map +1 -0
- package/dist/meta/path.mjs +112 -0
- package/dist/meta/path.mjs.map +1 -0
- package/dist/meta/type.d.cts +96 -0
- package/dist/meta/type.d.cts.map +1 -0
- package/dist/meta/type.d.mts +96 -0
- package/dist/meta/type.d.mts.map +1 -0
- package/dist/meta/validation.cjs +77 -0
- package/dist/meta/validation.d.cts +19 -0
- package/dist/meta/validation.d.cts.map +1 -0
- package/dist/meta/validation.d.mts +19 -0
- package/dist/meta/validation.d.mts.map +1 -0
- package/dist/meta/validation.mjs +77 -0
- package/dist/meta/validation.mjs.map +1 -0
- package/dist/meta/well-known-kinds.cjs +228 -0
- package/dist/meta/well-known-kinds.d.cts +52 -0
- package/dist/meta/well-known-kinds.d.cts.map +1 -0
- package/dist/meta/well-known-kinds.d.mts +52 -0
- package/dist/meta/well-known-kinds.d.mts.map +1 -0
- package/dist/meta/well-known-kinds.mjs +219 -0
- package/dist/meta/well-known-kinds.mjs.map +1 -0
- package/dist/node_modules/.pnpm/@types_json-schema@7.0.15/node_modules/@types/json-schema/index.d.cts +141 -0
- package/dist/node_modules/.pnpm/@types_json-schema@7.0.15/node_modules/@types/json-schema/index.d.cts.map +1 -0
- package/dist/node_modules/.pnpm/@types_json-schema@7.0.15/node_modules/@types/json-schema/index.d.mts +141 -0
- package/dist/node_modules/.pnpm/@types_json-schema@7.0.15/node_modules/@types/json-schema/index.d.mts.map +1 -0
- package/dist/path.cjs +255 -0
- package/dist/path.d.cts +93 -0
- package/dist/path.d.cts.map +1 -0
- package/dist/path.d.mts +93 -0
- package/dist/path.d.mts.map +1 -0
- package/dist/path.mjs +249 -0
- package/dist/path.mjs.map +1 -0
- package/dist/provider/base.cjs +425 -0
- package/dist/provider/base.d.cts +175 -0
- package/dist/provider/base.d.cts.map +1 -0
- package/dist/provider/base.d.mts +175 -0
- package/dist/provider/base.d.mts.map +1 -0
- package/dist/provider/base.mjs +426 -0
- package/dist/provider/base.mjs.map +1 -0
- package/dist/provider/decorators.cjs +268 -0
- package/dist/provider/decorators.d.cts +244 -0
- package/dist/provider/decorators.d.cts.map +1 -0
- package/dist/provider/decorators.d.mts +244 -0
- package/dist/provider/decorators.d.mts.map +1 -0
- package/dist/provider/decorators.mjs +256 -0
- package/dist/provider/decorators.mjs.map +1 -0
- package/dist/provider/index.cjs +19 -0
- package/dist/provider/index.d.cts +5 -0
- package/dist/provider/index.d.mts +5 -0
- package/dist/provider/index.mjs +5 -0
- package/dist/provider/router.cjs +185 -0
- package/dist/provider/router.d.cts +50 -0
- package/dist/provider/router.d.cts.map +1 -0
- package/dist/provider/router.d.mts +50 -0
- package/dist/provider/router.d.mts.map +1 -0
- package/dist/provider/router.mjs +185 -0
- package/dist/provider/router.mjs.map +1 -0
- package/dist/provider/types.d.cts +113 -0
- package/dist/provider/types.d.cts.map +1 -0
- package/dist/provider/types.d.mts +113 -0
- package/dist/provider/types.d.mts.map +1 -0
- package/dist/registry.cjs +358 -0
- package/dist/registry.d.cts +96 -0
- package/dist/registry.d.cts.map +1 -0
- package/dist/registry.d.mts +96 -0
- package/dist/registry.d.mts.map +1 -0
- package/dist/registry.mjs +360 -0
- package/dist/registry.mjs.map +1 -0
- package/dist/type.cjs +34 -0
- package/dist/type.d.cts +420 -0
- package/dist/type.d.cts.map +1 -0
- package/dist/type.d.mts +420 -0
- package/dist/type.d.mts.map +1 -0
- package/dist/type.mjs +33 -0
- package/dist/type.mjs.map +1 -0
- package/dist/utils/camelize.d.cts.map +1 -1
- package/dist/utils/camelize.d.mts.map +1 -1
- package/dist/utils/schema.cjs +129 -0
- package/dist/utils/schema.d.cts +65 -0
- package/dist/utils/schema.d.cts.map +1 -0
- package/dist/utils/schema.d.mts +65 -0
- package/dist/utils/schema.d.mts.map +1 -0
- package/dist/utils/schema.mjs +124 -0
- package/dist/utils/schema.mjs.map +1 -0
- package/dist/utils/type-utils.d.cts.map +1 -1
- package/dist/utils/type-utils.d.mts.map +1 -1
- package/dist/utils/uri-template.cjs +123 -0
- package/dist/utils/uri-template.d.cts +48 -0
- package/dist/utils/uri-template.d.cts.map +1 -0
- package/dist/utils/uri-template.d.mts +48 -0
- package/dist/utils/uri-template.d.mts.map +1 -0
- package/dist/utils/uri-template.mjs +120 -0
- package/dist/utils/uri-template.mjs.map +1 -0
- package/dist/utils/uri.cjs +49 -0
- package/dist/utils/uri.d.cts +34 -0
- package/dist/utils/uri.d.cts.map +1 -0
- package/dist/utils/uri.d.mts +34 -0
- package/dist/utils/uri.d.mts.map +1 -0
- package/dist/utils/uri.mjs +49 -0
- package/dist/utils/uri.mjs.map +1 -0
- package/dist/utils/zod.cjs +6 -8
- package/dist/utils/zod.d.cts +2 -2
- package/dist/utils/zod.d.cts.map +1 -1
- package/dist/utils/zod.d.mts +2 -2
- package/dist/utils/zod.d.mts.map +1 -1
- package/dist/utils/zod.mjs +6 -8
- package/dist/utils/zod.mjs.map +1 -1
- package/package.json +27 -4
- package/dist/index.d.cts.map +0 -1
- package/dist/index.d.mts.map +0 -1
- package/dist/index.mjs.map +0 -1
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { AFSExplainResult } from "../meta/type.mjs";
|
|
2
|
+
import { AFSDeleteOptions, AFSDeleteResult, AFSEntry, AFSExecOptions, AFSExecResult, AFSListOptions, AFSReadOptions, AFSRenameResult, AFSSearchOptions, AFSSearchResult, AFSStatResult, AFSWriteEntryPayload, AFSWriteOptions, AFSWriteResult } from "../type.mjs";
|
|
3
|
+
|
|
4
|
+
//#region src/provider/types.d.ts
|
|
5
|
+
/**
|
|
6
|
+
* Route operation types matching AFSModule methods
|
|
7
|
+
*/
|
|
8
|
+
type RouteOperation = "list" | "read" | "write" | "delete" | "exec" | "search" | "stat" | "explain" | "rename";
|
|
9
|
+
/**
|
|
10
|
+
* Union type for all possible operation options
|
|
11
|
+
*/
|
|
12
|
+
type RouteOptions = AFSListOptions | AFSReadOptions | AFSWriteOptions | AFSDeleteOptions | AFSExecOptions | AFSSearchOptions;
|
|
13
|
+
/**
|
|
14
|
+
* Context passed to route handlers
|
|
15
|
+
*
|
|
16
|
+
* Note: Wildcard params (e.g., :path*) may be undefined for paths that
|
|
17
|
+
* don't include that segment (e.g., root paths). Always check for undefined
|
|
18
|
+
* when using optional wildcard params.
|
|
19
|
+
*/
|
|
20
|
+
interface RouteContext<TParams = Record<string, string | undefined>> {
|
|
21
|
+
/** The full request path */
|
|
22
|
+
path: string;
|
|
23
|
+
/** Parameters extracted from the route pattern */
|
|
24
|
+
params: TParams;
|
|
25
|
+
/** Operation options (type depends on operation) */
|
|
26
|
+
options?: RouteOptions;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Result type for @List handlers
|
|
30
|
+
* - data: array of entries
|
|
31
|
+
* - total: optional, if present indicates complete dataset size
|
|
32
|
+
* if absent, data.length IS the total (all data returned)
|
|
33
|
+
* - noExpand: optional, paths that should not be expanded during BFS depth traversal
|
|
34
|
+
* (internal use only, not exposed in public API)
|
|
35
|
+
*/
|
|
36
|
+
interface ListHandlerResult {
|
|
37
|
+
data: AFSEntry[];
|
|
38
|
+
total?: number;
|
|
39
|
+
/** Paths that should not be expanded during BFS (internal, not exposed in public API) */
|
|
40
|
+
noExpand?: string[];
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Handler function types for each operation
|
|
44
|
+
*/
|
|
45
|
+
type ListRouteHandler<TParams = Record<string, string | undefined>> = (ctx: RouteContext<TParams>) => Promise<ListHandlerResult>;
|
|
46
|
+
type ReadRouteHandler<TParams = Record<string, string | undefined>> = (ctx: RouteContext<TParams>) => Promise<AFSEntry | undefined>;
|
|
47
|
+
type WriteRouteHandler<TParams = Record<string, string | undefined>> = (ctx: RouteContext<TParams>, content: AFSWriteEntryPayload) => Promise<AFSWriteResult>;
|
|
48
|
+
type DeleteRouteHandler<TParams = Record<string, string | undefined>> = (ctx: RouteContext<TParams>) => Promise<AFSDeleteResult>;
|
|
49
|
+
type ExecRouteHandler<TParams = Record<string, string | undefined>> = (ctx: RouteContext<TParams>, args: Record<string, unknown>) => Promise<AFSExecResult>;
|
|
50
|
+
type SearchRouteHandler<TParams = Record<string, string | undefined>> = (ctx: RouteContext<TParams>, query: string, options?: AFSSearchOptions) => Promise<AFSSearchResult>;
|
|
51
|
+
type StatRouteHandler<TParams = Record<string, string | undefined>> = (ctx: RouteContext<TParams>) => Promise<AFSStatResult>;
|
|
52
|
+
type ExplainRouteHandler<TParams = Record<string, string | undefined>> = (ctx: RouteContext<TParams>) => Promise<AFSExplainResult>;
|
|
53
|
+
type RenameRouteHandler<TParams = Record<string, string | undefined>> = (ctx: RouteContext<TParams>, newPath: string) => Promise<AFSRenameResult>;
|
|
54
|
+
/**
|
|
55
|
+
* Union type for all route handlers
|
|
56
|
+
*/
|
|
57
|
+
type RouteHandler = ListRouteHandler | ReadRouteHandler | WriteRouteHandler | DeleteRouteHandler | ExecRouteHandler | SearchRouteHandler | StatRouteHandler | ExplainRouteHandler | RenameRouteHandler;
|
|
58
|
+
/**
|
|
59
|
+
* Route definition stored in the router
|
|
60
|
+
*/
|
|
61
|
+
interface RouteDefinition {
|
|
62
|
+
/** Route pattern (e.g., "/:table/:pk") */
|
|
63
|
+
pattern: string;
|
|
64
|
+
/** Operation type */
|
|
65
|
+
operation: RouteOperation;
|
|
66
|
+
/** Handler function */
|
|
67
|
+
handler: RouteHandler;
|
|
68
|
+
/** Optional description for documentation */
|
|
69
|
+
description?: string;
|
|
70
|
+
/** Options specific to list operations */
|
|
71
|
+
listOptions?: ListDecoratorOptions;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Options for @List decorator
|
|
75
|
+
*/
|
|
76
|
+
interface ListDecoratorOptions {
|
|
77
|
+
/**
|
|
78
|
+
* Whether the handler handles maxDepth recursion itself.
|
|
79
|
+
* - false (default): Base provider will auto-expand depth via BFS
|
|
80
|
+
* - true: Handler is responsible for depth traversal
|
|
81
|
+
*
|
|
82
|
+
* Most providers can use the default (false) and just return single-level results.
|
|
83
|
+
* Set to true for providers that need custom depth handling (like S3 with delimiter optimization).
|
|
84
|
+
*/
|
|
85
|
+
handleDepth?: boolean;
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Metadata stored by decorators for later collection
|
|
89
|
+
*/
|
|
90
|
+
interface RouteMetadata {
|
|
91
|
+
/** Route pattern */
|
|
92
|
+
pattern: string;
|
|
93
|
+
/** Operation type */
|
|
94
|
+
operation: RouteOperation;
|
|
95
|
+
/** Method name on the class */
|
|
96
|
+
methodName: string;
|
|
97
|
+
/** Optional description */
|
|
98
|
+
description?: string;
|
|
99
|
+
/** Options specific to list operations */
|
|
100
|
+
listOptions?: ListDecoratorOptions;
|
|
101
|
+
}
|
|
102
|
+
/**
|
|
103
|
+
* Match result from router
|
|
104
|
+
*/
|
|
105
|
+
interface RouteMatch {
|
|
106
|
+
/** The matched route definition */
|
|
107
|
+
route: RouteDefinition;
|
|
108
|
+
/** Extracted parameters (wildcards may be undefined or empty string) */
|
|
109
|
+
params: Record<string, string | undefined>;
|
|
110
|
+
}
|
|
111
|
+
//#endregion
|
|
112
|
+
export { DeleteRouteHandler, ExecRouteHandler, ExplainRouteHandler, ListDecoratorOptions, ListHandlerResult, ListRouteHandler, ReadRouteHandler, RenameRouteHandler, RouteContext, RouteDefinition, RouteHandler, RouteMatch, RouteMetadata, RouteOperation, SearchRouteHandler, StatRouteHandler, WriteRouteHandler };
|
|
113
|
+
//# sourceMappingURL=types.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.mts","names":[],"sources":["../../src/provider/types.ts"],"mappings":";;;;;;;KAqBY,cAAA;;;;KAcA,YAAA,GACR,cAAA,GACA,cAAA,GACA,eAAA,GACA,gBAAA,GACA,cAAA,GACA,gBAAA;AANJ;;;;;;;AAAA,UAeiB,YAAA,WAAuB,MAAA;EATpC;EAWF,IAAA;EAXkB;EAclB,MAAA,EAAQ,OAAA;EAlBN;EAqBF,OAAA,GAAU,YAAA;AAAA;;;;;AARZ;;;;UAmBiB,iBAAA;EACf,IAAA,EAAM,QAAA;EACN,KAAA;EAbsB;EAetB,QAAA;AAAA;;;;KAMU,gBAAA,WAA2B,MAAA,iCACrC,GAAA,EAAK,YAAA,CAAa,OAAA,MACf,OAAA,CAAQ,iBAAA;AAAA,KAED,gBAAA,WAA2B,MAAA,iCACrC,GAAA,EAAK,YAAA,CAAa,OAAA,MACf,OAAA,CAAQ,QAAA;AAAA,KAED,iBAAA,WAA4B,MAAA,iCACtC,GAAA,EAAK,YAAA,CAAa,OAAA,GAClB,OAAA,EAAS,oBAAA,KACN,OAAA,CAAQ,cAAA;AAAA,KAED,kBAAA,WAA6B,MAAA,iCACvC,GAAA,EAAK,YAAA,CAAa,OAAA,MACf,OAAA,CAAQ,eAAA;AAAA,KAED,gBAAA,WAA2B,MAAA,iCACrC,GAAA,EAAK,YAAA,CAAa,OAAA,GAClB,IAAA,EAAM,MAAA,sBACH,OAAA,CAAQ,aAAA;AAAA,KAED,kBAAA,WAA6B,MAAA,iCACvC,GAAA,EAAK,YAAA,CAAa,OAAA,GAClB,KAAA,UACA,OAAA,GAAU,gBAAA,KACP,OAAA,CAAQ,eAAA;AAAA,KAED,gBAAA,WAA2B,MAAA,iCACrC,GAAA,EAAK,YAAA,CAAa,OAAA,MACf,OAAA,CAAQ,aAAA;AAAA,KAED,mBAAA,WAA8B,MAAA,iCACxC,GAAA,EAAK,YAAA,CAAa,OAAA,MACf,OAAA,CAAQ,gBAAA;AAAA,KAED,kBAAA,WAA6B,MAAA,iCACvC,GAAA,EAAK,YAAA,CAAa,OAAA,GAClB,OAAA,aACG,OAAA,CAAQ,eAAA;;;;KAKD,YAAA,GACR,gBAAA,GACA,gBAAA,GACA,iBAAA,GACA,kBAAA,GACA,gBAAA,GACA,kBAAA,GACA,gBAAA,GACA,mBAAA,GACA,kBAAA;;AArDJ;;UA0DiB,eAAA;EA1DsB;EA4DrC,OAAA;EA3DK;EA8DL,SAAA,EAAW,cAAA;EA7DR;EAgEH,OAAA,EAAS,YAAA;EAhEC;EAmEV,WAAA;EArEqC;EAwErC,WAAA,GAAc,oBAAA;AAAA;;;;UAMC,oBAAA;EA5Ea;AAE9B;;;;;;;EAmFE,WAAA;AAAA;;;;UAMe,aAAA;EAxFG;EA0FlB,OAAA;EAzFG;EA4FH,SAAA,EAAW,cAAA;EA5FQ;EA+FnB,UAAA;EA7FU;EAgGV,WAAA;EAhG2B;EAmG3B,WAAA,GAAc,oBAAA;AAAA;;;;UAMC,UAAA;EAtGL;EAwGV,KAAA,EAAO,eAAA;EA3GqB;EA8G5B,MAAA,EAAQ,MAAA;AAAA"}
|
|
@@ -0,0 +1,358 @@
|
|
|
1
|
+
const require_utils_uri = require('./utils/uri.cjs');
|
|
2
|
+
const require_utils_uri_template = require('./utils/uri-template.cjs');
|
|
3
|
+
let node_fs = require("node:fs");
|
|
4
|
+
let node_path = require("node:path");
|
|
5
|
+
|
|
6
|
+
//#region src/registry.ts
|
|
7
|
+
/**
|
|
8
|
+
* Resolve a package specifier to an importable path.
|
|
9
|
+
* If the specifier is a directory path (e.g. from npm install),
|
|
10
|
+
* read its package.json to find the ESM entry point.
|
|
11
|
+
*/
|
|
12
|
+
function resolveImportPath(specifier) {
|
|
13
|
+
if (!specifier.startsWith("/")) return specifier;
|
|
14
|
+
const pkgJsonPath = (0, node_path.join)(specifier, "package.json");
|
|
15
|
+
if (!(0, node_fs.existsSync)(pkgJsonPath)) return specifier;
|
|
16
|
+
try {
|
|
17
|
+
const pkg = JSON.parse((0, node_fs.readFileSync)(pkgJsonPath, "utf-8"));
|
|
18
|
+
const esmEntry = typeof pkg.exports === "object" && pkg.exports["."]?.import || pkg.module;
|
|
19
|
+
if (esmEntry) return (0, node_path.join)(specifier, esmEntry);
|
|
20
|
+
if (pkg.main) return (0, node_path.join)(specifier, pkg.main);
|
|
21
|
+
} catch {}
|
|
22
|
+
return specifier;
|
|
23
|
+
}
|
|
24
|
+
/** Mutex for npm install operations to prevent concurrent installs */
|
|
25
|
+
const npmInstallLocks = /* @__PURE__ */ new Map();
|
|
26
|
+
/**
|
|
27
|
+
* Validate npm package name format.
|
|
28
|
+
* Rejects path traversal and shell metacharacters.
|
|
29
|
+
*/
|
|
30
|
+
function isValidNpmPackageName(name) {
|
|
31
|
+
if (!name || name.length > 214) return false;
|
|
32
|
+
if (name.includes("..") || name.startsWith("/") || name.startsWith("\\")) return false;
|
|
33
|
+
for (const char of [
|
|
34
|
+
";",
|
|
35
|
+
"|",
|
|
36
|
+
"&",
|
|
37
|
+
"`",
|
|
38
|
+
"$",
|
|
39
|
+
"(",
|
|
40
|
+
")",
|
|
41
|
+
">",
|
|
42
|
+
"<",
|
|
43
|
+
"\n",
|
|
44
|
+
"\r",
|
|
45
|
+
" ",
|
|
46
|
+
"\0"
|
|
47
|
+
]) if (name.includes(char)) return false;
|
|
48
|
+
if (name.startsWith("@")) {
|
|
49
|
+
const parts = name.slice(1).split("/");
|
|
50
|
+
if (parts.length !== 2 || !parts[0] || !parts[1]) return false;
|
|
51
|
+
}
|
|
52
|
+
return true;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Install an npm package if not already present.
|
|
56
|
+
* Uses per-package mutex to prevent concurrent installs.
|
|
57
|
+
*/
|
|
58
|
+
async function npmInstall(packageName, packagesDir) {
|
|
59
|
+
const existing = npmInstallLocks.get(packageName);
|
|
60
|
+
if (existing) {
|
|
61
|
+
await existing;
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
const { mkdir } = await import("node:fs/promises");
|
|
65
|
+
const installPromise = (async () => {
|
|
66
|
+
await mkdir(packagesDir, { recursive: true });
|
|
67
|
+
const { execSync } = await import("node:child_process");
|
|
68
|
+
try {
|
|
69
|
+
execSync(`npm install --prefix ${JSON.stringify(packagesDir)} ${JSON.stringify(packageName)}`, {
|
|
70
|
+
stdio: "pipe",
|
|
71
|
+
timeout: 12e4
|
|
72
|
+
});
|
|
73
|
+
} catch (error) {
|
|
74
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
75
|
+
throw new Error(`Failed to install npm package "${packageName}": ${message}`);
|
|
76
|
+
}
|
|
77
|
+
})();
|
|
78
|
+
npmInstallLocks.set(packageName, installPromise);
|
|
79
|
+
try {
|
|
80
|
+
await installPromise;
|
|
81
|
+
} finally {
|
|
82
|
+
npmInstallLocks.delete(packageName);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
/**
|
|
86
|
+
* Get the npm packages install directory (~/.afs-config/packages/).
|
|
87
|
+
*/
|
|
88
|
+
function getNpmPackagesDir() {
|
|
89
|
+
const os = require("node:os");
|
|
90
|
+
const { resolve } = require("node:path");
|
|
91
|
+
return resolve(os.homedir(), ".afs-config", "packages");
|
|
92
|
+
}
|
|
93
|
+
/** How often to check for package updates (24 hours). */
|
|
94
|
+
const UPDATE_CHECK_STALE_MS = 1440 * 60 * 1e3;
|
|
95
|
+
/**
|
|
96
|
+
* Trigger a background npm update if the package hasn't been checked recently.
|
|
97
|
+
* Completely silent — never blocks, never throws, never produces output.
|
|
98
|
+
*/
|
|
99
|
+
function npmUpdateIfStale(packageName, packagesDir) {
|
|
100
|
+
const checkFile = (0, node_path.join)(packagesDir, ".update-check.json");
|
|
101
|
+
const now = Date.now();
|
|
102
|
+
let checks = {};
|
|
103
|
+
try {
|
|
104
|
+
checks = JSON.parse((0, node_fs.readFileSync)(checkFile, "utf-8"));
|
|
105
|
+
} catch {}
|
|
106
|
+
if (now - (checks[packageName] ?? 0) < UPDATE_CHECK_STALE_MS) return;
|
|
107
|
+
checks[packageName] = now;
|
|
108
|
+
try {
|
|
109
|
+
(0, node_fs.writeFileSync)(checkFile, JSON.stringify(checks, null, 2));
|
|
110
|
+
} catch {}
|
|
111
|
+
npmUpdateBackground(packageName, packagesDir).catch(() => {});
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Run `npm update` for a single package in the background.
|
|
115
|
+
* Errors are silently swallowed (e.g. no network).
|
|
116
|
+
*/
|
|
117
|
+
async function npmUpdateBackground(packageName, packagesDir) {
|
|
118
|
+
const { execSync } = await import("node:child_process");
|
|
119
|
+
try {
|
|
120
|
+
execSync(`npm update --prefix ${JSON.stringify(packagesDir)} ${JSON.stringify(packageName)}`, {
|
|
121
|
+
stdio: "ignore",
|
|
122
|
+
timeout: 12e4
|
|
123
|
+
});
|
|
124
|
+
} catch {}
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Package name overrides for schemes that don't follow the @aigne/afs-{scheme} convention.
|
|
128
|
+
* Class discovery uses the .manifest() static method — no class name mapping needed.
|
|
129
|
+
*/
|
|
130
|
+
const PACKAGE_OVERRIDES = { https: "@aigne/afs-http" };
|
|
131
|
+
/**
|
|
132
|
+
* Derive the base scheme for compound schemes.
|
|
133
|
+
* e.g. "mcp+stdio" → "mcp", "mcp+http" → "mcp"
|
|
134
|
+
*/
|
|
135
|
+
function baseScheme(scheme) {
|
|
136
|
+
const plusIdx = scheme.indexOf("+");
|
|
137
|
+
return plusIdx >= 0 ? scheme.slice(0, plusIdx) : scheme;
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Registry of provider factories with unified manifest-driven loading.
|
|
141
|
+
*
|
|
142
|
+
* Loading flow:
|
|
143
|
+
* 1. parseURI → get scheme
|
|
144
|
+
* 2. Check registered factories (workspace, custom) → use directly
|
|
145
|
+
* 3. Resolve package: mount.provider or @aigne/afs-{baseScheme}
|
|
146
|
+
* 4. Import package → get ProviderClass
|
|
147
|
+
* 5. Get manifest from ProviderClass.manifest()
|
|
148
|
+
* 6. Match manifest by scheme (for multi-manifest providers)
|
|
149
|
+
* 7. parseTemplate(uriTemplate, body) → extract path variables
|
|
150
|
+
* 8. Merge params: body vars > query > mount.options
|
|
151
|
+
* 9. Construct provider with merged options
|
|
152
|
+
*/
|
|
153
|
+
var ProviderRegistry = class {
|
|
154
|
+
factories = /* @__PURE__ */ new Map();
|
|
155
|
+
/** Register a scheme → factory mapping. Overwrites any existing registration. */
|
|
156
|
+
register(scheme, factory) {
|
|
157
|
+
this.factories.set(scheme.toLowerCase(), factory);
|
|
158
|
+
}
|
|
159
|
+
/** Check if a scheme has a registered factory. */
|
|
160
|
+
has(scheme) {
|
|
161
|
+
return this.factories.has(scheme.toLowerCase());
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Get provider metadata (schema, auth, manifest) for a URI.
|
|
165
|
+
*
|
|
166
|
+
* Used by CLI credential resolution to get schema and auth method
|
|
167
|
+
* without constructing the provider.
|
|
168
|
+
*
|
|
169
|
+
* Returns null if the provider class can't be loaded (e.g., unknown scheme).
|
|
170
|
+
*/
|
|
171
|
+
async getProviderInfo(uri) {
|
|
172
|
+
try {
|
|
173
|
+
const parsed = require_utils_uri.parseURI(uri);
|
|
174
|
+
const base = baseScheme(parsed.scheme);
|
|
175
|
+
const packageName = PACKAGE_OVERRIDES[base] ?? `@aigne/afs-${base}`;
|
|
176
|
+
const ProviderClass = await this.importProviderClass(packageName, base);
|
|
177
|
+
const auth = ProviderClass.auth ? ProviderClass.auth.bind(ProviderClass) : void 0;
|
|
178
|
+
let manifest = null;
|
|
179
|
+
if (ProviderClass.manifest) {
|
|
180
|
+
const manifests = this.getManifests(ProviderClass, packageName);
|
|
181
|
+
manifest = this.matchManifest(manifests, parsed.scheme, packageName);
|
|
182
|
+
}
|
|
183
|
+
let schema = null;
|
|
184
|
+
if (manifest?.schema) try {
|
|
185
|
+
const { z } = await import("zod");
|
|
186
|
+
schema = z.toJSONSchema(manifest.schema);
|
|
187
|
+
} catch {}
|
|
188
|
+
if (!schema && ProviderClass.schema) try {
|
|
189
|
+
const zodSchema = ProviderClass.schema();
|
|
190
|
+
const { z } = await import("zod");
|
|
191
|
+
schema = z.toJSONSchema(zodSchema);
|
|
192
|
+
} catch {}
|
|
193
|
+
return {
|
|
194
|
+
schema,
|
|
195
|
+
auth,
|
|
196
|
+
manifest
|
|
197
|
+
};
|
|
198
|
+
} catch {
|
|
199
|
+
return null;
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* Create a provider from a mount config.
|
|
204
|
+
*
|
|
205
|
+
* Uses registered factory if available, otherwise auto-loads
|
|
206
|
+
* via manifest-driven resolution.
|
|
207
|
+
*/
|
|
208
|
+
async createProvider(mount) {
|
|
209
|
+
const parsed = require_utils_uri.parseURI(mount.uri);
|
|
210
|
+
const factory = this.factories.get(parsed.scheme);
|
|
211
|
+
if (factory) {
|
|
212
|
+
const provider$1 = await factory(mount, parsed);
|
|
213
|
+
provider$1.uri = mount.uri;
|
|
214
|
+
return provider$1;
|
|
215
|
+
}
|
|
216
|
+
const provider = await this.autoLoadProvider(mount, parsed);
|
|
217
|
+
provider.uri = mount.uri;
|
|
218
|
+
return provider;
|
|
219
|
+
}
|
|
220
|
+
/**
|
|
221
|
+
* Auto-load a provider using the manifest-driven unified flow.
|
|
222
|
+
*/
|
|
223
|
+
async autoLoadProvider(mount, parsed) {
|
|
224
|
+
const base = baseScheme(parsed.scheme);
|
|
225
|
+
const packageName = PACKAGE_OVERRIDES[base] ?? `@aigne/afs-${base}`;
|
|
226
|
+
const ProviderClass = await this.importProviderClass(packageName, base);
|
|
227
|
+
const manifests = this.getManifests(ProviderClass, packageName);
|
|
228
|
+
const manifest = this.matchManifest(manifests, parsed.scheme, packageName);
|
|
229
|
+
const templateVars = require_utils_uri_template.parseTemplate(manifest.uriTemplate, parsed.body);
|
|
230
|
+
const mergedOptions = this.mergeOptions(templateVars, parsed.query, mount);
|
|
231
|
+
return this.constructProvider(ProviderClass, mount, parsed, mergedOptions, manifest);
|
|
232
|
+
}
|
|
233
|
+
/**
|
|
234
|
+
* Import a provider class from a package name.
|
|
235
|
+
* Resolution order:
|
|
236
|
+
* 1. Direct import (works when package is a dependency of the importing module)
|
|
237
|
+
* 2. createRequire from process.cwd() (works in monorepo dev environments)
|
|
238
|
+
* 3. npm auto-install to ~/.afs-config/packages/
|
|
239
|
+
*/
|
|
240
|
+
async importProviderClass(packageName, scheme, explicitClassName) {
|
|
241
|
+
let mod;
|
|
242
|
+
try {
|
|
243
|
+
mod = await this.resolveAndImport(packageName);
|
|
244
|
+
} catch {
|
|
245
|
+
if (!isValidNpmPackageName(packageName)) throw new Error(`Unknown URI scheme "${scheme}": package "${packageName}" not found and name is invalid.`);
|
|
246
|
+
const packagesDir = getNpmPackagesDir();
|
|
247
|
+
const { resolve } = await import("node:path");
|
|
248
|
+
const nodeModulesPath = resolve(packagesDir, "node_modules", ...packageName.split("/"));
|
|
249
|
+
if (!(0, node_fs.existsSync)(nodeModulesPath)) await npmInstall(packageName, packagesDir);
|
|
250
|
+
else npmUpdateIfStale(packageName, packagesDir);
|
|
251
|
+
const importPath = resolveImportPath(nodeModulesPath);
|
|
252
|
+
try {
|
|
253
|
+
mod = await import(importPath);
|
|
254
|
+
} catch (error) {
|
|
255
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
256
|
+
throw new Error(`Failed to import provider package "${packageName}" for scheme "${scheme}": ${msg}`);
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
if (explicitClassName && mod[explicitClassName]) return mod[explicitClassName];
|
|
260
|
+
const conventionName = `AFS${scheme.charAt(0).toUpperCase()}${scheme.slice(1).toUpperCase()}`;
|
|
261
|
+
if (mod[conventionName]) return mod[conventionName];
|
|
262
|
+
for (const key of Object.keys(mod)) {
|
|
263
|
+
const val = mod[key];
|
|
264
|
+
if (typeof val === "function" && key !== "default" && val.manifest) return val;
|
|
265
|
+
}
|
|
266
|
+
if (mod.default && typeof mod.default === "function") return mod.default;
|
|
267
|
+
throw new Error(`Package "${packageName}" does not export a valid AFS Provider class for scheme "${scheme}".`);
|
|
268
|
+
}
|
|
269
|
+
/**
|
|
270
|
+
* Get manifest(s) from a provider class.
|
|
271
|
+
*/
|
|
272
|
+
getManifests(ProviderClass, packageName) {
|
|
273
|
+
if (!ProviderClass.manifest) throw new Error(`Provider class from "${packageName}" does not implement static manifest(). Please add a static manifest() method to the provider class.`);
|
|
274
|
+
const result = ProviderClass.manifest();
|
|
275
|
+
return Array.isArray(result) ? result : [result];
|
|
276
|
+
}
|
|
277
|
+
/**
|
|
278
|
+
* Find the matching manifest for a given scheme.
|
|
279
|
+
* For multi-manifest providers (e.g., MCP with mcp+stdio, mcp+http, mcp+sse),
|
|
280
|
+
* match by the full scheme from the URI template.
|
|
281
|
+
*/
|
|
282
|
+
matchManifest(manifests, scheme, packageName) {
|
|
283
|
+
if (manifests.length === 1) return manifests[0];
|
|
284
|
+
for (const m of manifests) try {
|
|
285
|
+
if (require_utils_uri_template.extractSchemeFromTemplate(m.uriTemplate) === scheme) return m;
|
|
286
|
+
} catch {}
|
|
287
|
+
if (manifests.length > 0) return manifests[0];
|
|
288
|
+
throw new Error(`No matching manifest found for scheme "${scheme}" in package "${packageName}".`);
|
|
289
|
+
}
|
|
290
|
+
/**
|
|
291
|
+
* Merge parameters from multiple sources.
|
|
292
|
+
* Priority: template vars (from URI body) > query params > mount.options
|
|
293
|
+
*/
|
|
294
|
+
mergeOptions(templateVars, query, mount) {
|
|
295
|
+
const result = {};
|
|
296
|
+
if (mount.options) Object.assign(result, mount.options);
|
|
297
|
+
for (const [key, value] of Object.entries(query)) if (value !== "") result[key] = value;
|
|
298
|
+
for (const [key, value] of Object.entries(templateVars)) if (value !== void 0) result[key] = value;
|
|
299
|
+
return result;
|
|
300
|
+
}
|
|
301
|
+
/**
|
|
302
|
+
* Construct a provider instance with merged options.
|
|
303
|
+
*/
|
|
304
|
+
async constructProvider(ProviderClass, mount, _parsed, mergedOptions, manifest) {
|
|
305
|
+
const constructorOptions = {
|
|
306
|
+
...mergedOptions,
|
|
307
|
+
name: mount.path.slice(1).replace(/\//g, "-") || manifest.name,
|
|
308
|
+
description: mount.description,
|
|
309
|
+
accessMode: mount.access_mode,
|
|
310
|
+
uri: mount.uri
|
|
311
|
+
};
|
|
312
|
+
if (mount.auth !== void 0) constructorOptions.auth = mount.auth;
|
|
313
|
+
if (mount.token !== void 0) constructorOptions.token = mount.token;
|
|
314
|
+
const provider = new ProviderClass(constructorOptions);
|
|
315
|
+
if (typeof provider.ready === "function") await provider.ready();
|
|
316
|
+
return provider;
|
|
317
|
+
}
|
|
318
|
+
/**
|
|
319
|
+
* Resolve and import a package, trying multiple resolution strategies.
|
|
320
|
+
*
|
|
321
|
+
* In a monorepo (pnpm workspace), `import("@aigne/afs-fs")` inside packages/core
|
|
322
|
+
* won't find packages/cli's dependencies. We locate the package directory via
|
|
323
|
+
* createRequire, then use resolveImportPath to find the correct ESM entry.
|
|
324
|
+
*/
|
|
325
|
+
async resolveAndImport(packageName) {
|
|
326
|
+
try {
|
|
327
|
+
return await import(resolveImportPath(packageName));
|
|
328
|
+
} catch {}
|
|
329
|
+
const packageDir = this.locatePackageDir(packageName);
|
|
330
|
+
if (packageDir) return await import(resolveImportPath(packageDir));
|
|
331
|
+
throw new Error(`Cannot resolve module "${packageName}"`);
|
|
332
|
+
}
|
|
333
|
+
/**
|
|
334
|
+
* Locate a package directory using createRequire from various contexts.
|
|
335
|
+
* Returns the package directory path, or undefined if not found.
|
|
336
|
+
*/
|
|
337
|
+
locatePackageDir(packageName) {
|
|
338
|
+
const { createRequire } = require("node:module");
|
|
339
|
+
const { dirname } = require("node:path");
|
|
340
|
+
const contexts = [(0, node_path.join)(process.cwd(), "__resolve__.js"), ...process.argv[1] ? [(0, node_path.join)(dirname(process.argv[1]), "__resolve__.js")] : []];
|
|
341
|
+
for (const context of contexts) try {
|
|
342
|
+
return dirname(createRequire(context).resolve((0, node_path.join)(packageName, "package.json")));
|
|
343
|
+
} catch {
|
|
344
|
+
try {
|
|
345
|
+
let dir = dirname(createRequire(context).resolve(packageName));
|
|
346
|
+
for (let i = 0; i < 5; i++) {
|
|
347
|
+
if ((0, node_fs.existsSync)((0, node_path.join)(dir, "package.json"))) return dir;
|
|
348
|
+
const parent = dirname(dir);
|
|
349
|
+
if (parent === dir) break;
|
|
350
|
+
dir = parent;
|
|
351
|
+
}
|
|
352
|
+
} catch {}
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
};
|
|
356
|
+
|
|
357
|
+
//#endregion
|
|
358
|
+
exports.ProviderRegistry = ProviderRegistry;
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { AFSModule, MountConfig, ProviderManifest } from "./type.cjs";
|
|
2
|
+
import { ParsedURI } from "./utils/uri.cjs";
|
|
3
|
+
|
|
4
|
+
//#region src/registry.d.ts
|
|
5
|
+
/**
|
|
6
|
+
* Factory function that creates a provider from a mount config and pre-parsed URI.
|
|
7
|
+
*/
|
|
8
|
+
type ProviderFactory = (mount: MountConfig, parsed: ParsedURI) => Promise<AFSModule>;
|
|
9
|
+
/**
|
|
10
|
+
* Registry of provider factories with unified manifest-driven loading.
|
|
11
|
+
*
|
|
12
|
+
* Loading flow:
|
|
13
|
+
* 1. parseURI → get scheme
|
|
14
|
+
* 2. Check registered factories (workspace, custom) → use directly
|
|
15
|
+
* 3. Resolve package: mount.provider or @aigne/afs-{baseScheme}
|
|
16
|
+
* 4. Import package → get ProviderClass
|
|
17
|
+
* 5. Get manifest from ProviderClass.manifest()
|
|
18
|
+
* 6. Match manifest by scheme (for multi-manifest providers)
|
|
19
|
+
* 7. parseTemplate(uriTemplate, body) → extract path variables
|
|
20
|
+
* 8. Merge params: body vars > query > mount.options
|
|
21
|
+
* 9. Construct provider with merged options
|
|
22
|
+
*/
|
|
23
|
+
declare class ProviderRegistry {
|
|
24
|
+
private factories;
|
|
25
|
+
/** Register a scheme → factory mapping. Overwrites any existing registration. */
|
|
26
|
+
register(scheme: string, factory: ProviderFactory): void;
|
|
27
|
+
/** Check if a scheme has a registered factory. */
|
|
28
|
+
has(scheme: string): boolean;
|
|
29
|
+
/**
|
|
30
|
+
* Get provider metadata (schema, auth, manifest) for a URI.
|
|
31
|
+
*
|
|
32
|
+
* Used by CLI credential resolution to get schema and auth method
|
|
33
|
+
* without constructing the provider.
|
|
34
|
+
*
|
|
35
|
+
* Returns null if the provider class can't be loaded (e.g., unknown scheme).
|
|
36
|
+
*/
|
|
37
|
+
getProviderInfo(uri: string): Promise<{
|
|
38
|
+
schema: any | null;
|
|
39
|
+
auth: ((context: any) => Promise<Record<string, unknown> | null>) | undefined;
|
|
40
|
+
manifest: ProviderManifest | null;
|
|
41
|
+
} | null>;
|
|
42
|
+
/**
|
|
43
|
+
* Create a provider from a mount config.
|
|
44
|
+
*
|
|
45
|
+
* Uses registered factory if available, otherwise auto-loads
|
|
46
|
+
* via manifest-driven resolution.
|
|
47
|
+
*/
|
|
48
|
+
createProvider(mount: MountConfig): Promise<AFSModule>;
|
|
49
|
+
/**
|
|
50
|
+
* Auto-load a provider using the manifest-driven unified flow.
|
|
51
|
+
*/
|
|
52
|
+
private autoLoadProvider;
|
|
53
|
+
/**
|
|
54
|
+
* Import a provider class from a package name.
|
|
55
|
+
* Resolution order:
|
|
56
|
+
* 1. Direct import (works when package is a dependency of the importing module)
|
|
57
|
+
* 2. createRequire from process.cwd() (works in monorepo dev environments)
|
|
58
|
+
* 3. npm auto-install to ~/.afs-config/packages/
|
|
59
|
+
*/
|
|
60
|
+
private importProviderClass;
|
|
61
|
+
/**
|
|
62
|
+
* Get manifest(s) from a provider class.
|
|
63
|
+
*/
|
|
64
|
+
private getManifests;
|
|
65
|
+
/**
|
|
66
|
+
* Find the matching manifest for a given scheme.
|
|
67
|
+
* For multi-manifest providers (e.g., MCP with mcp+stdio, mcp+http, mcp+sse),
|
|
68
|
+
* match by the full scheme from the URI template.
|
|
69
|
+
*/
|
|
70
|
+
private matchManifest;
|
|
71
|
+
/**
|
|
72
|
+
* Merge parameters from multiple sources.
|
|
73
|
+
* Priority: template vars (from URI body) > query params > mount.options
|
|
74
|
+
*/
|
|
75
|
+
private mergeOptions;
|
|
76
|
+
/**
|
|
77
|
+
* Construct a provider instance with merged options.
|
|
78
|
+
*/
|
|
79
|
+
private constructProvider;
|
|
80
|
+
/**
|
|
81
|
+
* Resolve and import a package, trying multiple resolution strategies.
|
|
82
|
+
*
|
|
83
|
+
* In a monorepo (pnpm workspace), `import("@aigne/afs-fs")` inside packages/core
|
|
84
|
+
* won't find packages/cli's dependencies. We locate the package directory via
|
|
85
|
+
* createRequire, then use resolveImportPath to find the correct ESM entry.
|
|
86
|
+
*/
|
|
87
|
+
private resolveAndImport;
|
|
88
|
+
/**
|
|
89
|
+
* Locate a package directory using createRequire from various contexts.
|
|
90
|
+
* Returns the package directory path, or undefined if not found.
|
|
91
|
+
*/
|
|
92
|
+
private locatePackageDir;
|
|
93
|
+
}
|
|
94
|
+
//#endregion
|
|
95
|
+
export { ProviderFactory, ProviderRegistry };
|
|
96
|
+
//# sourceMappingURL=registry.d.cts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.d.cts","names":[],"sources":["../src/registry.ts"],"mappings":";;;;;;AASA;KAAY,eAAA,IAAmB,KAAA,EAAO,WAAA,EAAa,MAAA,EAAQ,SAAA,KAAc,OAAA,CAAQ,SAAA;;;;;;;;;;;;;;;cA4KpE,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;;;;;;EAmEM,cAAA,CAAe,KAAA,EAAO,WAAA,GAAc,OAAA,CAAQ,SAAA;EArDxC;;;EAAA,QAyEI,gBAAA;EAxEF;;;;;;;EAAA,QAuGE,mBAAA;EAwEN;;;EAAA,QAAA,YAAA;EAuHM;;;;;EAAA,QAtGN,aAAA;;;;;UAiCA,YAAA;;;;UAgCM,iBAAA;;;;;;;;UAqCA,gBAAA;;;;;UAyBN,gBAAA;AAAA"}
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { AFSModule, MountConfig, ProviderManifest } from "./type.mjs";
|
|
2
|
+
import { ParsedURI } from "./utils/uri.mjs";
|
|
3
|
+
|
|
4
|
+
//#region src/registry.d.ts
|
|
5
|
+
/**
|
|
6
|
+
* Factory function that creates a provider from a mount config and pre-parsed URI.
|
|
7
|
+
*/
|
|
8
|
+
type ProviderFactory = (mount: MountConfig, parsed: ParsedURI) => Promise<AFSModule>;
|
|
9
|
+
/**
|
|
10
|
+
* Registry of provider factories with unified manifest-driven loading.
|
|
11
|
+
*
|
|
12
|
+
* Loading flow:
|
|
13
|
+
* 1. parseURI → get scheme
|
|
14
|
+
* 2. Check registered factories (workspace, custom) → use directly
|
|
15
|
+
* 3. Resolve package: mount.provider or @aigne/afs-{baseScheme}
|
|
16
|
+
* 4. Import package → get ProviderClass
|
|
17
|
+
* 5. Get manifest from ProviderClass.manifest()
|
|
18
|
+
* 6. Match manifest by scheme (for multi-manifest providers)
|
|
19
|
+
* 7. parseTemplate(uriTemplate, body) → extract path variables
|
|
20
|
+
* 8. Merge params: body vars > query > mount.options
|
|
21
|
+
* 9. Construct provider with merged options
|
|
22
|
+
*/
|
|
23
|
+
declare class ProviderRegistry {
|
|
24
|
+
private factories;
|
|
25
|
+
/** Register a scheme → factory mapping. Overwrites any existing registration. */
|
|
26
|
+
register(scheme: string, factory: ProviderFactory): void;
|
|
27
|
+
/** Check if a scheme has a registered factory. */
|
|
28
|
+
has(scheme: string): boolean;
|
|
29
|
+
/**
|
|
30
|
+
* Get provider metadata (schema, auth, manifest) for a URI.
|
|
31
|
+
*
|
|
32
|
+
* Used by CLI credential resolution to get schema and auth method
|
|
33
|
+
* without constructing the provider.
|
|
34
|
+
*
|
|
35
|
+
* Returns null if the provider class can't be loaded (e.g., unknown scheme).
|
|
36
|
+
*/
|
|
37
|
+
getProviderInfo(uri: string): Promise<{
|
|
38
|
+
schema: any | null;
|
|
39
|
+
auth: ((context: any) => Promise<Record<string, unknown> | null>) | undefined;
|
|
40
|
+
manifest: ProviderManifest | null;
|
|
41
|
+
} | null>;
|
|
42
|
+
/**
|
|
43
|
+
* Create a provider from a mount config.
|
|
44
|
+
*
|
|
45
|
+
* Uses registered factory if available, otherwise auto-loads
|
|
46
|
+
* via manifest-driven resolution.
|
|
47
|
+
*/
|
|
48
|
+
createProvider(mount: MountConfig): Promise<AFSModule>;
|
|
49
|
+
/**
|
|
50
|
+
* Auto-load a provider using the manifest-driven unified flow.
|
|
51
|
+
*/
|
|
52
|
+
private autoLoadProvider;
|
|
53
|
+
/**
|
|
54
|
+
* Import a provider class from a package name.
|
|
55
|
+
* Resolution order:
|
|
56
|
+
* 1. Direct import (works when package is a dependency of the importing module)
|
|
57
|
+
* 2. createRequire from process.cwd() (works in monorepo dev environments)
|
|
58
|
+
* 3. npm auto-install to ~/.afs-config/packages/
|
|
59
|
+
*/
|
|
60
|
+
private importProviderClass;
|
|
61
|
+
/**
|
|
62
|
+
* Get manifest(s) from a provider class.
|
|
63
|
+
*/
|
|
64
|
+
private getManifests;
|
|
65
|
+
/**
|
|
66
|
+
* Find the matching manifest for a given scheme.
|
|
67
|
+
* For multi-manifest providers (e.g., MCP with mcp+stdio, mcp+http, mcp+sse),
|
|
68
|
+
* match by the full scheme from the URI template.
|
|
69
|
+
*/
|
|
70
|
+
private matchManifest;
|
|
71
|
+
/**
|
|
72
|
+
* Merge parameters from multiple sources.
|
|
73
|
+
* Priority: template vars (from URI body) > query params > mount.options
|
|
74
|
+
*/
|
|
75
|
+
private mergeOptions;
|
|
76
|
+
/**
|
|
77
|
+
* Construct a provider instance with merged options.
|
|
78
|
+
*/
|
|
79
|
+
private constructProvider;
|
|
80
|
+
/**
|
|
81
|
+
* Resolve and import a package, trying multiple resolution strategies.
|
|
82
|
+
*
|
|
83
|
+
* In a monorepo (pnpm workspace), `import("@aigne/afs-fs")` inside packages/core
|
|
84
|
+
* won't find packages/cli's dependencies. We locate the package directory via
|
|
85
|
+
* createRequire, then use resolveImportPath to find the correct ESM entry.
|
|
86
|
+
*/
|
|
87
|
+
private resolveAndImport;
|
|
88
|
+
/**
|
|
89
|
+
* Locate a package directory using createRequire from various contexts.
|
|
90
|
+
* Returns the package directory path, or undefined if not found.
|
|
91
|
+
*/
|
|
92
|
+
private locatePackageDir;
|
|
93
|
+
}
|
|
94
|
+
//#endregion
|
|
95
|
+
export { ProviderFactory, ProviderRegistry };
|
|
96
|
+
//# sourceMappingURL=registry.d.mts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.d.mts","names":[],"sources":["../src/registry.ts"],"mappings":";;;;;;AASA;KAAY,eAAA,IAAmB,KAAA,EAAO,WAAA,EAAa,MAAA,EAAQ,SAAA,KAAc,OAAA,CAAQ,SAAA;;;;;;;;;;;;;;;cA4KpE,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;;;;;;EAmEM,cAAA,CAAe,KAAA,EAAO,WAAA,GAAc,OAAA,CAAQ,SAAA;EArDxC;;;EAAA,QAyEI,gBAAA;EAxEF;;;;;;;EAAA,QAuGE,mBAAA;EAwEN;;;EAAA,QAAA,YAAA;EAuHM;;;;;EAAA,QAtGN,aAAA;;;;;UAiCA,YAAA;;;;UAgCM,iBAAA;;;;;;;;UAqCA,gBAAA;;;;;UAyBN,gBAAA;AAAA"}
|