fridayy 1.2.0 → 1.3.0
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/README.md +61 -3
- package/dist/adapters/laravel/adapter.d.ts +21 -0
- package/dist/adapters/laravel/adapter.d.ts.map +1 -0
- package/dist/adapters/laravel/adapter.js +133 -0
- package/dist/adapters/laravel/adapter.js.map +1 -0
- package/dist/adapters/laravel/route-scanner.d.ts +39 -0
- package/dist/adapters/laravel/route-scanner.d.ts.map +1 -0
- package/dist/adapters/laravel/route-scanner.js +238 -0
- package/dist/adapters/laravel/route-scanner.js.map +1 -0
- package/dist/adapters/nodejs/ast-scanner.d.ts +5 -3
- package/dist/adapters/nodejs/ast-scanner.d.ts.map +1 -1
- package/dist/adapters/nodejs/ast-scanner.js +104 -29
- package/dist/adapters/nodejs/ast-scanner.js.map +1 -1
- package/dist/adapters/registry.d.ts.map +1 -1
- package/dist/adapters/registry.js +2 -0
- package/dist/adapters/registry.js.map +1 -1
- package/dist/adapters/rest/adapter.d.ts +1 -0
- package/dist/adapters/rest/adapter.d.ts.map +1 -1
- package/dist/adapters/rest/adapter.js +124 -2
- package/dist/adapters/rest/adapter.js.map +1 -1
- package/dist/adapters/rest/executor.d.ts.map +1 -1
- package/dist/adapters/rest/executor.js +1 -2
- package/dist/adapters/rest/executor.js.map +1 -1
- package/dist/cli/commands/config.d.ts.map +1 -1
- package/dist/cli/commands/config.js +27 -3
- package/dist/cli/commands/config.js.map +1 -1
- package/dist/cli/commands/doctor.d.ts.map +1 -1
- package/dist/cli/commands/doctor.js +105 -4
- package/dist/cli/commands/doctor.js.map +1 -1
- package/dist/cli/commands/generate.d.ts.map +1 -1
- package/dist/cli/commands/generate.js +11 -1
- package/dist/cli/commands/generate.js.map +1 -1
- package/dist/cli/commands/init.d.ts +1 -1
- package/dist/cli/commands/init.d.ts.map +1 -1
- package/dist/cli/commands/init.js +65 -8
- package/dist/cli/commands/init.js.map +1 -1
- package/dist/cli/commands/scan.d.ts.map +1 -1
- package/dist/cli/commands/scan.js +33 -17
- package/dist/cli/commands/scan.js.map +1 -1
- package/dist/cli/commands/secrets.d.ts +9 -0
- package/dist/cli/commands/secrets.d.ts.map +1 -0
- package/dist/cli/commands/secrets.js +50 -0
- package/dist/cli/commands/secrets.js.map +1 -0
- package/dist/cli/commands/start.d.ts.map +1 -1
- package/dist/cli/commands/start.js +14 -1
- package/dist/cli/commands/start.js.map +1 -1
- package/dist/cli/index.d.ts.map +1 -1
- package/dist/cli/index.js +26 -3
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/ui/banner.d.ts.map +1 -1
- package/dist/cli/ui/banner.js +2 -1
- package/dist/cli/ui/banner.js.map +1 -1
- package/dist/config/credentials-store.d.ts +24 -0
- package/dist/config/credentials-store.d.ts.map +1 -0
- package/dist/config/credentials-store.js +73 -0
- package/dist/config/credentials-store.js.map +1 -0
- package/dist/config/global-dir.d.ts +21 -0
- package/dist/config/global-dir.d.ts.map +1 -0
- package/dist/config/global-dir.js +34 -0
- package/dist/config/global-dir.js.map +1 -0
- package/dist/config/package-info.d.ts +8 -0
- package/dist/config/package-info.d.ts.map +1 -0
- package/dist/config/package-info.js +27 -0
- package/dist/config/package-info.js.map +1 -0
- package/dist/core/authentication/secret-resolver.d.ts +11 -2
- package/dist/core/authentication/secret-resolver.d.ts.map +1 -1
- package/dist/core/authentication/secret-resolver.js +18 -3
- package/dist/core/authentication/secret-resolver.js.map +1 -1
- package/dist/core/discovery/project-scanner.d.ts +1 -0
- package/dist/core/discovery/project-scanner.d.ts.map +1 -1
- package/dist/core/discovery/project-scanner.js +60 -20
- package/dist/core/discovery/project-scanner.js.map +1 -1
- package/dist/core/permissions/classifier.js +3 -3
- package/dist/core/permissions/classifier.js.map +1 -1
- package/dist/core/permissions/enforcer.d.ts +10 -0
- package/dist/core/permissions/enforcer.d.ts.map +1 -1
- package/dist/core/permissions/enforcer.js +16 -0
- package/dist/core/permissions/enforcer.js.map +1 -1
- package/dist/core/schema/types.d.ts +5 -2
- package/dist/core/schema/types.d.ts.map +1 -1
- package/dist/core/tool-generator/generator.d.ts +3 -1
- package/dist/core/tool-generator/generator.d.ts.map +1 -1
- package/dist/core/tool-generator/generator.js +33 -5
- package/dist/core/tool-generator/generator.js.map +1 -1
- package/dist/core/validation/config-schema.d.ts +10 -5
- package/dist/core/validation/config-schema.d.ts.map +1 -1
- package/dist/core/validation/config-schema.js +3 -2
- package/dist/core/validation/config-schema.js.map +1 -1
- package/dist/mcp/server/fridayy-server.d.ts +8 -1
- package/dist/mcp/server/fridayy-server.d.ts.map +1 -1
- package/dist/mcp/server/fridayy-server.js +29 -1
- package/dist/mcp/server/fridayy-server.js.map +1 -1
- package/dist/mcp/tools/tool-handler.d.ts.map +1 -1
- package/dist/mcp/tools/tool-handler.js +35 -0
- package/dist/mcp/tools/tool-handler.js.map +1 -1
- package/dist/security/audit-logger.d.ts.map +1 -1
- package/dist/security/audit-logger.js +4 -1
- package/dist/security/audit-logger.js.map +1 -1
- package/dist/security/sanitizer.d.ts.map +1 -1
- package/dist/security/sanitizer.js +26 -5
- package/dist/security/sanitizer.js.map +1 -1
- package/package.json +4 -2
package/README.md
CHANGED
|
@@ -17,7 +17,8 @@ Instead of rewriting backend code or exposing raw endpoints to AI agents without
|
|
|
17
17
|
```
|
|
18
18
|
┌───────────────────────────────┐
|
|
19
19
|
│ Existing Application │
|
|
20
|
-
│
|
|
20
|
+
│ (OpenAPI / REST / Node.js / │
|
|
21
|
+
│ Laravel) │
|
|
21
22
|
└───────────────┬───────────────┘
|
|
22
23
|
│
|
|
23
24
|
▼
|
|
@@ -57,6 +58,8 @@ Connecting existing production software to LLMs presents three major challenges:
|
|
|
57
58
|
|
|
58
59
|
## 🚀 Quick Start
|
|
59
60
|
|
|
61
|
+
**Requirements:** Node.js ≥ 18 (Windows, macOS, or Linux). fridayy uses no OS-specific shell commands and resolves per-project config with `path.resolve` and per-device credentials via an OS-appropriate config directory, so it behaves the same on any of the three.
|
|
62
|
+
|
|
60
63
|
### 1. Installation
|
|
61
64
|
|
|
62
65
|
Install globally via npm:
|
|
@@ -97,6 +100,40 @@ fridayy start
|
|
|
97
100
|
|
|
98
101
|
---
|
|
99
102
|
|
|
103
|
+
### 🔌 Supported Source Adapters
|
|
104
|
+
|
|
105
|
+
| Source | Detection | `--source` value | Notes |
|
|
106
|
+
|---|---|---|---|
|
|
107
|
+
| OpenAPI / Swagger | `openapi.yaml`, `swagger.json`, etc. found in the project | `openapi` | Works with any backend language that can export a spec |
|
|
108
|
+
| Node.js (Express / Fastify / Koa / NestJS / Next.js) | `package.json` + route scan | `nodejs` | Scans your JS/TS source directly, no spec needed |
|
|
109
|
+
| **Laravel** | `artisan` file or `laravel/framework` in `composer.json` | `laravel` | Scans `routes/*.php` directly, no spec needed — see below |
|
|
110
|
+
| Generic REST | Fallback when nothing else is detected | `rest` | Works with literally any HTTP backend, less granular |
|
|
111
|
+
|
|
112
|
+
#### Using fridayy with a Laravel project
|
|
113
|
+
|
|
114
|
+
Run these from your Laravel project root (where `artisan` lives):
|
|
115
|
+
|
|
116
|
+
```bash
|
|
117
|
+
fridayy init --source laravel --url http://localhost:8000
|
|
118
|
+
fridayy scan # lists routes discovered in routes/web.php and routes/api.php
|
|
119
|
+
fridayy generate # generates one tool per route
|
|
120
|
+
fridayy review --approve-read
|
|
121
|
+
fridayy start
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
The Laravel adapter reads `routes/*.php` directly — no OpenAPI spec required — and understands:
|
|
125
|
+
- Plain declarations: `Route::get('/users', [UserController::class, 'index'])`
|
|
126
|
+
- `Route::apiResource('users', UserController::class)` / `Route::resource(...)`, including `->only([...])` / `->except([...])`
|
|
127
|
+
- `Route::prefix('v1')->group(function () { ... })` and nested groups
|
|
128
|
+
- Laravel's convention that everything in `routes/api.php` is served under `/api`
|
|
129
|
+
- Route parameters (`{id}`, `{id?}`) mapped to tool input parameters
|
|
130
|
+
|
|
131
|
+
As with every other adapter, `DELETE` routes (and `apiResource`'s `destroy` action) are classified `DESTRUCTIVE` and `BLOCKED` until you explicitly approve them via `fridayy review`.
|
|
132
|
+
|
|
133
|
+
> This is a regex-based scanner, not a full PHP parser — it expects conventionally-formatted route files (one route or group-opener per line, as Laravel's own docs and starter kits write them). Routes built up dynamically in a loop, or registered from third-party service providers, won't be discovered; use an OpenAPI spec (e.g. via `l5-swagger`) for full coverage in those cases.
|
|
134
|
+
|
|
135
|
+
---
|
|
136
|
+
|
|
100
137
|
### 🤖 Pointing AI Assistants to Your Project
|
|
101
138
|
|
|
102
139
|
Simply point any LLM or AI agent (Cursor, Claude, ChatGPT, Gemini, Antigravity) to:
|
|
@@ -129,6 +166,7 @@ fridayy/
|
|
|
129
166
|
│ ├── openapi/ # OpenAPI 3.0, 3.1 & Swagger 2.0 parser & request builder
|
|
130
167
|
│ ├── rest/ # Generic HTTP / REST executor
|
|
131
168
|
│ ├── nodejs/ # Express / Fastify / Koa AST route scanner
|
|
169
|
+
│ ├── laravel/ # Laravel routes/*.php scanner (Route::, resource/apiResource, groups)
|
|
132
170
|
│ ├── manual/ # Custom user-defined tools
|
|
133
171
|
│ └── registry.ts # Adapter Registry (extensible to GraphQL, SQL, etc.)
|
|
134
172
|
│
|
|
@@ -164,13 +202,31 @@ Every operation is automatically classified:
|
|
|
164
202
|
|
|
165
203
|
### 2. Zero-Leak Secret Isolation
|
|
166
204
|
- Secrets and tokens are **never** embedded in tool schemas, descriptions, or LLM-visible payloads.
|
|
167
|
-
- Authentication tokens are resolved
|
|
205
|
+
- Authentication tokens are resolved from, in priority order: an explicit `envKey`, standard `FRIDAYY_*` environment variables, and the global per-device credentials store:
|
|
168
206
|
```env
|
|
169
207
|
FRIDAYY_API_KEY=your_api_key_here
|
|
170
208
|
FRIDAYY_BEARER_TOKEN=your_bearer_token_here
|
|
171
209
|
FRIDAYY_API_URL=http://localhost:4000
|
|
172
210
|
```
|
|
173
|
-
|
|
211
|
+
Prefer environment variables (or `fridayy secrets set FRIDAYY_API_KEY <value>` to store it once per machine) over the `auth.<scheme>.value` config field — anything in `fridayy.config.json` is easy to accidentally commit to source control.
|
|
212
|
+
- Sensitive headers (`Authorization`, `x-api-key`, `Cookie`) and payload fields (`password`, `token`, `secret`), along with JWTs, common vendor API-key formats, and long hex tokens found anywhere in a value, are automatically redacted in audit logs and error messages — regardless of the field name they're stored under.
|
|
213
|
+
|
|
214
|
+
### 2b. Global Credentials Store (works the same on any device)
|
|
215
|
+
Instead of duplicating a secret in every project's `fridayy.config.json`, store it once per machine:
|
|
216
|
+
```bash
|
|
217
|
+
fridayy secrets set FRIDAYY_API_KEY sk_live_...
|
|
218
|
+
fridayy secrets list
|
|
219
|
+
fridayy secrets remove FRIDAYY_API_KEY
|
|
220
|
+
```
|
|
221
|
+
This writes to an OS-appropriate, user-scoped location (`%APPDATA%\fridayy` on Windows, `~/Library/Application Support/fridayy` on macOS, `$XDG_CONFIG_HOME/fridayy` or `~/.config/fridayy` on Linux) with owner-only file permissions. It's a convenience layer over plain JSON, not an OS keychain — for production deployments, prefer real environment variables or a secrets manager.
|
|
222
|
+
|
|
223
|
+
### 2c. Securing the SSE/HTTP Transport
|
|
224
|
+
`fridayy start --transport sse` has **no authentication by default**, since it's designed primarily for local, single-user use. Before exposing it beyond `localhost`, set an API key:
|
|
225
|
+
```bash
|
|
226
|
+
export FRIDAYY_SERVER_API_KEY=some-long-random-value
|
|
227
|
+
fridayy start --transport sse --host 0.0.0.0 --port 3000
|
|
228
|
+
```
|
|
229
|
+
Every request (except `/health`) must then present the key via `Authorization: Bearer <key>`, an `x-api-key` header, or an `?apiKey=` query parameter. Starting `sse` on a non-loopback host without a key refuses to start unless you pass `--allow-insecure` — which is not recommended.
|
|
174
230
|
|
|
175
231
|
### 3. Dynamic Schema Validation
|
|
176
232
|
All input arguments provided by AI agents are validated against the tool's JSON Schema (types, required fields, ranges, and enum constraints) prior to dispatching HTTP requests.
|
|
@@ -192,6 +248,7 @@ All input arguments provided by AI agents are validated against the tool's JSON
|
|
|
192
248
|
| `fridayy start` | Boots standard MCP server (Stdio or SSE) | `fridayy start --transport sse --port 3000` |
|
|
193
249
|
| `fridayy tools` | Lists tool statuses and permission types | `fridayy tools --approved` |
|
|
194
250
|
| `fridayy config` | Displays or updates configuration | `fridayy config get source.baseUrl` |
|
|
251
|
+
| `fridayy secrets` | Manages the global per-device credentials store | `fridayy secrets set FRIDAYY_API_KEY <value>` |
|
|
195
252
|
| `fridayy doctor` | Runs diagnostics on config, secrets, and API | `fridayy doctor` |
|
|
196
253
|
|
|
197
254
|
---
|
|
@@ -279,6 +336,7 @@ npm run example:demo
|
|
|
279
336
|
|
|
280
337
|
- [x] OpenAPI 3.0, 3.1 & Swagger 2.0 support
|
|
281
338
|
- [x] Node.js / Express / Fastify route discovery
|
|
339
|
+
- [x] Laravel PHP route discovery (`routes/*.php`, resource/apiResource, groups)
|
|
282
340
|
- [x] Stdio & SSE Transport support
|
|
283
341
|
- [x] Granular permission classifier & destructive blocking
|
|
284
342
|
- [x] Zero-leak secret isolation
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fridayy - Laravel Framework Adapter
|
|
3
|
+
* Discovers endpoints from a Laravel application's routes/*.php files and
|
|
4
|
+
* executes them the same way the generic REST adapter does (Laravel is just
|
|
5
|
+
* an HTTP API from the caller's point of view; no PHP runtime is needed here).
|
|
6
|
+
*/
|
|
7
|
+
import { BaseAdapter, AdapterScanContext, AdapterGenerationContext, AdapterExecutionContext } from '../base.js';
|
|
8
|
+
import { FridayyToolDefinition, ToolExecutionResult } from '../../core/schema/types.js';
|
|
9
|
+
export declare class LaravelAdapter extends BaseAdapter {
|
|
10
|
+
readonly name = "laravel";
|
|
11
|
+
readonly description = "Adapter for Laravel PHP applications (routes/web.php, routes/api.php)";
|
|
12
|
+
private scanner;
|
|
13
|
+
private restExecutor;
|
|
14
|
+
detect(context: AdapterScanContext): Promise<{
|
|
15
|
+
detected: boolean;
|
|
16
|
+
details?: any;
|
|
17
|
+
}>;
|
|
18
|
+
generateTools(context: AdapterGenerationContext): Promise<FridayyToolDefinition[]>;
|
|
19
|
+
executeTool(tool: FridayyToolDefinition, input: Record<string, any>, context?: AdapterExecutionContext): Promise<ToolExecutionResult>;
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=adapter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../../../src/adapters/laravel/adapter.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,EACL,WAAW,EACX,kBAAkB,EAClB,wBAAwB,EACxB,uBAAuB,EACxB,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,qBAAqB,EACrB,mBAAmB,EAEpB,MAAM,4BAA4B,CAAC;AAWpC,qBAAa,cAAe,SAAQ,WAAW;IAC7C,SAAgB,IAAI,aAAa;IACjC,SAAgB,WAAW,2EAA2E;IAEtG,OAAO,CAAC,OAAO,CAA6B;IAC5C,OAAO,CAAC,YAAY,CAAuB;IAE9B,MAAM,CAAC,OAAO,EAAE,kBAAkB,GAAG,OAAO,CAAC;QAAE,QAAQ,EAAE,OAAO,CAAC;QAAC,OAAO,CAAC,EAAE,GAAG,CAAA;KAAE,CAAC;IA2BlF,aAAa,CAAC,OAAO,EAAE,wBAAwB,GAAG,OAAO,CAAC,qBAAqB,EAAE,CAAC;IAkFlF,WAAW,CACtB,IAAI,EAAE,qBAAqB,EAC3B,KAAK,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAC1B,OAAO,GAAE,uBAA4B,GACpC,OAAO,CAAC,mBAAmB,CAAC;CAmBhC"}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fridayy - Laravel Framework Adapter
|
|
3
|
+
* Discovers endpoints from a Laravel application's routes/*.php files and
|
|
4
|
+
* executes them the same way the generic REST adapter does (Laravel is just
|
|
5
|
+
* an HTTP API from the caller's point of view; no PHP runtime is needed here).
|
|
6
|
+
*/
|
|
7
|
+
import fs from 'node:fs';
|
|
8
|
+
import path from 'node:path';
|
|
9
|
+
import { BaseAdapter } from '../base.js';
|
|
10
|
+
import { LaravelRouteScanner } from './route-scanner.js';
|
|
11
|
+
import { generateToolNameFromRoute } from '../../core/tool-generator/name-sanitizer.js';
|
|
12
|
+
import { classifyOperation } from '../../core/permissions/classifier.js';
|
|
13
|
+
import { buildToolDescription } from '../../core/tool-generator/description-builder.js';
|
|
14
|
+
import { buildUnifiedInputSchema } from '../../core/schema/json-schema.js';
|
|
15
|
+
import { defaultRestExecutor } from '../rest/executor.js';
|
|
16
|
+
import { buildHttpRequest } from '../openapi/request-builder.js';
|
|
17
|
+
import { AuthenticationManager } from '../../core/authentication/manager.js';
|
|
18
|
+
import { defaultSecretResolver } from '../../core/authentication/secret-resolver.js';
|
|
19
|
+
export class LaravelAdapter extends BaseAdapter {
|
|
20
|
+
name = 'laravel';
|
|
21
|
+
description = 'Adapter for Laravel PHP applications (routes/web.php, routes/api.php)';
|
|
22
|
+
scanner = new LaravelRouteScanner();
|
|
23
|
+
restExecutor = defaultRestExecutor;
|
|
24
|
+
async detect(context) {
|
|
25
|
+
const rootDir = context.rootDir;
|
|
26
|
+
const hasArtisan = fs.existsSync(path.join(rootDir, 'artisan'));
|
|
27
|
+
let hasLaravelComposerDep = false;
|
|
28
|
+
const composerPath = path.join(rootDir, 'composer.json');
|
|
29
|
+
if (fs.existsSync(composerPath)) {
|
|
30
|
+
try {
|
|
31
|
+
const composer = JSON.parse(fs.readFileSync(composerPath, 'utf-8'));
|
|
32
|
+
const allDeps = { ...composer.require, ...composer['require-dev'] };
|
|
33
|
+
hasLaravelComposerDep = Boolean(allDeps['laravel/framework'] || allDeps['laravel/lumen-framework']);
|
|
34
|
+
}
|
|
35
|
+
catch {
|
|
36
|
+
// ignore malformed composer.json
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
const routes = await this.scanner.scanDirectory(rootDir, 50);
|
|
40
|
+
return {
|
|
41
|
+
detected: Boolean(hasArtisan || hasLaravelComposerDep || routes.length > 0),
|
|
42
|
+
details: {
|
|
43
|
+
framework: hasArtisan || hasLaravelComposerDep ? 'laravel' : routes.length > 0 ? 'custom-php' : undefined,
|
|
44
|
+
discoveredRoutesCount: routes.length
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
async generateTools(context) {
|
|
49
|
+
const rootDir = context.rootDir || process.cwd();
|
|
50
|
+
const routes = await this.scanner.scanDirectory(rootDir);
|
|
51
|
+
const tools = [];
|
|
52
|
+
const usedToolNames = new Set();
|
|
53
|
+
// `php artisan serve` defaults to :8000, unlike the Node.js adapter's :3000.
|
|
54
|
+
const baseUrl = defaultSecretResolver.resolveBaseUrl(context.config?.source?.baseUrl) ||
|
|
55
|
+
'http://localhost:8000';
|
|
56
|
+
for (const r of routes) {
|
|
57
|
+
let toolName = generateToolNameFromRoute(r.method, r.path);
|
|
58
|
+
if (usedToolNames.has(toolName)) {
|
|
59
|
+
let suffix = 2;
|
|
60
|
+
while (usedToolNames.has(`${toolName}_${suffix}`))
|
|
61
|
+
suffix++;
|
|
62
|
+
toolName = `${toolName}_${suffix}`;
|
|
63
|
+
}
|
|
64
|
+
usedToolNames.add(toolName);
|
|
65
|
+
const pathParams = r.pathParams.map(name => ({
|
|
66
|
+
name,
|
|
67
|
+
in: 'path',
|
|
68
|
+
required: true,
|
|
69
|
+
schema: { type: 'string' },
|
|
70
|
+
description: `Path parameter ${name}`
|
|
71
|
+
}));
|
|
72
|
+
const classification = classifyOperation({
|
|
73
|
+
method: r.method,
|
|
74
|
+
path: r.path,
|
|
75
|
+
name: toolName,
|
|
76
|
+
summary: r.description
|
|
77
|
+
}, context.config);
|
|
78
|
+
const description = buildToolDescription({
|
|
79
|
+
summary: r.description,
|
|
80
|
+
method: r.method,
|
|
81
|
+
path: r.path,
|
|
82
|
+
permissionType: classification.permissions.type,
|
|
83
|
+
risk: classification.risk
|
|
84
|
+
});
|
|
85
|
+
const inputSchema = buildUnifiedInputSchema({
|
|
86
|
+
parameters: { path: pathParams }
|
|
87
|
+
});
|
|
88
|
+
const tool = {
|
|
89
|
+
id: `tool_${toolName}`,
|
|
90
|
+
name: toolName,
|
|
91
|
+
description,
|
|
92
|
+
inputSchema,
|
|
93
|
+
source: {
|
|
94
|
+
type: 'laravel',
|
|
95
|
+
method: r.method,
|
|
96
|
+
path: r.path,
|
|
97
|
+
baseUrl
|
|
98
|
+
},
|
|
99
|
+
parameters: {
|
|
100
|
+
path: pathParams
|
|
101
|
+
},
|
|
102
|
+
permissions: classification.permissions,
|
|
103
|
+
risk: classification.risk,
|
|
104
|
+
status: classification.status,
|
|
105
|
+
metadata: {
|
|
106
|
+
createdAt: new Date().toISOString(),
|
|
107
|
+
autoGenerated: true,
|
|
108
|
+
sourceFile: r.file,
|
|
109
|
+
line: r.line,
|
|
110
|
+
...(r.controller ? { controller: r.controller } : {})
|
|
111
|
+
}
|
|
112
|
+
};
|
|
113
|
+
tools.push(tool);
|
|
114
|
+
}
|
|
115
|
+
return tools;
|
|
116
|
+
}
|
|
117
|
+
async executeTool(tool, input, context = {}) {
|
|
118
|
+
const authManager = new AuthenticationManager(context.config);
|
|
119
|
+
const baseUrl = defaultSecretResolver.resolveBaseUrl(context.config?.source?.baseUrl);
|
|
120
|
+
const preparedReq = buildHttpRequest(tool, input, baseUrl);
|
|
121
|
+
if (context.headers) {
|
|
122
|
+
Object.assign(preparedReq.headers, context.headers);
|
|
123
|
+
}
|
|
124
|
+
authManager.applyAuth(tool.authentication, {
|
|
125
|
+
headers: preparedReq.headers,
|
|
126
|
+
queryParams: {}
|
|
127
|
+
});
|
|
128
|
+
return await this.restExecutor.execute(preparedReq, tool.name, {
|
|
129
|
+
timeoutMs: context.timeoutMs
|
|
130
|
+
});
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
//# sourceMappingURL=adapter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"adapter.js","sourceRoot":"","sources":["../../../src/adapters/laravel/adapter.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fridayy - Laravel Route Scanner
|
|
3
|
+
* Scans a Laravel application's routes/*.php files for `Route::` declarations
|
|
4
|
+
* (including prefix/middleware groups and resource/apiResource shorthand) and
|
|
5
|
+
* turns them into the same DiscoveredRoute shape the Node.js scanner produces,
|
|
6
|
+
* so both can feed the same tool-generation pipeline.
|
|
7
|
+
*
|
|
8
|
+
* This is a regex/line-based heuristic scanner, not a real PHP parser (Laravel
|
|
9
|
+
* route files can contain arbitrarily complex PHP). It handles the common,
|
|
10
|
+
* conventionally-formatted patterns Laravel's own documentation and starter
|
|
11
|
+
* kits use: one route/group-opener per line, with the group's opening `{` on
|
|
12
|
+
* the same line as `->group(`.
|
|
13
|
+
*/
|
|
14
|
+
export interface DiscoveredRoute {
|
|
15
|
+
method: string;
|
|
16
|
+
path: string;
|
|
17
|
+
file: string;
|
|
18
|
+
line: number;
|
|
19
|
+
description?: string;
|
|
20
|
+
pathParams: string[];
|
|
21
|
+
controller?: string;
|
|
22
|
+
}
|
|
23
|
+
export declare class LaravelRouteScanner {
|
|
24
|
+
/**
|
|
25
|
+
* Scans a Laravel project's routes/ directory (routes/web.php, routes/api.php,
|
|
26
|
+
* and any other *.php files under routes/) for route declarations.
|
|
27
|
+
*/
|
|
28
|
+
scanDirectory(rootDir: string, maxFiles?: number): Promise<DiscoveredRoute[]>;
|
|
29
|
+
/**
|
|
30
|
+
* Scans a single route file's content. `filePath`'s basename drives Laravel's
|
|
31
|
+
* conventional default prefix: routes registered in a file named `api.php`
|
|
32
|
+
* are served under `/api` unless the path is already prefixed with it.
|
|
33
|
+
*/
|
|
34
|
+
scanFileContent(content: string, filePath: string): DiscoveredRoute[];
|
|
35
|
+
private extractComment;
|
|
36
|
+
private collectRouteFiles;
|
|
37
|
+
}
|
|
38
|
+
export declare const HTTP_METHOD_LIST: readonly ["get", "post", "put", "patch", "delete", "options"];
|
|
39
|
+
//# sourceMappingURL=route-scanner.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"route-scanner.d.ts","sourceRoot":"","sources":["../../../src/adapters/laravel/route-scanner.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAKH,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,EAAE,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAyED,qBAAa,mBAAmB;IAC9B;;;OAGG;IACU,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,SAAM,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC;IA2BvF;;;;OAIG;IACI,eAAe,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,eAAe,EAAE;IA8F5E,OAAO,CAAC,cAAc;IA+BtB,OAAO,CAAC,iBAAiB;CAsB1B;AAED,eAAO,MAAM,gBAAgB,+DAAe,CAAC"}
|
|
@@ -0,0 +1,238 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Fridayy - Laravel Route Scanner
|
|
3
|
+
* Scans a Laravel application's routes/*.php files for `Route::` declarations
|
|
4
|
+
* (including prefix/middleware groups and resource/apiResource shorthand) and
|
|
5
|
+
* turns them into the same DiscoveredRoute shape the Node.js scanner produces,
|
|
6
|
+
* so both can feed the same tool-generation pipeline.
|
|
7
|
+
*
|
|
8
|
+
* This is a regex/line-based heuristic scanner, not a real PHP parser (Laravel
|
|
9
|
+
* route files can contain arbitrarily complex PHP). It handles the common,
|
|
10
|
+
* conventionally-formatted patterns Laravel's own documentation and starter
|
|
11
|
+
* kits use: one route/group-opener per line, with the group's opening `{` on
|
|
12
|
+
* the same line as `->group(`.
|
|
13
|
+
*/
|
|
14
|
+
import fs from 'node:fs';
|
|
15
|
+
import path from 'node:path';
|
|
16
|
+
const HTTP_METHODS = ['get', 'post', 'put', 'patch', 'delete', 'options'];
|
|
17
|
+
// Route::get('/users', ...), Route::post('/users', [UserController::class, 'store']), etc.
|
|
18
|
+
// `any`/`match` are intentionally excluded: their effective HTTP method(s) can't be
|
|
19
|
+
// determined from the call site alone.
|
|
20
|
+
const ROUTE_CALL_PATTERN = /Route::(get|post|put|patch|delete|options)\s*\(\s*(['"])((?:(?!\2).)*)\2/i;
|
|
21
|
+
// Route::apiResource('users', UserController::class) / Route::resource('users', UserController::class)
|
|
22
|
+
const RESOURCE_CALL_PATTERN = /Route::(apiResource|resource)\s*\(\s*(['"])((?:(?!\2).)*)\2\s*,\s*([A-Za-z0-9_\\]+)(?:::class)?\s*\)/i;
|
|
23
|
+
const ONLY_MODIFIER_PATTERN = /->only\(\s*\[([^\]]*)\]\s*\)/i;
|
|
24
|
+
const EXCEPT_MODIFIER_PATTERN = /->except\(\s*\[([^\]]*)\]\s*\)/i;
|
|
25
|
+
// Route::prefix('v1')->middleware('api')->group(function () { <- opens a prefixed group
|
|
26
|
+
const PREFIX_GROUP_OPEN_PATTERN = /Route::prefix\s*\(\s*(['"])((?:(?!\1).)*)\1\s*\)(?:\s*->\s*[a-zA-Z]+\([^)]*\))*\s*->\s*group\s*\([^{]*\{/i;
|
|
27
|
+
// Route::middleware('api')->group(function () { <- opens a group with no added path prefix
|
|
28
|
+
const PLAIN_GROUP_OPEN_PATTERN = /Route::(?:middleware|group)\s*\([^)]*\)\s*->\s*group\s*\([^{]*\{/i;
|
|
29
|
+
const RESOURCE_ACTIONS = {
|
|
30
|
+
apiResource: [
|
|
31
|
+
{ method: 'GET', suffix: '' },
|
|
32
|
+
{ method: 'POST', suffix: '' },
|
|
33
|
+
{ method: 'GET', suffix: '/{id}' },
|
|
34
|
+
{ method: 'PUT', suffix: '/{id}' },
|
|
35
|
+
{ method: 'PATCH', suffix: '/{id}' },
|
|
36
|
+
{ method: 'DELETE', suffix: '/{id}' }
|
|
37
|
+
],
|
|
38
|
+
resource: [
|
|
39
|
+
{ method: 'GET', suffix: '' },
|
|
40
|
+
{ method: 'GET', suffix: '/create' },
|
|
41
|
+
{ method: 'POST', suffix: '' },
|
|
42
|
+
{ method: 'GET', suffix: '/{id}' },
|
|
43
|
+
{ method: 'GET', suffix: '/{id}/edit' },
|
|
44
|
+
{ method: 'PUT', suffix: '/{id}' },
|
|
45
|
+
{ method: 'PATCH', suffix: '/{id}' },
|
|
46
|
+
{ method: 'DELETE', suffix: '/{id}' }
|
|
47
|
+
]
|
|
48
|
+
};
|
|
49
|
+
// Maps each synthesized action to the Laravel resource-controller method name,
|
|
50
|
+
// used to honor ->only([...]) / ->except([...]) filters.
|
|
51
|
+
const RESOURCE_ACTION_NAMES = {
|
|
52
|
+
'GET:': 'index',
|
|
53
|
+
'POST:': 'store',
|
|
54
|
+
'GET:/create': 'create',
|
|
55
|
+
'GET:/{id}': 'show',
|
|
56
|
+
'GET:/{id}/edit': 'edit',
|
|
57
|
+
'PUT:/{id}': 'update',
|
|
58
|
+
'PATCH:/{id}': 'update',
|
|
59
|
+
'DELETE:/{id}': 'destroy'
|
|
60
|
+
};
|
|
61
|
+
function joinPaths(...segments) {
|
|
62
|
+
const cleaned = segments
|
|
63
|
+
.map(s => s.trim().replace(/^\/+|\/+$/g, ''))
|
|
64
|
+
.filter(s => s.length > 0);
|
|
65
|
+
return `/${cleaned.join('/')}`;
|
|
66
|
+
}
|
|
67
|
+
function extractPathParams(routePath) {
|
|
68
|
+
return (routePath.match(/\{([a-zA-Z0-9_]+)\??\}/g) || []).map(p => p.replace(/[{}?]/g, ''));
|
|
69
|
+
}
|
|
70
|
+
export class LaravelRouteScanner {
|
|
71
|
+
/**
|
|
72
|
+
* Scans a Laravel project's routes/ directory (routes/web.php, routes/api.php,
|
|
73
|
+
* and any other *.php files under routes/) for route declarations.
|
|
74
|
+
*/
|
|
75
|
+
async scanDirectory(rootDir, maxFiles = 200) {
|
|
76
|
+
const routesDir = path.join(rootDir, 'routes');
|
|
77
|
+
const discovered = [];
|
|
78
|
+
const files = this.collectRouteFiles(routesDir, maxFiles);
|
|
79
|
+
for (const file of files) {
|
|
80
|
+
try {
|
|
81
|
+
const content = fs.readFileSync(file, 'utf-8');
|
|
82
|
+
discovered.push(...this.scanFileContent(content, file));
|
|
83
|
+
}
|
|
84
|
+
catch {
|
|
85
|
+
// Skip unreadable files
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
// Deduplicate by method + path (a route registered in multiple files/groups
|
|
89
|
+
// should only produce one tool).
|
|
90
|
+
const uniqueMap = new Map();
|
|
91
|
+
for (const r of discovered) {
|
|
92
|
+
const key = `${r.method}:${r.path}`;
|
|
93
|
+
if (!uniqueMap.has(key)) {
|
|
94
|
+
uniqueMap.set(key, r);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
return Array.from(uniqueMap.values());
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* Scans a single route file's content. `filePath`'s basename drives Laravel's
|
|
101
|
+
* conventional default prefix: routes registered in a file named `api.php`
|
|
102
|
+
* are served under `/api` unless the path is already prefixed with it.
|
|
103
|
+
*/
|
|
104
|
+
scanFileContent(content, filePath) {
|
|
105
|
+
const routes = [];
|
|
106
|
+
const lines = content.split('\n');
|
|
107
|
+
const basename = path.basename(filePath).toLowerCase();
|
|
108
|
+
const isApiFile = basename === 'api.php';
|
|
109
|
+
const groupStack = [];
|
|
110
|
+
let depth = 0;
|
|
111
|
+
const currentPrefix = () => groupStack.map(g => g.prefix).filter(Boolean);
|
|
112
|
+
for (let lineIndex = 0; lineIndex < lines.length; lineIndex++) {
|
|
113
|
+
const line = lines[lineIndex];
|
|
114
|
+
// 1. Group openers (checked before applying this line's brace delta, since
|
|
115
|
+
// the opening brace they introduce belongs to the *new* nested depth).
|
|
116
|
+
const prefixGroupMatch = line.match(PREFIX_GROUP_OPEN_PATTERN);
|
|
117
|
+
const plainGroupMatch = !prefixGroupMatch && line.match(PLAIN_GROUP_OPEN_PATTERN);
|
|
118
|
+
const braceDelta = (line.match(/\{/g) || []).length - (line.match(/\}/g) || []).length;
|
|
119
|
+
const newDepth = depth + braceDelta;
|
|
120
|
+
if (prefixGroupMatch) {
|
|
121
|
+
groupStack.push({ prefix: prefixGroupMatch[2], depthAfterOpen: newDepth });
|
|
122
|
+
}
|
|
123
|
+
else if (plainGroupMatch) {
|
|
124
|
+
groupStack.push({ prefix: '', depthAfterOpen: newDepth });
|
|
125
|
+
}
|
|
126
|
+
depth = newDepth;
|
|
127
|
+
// Pop any group frames we've closed out of.
|
|
128
|
+
while (groupStack.length > 0 && groupStack[groupStack.length - 1].depthAfterOpen > depth) {
|
|
129
|
+
groupStack.pop();
|
|
130
|
+
}
|
|
131
|
+
// 2. Resource / apiResource shorthand.
|
|
132
|
+
const resourceMatch = line.match(RESOURCE_CALL_PATTERN);
|
|
133
|
+
if (resourceMatch) {
|
|
134
|
+
const kind = resourceMatch[1].toLowerCase() === 'apiresource' ? 'apiResource' : 'resource';
|
|
135
|
+
const resourceName = resourceMatch[3];
|
|
136
|
+
const controller = resourceMatch[4];
|
|
137
|
+
const onlyMatch = line.match(ONLY_MODIFIER_PATTERN);
|
|
138
|
+
const exceptMatch = line.match(EXCEPT_MODIFIER_PATTERN);
|
|
139
|
+
const onlyActions = onlyMatch
|
|
140
|
+
? onlyMatch[1].split(',').map(s => s.trim().replace(/^['"]|['"]$/g, ''))
|
|
141
|
+
: undefined;
|
|
142
|
+
const exceptActions = exceptMatch
|
|
143
|
+
? exceptMatch[1].split(',').map(s => s.trim().replace(/^['"]|['"]$/g, ''))
|
|
144
|
+
: undefined;
|
|
145
|
+
for (const action of RESOURCE_ACTIONS[kind]) {
|
|
146
|
+
const actionName = RESOURCE_ACTION_NAMES[`${action.method}:${action.suffix}`];
|
|
147
|
+
if (onlyActions && !onlyActions.includes(actionName))
|
|
148
|
+
continue;
|
|
149
|
+
if (exceptActions && exceptActions.includes(actionName))
|
|
150
|
+
continue;
|
|
151
|
+
const rawPath = joinPaths(...currentPrefix(), resourceName) + action.suffix;
|
|
152
|
+
const finalPath = isApiFile && !rawPath.startsWith('/api/') && rawPath !== '/api' ? `/api${rawPath}` : rawPath;
|
|
153
|
+
routes.push({
|
|
154
|
+
method: action.method,
|
|
155
|
+
path: finalPath,
|
|
156
|
+
file: filePath,
|
|
157
|
+
line: lineIndex + 1,
|
|
158
|
+
description: `Laravel ${kind} route (${resourceName}.${actionName})`,
|
|
159
|
+
pathParams: extractPathParams(finalPath),
|
|
160
|
+
controller
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
continue;
|
|
164
|
+
}
|
|
165
|
+
// 3. Plain Route::{method}(...) calls.
|
|
166
|
+
const routeMatch = line.match(ROUTE_CALL_PATTERN);
|
|
167
|
+
if (routeMatch) {
|
|
168
|
+
const method = routeMatch[1].toUpperCase();
|
|
169
|
+
const rawPath = joinPaths(...currentPrefix(), routeMatch[3]);
|
|
170
|
+
const finalPath = isApiFile && !rawPath.startsWith('/api/') && rawPath !== '/api' ? `/api${rawPath}` : rawPath;
|
|
171
|
+
const comment = this.extractComment(lines, lineIndex);
|
|
172
|
+
routes.push({
|
|
173
|
+
method,
|
|
174
|
+
path: finalPath,
|
|
175
|
+
file: filePath,
|
|
176
|
+
line: lineIndex + 1,
|
|
177
|
+
description: comment,
|
|
178
|
+
pathParams: extractPathParams(finalPath)
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
return routes;
|
|
183
|
+
}
|
|
184
|
+
extractComment(lines, lineIndex) {
|
|
185
|
+
if (lineIndex <= 0)
|
|
186
|
+
return undefined;
|
|
187
|
+
const prevLine = lines[lineIndex - 1].trim();
|
|
188
|
+
if (prevLine.startsWith('//') || prevLine.startsWith('#')) {
|
|
189
|
+
return prevLine.replace(/^(\/\/|#)\s*/, '');
|
|
190
|
+
}
|
|
191
|
+
// PHP doc block: /** ... */ possibly spanning several lines, with the
|
|
192
|
+
// route directly following the closing `*/`. Walk back to find the last
|
|
193
|
+
// non-empty content line inside the block.
|
|
194
|
+
if (prevLine === '*/' || prevLine.endsWith('*/')) {
|
|
195
|
+
for (let i = lineIndex - 2; i >= 0; i--) {
|
|
196
|
+
const line = lines[i].trim();
|
|
197
|
+
if (line.startsWith('/**') || line.startsWith('/*'))
|
|
198
|
+
break;
|
|
199
|
+
const cleaned = line.replace(/^\*\s?/, '').trim();
|
|
200
|
+
if (cleaned.length > 0) {
|
|
201
|
+
return cleaned;
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
return undefined;
|
|
205
|
+
}
|
|
206
|
+
if (prevLine.startsWith('*')) {
|
|
207
|
+
const cleaned = prevLine.replace(/^\*\s*/, '').trim();
|
|
208
|
+
return cleaned.length > 0 ? cleaned : undefined;
|
|
209
|
+
}
|
|
210
|
+
return undefined;
|
|
211
|
+
}
|
|
212
|
+
collectRouteFiles(routesDir, maxFiles, collected = []) {
|
|
213
|
+
if (!fs.existsSync(routesDir))
|
|
214
|
+
return collected;
|
|
215
|
+
if (collected.length >= maxFiles)
|
|
216
|
+
return collected;
|
|
217
|
+
try {
|
|
218
|
+
const entries = fs.readdirSync(routesDir, { withFileTypes: true });
|
|
219
|
+
for (const entry of entries) {
|
|
220
|
+
if (collected.length >= maxFiles)
|
|
221
|
+
break;
|
|
222
|
+
const fullPath = path.join(routesDir, entry.name);
|
|
223
|
+
if (entry.isDirectory()) {
|
|
224
|
+
this.collectRouteFiles(fullPath, maxFiles, collected);
|
|
225
|
+
}
|
|
226
|
+
else if (entry.isFile() && entry.name.toLowerCase().endsWith('.php')) {
|
|
227
|
+
collected.push(fullPath);
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
catch {
|
|
232
|
+
// ignore permission errors
|
|
233
|
+
}
|
|
234
|
+
return collected;
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
export const HTTP_METHOD_LIST = HTTP_METHODS;
|
|
238
|
+
//# sourceMappingURL=route-scanner.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"route-scanner.js","sourceRoot":"","sources":["../../../src/adapters/laravel/route-scanner.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Fridayy - Node.js Route Scanner
|
|
3
|
-
* Scans JavaScript and TypeScript files for Express
|
|
2
|
+
* Fridayy - Enhanced Node.js Route Scanner
|
|
3
|
+
* Scans JavaScript and TypeScript files for Express, Fastify, Koa, NestJS, and Next.js route declarations.
|
|
4
4
|
*/
|
|
5
5
|
export interface DiscoveredRoute {
|
|
6
6
|
method: string;
|
|
@@ -12,10 +12,12 @@ export interface DiscoveredRoute {
|
|
|
12
12
|
}
|
|
13
13
|
export declare class NodeJsScanner {
|
|
14
14
|
/**
|
|
15
|
-
* Scans a directory recursively for Express/Fastify routes.
|
|
15
|
+
* Scans a directory recursively for Express/Fastify/Koa/NestJS/Next.js routes.
|
|
16
16
|
*/
|
|
17
17
|
scanDirectory(rootDir: string, maxFiles?: number): Promise<DiscoveredRoute[]>;
|
|
18
18
|
scanFileContent(content: string, filePath: string): DiscoveredRoute[];
|
|
19
|
+
private scanNextJsRouteFile;
|
|
20
|
+
private extractComment;
|
|
19
21
|
private collectSourceFiles;
|
|
20
22
|
}
|
|
21
23
|
//# sourceMappingURL=ast-scanner.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ast-scanner.d.ts","sourceRoot":"","sources":["../../../src/adapters/nodejs/ast-scanner.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAKH,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,EAAE,CAAC;CACtB;
|
|
1
|
+
{"version":3,"file":"ast-scanner.d.ts","sourceRoot":"","sources":["../../../src/adapters/nodejs/ast-scanner.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAKH,MAAM,WAAW,eAAe;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,EAAE,MAAM,EAAE,CAAC;CACtB;AAWD,qBAAa,aAAa;IACxB;;OAEG;IACU,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,SAAM,GAAG,OAAO,CAAC,eAAe,EAAE,CAAC;IA8BhF,eAAe,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,eAAe,EAAE;IAsD5E,OAAO,CAAC,mBAAmB;IAyC3B,OAAO,CAAC,cAAc;IAoBtB,OAAO,CAAC,kBAAkB;CA8B3B"}
|