@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,360 @@
|
|
|
1
|
+
import { __require } from "./_virtual/rolldown_runtime.mjs";
|
|
2
|
+
import { parseURI } from "./utils/uri.mjs";
|
|
3
|
+
import { extractSchemeFromTemplate, parseTemplate } from "./utils/uri-template.mjs";
|
|
4
|
+
import { existsSync, readFileSync, writeFileSync } from "node:fs";
|
|
5
|
+
import { join } from "node:path";
|
|
6
|
+
|
|
7
|
+
//#region src/registry.ts
|
|
8
|
+
/**
|
|
9
|
+
* Resolve a package specifier to an importable path.
|
|
10
|
+
* If the specifier is a directory path (e.g. from npm install),
|
|
11
|
+
* read its package.json to find the ESM entry point.
|
|
12
|
+
*/
|
|
13
|
+
function resolveImportPath(specifier) {
|
|
14
|
+
if (!specifier.startsWith("/")) return specifier;
|
|
15
|
+
const pkgJsonPath = join(specifier, "package.json");
|
|
16
|
+
if (!existsSync(pkgJsonPath)) return specifier;
|
|
17
|
+
try {
|
|
18
|
+
const pkg = JSON.parse(readFileSync(pkgJsonPath, "utf-8"));
|
|
19
|
+
const esmEntry = typeof pkg.exports === "object" && pkg.exports["."]?.import || pkg.module;
|
|
20
|
+
if (esmEntry) return join(specifier, esmEntry);
|
|
21
|
+
if (pkg.main) return join(specifier, pkg.main);
|
|
22
|
+
} catch {}
|
|
23
|
+
return specifier;
|
|
24
|
+
}
|
|
25
|
+
/** Mutex for npm install operations to prevent concurrent installs */
|
|
26
|
+
const npmInstallLocks = /* @__PURE__ */ new Map();
|
|
27
|
+
/**
|
|
28
|
+
* Validate npm package name format.
|
|
29
|
+
* Rejects path traversal and shell metacharacters.
|
|
30
|
+
*/
|
|
31
|
+
function isValidNpmPackageName(name) {
|
|
32
|
+
if (!name || name.length > 214) return false;
|
|
33
|
+
if (name.includes("..") || name.startsWith("/") || name.startsWith("\\")) return false;
|
|
34
|
+
for (const char of [
|
|
35
|
+
";",
|
|
36
|
+
"|",
|
|
37
|
+
"&",
|
|
38
|
+
"`",
|
|
39
|
+
"$",
|
|
40
|
+
"(",
|
|
41
|
+
")",
|
|
42
|
+
">",
|
|
43
|
+
"<",
|
|
44
|
+
"\n",
|
|
45
|
+
"\r",
|
|
46
|
+
" ",
|
|
47
|
+
"\0"
|
|
48
|
+
]) if (name.includes(char)) return false;
|
|
49
|
+
if (name.startsWith("@")) {
|
|
50
|
+
const parts = name.slice(1).split("/");
|
|
51
|
+
if (parts.length !== 2 || !parts[0] || !parts[1]) return false;
|
|
52
|
+
}
|
|
53
|
+
return true;
|
|
54
|
+
}
|
|
55
|
+
/**
|
|
56
|
+
* Install an npm package if not already present.
|
|
57
|
+
* Uses per-package mutex to prevent concurrent installs.
|
|
58
|
+
*/
|
|
59
|
+
async function npmInstall(packageName, packagesDir) {
|
|
60
|
+
const existing = npmInstallLocks.get(packageName);
|
|
61
|
+
if (existing) {
|
|
62
|
+
await existing;
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
const { mkdir } = await import("node:fs/promises");
|
|
66
|
+
const installPromise = (async () => {
|
|
67
|
+
await mkdir(packagesDir, { recursive: true });
|
|
68
|
+
const { execSync } = await import("node:child_process");
|
|
69
|
+
try {
|
|
70
|
+
execSync(`npm install --prefix ${JSON.stringify(packagesDir)} ${JSON.stringify(packageName)}`, {
|
|
71
|
+
stdio: "pipe",
|
|
72
|
+
timeout: 12e4
|
|
73
|
+
});
|
|
74
|
+
} catch (error) {
|
|
75
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
76
|
+
throw new Error(`Failed to install npm package "${packageName}": ${message}`);
|
|
77
|
+
}
|
|
78
|
+
})();
|
|
79
|
+
npmInstallLocks.set(packageName, installPromise);
|
|
80
|
+
try {
|
|
81
|
+
await installPromise;
|
|
82
|
+
} finally {
|
|
83
|
+
npmInstallLocks.delete(packageName);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
/**
|
|
87
|
+
* Get the npm packages install directory (~/.afs-config/packages/).
|
|
88
|
+
*/
|
|
89
|
+
function getNpmPackagesDir() {
|
|
90
|
+
const os = __require("node:os");
|
|
91
|
+
const { resolve } = __require("node:path");
|
|
92
|
+
return resolve(os.homedir(), ".afs-config", "packages");
|
|
93
|
+
}
|
|
94
|
+
/** How often to check for package updates (24 hours). */
|
|
95
|
+
const UPDATE_CHECK_STALE_MS = 1440 * 60 * 1e3;
|
|
96
|
+
/**
|
|
97
|
+
* Trigger a background npm update if the package hasn't been checked recently.
|
|
98
|
+
* Completely silent — never blocks, never throws, never produces output.
|
|
99
|
+
*/
|
|
100
|
+
function npmUpdateIfStale(packageName, packagesDir) {
|
|
101
|
+
const checkFile = join(packagesDir, ".update-check.json");
|
|
102
|
+
const now = Date.now();
|
|
103
|
+
let checks = {};
|
|
104
|
+
try {
|
|
105
|
+
checks = JSON.parse(readFileSync(checkFile, "utf-8"));
|
|
106
|
+
} catch {}
|
|
107
|
+
if (now - (checks[packageName] ?? 0) < UPDATE_CHECK_STALE_MS) return;
|
|
108
|
+
checks[packageName] = now;
|
|
109
|
+
try {
|
|
110
|
+
writeFileSync(checkFile, JSON.stringify(checks, null, 2));
|
|
111
|
+
} catch {}
|
|
112
|
+
npmUpdateBackground(packageName, packagesDir).catch(() => {});
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* Run `npm update` for a single package in the background.
|
|
116
|
+
* Errors are silently swallowed (e.g. no network).
|
|
117
|
+
*/
|
|
118
|
+
async function npmUpdateBackground(packageName, packagesDir) {
|
|
119
|
+
const { execSync } = await import("node:child_process");
|
|
120
|
+
try {
|
|
121
|
+
execSync(`npm update --prefix ${JSON.stringify(packagesDir)} ${JSON.stringify(packageName)}`, {
|
|
122
|
+
stdio: "ignore",
|
|
123
|
+
timeout: 12e4
|
|
124
|
+
});
|
|
125
|
+
} catch {}
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Package name overrides for schemes that don't follow the @aigne/afs-{scheme} convention.
|
|
129
|
+
* Class discovery uses the .manifest() static method — no class name mapping needed.
|
|
130
|
+
*/
|
|
131
|
+
const PACKAGE_OVERRIDES = { https: "@aigne/afs-http" };
|
|
132
|
+
/**
|
|
133
|
+
* Derive the base scheme for compound schemes.
|
|
134
|
+
* e.g. "mcp+stdio" → "mcp", "mcp+http" → "mcp"
|
|
135
|
+
*/
|
|
136
|
+
function baseScheme(scheme) {
|
|
137
|
+
const plusIdx = scheme.indexOf("+");
|
|
138
|
+
return plusIdx >= 0 ? scheme.slice(0, plusIdx) : scheme;
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Registry of provider factories with unified manifest-driven loading.
|
|
142
|
+
*
|
|
143
|
+
* Loading flow:
|
|
144
|
+
* 1. parseURI → get scheme
|
|
145
|
+
* 2. Check registered factories (workspace, custom) → use directly
|
|
146
|
+
* 3. Resolve package: mount.provider or @aigne/afs-{baseScheme}
|
|
147
|
+
* 4. Import package → get ProviderClass
|
|
148
|
+
* 5. Get manifest from ProviderClass.manifest()
|
|
149
|
+
* 6. Match manifest by scheme (for multi-manifest providers)
|
|
150
|
+
* 7. parseTemplate(uriTemplate, body) → extract path variables
|
|
151
|
+
* 8. Merge params: body vars > query > mount.options
|
|
152
|
+
* 9. Construct provider with merged options
|
|
153
|
+
*/
|
|
154
|
+
var ProviderRegistry = class {
|
|
155
|
+
factories = /* @__PURE__ */ new Map();
|
|
156
|
+
/** Register a scheme → factory mapping. Overwrites any existing registration. */
|
|
157
|
+
register(scheme, factory) {
|
|
158
|
+
this.factories.set(scheme.toLowerCase(), factory);
|
|
159
|
+
}
|
|
160
|
+
/** Check if a scheme has a registered factory. */
|
|
161
|
+
has(scheme) {
|
|
162
|
+
return this.factories.has(scheme.toLowerCase());
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Get provider metadata (schema, auth, manifest) for a URI.
|
|
166
|
+
*
|
|
167
|
+
* Used by CLI credential resolution to get schema and auth method
|
|
168
|
+
* without constructing the provider.
|
|
169
|
+
*
|
|
170
|
+
* Returns null if the provider class can't be loaded (e.g., unknown scheme).
|
|
171
|
+
*/
|
|
172
|
+
async getProviderInfo(uri) {
|
|
173
|
+
try {
|
|
174
|
+
const parsed = parseURI(uri);
|
|
175
|
+
const base = baseScheme(parsed.scheme);
|
|
176
|
+
const packageName = PACKAGE_OVERRIDES[base] ?? `@aigne/afs-${base}`;
|
|
177
|
+
const ProviderClass = await this.importProviderClass(packageName, base);
|
|
178
|
+
const auth = ProviderClass.auth ? ProviderClass.auth.bind(ProviderClass) : void 0;
|
|
179
|
+
let manifest = null;
|
|
180
|
+
if (ProviderClass.manifest) {
|
|
181
|
+
const manifests = this.getManifests(ProviderClass, packageName);
|
|
182
|
+
manifest = this.matchManifest(manifests, parsed.scheme, packageName);
|
|
183
|
+
}
|
|
184
|
+
let schema = null;
|
|
185
|
+
if (manifest?.schema) try {
|
|
186
|
+
const { z } = await import("zod");
|
|
187
|
+
schema = z.toJSONSchema(manifest.schema);
|
|
188
|
+
} catch {}
|
|
189
|
+
if (!schema && ProviderClass.schema) try {
|
|
190
|
+
const zodSchema = ProviderClass.schema();
|
|
191
|
+
const { z } = await import("zod");
|
|
192
|
+
schema = z.toJSONSchema(zodSchema);
|
|
193
|
+
} catch {}
|
|
194
|
+
return {
|
|
195
|
+
schema,
|
|
196
|
+
auth,
|
|
197
|
+
manifest
|
|
198
|
+
};
|
|
199
|
+
} catch {
|
|
200
|
+
return null;
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* Create a provider from a mount config.
|
|
205
|
+
*
|
|
206
|
+
* Uses registered factory if available, otherwise auto-loads
|
|
207
|
+
* via manifest-driven resolution.
|
|
208
|
+
*/
|
|
209
|
+
async createProvider(mount) {
|
|
210
|
+
const parsed = parseURI(mount.uri);
|
|
211
|
+
const factory = this.factories.get(parsed.scheme);
|
|
212
|
+
if (factory) {
|
|
213
|
+
const provider$1 = await factory(mount, parsed);
|
|
214
|
+
provider$1.uri = mount.uri;
|
|
215
|
+
return provider$1;
|
|
216
|
+
}
|
|
217
|
+
const provider = await this.autoLoadProvider(mount, parsed);
|
|
218
|
+
provider.uri = mount.uri;
|
|
219
|
+
return provider;
|
|
220
|
+
}
|
|
221
|
+
/**
|
|
222
|
+
* Auto-load a provider using the manifest-driven unified flow.
|
|
223
|
+
*/
|
|
224
|
+
async autoLoadProvider(mount, parsed) {
|
|
225
|
+
const base = baseScheme(parsed.scheme);
|
|
226
|
+
const packageName = PACKAGE_OVERRIDES[base] ?? `@aigne/afs-${base}`;
|
|
227
|
+
const ProviderClass = await this.importProviderClass(packageName, base);
|
|
228
|
+
const manifests = this.getManifests(ProviderClass, packageName);
|
|
229
|
+
const manifest = this.matchManifest(manifests, parsed.scheme, packageName);
|
|
230
|
+
const templateVars = parseTemplate(manifest.uriTemplate, parsed.body);
|
|
231
|
+
const mergedOptions = this.mergeOptions(templateVars, parsed.query, mount);
|
|
232
|
+
return this.constructProvider(ProviderClass, mount, parsed, mergedOptions, manifest);
|
|
233
|
+
}
|
|
234
|
+
/**
|
|
235
|
+
* Import a provider class from a package name.
|
|
236
|
+
* Resolution order:
|
|
237
|
+
* 1. Direct import (works when package is a dependency of the importing module)
|
|
238
|
+
* 2. createRequire from process.cwd() (works in monorepo dev environments)
|
|
239
|
+
* 3. npm auto-install to ~/.afs-config/packages/
|
|
240
|
+
*/
|
|
241
|
+
async importProviderClass(packageName, scheme, explicitClassName) {
|
|
242
|
+
let mod;
|
|
243
|
+
try {
|
|
244
|
+
mod = await this.resolveAndImport(packageName);
|
|
245
|
+
} catch {
|
|
246
|
+
if (!isValidNpmPackageName(packageName)) throw new Error(`Unknown URI scheme "${scheme}": package "${packageName}" not found and name is invalid.`);
|
|
247
|
+
const packagesDir = getNpmPackagesDir();
|
|
248
|
+
const { resolve } = await import("node:path");
|
|
249
|
+
const nodeModulesPath = resolve(packagesDir, "node_modules", ...packageName.split("/"));
|
|
250
|
+
if (!existsSync(nodeModulesPath)) await npmInstall(packageName, packagesDir);
|
|
251
|
+
else npmUpdateIfStale(packageName, packagesDir);
|
|
252
|
+
const importPath = resolveImportPath(nodeModulesPath);
|
|
253
|
+
try {
|
|
254
|
+
mod = await import(importPath);
|
|
255
|
+
} catch (error) {
|
|
256
|
+
const msg = error instanceof Error ? error.message : String(error);
|
|
257
|
+
throw new Error(`Failed to import provider package "${packageName}" for scheme "${scheme}": ${msg}`);
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
if (explicitClassName && mod[explicitClassName]) return mod[explicitClassName];
|
|
261
|
+
const conventionName = `AFS${scheme.charAt(0).toUpperCase()}${scheme.slice(1).toUpperCase()}`;
|
|
262
|
+
if (mod[conventionName]) return mod[conventionName];
|
|
263
|
+
for (const key of Object.keys(mod)) {
|
|
264
|
+
const val = mod[key];
|
|
265
|
+
if (typeof val === "function" && key !== "default" && val.manifest) return val;
|
|
266
|
+
}
|
|
267
|
+
if (mod.default && typeof mod.default === "function") return mod.default;
|
|
268
|
+
throw new Error(`Package "${packageName}" does not export a valid AFS Provider class for scheme "${scheme}".`);
|
|
269
|
+
}
|
|
270
|
+
/**
|
|
271
|
+
* Get manifest(s) from a provider class.
|
|
272
|
+
*/
|
|
273
|
+
getManifests(ProviderClass, packageName) {
|
|
274
|
+
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.`);
|
|
275
|
+
const result = ProviderClass.manifest();
|
|
276
|
+
return Array.isArray(result) ? result : [result];
|
|
277
|
+
}
|
|
278
|
+
/**
|
|
279
|
+
* Find the matching manifest for a given scheme.
|
|
280
|
+
* For multi-manifest providers (e.g., MCP with mcp+stdio, mcp+http, mcp+sse),
|
|
281
|
+
* match by the full scheme from the URI template.
|
|
282
|
+
*/
|
|
283
|
+
matchManifest(manifests, scheme, packageName) {
|
|
284
|
+
if (manifests.length === 1) return manifests[0];
|
|
285
|
+
for (const m of manifests) try {
|
|
286
|
+
if (extractSchemeFromTemplate(m.uriTemplate) === scheme) return m;
|
|
287
|
+
} catch {}
|
|
288
|
+
if (manifests.length > 0) return manifests[0];
|
|
289
|
+
throw new Error(`No matching manifest found for scheme "${scheme}" in package "${packageName}".`);
|
|
290
|
+
}
|
|
291
|
+
/**
|
|
292
|
+
* Merge parameters from multiple sources.
|
|
293
|
+
* Priority: template vars (from URI body) > query params > mount.options
|
|
294
|
+
*/
|
|
295
|
+
mergeOptions(templateVars, query, mount) {
|
|
296
|
+
const result = {};
|
|
297
|
+
if (mount.options) Object.assign(result, mount.options);
|
|
298
|
+
for (const [key, value] of Object.entries(query)) if (value !== "") result[key] = value;
|
|
299
|
+
for (const [key, value] of Object.entries(templateVars)) if (value !== void 0) result[key] = value;
|
|
300
|
+
return result;
|
|
301
|
+
}
|
|
302
|
+
/**
|
|
303
|
+
* Construct a provider instance with merged options.
|
|
304
|
+
*/
|
|
305
|
+
async constructProvider(ProviderClass, mount, _parsed, mergedOptions, manifest) {
|
|
306
|
+
const constructorOptions = {
|
|
307
|
+
...mergedOptions,
|
|
308
|
+
name: mount.path.slice(1).replace(/\//g, "-") || manifest.name,
|
|
309
|
+
description: mount.description,
|
|
310
|
+
accessMode: mount.access_mode,
|
|
311
|
+
uri: mount.uri
|
|
312
|
+
};
|
|
313
|
+
if (mount.auth !== void 0) constructorOptions.auth = mount.auth;
|
|
314
|
+
if (mount.token !== void 0) constructorOptions.token = mount.token;
|
|
315
|
+
const provider = new ProviderClass(constructorOptions);
|
|
316
|
+
if (typeof provider.ready === "function") await provider.ready();
|
|
317
|
+
return provider;
|
|
318
|
+
}
|
|
319
|
+
/**
|
|
320
|
+
* Resolve and import a package, trying multiple resolution strategies.
|
|
321
|
+
*
|
|
322
|
+
* In a monorepo (pnpm workspace), `import("@aigne/afs-fs")` inside packages/core
|
|
323
|
+
* won't find packages/cli's dependencies. We locate the package directory via
|
|
324
|
+
* createRequire, then use resolveImportPath to find the correct ESM entry.
|
|
325
|
+
*/
|
|
326
|
+
async resolveAndImport(packageName) {
|
|
327
|
+
try {
|
|
328
|
+
return await import(resolveImportPath(packageName));
|
|
329
|
+
} catch {}
|
|
330
|
+
const packageDir = this.locatePackageDir(packageName);
|
|
331
|
+
if (packageDir) return await import(resolveImportPath(packageDir));
|
|
332
|
+
throw new Error(`Cannot resolve module "${packageName}"`);
|
|
333
|
+
}
|
|
334
|
+
/**
|
|
335
|
+
* Locate a package directory using createRequire from various contexts.
|
|
336
|
+
* Returns the package directory path, or undefined if not found.
|
|
337
|
+
*/
|
|
338
|
+
locatePackageDir(packageName) {
|
|
339
|
+
const { createRequire } = __require("node:module");
|
|
340
|
+
const { dirname } = __require("node:path");
|
|
341
|
+
const contexts = [join(process.cwd(), "__resolve__.js"), ...process.argv[1] ? [join(dirname(process.argv[1]), "__resolve__.js")] : []];
|
|
342
|
+
for (const context of contexts) try {
|
|
343
|
+
return dirname(createRequire(context).resolve(join(packageName, "package.json")));
|
|
344
|
+
} catch {
|
|
345
|
+
try {
|
|
346
|
+
let dir = dirname(createRequire(context).resolve(packageName));
|
|
347
|
+
for (let i = 0; i < 5; i++) {
|
|
348
|
+
if (existsSync(join(dir, "package.json"))) return dir;
|
|
349
|
+
const parent = dirname(dir);
|
|
350
|
+
if (parent === dir) break;
|
|
351
|
+
dir = parent;
|
|
352
|
+
}
|
|
353
|
+
} catch {}
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
};
|
|
357
|
+
|
|
358
|
+
//#endregion
|
|
359
|
+
export { ProviderRegistry };
|
|
360
|
+
//# sourceMappingURL=registry.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.mjs","names":["provider"],"sources":["../src/registry.ts"],"sourcesContent":["import { existsSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport type { AFSModule, MountConfig, ProviderManifest } from \"./type.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// ─── 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 any).toJSONSchema(manifest.schema);\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 any).toJSONSchema(zodSchema);\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\" && (val as any).manifest) {\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 const constructorOptions: Record<string, unknown> = {\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 // 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 as any)(constructorOptions) as AFSModule;\n\n // Generic post-construction initialization\n if (typeof (provider as any).ready === \"function\") {\n await (provider as any).ready();\n }\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 // 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 const { dirname } = require(\"node:path\") as typeof import(\"node:path\");\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/type.cjs
ADDED
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
let zod = require("zod");
|
|
2
|
+
|
|
3
|
+
//#region src/type.ts
|
|
4
|
+
/**
|
|
5
|
+
* Zod schema for access mode validation.
|
|
6
|
+
* Can be reused across modules that support access mode configuration.
|
|
7
|
+
*/
|
|
8
|
+
const accessModeSchema = zod.z.enum(["readonly", "readwrite"]).optional();
|
|
9
|
+
/**
|
|
10
|
+
* Zod schema for ActionSummary validation.
|
|
11
|
+
*/
|
|
12
|
+
const actionSummarySchema = zod.z.object({
|
|
13
|
+
name: zod.z.string(),
|
|
14
|
+
description: zod.z.string().optional(),
|
|
15
|
+
inputSchema: zod.z.record(zod.z.string(), zod.z.any()).optional()
|
|
16
|
+
});
|
|
17
|
+
const afsEntrySchema = zod.z.object({
|
|
18
|
+
id: zod.z.string(),
|
|
19
|
+
createdAt: zod.z.date().optional(),
|
|
20
|
+
updatedAt: zod.z.date().optional(),
|
|
21
|
+
path: zod.z.string(),
|
|
22
|
+
userId: zod.z.string().nullable().optional(),
|
|
23
|
+
sessionId: zod.z.string().nullable().optional(),
|
|
24
|
+
summary: zod.z.string().nullable().optional(),
|
|
25
|
+
meta: zod.z.record(zod.z.string(), zod.z.any()).nullable().optional(),
|
|
26
|
+
linkTo: zod.z.string().nullable().optional(),
|
|
27
|
+
content: zod.z.any().optional(),
|
|
28
|
+
actions: zod.z.array(actionSummarySchema).optional()
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
//#endregion
|
|
32
|
+
exports.accessModeSchema = accessModeSchema;
|
|
33
|
+
exports.actionSummarySchema = actionSummarySchema;
|
|
34
|
+
exports.afsEntrySchema = afsEntrySchema;
|