@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.
Files changed (164) hide show
  1. package/LICENSE.md +17 -84
  2. package/README.md +4 -13
  3. package/dist/_virtual/rolldown_runtime.mjs +7 -0
  4. package/dist/afs.cjs +1330 -0
  5. package/dist/afs.d.cts +275 -0
  6. package/dist/afs.d.cts.map +1 -0
  7. package/dist/afs.d.mts +275 -0
  8. package/dist/afs.d.mts.map +1 -0
  9. package/dist/afs.mjs +1331 -0
  10. package/dist/afs.mjs.map +1 -0
  11. package/dist/capabilities/index.d.mts +2 -0
  12. package/dist/capabilities/types.d.cts +100 -0
  13. package/dist/capabilities/types.d.cts.map +1 -0
  14. package/dist/capabilities/types.d.mts +100 -0
  15. package/dist/capabilities/types.d.mts.map +1 -0
  16. package/dist/capabilities/world-mapping.cjs +20 -0
  17. package/dist/capabilities/world-mapping.d.cts +139 -0
  18. package/dist/capabilities/world-mapping.d.cts.map +1 -0
  19. package/dist/capabilities/world-mapping.d.mts +139 -0
  20. package/dist/capabilities/world-mapping.d.mts.map +1 -0
  21. package/dist/capabilities/world-mapping.mjs +20 -0
  22. package/dist/capabilities/world-mapping.mjs.map +1 -0
  23. package/dist/error.cjs +63 -0
  24. package/dist/error.d.cts +39 -0
  25. package/dist/error.d.cts.map +1 -0
  26. package/dist/error.d.mts +39 -0
  27. package/dist/error.d.mts.map +1 -0
  28. package/dist/error.mjs +59 -0
  29. package/dist/error.mjs.map +1 -0
  30. package/dist/index.cjs +72 -345
  31. package/dist/index.d.cts +18 -300
  32. package/dist/index.d.mts +20 -300
  33. package/dist/index.mjs +16 -342
  34. package/dist/loader/index.cjs +110 -0
  35. package/dist/loader/index.d.cts +48 -0
  36. package/dist/loader/index.d.cts.map +1 -0
  37. package/dist/loader/index.d.mts +48 -0
  38. package/dist/loader/index.d.mts.map +1 -0
  39. package/dist/loader/index.mjs +110 -0
  40. package/dist/loader/index.mjs.map +1 -0
  41. package/dist/meta/index.cjs +4 -0
  42. package/dist/meta/index.mjs +6 -0
  43. package/dist/meta/kind.cjs +161 -0
  44. package/dist/meta/kind.d.cts +134 -0
  45. package/dist/meta/kind.d.cts.map +1 -0
  46. package/dist/meta/kind.d.mts +134 -0
  47. package/dist/meta/kind.d.mts.map +1 -0
  48. package/dist/meta/kind.mjs +157 -0
  49. package/dist/meta/kind.mjs.map +1 -0
  50. package/dist/meta/path.cjs +116 -0
  51. package/dist/meta/path.d.cts +43 -0
  52. package/dist/meta/path.d.cts.map +1 -0
  53. package/dist/meta/path.d.mts +43 -0
  54. package/dist/meta/path.d.mts.map +1 -0
  55. package/dist/meta/path.mjs +112 -0
  56. package/dist/meta/path.mjs.map +1 -0
  57. package/dist/meta/type.d.cts +96 -0
  58. package/dist/meta/type.d.cts.map +1 -0
  59. package/dist/meta/type.d.mts +96 -0
  60. package/dist/meta/type.d.mts.map +1 -0
  61. package/dist/meta/validation.cjs +77 -0
  62. package/dist/meta/validation.d.cts +19 -0
  63. package/dist/meta/validation.d.cts.map +1 -0
  64. package/dist/meta/validation.d.mts +19 -0
  65. package/dist/meta/validation.d.mts.map +1 -0
  66. package/dist/meta/validation.mjs +77 -0
  67. package/dist/meta/validation.mjs.map +1 -0
  68. package/dist/meta/well-known-kinds.cjs +228 -0
  69. package/dist/meta/well-known-kinds.d.cts +52 -0
  70. package/dist/meta/well-known-kinds.d.cts.map +1 -0
  71. package/dist/meta/well-known-kinds.d.mts +52 -0
  72. package/dist/meta/well-known-kinds.d.mts.map +1 -0
  73. package/dist/meta/well-known-kinds.mjs +219 -0
  74. package/dist/meta/well-known-kinds.mjs.map +1 -0
  75. package/dist/node_modules/.pnpm/@types_json-schema@7.0.15/node_modules/@types/json-schema/index.d.cts +141 -0
  76. package/dist/node_modules/.pnpm/@types_json-schema@7.0.15/node_modules/@types/json-schema/index.d.cts.map +1 -0
  77. package/dist/node_modules/.pnpm/@types_json-schema@7.0.15/node_modules/@types/json-schema/index.d.mts +141 -0
  78. package/dist/node_modules/.pnpm/@types_json-schema@7.0.15/node_modules/@types/json-schema/index.d.mts.map +1 -0
  79. package/dist/path.cjs +255 -0
  80. package/dist/path.d.cts +93 -0
  81. package/dist/path.d.cts.map +1 -0
  82. package/dist/path.d.mts +93 -0
  83. package/dist/path.d.mts.map +1 -0
  84. package/dist/path.mjs +249 -0
  85. package/dist/path.mjs.map +1 -0
  86. package/dist/provider/base.cjs +425 -0
  87. package/dist/provider/base.d.cts +175 -0
  88. package/dist/provider/base.d.cts.map +1 -0
  89. package/dist/provider/base.d.mts +175 -0
  90. package/dist/provider/base.d.mts.map +1 -0
  91. package/dist/provider/base.mjs +426 -0
  92. package/dist/provider/base.mjs.map +1 -0
  93. package/dist/provider/decorators.cjs +268 -0
  94. package/dist/provider/decorators.d.cts +244 -0
  95. package/dist/provider/decorators.d.cts.map +1 -0
  96. package/dist/provider/decorators.d.mts +244 -0
  97. package/dist/provider/decorators.d.mts.map +1 -0
  98. package/dist/provider/decorators.mjs +256 -0
  99. package/dist/provider/decorators.mjs.map +1 -0
  100. package/dist/provider/index.cjs +19 -0
  101. package/dist/provider/index.d.cts +5 -0
  102. package/dist/provider/index.d.mts +5 -0
  103. package/dist/provider/index.mjs +5 -0
  104. package/dist/provider/router.cjs +185 -0
  105. package/dist/provider/router.d.cts +50 -0
  106. package/dist/provider/router.d.cts.map +1 -0
  107. package/dist/provider/router.d.mts +50 -0
  108. package/dist/provider/router.d.mts.map +1 -0
  109. package/dist/provider/router.mjs +185 -0
  110. package/dist/provider/router.mjs.map +1 -0
  111. package/dist/provider/types.d.cts +113 -0
  112. package/dist/provider/types.d.cts.map +1 -0
  113. package/dist/provider/types.d.mts +113 -0
  114. package/dist/provider/types.d.mts.map +1 -0
  115. package/dist/registry.cjs +358 -0
  116. package/dist/registry.d.cts +96 -0
  117. package/dist/registry.d.cts.map +1 -0
  118. package/dist/registry.d.mts +96 -0
  119. package/dist/registry.d.mts.map +1 -0
  120. package/dist/registry.mjs +360 -0
  121. package/dist/registry.mjs.map +1 -0
  122. package/dist/type.cjs +34 -0
  123. package/dist/type.d.cts +420 -0
  124. package/dist/type.d.cts.map +1 -0
  125. package/dist/type.d.mts +420 -0
  126. package/dist/type.d.mts.map +1 -0
  127. package/dist/type.mjs +33 -0
  128. package/dist/type.mjs.map +1 -0
  129. package/dist/utils/camelize.d.cts.map +1 -1
  130. package/dist/utils/camelize.d.mts.map +1 -1
  131. package/dist/utils/schema.cjs +129 -0
  132. package/dist/utils/schema.d.cts +65 -0
  133. package/dist/utils/schema.d.cts.map +1 -0
  134. package/dist/utils/schema.d.mts +65 -0
  135. package/dist/utils/schema.d.mts.map +1 -0
  136. package/dist/utils/schema.mjs +124 -0
  137. package/dist/utils/schema.mjs.map +1 -0
  138. package/dist/utils/type-utils.d.cts.map +1 -1
  139. package/dist/utils/type-utils.d.mts.map +1 -1
  140. package/dist/utils/uri-template.cjs +123 -0
  141. package/dist/utils/uri-template.d.cts +48 -0
  142. package/dist/utils/uri-template.d.cts.map +1 -0
  143. package/dist/utils/uri-template.d.mts +48 -0
  144. package/dist/utils/uri-template.d.mts.map +1 -0
  145. package/dist/utils/uri-template.mjs +120 -0
  146. package/dist/utils/uri-template.mjs.map +1 -0
  147. package/dist/utils/uri.cjs +49 -0
  148. package/dist/utils/uri.d.cts +34 -0
  149. package/dist/utils/uri.d.cts.map +1 -0
  150. package/dist/utils/uri.d.mts +34 -0
  151. package/dist/utils/uri.d.mts.map +1 -0
  152. package/dist/utils/uri.mjs +49 -0
  153. package/dist/utils/uri.mjs.map +1 -0
  154. package/dist/utils/zod.cjs +6 -8
  155. package/dist/utils/zod.d.cts +2 -2
  156. package/dist/utils/zod.d.cts.map +1 -1
  157. package/dist/utils/zod.d.mts +2 -2
  158. package/dist/utils/zod.d.mts.map +1 -1
  159. package/dist/utils/zod.mjs +6 -8
  160. package/dist/utils/zod.mjs.map +1 -1
  161. package/package.json +27 -4
  162. package/dist/index.d.cts.map +0 -1
  163. package/dist/index.d.mts.map +0 -1
  164. 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"}