@dirxai/core 0.3.0 → 0.3.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,177 @@
1
+ // src/scanner/detect.ts
2
+ import { existsSync, readFileSync } from "fs";
3
+ import { join } from "path";
4
+ var FRAMEWORK_PACKAGES = {
5
+ next: "nextjs",
6
+ hono: "hono",
7
+ fastify: "fastify",
8
+ express: "express",
9
+ "@hono/node-server": "hono",
10
+ koa: "koa"
11
+ };
12
+ function detectFramework(target) {
13
+ if (existsSync(join(target, "Cargo.toml"))) {
14
+ return { lang: "rust", framework: "axum" };
15
+ }
16
+ if (existsSync(join(target, "go.mod"))) {
17
+ return { lang: "go", framework: "net/http" };
18
+ }
19
+ if (existsSync(join(target, "package.json"))) {
20
+ const detected = detectFrameworkFromDeps(target);
21
+ if (detected) return { lang: "node", framework: detected };
22
+ return { lang: "node", framework: "express" };
23
+ }
24
+ if (existsSync(join(target, "requirements.txt")) || existsSync(join(target, "pyproject.toml"))) {
25
+ return { lang: "python", framework: "fastapi" };
26
+ }
27
+ return { lang: "unknown", framework: "generic" };
28
+ }
29
+ function detectFrameworkFromDeps(target) {
30
+ const pkgPath = join(target, "package.json");
31
+ if (!existsSync(pkgPath)) return null;
32
+ try {
33
+ const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
34
+ const deps = {
35
+ ...pkg.dependencies,
36
+ ...pkg.devDependencies
37
+ };
38
+ for (const [pkg2, fw] of Object.entries(FRAMEWORK_PACKAGES)) {
39
+ if (pkg2 in deps) return fw;
40
+ }
41
+ } catch {
42
+ }
43
+ return null;
44
+ }
45
+ function hasDirxSdk(target) {
46
+ const pkgPath = join(target, "package.json");
47
+ if (!existsSync(pkgPath)) return false;
48
+ try {
49
+ const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
50
+ const deps = {
51
+ ...pkg.dependencies,
52
+ ...pkg.devDependencies
53
+ };
54
+ return "@dirxai/core" in deps;
55
+ } catch {
56
+ return false;
57
+ }
58
+ }
59
+
60
+ // src/scanner/routes.ts
61
+ import { readFileSync as readFileSync2, readdirSync, statSync } from "fs";
62
+ import { join as join2, relative, extname } from "path";
63
+ var MAX_SCAN_DEPTH = 8;
64
+ var SKIP_DIRS = /* @__PURE__ */ new Set([
65
+ "node_modules",
66
+ ".git",
67
+ "target",
68
+ "__pycache__",
69
+ "vendor",
70
+ "dist",
71
+ "build",
72
+ ".next"
73
+ ]);
74
+ var SCAN_EXTENSIONS = /* @__PURE__ */ new Set([
75
+ ".ts",
76
+ ".tsx",
77
+ ".js",
78
+ ".jsx",
79
+ ".py",
80
+ ".go",
81
+ ".rs"
82
+ ]);
83
+ function getRoutePatterns(framework) {
84
+ switch (framework) {
85
+ case "express":
86
+ case "hono":
87
+ case "fastify":
88
+ case "koa":
89
+ return [".get(", ".post(", ".put(", ".delete(", ".patch(", "router."];
90
+ case "nextjs":
91
+ return ["export default", "export async function"];
92
+ case "fastapi":
93
+ return ["@app.get", "@app.post", "@app.put", "@app.delete", "@router."];
94
+ case "go":
95
+ case "net/http":
96
+ return ["HandleFunc(", "Get(", "Post(", "Put(", "Delete(", "r.Route("];
97
+ case "axum":
98
+ return [".route(", ".get(", ".post(", ".put(", ".delete("];
99
+ default:
100
+ return [];
101
+ }
102
+ }
103
+ function extractRoutesRegex(content) {
104
+ const regex = /\.\s*(get|post|put|patch|delete)\s*\(\s*["'`](\/[^"'`]*)["'`]/gi;
105
+ const results = [];
106
+ let match;
107
+ while ((match = regex.exec(content)) !== null) {
108
+ results.push({
109
+ method: match[1].toUpperCase(),
110
+ path: match[2]
111
+ });
112
+ }
113
+ return results;
114
+ }
115
+ function scanRoutes(root, framework) {
116
+ const patterns = getRoutePatterns(framework);
117
+ if (patterns.length === 0) return [];
118
+ const routes = [];
119
+ walkDir(root, root, patterns, framework, routes, 0);
120
+ return routes;
121
+ }
122
+ function walkDir(root, dir, patterns, framework, routes, depth) {
123
+ if (depth > MAX_SCAN_DEPTH) return;
124
+ let entries;
125
+ try {
126
+ entries = readdirSync(dir);
127
+ } catch {
128
+ return;
129
+ }
130
+ for (const name of entries) {
131
+ if (SKIP_DIRS.has(name)) continue;
132
+ const fullPath = join2(dir, name);
133
+ let stat;
134
+ try {
135
+ stat = statSync(fullPath);
136
+ } catch {
137
+ continue;
138
+ }
139
+ if (stat.isDirectory()) {
140
+ walkDir(root, fullPath, patterns, framework, routes, depth + 1);
141
+ continue;
142
+ }
143
+ if (!stat.isFile()) continue;
144
+ if (!SCAN_EXTENSIONS.has(extname(name))) continue;
145
+ try {
146
+ const content = readFileSync2(fullPath, "utf-8");
147
+ if (patterns.some((p) => content.includes(p))) {
148
+ routes.push({
149
+ file: relative(root, fullPath),
150
+ framework
151
+ });
152
+ }
153
+ } catch {
154
+ }
155
+ }
156
+ }
157
+
158
+ // src/scanner/schema.ts
159
+ function extractPrismaModelNames(content) {
160
+ const models = [];
161
+ const regex = /model\s+(\w+)\s*\{/g;
162
+ let match;
163
+ while ((match = regex.exec(content)) !== null) {
164
+ models.push(match[1]);
165
+ }
166
+ return models;
167
+ }
168
+
169
+ export {
170
+ detectFramework,
171
+ detectFrameworkFromDeps,
172
+ hasDirxSdk,
173
+ getRoutePatterns,
174
+ extractRoutesRegex,
175
+ scanRoutes,
176
+ extractPrismaModelNames
177
+ };
@@ -0,0 +1,30 @@
1
+ // src/types.ts
2
+ var KNOWN_PROVIDERS = {
3
+ "api.github.com": {
4
+ envVar: "GITHUB_TOKEN",
5
+ guideUrl: "https://github.com/settings/tokens"
6
+ },
7
+ "api.openai.com": {
8
+ envVar: "OPENAI_API_KEY",
9
+ guideUrl: "https://platform.openai.com/api-keys"
10
+ },
11
+ "api.anthropic.com": {
12
+ envVar: "ANTHROPIC_API_KEY",
13
+ guideUrl: "https://console.anthropic.com/settings/keys"
14
+ },
15
+ "generativelanguage.googleapis.com": {
16
+ envVar: "GOOGLE_API_KEY",
17
+ guideUrl: "https://aistudio.google.com/apikey"
18
+ },
19
+ "api.stripe.com": {
20
+ envVar: "STRIPE_SECRET_KEY",
21
+ guideUrl: "https://dashboard.stripe.com/apikeys"
22
+ }
23
+ };
24
+ function getAuthHint(domain) {
25
+ return KNOWN_PROVIDERS[domain] ?? null;
26
+ }
27
+
28
+ export {
29
+ getAuthHint
30
+ };
package/dist/index.cjs CHANGED
@@ -25,10 +25,215 @@ __export(index_exports, {
25
25
  DirxErrorCode: () => DirxErrorCode,
26
26
  Guard: () => Guard,
27
27
  JwksClient: () => JwksClient,
28
- createGuard: () => createGuard
28
+ createGuard: () => createGuard,
29
+ detectFramework: () => detectFramework,
30
+ detectFrameworkFromDeps: () => detectFrameworkFromDeps,
31
+ extractPrismaModelNames: () => extractPrismaModelNames,
32
+ extractRoutesRegex: () => extractRoutesRegex,
33
+ generateDirJson: () => generateDirJson,
34
+ generateDirMd: () => generateDirMd,
35
+ getAuthHint: () => getAuthHint,
36
+ getRoutePatterns: () => getRoutePatterns,
37
+ hasDirxSdk: () => hasDirxSdk,
38
+ scanRoutes: () => scanRoutes
29
39
  });
30
40
  module.exports = __toCommonJS(index_exports);
31
41
 
42
+ // src/scanner/detect.ts
43
+ var import_node_fs = require("fs");
44
+ var import_node_path = require("path");
45
+ var FRAMEWORK_PACKAGES = {
46
+ next: "nextjs",
47
+ hono: "hono",
48
+ fastify: "fastify",
49
+ express: "express",
50
+ "@hono/node-server": "hono",
51
+ koa: "koa"
52
+ };
53
+ function detectFramework(target) {
54
+ if ((0, import_node_fs.existsSync)((0, import_node_path.join)(target, "Cargo.toml"))) {
55
+ return { lang: "rust", framework: "axum" };
56
+ }
57
+ if ((0, import_node_fs.existsSync)((0, import_node_path.join)(target, "go.mod"))) {
58
+ return { lang: "go", framework: "net/http" };
59
+ }
60
+ if ((0, import_node_fs.existsSync)((0, import_node_path.join)(target, "package.json"))) {
61
+ const detected = detectFrameworkFromDeps(target);
62
+ if (detected) return { lang: "node", framework: detected };
63
+ return { lang: "node", framework: "express" };
64
+ }
65
+ if ((0, import_node_fs.existsSync)((0, import_node_path.join)(target, "requirements.txt")) || (0, import_node_fs.existsSync)((0, import_node_path.join)(target, "pyproject.toml"))) {
66
+ return { lang: "python", framework: "fastapi" };
67
+ }
68
+ return { lang: "unknown", framework: "generic" };
69
+ }
70
+ function detectFrameworkFromDeps(target) {
71
+ const pkgPath = (0, import_node_path.join)(target, "package.json");
72
+ if (!(0, import_node_fs.existsSync)(pkgPath)) return null;
73
+ try {
74
+ const pkg = JSON.parse((0, import_node_fs.readFileSync)(pkgPath, "utf-8"));
75
+ const deps = {
76
+ ...pkg.dependencies,
77
+ ...pkg.devDependencies
78
+ };
79
+ for (const [pkg2, fw] of Object.entries(FRAMEWORK_PACKAGES)) {
80
+ if (pkg2 in deps) return fw;
81
+ }
82
+ } catch {
83
+ }
84
+ return null;
85
+ }
86
+ function hasDirxSdk(target) {
87
+ const pkgPath = (0, import_node_path.join)(target, "package.json");
88
+ if (!(0, import_node_fs.existsSync)(pkgPath)) return false;
89
+ try {
90
+ const pkg = JSON.parse((0, import_node_fs.readFileSync)(pkgPath, "utf-8"));
91
+ const deps = {
92
+ ...pkg.dependencies,
93
+ ...pkg.devDependencies
94
+ };
95
+ return "@dirxai/core" in deps;
96
+ } catch {
97
+ return false;
98
+ }
99
+ }
100
+
101
+ // src/scanner/routes.ts
102
+ var import_node_fs2 = require("fs");
103
+ var import_node_path2 = require("path");
104
+ var MAX_SCAN_DEPTH = 8;
105
+ var SKIP_DIRS = /* @__PURE__ */ new Set([
106
+ "node_modules",
107
+ ".git",
108
+ "target",
109
+ "__pycache__",
110
+ "vendor",
111
+ "dist",
112
+ "build",
113
+ ".next"
114
+ ]);
115
+ var SCAN_EXTENSIONS = /* @__PURE__ */ new Set([
116
+ ".ts",
117
+ ".tsx",
118
+ ".js",
119
+ ".jsx",
120
+ ".py",
121
+ ".go",
122
+ ".rs"
123
+ ]);
124
+ function getRoutePatterns(framework) {
125
+ switch (framework) {
126
+ case "express":
127
+ case "hono":
128
+ case "fastify":
129
+ case "koa":
130
+ return [".get(", ".post(", ".put(", ".delete(", ".patch(", "router."];
131
+ case "nextjs":
132
+ return ["export default", "export async function"];
133
+ case "fastapi":
134
+ return ["@app.get", "@app.post", "@app.put", "@app.delete", "@router."];
135
+ case "go":
136
+ case "net/http":
137
+ return ["HandleFunc(", "Get(", "Post(", "Put(", "Delete(", "r.Route("];
138
+ case "axum":
139
+ return [".route(", ".get(", ".post(", ".put(", ".delete("];
140
+ default:
141
+ return [];
142
+ }
143
+ }
144
+ function extractRoutesRegex(content) {
145
+ const regex = /\.\s*(get|post|put|patch|delete)\s*\(\s*["'`](\/[^"'`]*)["'`]/gi;
146
+ const results = [];
147
+ let match;
148
+ while ((match = regex.exec(content)) !== null) {
149
+ results.push({
150
+ method: match[1].toUpperCase(),
151
+ path: match[2]
152
+ });
153
+ }
154
+ return results;
155
+ }
156
+ function scanRoutes(root, framework) {
157
+ const patterns = getRoutePatterns(framework);
158
+ if (patterns.length === 0) return [];
159
+ const routes = [];
160
+ walkDir(root, root, patterns, framework, routes, 0);
161
+ return routes;
162
+ }
163
+ function walkDir(root, dir, patterns, framework, routes, depth) {
164
+ if (depth > MAX_SCAN_DEPTH) return;
165
+ let entries;
166
+ try {
167
+ entries = (0, import_node_fs2.readdirSync)(dir);
168
+ } catch {
169
+ return;
170
+ }
171
+ for (const name of entries) {
172
+ if (SKIP_DIRS.has(name)) continue;
173
+ const fullPath = (0, import_node_path2.join)(dir, name);
174
+ let stat;
175
+ try {
176
+ stat = (0, import_node_fs2.statSync)(fullPath);
177
+ } catch {
178
+ continue;
179
+ }
180
+ if (stat.isDirectory()) {
181
+ walkDir(root, fullPath, patterns, framework, routes, depth + 1);
182
+ continue;
183
+ }
184
+ if (!stat.isFile()) continue;
185
+ if (!SCAN_EXTENSIONS.has((0, import_node_path2.extname)(name))) continue;
186
+ try {
187
+ const content = (0, import_node_fs2.readFileSync)(fullPath, "utf-8");
188
+ if (patterns.some((p) => content.includes(p))) {
189
+ routes.push({
190
+ file: (0, import_node_path2.relative)(root, fullPath),
191
+ framework
192
+ });
193
+ }
194
+ } catch {
195
+ }
196
+ }
197
+ }
198
+
199
+ // src/scanner/schema.ts
200
+ function extractPrismaModelNames(content) {
201
+ const models = [];
202
+ const regex = /model\s+(\w+)\s*\{/g;
203
+ let match;
204
+ while ((match = regex.exec(content)) !== null) {
205
+ models.push(match[1]);
206
+ }
207
+ return models;
208
+ }
209
+
210
+ // src/types.ts
211
+ var KNOWN_PROVIDERS = {
212
+ "api.github.com": {
213
+ envVar: "GITHUB_TOKEN",
214
+ guideUrl: "https://github.com/settings/tokens"
215
+ },
216
+ "api.openai.com": {
217
+ envVar: "OPENAI_API_KEY",
218
+ guideUrl: "https://platform.openai.com/api-keys"
219
+ },
220
+ "api.anthropic.com": {
221
+ envVar: "ANTHROPIC_API_KEY",
222
+ guideUrl: "https://console.anthropic.com/settings/keys"
223
+ },
224
+ "generativelanguage.googleapis.com": {
225
+ envVar: "GOOGLE_API_KEY",
226
+ guideUrl: "https://aistudio.google.com/apikey"
227
+ },
228
+ "api.stripe.com": {
229
+ envVar: "STRIPE_SECRET_KEY",
230
+ guideUrl: "https://dashboard.stripe.com/apikeys"
231
+ }
232
+ };
233
+ function getAuthHint(domain) {
234
+ return KNOWN_PROVIDERS[domain] ?? null;
235
+ }
236
+
32
237
  // src/auth/jwks.ts
33
238
  var import_jose = require("jose");
34
239
 
@@ -217,6 +422,48 @@ var Guard = class {
217
422
  function createGuard(options) {
218
423
  return new Guard(options);
219
424
  }
425
+
426
+ // src/generator.ts
427
+ function generateDirMd(service, options) {
428
+ const sections = [];
429
+ sections.push(`# ${service.title}`);
430
+ if (service.description) {
431
+ sections.push(service.description);
432
+ }
433
+ if (service.base_url) {
434
+ sections.push(`## Base URL
435
+
436
+ \`${service.base_url}\``);
437
+ }
438
+ if (service.actions.length > 0) {
439
+ sections.push(
440
+ `## Actions
441
+
442
+ ${service.actions.map((a) => `- \`${a}\``).join("\n")}`
443
+ );
444
+ }
445
+ if (service.endpoints.length > 0) {
446
+ const lines = ["## Endpoints", ""];
447
+ lines.push("| Method | Path | Description |");
448
+ lines.push("|--------|------|-------------|");
449
+ for (const ep of service.endpoints) {
450
+ const desc = ep.description ?? "";
451
+ lines.push(`| ${ep.method} | \`${ep.path}\` | ${desc} |`);
452
+ }
453
+ sections.push(lines.join("\n"));
454
+ }
455
+ if (options?.includeTimestamp) {
456
+ sections.push(
457
+ `---
458
+
459
+ *Generated at ${(/* @__PURE__ */ new Date()).toISOString()}*`
460
+ );
461
+ }
462
+ return sections.join("\n\n") + "\n";
463
+ }
464
+ function generateDirJson(service) {
465
+ return JSON.stringify(service, null, 2);
466
+ }
220
467
  // Annotate the CommonJS export names for ESM import in node:
221
468
  0 && (module.exports = {
222
469
  AgentContext,
@@ -224,5 +471,15 @@ function createGuard(options) {
224
471
  DirxErrorCode,
225
472
  Guard,
226
473
  JwksClient,
227
- createGuard
474
+ createGuard,
475
+ detectFramework,
476
+ detectFrameworkFromDeps,
477
+ extractPrismaModelNames,
478
+ extractRoutesRegex,
479
+ generateDirJson,
480
+ generateDirMd,
481
+ getAuthHint,
482
+ getRoutePatterns,
483
+ hasDirxSdk,
484
+ scanRoutes
228
485
  });
package/dist/index.d.cts CHANGED
@@ -1,3 +1,6 @@
1
+ export { DetectedStack, RouteHint, detectFramework, detectFrameworkFromDeps, extractPrismaModelNames, extractRoutesRegex, getRoutePatterns, hasDirxSdk, scanRoutes } from './scanner/index.cjs';
2
+ import { DirxService } from './types.cjs';
3
+ export { ByokAuth, DirxEndpoint, DirxEnvelope, EndpointMatch, ProviderHint, SearchResult, getAuthHint } from './types.cjs';
1
4
  import { J as JwksClientOptions, A as AgentContext } from './context-C7RRNS5U.cjs';
2
5
  export { D as DirxTokenPayload, a as JwksClient } from './context-C7RRNS5U.cjs';
3
6
  import 'jose';
@@ -57,6 +60,24 @@ declare class Guard {
57
60
  }
58
61
  declare function createGuard(options?: GuardOptions): Guard;
59
62
 
63
+ /**
64
+ * DIR.md generator — produces a DirX service description from structured input.
65
+ *
66
+ * Third-party projects can use this to programmatically generate DIR.md files.
67
+ */
68
+
69
+ interface GenerateOptions {
70
+ includeTimestamp?: boolean;
71
+ }
72
+ /**
73
+ * Generate a DIR.md markdown string from a DirxService definition.
74
+ */
75
+ declare function generateDirMd(service: DirxService, options?: GenerateOptions): string;
76
+ /**
77
+ * Generate a dir.json object from a DirxService definition.
78
+ */
79
+ declare function generateDirJson(service: DirxService): string;
80
+
60
81
  /**
61
82
  * DirX error codes and typed error class.
62
83
  *
@@ -87,4 +108,4 @@ declare class DirxError extends Error {
87
108
  };
88
109
  }
89
110
 
90
- export { AgentContext, DirxError, DirxErrorCode, Guard, type GuardOptions, JwksClientOptions, createGuard };
111
+ export { AgentContext, DirxError, DirxErrorCode, DirxService, type GenerateOptions, Guard, type GuardOptions, JwksClientOptions, createGuard, generateDirJson, generateDirMd };
package/dist/index.d.ts CHANGED
@@ -1,3 +1,6 @@
1
+ export { DetectedStack, RouteHint, detectFramework, detectFrameworkFromDeps, extractPrismaModelNames, extractRoutesRegex, getRoutePatterns, hasDirxSdk, scanRoutes } from './scanner/index.js';
2
+ import { DirxService } from './types.js';
3
+ export { ByokAuth, DirxEndpoint, DirxEnvelope, EndpointMatch, ProviderHint, SearchResult, getAuthHint } from './types.js';
1
4
  import { J as JwksClientOptions, A as AgentContext } from './context-C7RRNS5U.js';
2
5
  export { D as DirxTokenPayload, a as JwksClient } from './context-C7RRNS5U.js';
3
6
  import 'jose';
@@ -57,6 +60,24 @@ declare class Guard {
57
60
  }
58
61
  declare function createGuard(options?: GuardOptions): Guard;
59
62
 
63
+ /**
64
+ * DIR.md generator — produces a DirX service description from structured input.
65
+ *
66
+ * Third-party projects can use this to programmatically generate DIR.md files.
67
+ */
68
+
69
+ interface GenerateOptions {
70
+ includeTimestamp?: boolean;
71
+ }
72
+ /**
73
+ * Generate a DIR.md markdown string from a DirxService definition.
74
+ */
75
+ declare function generateDirMd(service: DirxService, options?: GenerateOptions): string;
76
+ /**
77
+ * Generate a dir.json object from a DirxService definition.
78
+ */
79
+ declare function generateDirJson(service: DirxService): string;
80
+
60
81
  /**
61
82
  * DirX error codes and typed error class.
62
83
  *
@@ -87,4 +108,4 @@ declare class DirxError extends Error {
87
108
  };
88
109
  }
89
110
 
90
- export { AgentContext, DirxError, DirxErrorCode, Guard, type GuardOptions, JwksClientOptions, createGuard };
111
+ export { AgentContext, DirxError, DirxErrorCode, DirxService, type GenerateOptions, Guard, type GuardOptions, JwksClientOptions, createGuard, generateDirJson, generateDirMd };
package/dist/index.js CHANGED
@@ -1,6 +1,18 @@
1
1
  import {
2
2
  AgentContext
3
3
  } from "./chunk-5BEMU43U.js";
4
+ import {
5
+ getAuthHint
6
+ } from "./chunk-VTJP4C2Q.js";
7
+ import {
8
+ detectFramework,
9
+ detectFrameworkFromDeps,
10
+ extractPrismaModelNames,
11
+ extractRoutesRegex,
12
+ getRoutePatterns,
13
+ hasDirxSdk,
14
+ scanRoutes
15
+ } from "./chunk-AMKKT77F.js";
4
16
 
5
17
  // src/auth/jwks.ts
6
18
  import { createRemoteJWKSet, jwtVerify } from "jose";
@@ -159,11 +171,63 @@ var Guard = class {
159
171
  function createGuard(options) {
160
172
  return new Guard(options);
161
173
  }
174
+
175
+ // src/generator.ts
176
+ function generateDirMd(service, options) {
177
+ const sections = [];
178
+ sections.push(`# ${service.title}`);
179
+ if (service.description) {
180
+ sections.push(service.description);
181
+ }
182
+ if (service.base_url) {
183
+ sections.push(`## Base URL
184
+
185
+ \`${service.base_url}\``);
186
+ }
187
+ if (service.actions.length > 0) {
188
+ sections.push(
189
+ `## Actions
190
+
191
+ ${service.actions.map((a) => `- \`${a}\``).join("\n")}`
192
+ );
193
+ }
194
+ if (service.endpoints.length > 0) {
195
+ const lines = ["## Endpoints", ""];
196
+ lines.push("| Method | Path | Description |");
197
+ lines.push("|--------|------|-------------|");
198
+ for (const ep of service.endpoints) {
199
+ const desc = ep.description ?? "";
200
+ lines.push(`| ${ep.method} | \`${ep.path}\` | ${desc} |`);
201
+ }
202
+ sections.push(lines.join("\n"));
203
+ }
204
+ if (options?.includeTimestamp) {
205
+ sections.push(
206
+ `---
207
+
208
+ *Generated at ${(/* @__PURE__ */ new Date()).toISOString()}*`
209
+ );
210
+ }
211
+ return sections.join("\n\n") + "\n";
212
+ }
213
+ function generateDirJson(service) {
214
+ return JSON.stringify(service, null, 2);
215
+ }
162
216
  export {
163
217
  AgentContext,
164
218
  DirxError,
165
219
  DirxErrorCode,
166
220
  Guard,
167
221
  JwksClient,
168
- createGuard
222
+ createGuard,
223
+ detectFramework,
224
+ detectFrameworkFromDeps,
225
+ extractPrismaModelNames,
226
+ extractRoutesRegex,
227
+ generateDirJson,
228
+ generateDirMd,
229
+ getAuthHint,
230
+ getRoutePatterns,
231
+ hasDirxSdk,
232
+ scanRoutes
169
233
  };
@@ -0,0 +1,209 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/scanner/index.ts
21
+ var scanner_exports = {};
22
+ __export(scanner_exports, {
23
+ detectFramework: () => detectFramework,
24
+ detectFrameworkFromDeps: () => detectFrameworkFromDeps,
25
+ extractPrismaModelNames: () => extractPrismaModelNames,
26
+ extractRoutesRegex: () => extractRoutesRegex,
27
+ getRoutePatterns: () => getRoutePatterns,
28
+ hasDirxSdk: () => hasDirxSdk,
29
+ scanRoutes: () => scanRoutes
30
+ });
31
+ module.exports = __toCommonJS(scanner_exports);
32
+
33
+ // src/scanner/detect.ts
34
+ var import_node_fs = require("fs");
35
+ var import_node_path = require("path");
36
+ var FRAMEWORK_PACKAGES = {
37
+ next: "nextjs",
38
+ hono: "hono",
39
+ fastify: "fastify",
40
+ express: "express",
41
+ "@hono/node-server": "hono",
42
+ koa: "koa"
43
+ };
44
+ function detectFramework(target) {
45
+ if ((0, import_node_fs.existsSync)((0, import_node_path.join)(target, "Cargo.toml"))) {
46
+ return { lang: "rust", framework: "axum" };
47
+ }
48
+ if ((0, import_node_fs.existsSync)((0, import_node_path.join)(target, "go.mod"))) {
49
+ return { lang: "go", framework: "net/http" };
50
+ }
51
+ if ((0, import_node_fs.existsSync)((0, import_node_path.join)(target, "package.json"))) {
52
+ const detected = detectFrameworkFromDeps(target);
53
+ if (detected) return { lang: "node", framework: detected };
54
+ return { lang: "node", framework: "express" };
55
+ }
56
+ if ((0, import_node_fs.existsSync)((0, import_node_path.join)(target, "requirements.txt")) || (0, import_node_fs.existsSync)((0, import_node_path.join)(target, "pyproject.toml"))) {
57
+ return { lang: "python", framework: "fastapi" };
58
+ }
59
+ return { lang: "unknown", framework: "generic" };
60
+ }
61
+ function detectFrameworkFromDeps(target) {
62
+ const pkgPath = (0, import_node_path.join)(target, "package.json");
63
+ if (!(0, import_node_fs.existsSync)(pkgPath)) return null;
64
+ try {
65
+ const pkg = JSON.parse((0, import_node_fs.readFileSync)(pkgPath, "utf-8"));
66
+ const deps = {
67
+ ...pkg.dependencies,
68
+ ...pkg.devDependencies
69
+ };
70
+ for (const [pkg2, fw] of Object.entries(FRAMEWORK_PACKAGES)) {
71
+ if (pkg2 in deps) return fw;
72
+ }
73
+ } catch {
74
+ }
75
+ return null;
76
+ }
77
+ function hasDirxSdk(target) {
78
+ const pkgPath = (0, import_node_path.join)(target, "package.json");
79
+ if (!(0, import_node_fs.existsSync)(pkgPath)) return false;
80
+ try {
81
+ const pkg = JSON.parse((0, import_node_fs.readFileSync)(pkgPath, "utf-8"));
82
+ const deps = {
83
+ ...pkg.dependencies,
84
+ ...pkg.devDependencies
85
+ };
86
+ return "@dirxai/core" in deps;
87
+ } catch {
88
+ return false;
89
+ }
90
+ }
91
+
92
+ // src/scanner/routes.ts
93
+ var import_node_fs2 = require("fs");
94
+ var import_node_path2 = require("path");
95
+ var MAX_SCAN_DEPTH = 8;
96
+ var SKIP_DIRS = /* @__PURE__ */ new Set([
97
+ "node_modules",
98
+ ".git",
99
+ "target",
100
+ "__pycache__",
101
+ "vendor",
102
+ "dist",
103
+ "build",
104
+ ".next"
105
+ ]);
106
+ var SCAN_EXTENSIONS = /* @__PURE__ */ new Set([
107
+ ".ts",
108
+ ".tsx",
109
+ ".js",
110
+ ".jsx",
111
+ ".py",
112
+ ".go",
113
+ ".rs"
114
+ ]);
115
+ function getRoutePatterns(framework) {
116
+ switch (framework) {
117
+ case "express":
118
+ case "hono":
119
+ case "fastify":
120
+ case "koa":
121
+ return [".get(", ".post(", ".put(", ".delete(", ".patch(", "router."];
122
+ case "nextjs":
123
+ return ["export default", "export async function"];
124
+ case "fastapi":
125
+ return ["@app.get", "@app.post", "@app.put", "@app.delete", "@router."];
126
+ case "go":
127
+ case "net/http":
128
+ return ["HandleFunc(", "Get(", "Post(", "Put(", "Delete(", "r.Route("];
129
+ case "axum":
130
+ return [".route(", ".get(", ".post(", ".put(", ".delete("];
131
+ default:
132
+ return [];
133
+ }
134
+ }
135
+ function extractRoutesRegex(content) {
136
+ const regex = /\.\s*(get|post|put|patch|delete)\s*\(\s*["'`](\/[^"'`]*)["'`]/gi;
137
+ const results = [];
138
+ let match;
139
+ while ((match = regex.exec(content)) !== null) {
140
+ results.push({
141
+ method: match[1].toUpperCase(),
142
+ path: match[2]
143
+ });
144
+ }
145
+ return results;
146
+ }
147
+ function scanRoutes(root, framework) {
148
+ const patterns = getRoutePatterns(framework);
149
+ if (patterns.length === 0) return [];
150
+ const routes = [];
151
+ walkDir(root, root, patterns, framework, routes, 0);
152
+ return routes;
153
+ }
154
+ function walkDir(root, dir, patterns, framework, routes, depth) {
155
+ if (depth > MAX_SCAN_DEPTH) return;
156
+ let entries;
157
+ try {
158
+ entries = (0, import_node_fs2.readdirSync)(dir);
159
+ } catch {
160
+ return;
161
+ }
162
+ for (const name of entries) {
163
+ if (SKIP_DIRS.has(name)) continue;
164
+ const fullPath = (0, import_node_path2.join)(dir, name);
165
+ let stat;
166
+ try {
167
+ stat = (0, import_node_fs2.statSync)(fullPath);
168
+ } catch {
169
+ continue;
170
+ }
171
+ if (stat.isDirectory()) {
172
+ walkDir(root, fullPath, patterns, framework, routes, depth + 1);
173
+ continue;
174
+ }
175
+ if (!stat.isFile()) continue;
176
+ if (!SCAN_EXTENSIONS.has((0, import_node_path2.extname)(name))) continue;
177
+ try {
178
+ const content = (0, import_node_fs2.readFileSync)(fullPath, "utf-8");
179
+ if (patterns.some((p) => content.includes(p))) {
180
+ routes.push({
181
+ file: (0, import_node_path2.relative)(root, fullPath),
182
+ framework
183
+ });
184
+ }
185
+ } catch {
186
+ }
187
+ }
188
+ }
189
+
190
+ // src/scanner/schema.ts
191
+ function extractPrismaModelNames(content) {
192
+ const models = [];
193
+ const regex = /model\s+(\w+)\s*\{/g;
194
+ let match;
195
+ while ((match = regex.exec(content)) !== null) {
196
+ models.push(match[1]);
197
+ }
198
+ return models;
199
+ }
200
+ // Annotate the CommonJS export names for ESM import in node:
201
+ 0 && (module.exports = {
202
+ detectFramework,
203
+ detectFrameworkFromDeps,
204
+ extractPrismaModelNames,
205
+ extractRoutesRegex,
206
+ getRoutePatterns,
207
+ hasDirxSdk,
208
+ scanRoutes
209
+ });
@@ -0,0 +1,60 @@
1
+ /**
2
+ * Framework detection from project files and dependencies.
3
+ *
4
+ * Detects language and framework by inspecting dependency manifests
5
+ * (package.json, go.mod, Cargo.toml, requirements.txt, pyproject.toml).
6
+ */
7
+ interface DetectedStack {
8
+ lang: string;
9
+ framework: string;
10
+ }
11
+ /**
12
+ * Detect framework from a project directory by inspecting manifest files.
13
+ */
14
+ declare function detectFramework(target: string): DetectedStack;
15
+ /**
16
+ * Detect framework from package.json dependencies.
17
+ * Returns null if no known framework is found.
18
+ */
19
+ declare function detectFrameworkFromDeps(target: string): string | null;
20
+ /**
21
+ * Check if a project has @dirxai/core in its dependencies.
22
+ */
23
+ declare function hasDirxSdk(target: string): boolean;
24
+
25
+ /**
26
+ * Route extraction from source code.
27
+ *
28
+ * Uses pattern matching to detect route definitions across
29
+ * multiple frameworks (Express, Hono, Fastify, Next.js, FastAPI, Go, Axum).
30
+ */
31
+ interface RouteHint {
32
+ file: string;
33
+ framework: string;
34
+ }
35
+ /**
36
+ * Get route detection patterns for a given framework.
37
+ */
38
+ declare function getRoutePatterns(framework: string): string[];
39
+ /**
40
+ * Extract routes from source code using regex.
41
+ * Returns method + path pairs found in the content.
42
+ */
43
+ declare function extractRoutesRegex(content: string): {
44
+ method: string;
45
+ path: string;
46
+ }[];
47
+ /**
48
+ * Scan a directory tree for files containing route definitions.
49
+ */
50
+ declare function scanRoutes(root: string, framework: string): RouteHint[];
51
+
52
+ /**
53
+ * Schema extraction from Prisma and other ORM definitions.
54
+ */
55
+ /**
56
+ * Extract model names from a Prisma schema file content.
57
+ */
58
+ declare function extractPrismaModelNames(content: string): string[];
59
+
60
+ export { type DetectedStack, type RouteHint, detectFramework, detectFrameworkFromDeps, extractPrismaModelNames, extractRoutesRegex, getRoutePatterns, hasDirxSdk, scanRoutes };
@@ -0,0 +1,60 @@
1
+ /**
2
+ * Framework detection from project files and dependencies.
3
+ *
4
+ * Detects language and framework by inspecting dependency manifests
5
+ * (package.json, go.mod, Cargo.toml, requirements.txt, pyproject.toml).
6
+ */
7
+ interface DetectedStack {
8
+ lang: string;
9
+ framework: string;
10
+ }
11
+ /**
12
+ * Detect framework from a project directory by inspecting manifest files.
13
+ */
14
+ declare function detectFramework(target: string): DetectedStack;
15
+ /**
16
+ * Detect framework from package.json dependencies.
17
+ * Returns null if no known framework is found.
18
+ */
19
+ declare function detectFrameworkFromDeps(target: string): string | null;
20
+ /**
21
+ * Check if a project has @dirxai/core in its dependencies.
22
+ */
23
+ declare function hasDirxSdk(target: string): boolean;
24
+
25
+ /**
26
+ * Route extraction from source code.
27
+ *
28
+ * Uses pattern matching to detect route definitions across
29
+ * multiple frameworks (Express, Hono, Fastify, Next.js, FastAPI, Go, Axum).
30
+ */
31
+ interface RouteHint {
32
+ file: string;
33
+ framework: string;
34
+ }
35
+ /**
36
+ * Get route detection patterns for a given framework.
37
+ */
38
+ declare function getRoutePatterns(framework: string): string[];
39
+ /**
40
+ * Extract routes from source code using regex.
41
+ * Returns method + path pairs found in the content.
42
+ */
43
+ declare function extractRoutesRegex(content: string): {
44
+ method: string;
45
+ path: string;
46
+ }[];
47
+ /**
48
+ * Scan a directory tree for files containing route definitions.
49
+ */
50
+ declare function scanRoutes(root: string, framework: string): RouteHint[];
51
+
52
+ /**
53
+ * Schema extraction from Prisma and other ORM definitions.
54
+ */
55
+ /**
56
+ * Extract model names from a Prisma schema file content.
57
+ */
58
+ declare function extractPrismaModelNames(content: string): string[];
59
+
60
+ export { type DetectedStack, type RouteHint, detectFramework, detectFrameworkFromDeps, extractPrismaModelNames, extractRoutesRegex, getRoutePatterns, hasDirxSdk, scanRoutes };
@@ -0,0 +1,18 @@
1
+ import {
2
+ detectFramework,
3
+ detectFrameworkFromDeps,
4
+ extractPrismaModelNames,
5
+ extractRoutesRegex,
6
+ getRoutePatterns,
7
+ hasDirxSdk,
8
+ scanRoutes
9
+ } from "../chunk-AMKKT77F.js";
10
+ export {
11
+ detectFramework,
12
+ detectFrameworkFromDeps,
13
+ extractPrismaModelNames,
14
+ extractRoutesRegex,
15
+ getRoutePatterns,
16
+ hasDirxSdk,
17
+ scanRoutes
18
+ };
package/dist/types.cjs ADDED
@@ -0,0 +1,54 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/types.ts
21
+ var types_exports = {};
22
+ __export(types_exports, {
23
+ getAuthHint: () => getAuthHint
24
+ });
25
+ module.exports = __toCommonJS(types_exports);
26
+ var KNOWN_PROVIDERS = {
27
+ "api.github.com": {
28
+ envVar: "GITHUB_TOKEN",
29
+ guideUrl: "https://github.com/settings/tokens"
30
+ },
31
+ "api.openai.com": {
32
+ envVar: "OPENAI_API_KEY",
33
+ guideUrl: "https://platform.openai.com/api-keys"
34
+ },
35
+ "api.anthropic.com": {
36
+ envVar: "ANTHROPIC_API_KEY",
37
+ guideUrl: "https://console.anthropic.com/settings/keys"
38
+ },
39
+ "generativelanguage.googleapis.com": {
40
+ envVar: "GOOGLE_API_KEY",
41
+ guideUrl: "https://aistudio.google.com/apikey"
42
+ },
43
+ "api.stripe.com": {
44
+ envVar: "STRIPE_SECRET_KEY",
45
+ guideUrl: "https://dashboard.stripe.com/apikeys"
46
+ }
47
+ };
48
+ function getAuthHint(domain) {
49
+ return KNOWN_PROVIDERS[domain] ?? null;
50
+ }
51
+ // Annotate the CommonJS export names for ESM import in node:
52
+ 0 && (module.exports = {
53
+ getAuthHint
54
+ });
@@ -0,0 +1,56 @@
1
+ /**
2
+ * Shared DirX types for CLI, SDK, and server interop.
3
+ *
4
+ * DirxEnvelope is the canonical response wrapper used by the gateway.
5
+ * All other types define the domain model for DirX services.
6
+ */
7
+ interface DirxEnvelope<T = unknown> {
8
+ ok: boolean;
9
+ data?: T;
10
+ error?: string | {
11
+ code: string;
12
+ message: string;
13
+ };
14
+ meta?: Record<string, unknown>;
15
+ }
16
+ interface DirxEndpoint {
17
+ path: string;
18
+ method: string;
19
+ description?: string;
20
+ }
21
+ interface DirxService {
22
+ title: string;
23
+ description?: string;
24
+ base_url: string;
25
+ actions: string[];
26
+ endpoints: DirxEndpoint[];
27
+ }
28
+ interface SearchResult {
29
+ domain: string;
30
+ title: string;
31
+ description?: string;
32
+ path?: string;
33
+ score?: number;
34
+ matched_endpoints?: EndpointMatch[];
35
+ }
36
+ interface EndpointMatch {
37
+ method: string;
38
+ path: string;
39
+ description?: string;
40
+ }
41
+ interface ByokAuth {
42
+ type: string;
43
+ token?: string;
44
+ header?: string;
45
+ key?: string;
46
+ }
47
+ interface ProviderHint {
48
+ envVar?: string;
49
+ guideUrl: string;
50
+ }
51
+ /**
52
+ * Get authentication hint for a known provider domain.
53
+ */
54
+ declare function getAuthHint(domain: string): ProviderHint | null;
55
+
56
+ export { type ByokAuth, type DirxEndpoint, type DirxEnvelope, type DirxService, type EndpointMatch, type ProviderHint, type SearchResult, getAuthHint };
@@ -0,0 +1,56 @@
1
+ /**
2
+ * Shared DirX types for CLI, SDK, and server interop.
3
+ *
4
+ * DirxEnvelope is the canonical response wrapper used by the gateway.
5
+ * All other types define the domain model for DirX services.
6
+ */
7
+ interface DirxEnvelope<T = unknown> {
8
+ ok: boolean;
9
+ data?: T;
10
+ error?: string | {
11
+ code: string;
12
+ message: string;
13
+ };
14
+ meta?: Record<string, unknown>;
15
+ }
16
+ interface DirxEndpoint {
17
+ path: string;
18
+ method: string;
19
+ description?: string;
20
+ }
21
+ interface DirxService {
22
+ title: string;
23
+ description?: string;
24
+ base_url: string;
25
+ actions: string[];
26
+ endpoints: DirxEndpoint[];
27
+ }
28
+ interface SearchResult {
29
+ domain: string;
30
+ title: string;
31
+ description?: string;
32
+ path?: string;
33
+ score?: number;
34
+ matched_endpoints?: EndpointMatch[];
35
+ }
36
+ interface EndpointMatch {
37
+ method: string;
38
+ path: string;
39
+ description?: string;
40
+ }
41
+ interface ByokAuth {
42
+ type: string;
43
+ token?: string;
44
+ header?: string;
45
+ key?: string;
46
+ }
47
+ interface ProviderHint {
48
+ envVar?: string;
49
+ guideUrl: string;
50
+ }
51
+ /**
52
+ * Get authentication hint for a known provider domain.
53
+ */
54
+ declare function getAuthHint(domain: string): ProviderHint | null;
55
+
56
+ export { type ByokAuth, type DirxEndpoint, type DirxEnvelope, type DirxService, type EndpointMatch, type ProviderHint, type SearchResult, getAuthHint };
package/dist/types.js ADDED
@@ -0,0 +1,6 @@
1
+ import {
2
+ getAuthHint
3
+ } from "./chunk-VTJP4C2Q.js";
4
+ export {
5
+ getAuthHint
6
+ };
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@dirxai/core",
3
- "version": "0.3.0",
4
- "description": "DirX server-side SDK — Guard middleware, JWKS auth, AgentContext, error codes",
3
+ "version": "0.3.2",
4
+ "description": "DirX SDK — scanner, types, Guard middleware, JWKS auth, error model",
5
5
  "license": "MIT",
6
6
  "type": "module",
7
7
  "main": "./dist/index.cjs",
@@ -17,6 +17,16 @@
17
17
  "types": "./dist/testing.d.ts",
18
18
  "import": "./dist/testing.js",
19
19
  "require": "./dist/testing.cjs"
20
+ },
21
+ "./scanner": {
22
+ "types": "./dist/scanner/index.d.ts",
23
+ "import": "./dist/scanner/index.js",
24
+ "require": "./dist/scanner/index.cjs"
25
+ },
26
+ "./types": {
27
+ "types": "./dist/types.d.ts",
28
+ "import": "./dist/types.js",
29
+ "require": "./dist/types.cjs"
20
30
  }
21
31
  },
22
32
  "scripts": {
@@ -36,6 +46,7 @@
36
46
  "dirx",
37
47
  "agent",
38
48
  "sdk",
49
+ "scanner",
39
50
  "gateway",
40
51
  "guard",
41
52
  "jwks",