heicat 0.1.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.
- package/.eslintrc.js +29 -0
- package/README.md +346 -0
- package/examples/express-app/README.md +72 -0
- package/examples/express-app/contracts/auth.contract.json +38 -0
- package/examples/express-app/contracts/users.contract.json +49 -0
- package/examples/express-app/debug.js +13 -0
- package/examples/express-app/package-lock.json +913 -0
- package/examples/express-app/package.json +21 -0
- package/examples/express-app/server.js +116 -0
- package/jest.config.js +5 -0
- package/package.json +43 -0
- package/packages/cli/jest.config.js +7 -0
- package/packages/cli/package-lock.json +5041 -0
- package/packages/cli/package.json +37 -0
- package/packages/cli/src/cli.ts +49 -0
- package/packages/cli/src/commands/init.ts +103 -0
- package/packages/cli/src/commands/status.ts +75 -0
- package/packages/cli/src/commands/test.ts +188 -0
- package/packages/cli/src/commands/validate.ts +73 -0
- package/packages/cli/src/commands/watch.ts +655 -0
- package/packages/cli/src/index.ts +3 -0
- package/packages/cli/tsconfig.json +18 -0
- package/packages/core/jest.config.js +7 -0
- package/packages/core/package-lock.json +4581 -0
- package/packages/core/package.json +45 -0
- package/packages/core/src/__tests__/contract-loader.test.ts +112 -0
- package/packages/core/src/__tests__/validation-engine.test.ts +213 -0
- package/packages/core/src/contract-loader.ts +55 -0
- package/packages/core/src/engine.ts +95 -0
- package/packages/core/src/index.ts +9 -0
- package/packages/core/src/middleware.ts +97 -0
- package/packages/core/src/types/contract.ts +28 -0
- package/packages/core/src/types/options.ts +7 -0
- package/packages/core/src/types/violation.ts +19 -0
- package/packages/core/src/validation-engine.ts +157 -0
- package/packages/core/src/violation-store.ts +46 -0
- package/packages/core/tsconfig.json +18 -0
package/.eslintrc.js
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
module.exports = {
|
|
2
|
+
env: {
|
|
3
|
+
node: true,
|
|
4
|
+
es2020: true
|
|
5
|
+
},
|
|
6
|
+
extends: [
|
|
7
|
+
'eslint:recommended',
|
|
8
|
+
'@typescript-eslint/recommended'
|
|
9
|
+
],
|
|
10
|
+
parser: '@typescript-eslint/parser',
|
|
11
|
+
parserOptions: {
|
|
12
|
+
ecmaVersion: 2020,
|
|
13
|
+
sourceType: 'module'
|
|
14
|
+
},
|
|
15
|
+
plugins: [
|
|
16
|
+
'@typescript-eslint'
|
|
17
|
+
],
|
|
18
|
+
rules: {
|
|
19
|
+
'@typescript-eslint/no-unused-vars': ['error', { argsIgnorePattern: '^_' }],
|
|
20
|
+
'@typescript-eslint/explicit-function-return-type': 'off',
|
|
21
|
+
'@typescript-eslint/explicit-module-boundary-types': 'off',
|
|
22
|
+
'@typescript-eslint/no-explicit-any': 'off'
|
|
23
|
+
},
|
|
24
|
+
ignorePatterns: [
|
|
25
|
+
'dist/',
|
|
26
|
+
'node_modules/',
|
|
27
|
+
'*.js'
|
|
28
|
+
]
|
|
29
|
+
};
|
package/README.md
ADDED
|
@@ -0,0 +1,346 @@
|
|
|
1
|
+
# Heicat
|
|
2
|
+
|
|
3
|
+
Runtime-enforced API contract system for Node.js. Catches bugs that TypeScript cannot.
|
|
4
|
+
|
|
5
|
+
[](https://badge.fury.io/js/%40heicat%2Fcore)
|
|
6
|
+
[](https://badge.fury.io/js/%40heicat%2Fcli)
|
|
7
|
+
[](https://opensource.org/licenses/MIT)
|
|
8
|
+
|
|
9
|
+
## Quick Start
|
|
10
|
+
|
|
11
|
+
### Installation
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
# Install both packages
|
|
15
|
+
npm install @heicat/core @heicat/cli
|
|
16
|
+
|
|
17
|
+
# Or install individually
|
|
18
|
+
npm install @heicat/core
|
|
19
|
+
npm install -D @heicat/cli
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
### Setup
|
|
23
|
+
|
|
24
|
+
Initialize contracts in your project:
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
npx heicat init
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
Add middleware to your Express app:
|
|
31
|
+
|
|
32
|
+
```typescript
|
|
33
|
+
import { contractMiddleware } from "@heicat/core";
|
|
34
|
+
|
|
35
|
+
app.use(
|
|
36
|
+
contractMiddleware({
|
|
37
|
+
contractsPath: "./contracts",
|
|
38
|
+
mode: "dev"
|
|
39
|
+
})
|
|
40
|
+
);
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
That's it! Your API now has runtime contract enforcement.
|
|
44
|
+
|
|
45
|
+
## What It Does
|
|
46
|
+
|
|
47
|
+
- **Validates requests** before they reach your handlers
|
|
48
|
+
- **Validates responses** before they're sent to clients
|
|
49
|
+
- **Validates errors** to ensure consistent error shapes
|
|
50
|
+
- **Logs violations** with clear, actionable messages
|
|
51
|
+
- **Works in dev, strict, and CI modes**
|
|
52
|
+
|
|
53
|
+
## Example Violation
|
|
54
|
+
|
|
55
|
+
```
|
|
56
|
+
❌ POST /users: Response missing field: email
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## CLI Commands
|
|
60
|
+
|
|
61
|
+
```bash
|
|
62
|
+
# Initialize contracts in your project
|
|
63
|
+
heicat init [--contracts-path <path>]
|
|
64
|
+
|
|
65
|
+
# Validate contract files (syntax + schema)
|
|
66
|
+
heicat validate [--contracts-path <path>]
|
|
67
|
+
|
|
68
|
+
# Show contract status and statistics
|
|
69
|
+
heicat status [--contracts-path <path>]
|
|
70
|
+
|
|
71
|
+
# Watch contracts and validate in real-time
|
|
72
|
+
heicat watch [--contracts-path <path>] [--port <port>]
|
|
73
|
+
|
|
74
|
+
# Test contracts against running server
|
|
75
|
+
heicat test <url> [--contracts-path <path>]
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
## Contract Format
|
|
79
|
+
|
|
80
|
+
Contracts are simple JSON files:
|
|
81
|
+
|
|
82
|
+
```json
|
|
83
|
+
{
|
|
84
|
+
"method": "POST",
|
|
85
|
+
"path": "/users",
|
|
86
|
+
"request": {
|
|
87
|
+
"body": {
|
|
88
|
+
"email": { "type": "string", "required": true },
|
|
89
|
+
"password": { "type": "string", "minLength": 8 }
|
|
90
|
+
}
|
|
91
|
+
},
|
|
92
|
+
"response": {
|
|
93
|
+
"200": {
|
|
94
|
+
"id": "string",
|
|
95
|
+
"email": "string"
|
|
96
|
+
}
|
|
97
|
+
},
|
|
98
|
+
"errors": {
|
|
99
|
+
"400": { "message": "string" }
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
## Modes
|
|
105
|
+
|
|
106
|
+
- **`dev`**: Logs warnings, doesn't block responses
|
|
107
|
+
- **`strict`**: Blocks invalid responses (implemented)
|
|
108
|
+
- **`ci`**: Fails process on violations (implemented)
|
|
109
|
+
|
|
110
|
+
## Why This Works
|
|
111
|
+
|
|
112
|
+
TypeScript validates at compile time. This validates at runtime.
|
|
113
|
+
|
|
114
|
+
- Catches silent API drift
|
|
115
|
+
- Enforces backend behavior consistency
|
|
116
|
+
- Makes contracts the source of truth
|
|
117
|
+
- Requires almost zero adoption effort
|
|
118
|
+
|
|
119
|
+
## Project Structure
|
|
120
|
+
|
|
121
|
+
```
|
|
122
|
+
your-project/
|
|
123
|
+
├─ contracts/
|
|
124
|
+
│ ├─ users.contract.json
|
|
125
|
+
│ ├─ auth.contract.json
|
|
126
|
+
├─ src/
|
|
127
|
+
│ ├─ routes/
|
|
128
|
+
└─ package.json
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
## Testing
|
|
132
|
+
|
|
133
|
+
### Testing Contracts
|
|
134
|
+
|
|
135
|
+
#### 1. Validate Contract Syntax
|
|
136
|
+
```bash
|
|
137
|
+
# Validate all contract files
|
|
138
|
+
heicat validate
|
|
139
|
+
|
|
140
|
+
# Validate specific contracts directory
|
|
141
|
+
heicat validate --contracts-path ./my-contracts
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
#### 2. Test Against Running Server
|
|
145
|
+
```bash
|
|
146
|
+
# Start your server first
|
|
147
|
+
npm start
|
|
148
|
+
|
|
149
|
+
# Test all contracts against localhost:3000
|
|
150
|
+
heicat test http://localhost:3000
|
|
151
|
+
|
|
152
|
+
# Test specific contracts
|
|
153
|
+
heicat test http://localhost:3000 --contracts-path ./contracts
|
|
154
|
+
```
|
|
155
|
+
|
|
156
|
+
#### 3. Watch Mode with Live GUI
|
|
157
|
+
```bash
|
|
158
|
+
# Start watch mode with GUI dashboard
|
|
159
|
+
heicat watch
|
|
160
|
+
|
|
161
|
+
# Opens http://localhost:3333 with live violations dashboard
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
### Manual Testing
|
|
165
|
+
|
|
166
|
+
#### Testing the Middleware
|
|
167
|
+
1. Start the example app:
|
|
168
|
+
```bash
|
|
169
|
+
cd examples/express-app
|
|
170
|
+
npm install
|
|
171
|
+
npm start
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
2. Test valid request:
|
|
175
|
+
```bash
|
|
176
|
+
curl -X POST http://localhost:3000/users \
|
|
177
|
+
-H "Content-Type: application/json" \
|
|
178
|
+
-d '{"email":"test@example.com","password":"password123","name":"Test User"}'
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
3. Test invalid request (missing required field):
|
|
182
|
+
```bash
|
|
183
|
+
curl -X POST http://localhost:3000/users \
|
|
184
|
+
-H "Content-Type: application/json" \
|
|
185
|
+
-d '{"password":"password123"}'
|
|
186
|
+
# Should return 400 with validation error
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
4. Test login:
|
|
190
|
+
```bash
|
|
191
|
+
curl -X POST http://localhost:3000/auth/login \
|
|
192
|
+
-H "Content-Type: application/json" \
|
|
193
|
+
-d '{"email":"test@example.com","password":"password123"}'
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
### Unit Testing
|
|
197
|
+
|
|
198
|
+
#### Running Tests
|
|
199
|
+
```bash
|
|
200
|
+
# Test all packages
|
|
201
|
+
npm test
|
|
202
|
+
|
|
203
|
+
# Test specific package
|
|
204
|
+
cd packages/core
|
|
205
|
+
npm test
|
|
206
|
+
|
|
207
|
+
cd packages/cli
|
|
208
|
+
npm test
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
#### Writing Tests
|
|
212
|
+
Tests use Jest and are located in `__tests__/` directories or `*.test.ts` files.
|
|
213
|
+
|
|
214
|
+
Example test structure:
|
|
215
|
+
```
|
|
216
|
+
packages/core/
|
|
217
|
+
src/
|
|
218
|
+
__tests__/
|
|
219
|
+
validation-engine.test.ts
|
|
220
|
+
middleware.test.ts
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
### Integration Testing
|
|
224
|
+
|
|
225
|
+
#### End-to-End Testing
|
|
226
|
+
1. Start the example server
|
|
227
|
+
2. Run contract tests:
|
|
228
|
+
```bash
|
|
229
|
+
contract-studio test http://localhost:3000
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
#### CI/CD Testing
|
|
233
|
+
Add to your CI pipeline:
|
|
234
|
+
```yaml
|
|
235
|
+
- name: Validate Contracts
|
|
236
|
+
run: npx heicat validate
|
|
237
|
+
|
|
238
|
+
- name: Test Contracts
|
|
239
|
+
run: |
|
|
240
|
+
npm start &
|
|
241
|
+
sleep 5
|
|
242
|
+
npx heicat test http://localhost:3000
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
## Local Developer GUI
|
|
246
|
+
|
|
247
|
+
Start the interactive dashboard for real-time contract monitoring:
|
|
248
|
+
|
|
249
|
+
```bash
|
|
250
|
+
npx heicat watch --port 3333
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
**Features:**
|
|
254
|
+
- **Dark Mode**: Modern ShadCN-inspired dark theme
|
|
255
|
+
- **Real-time Monitoring**: Auto-updates every 3 seconds
|
|
256
|
+
- **Violation Dashboard**: Live statistics and detailed violation logs
|
|
257
|
+
- **Contract Status**: Shows loaded contracts and monitoring status
|
|
258
|
+
- **Responsive Design**: Works on desktop and mobile devices
|
|
259
|
+
|
|
260
|
+
**Dashboard Includes:**
|
|
261
|
+
- **Statistics Cards**: Total violations, errors, and warnings with icons
|
|
262
|
+
- **Status Indicator**: Live monitoring status with animated pulse
|
|
263
|
+
- **Violation Details**: Formatted error messages with severity badges
|
|
264
|
+
- **Clear Function**: Reset violation logs for fresh monitoring
|
|
265
|
+
- **Auto-scroll**: Smooth scrolling for long violation lists
|
|
266
|
+
|
|
267
|
+
**Design System:**
|
|
268
|
+
- ShadCN-inspired components with proper dark mode colors
|
|
269
|
+
- Inter font for modern typography
|
|
270
|
+
- Consistent spacing and border radius
|
|
271
|
+
- Subtle shadows and hover effects
|
|
272
|
+
- Accessible focus states and keyboard navigation
|
|
273
|
+
|
|
274
|
+
Runs locally at `http://localhost:3333` with no authentication required.
|
|
275
|
+
|
|
276
|
+
## Development
|
|
277
|
+
|
|
278
|
+
### Monorepo Setup
|
|
279
|
+
|
|
280
|
+
This is a monorepo managed with NPM workspaces.
|
|
281
|
+
|
|
282
|
+
```bash
|
|
283
|
+
# Install all dependencies
|
|
284
|
+
npm install
|
|
285
|
+
|
|
286
|
+
# Build all packages
|
|
287
|
+
npm run build
|
|
288
|
+
|
|
289
|
+
# Build individual packages
|
|
290
|
+
npm run build:core
|
|
291
|
+
npm run build:cli
|
|
292
|
+
|
|
293
|
+
# Run tests
|
|
294
|
+
npm test
|
|
295
|
+
|
|
296
|
+
# Clean build artifacts
|
|
297
|
+
npm run clean
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
### Publishing
|
|
301
|
+
|
|
302
|
+
```bash
|
|
303
|
+
# Bump version and publish all packages
|
|
304
|
+
npm run release
|
|
305
|
+
|
|
306
|
+
# Or publish individually
|
|
307
|
+
cd packages/core && npm publish
|
|
308
|
+
cd packages/cli && npm publish
|
|
309
|
+
```
|
|
310
|
+
|
|
311
|
+
### Example App
|
|
312
|
+
|
|
313
|
+
```bash
|
|
314
|
+
# Run the example Express app
|
|
315
|
+
cd examples/express-app
|
|
316
|
+
npm install
|
|
317
|
+
npm start
|
|
318
|
+
|
|
319
|
+
# Start GUI dashboard
|
|
320
|
+
npm run watch
|
|
321
|
+
```
|
|
322
|
+
|
|
323
|
+
## Project Structure
|
|
324
|
+
|
|
325
|
+
```
|
|
326
|
+
heicat/
|
|
327
|
+
├── packages/
|
|
328
|
+
│ ├── core/ # Runtime middleware package
|
|
329
|
+
│ └── cli/ # CLI tools package
|
|
330
|
+
├── examples/
|
|
331
|
+
│ └── express-app/ # Example implementation
|
|
332
|
+
├── package.json # Monorepo root
|
|
333
|
+
└── README.md
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
## Contributing
|
|
337
|
+
|
|
338
|
+
1. Fork the repository
|
|
339
|
+
2. Create a feature branch
|
|
340
|
+
3. Make your changes
|
|
341
|
+
4. Add tests
|
|
342
|
+
5. Submit a pull request
|
|
343
|
+
|
|
344
|
+
## License
|
|
345
|
+
|
|
346
|
+
MIT
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
# Contract Studio Example
|
|
2
|
+
|
|
3
|
+
A simple Express.js app demonstrating Backend Contract Studio.
|
|
4
|
+
|
|
5
|
+
## Setup
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Initialize Contracts
|
|
12
|
+
|
|
13
|
+
The contracts are already created, but you can regenerate them:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npm run init-contracts
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## Validate Contracts
|
|
20
|
+
|
|
21
|
+
Check that your contracts are valid:
|
|
22
|
+
|
|
23
|
+
```bash
|
|
24
|
+
npm run validate-contracts
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## View Status
|
|
28
|
+
|
|
29
|
+
See contract statistics:
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
npm run status
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Run the App
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
npm start
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Or for development with auto-restart:
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
npm run dev
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Test the Contracts
|
|
48
|
+
|
|
49
|
+
Try these requests:
|
|
50
|
+
|
|
51
|
+
### Create a user (valid):
|
|
52
|
+
```bash
|
|
53
|
+
curl -X POST http://localhost:3000/users \
|
|
54
|
+
-H "Content-Type: application/json" \
|
|
55
|
+
-d '{"email":"user@example.com","password":"password123","name":"John Doe"}'
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### Create a user (missing password - should fail):
|
|
59
|
+
```bash
|
|
60
|
+
curl -X POST http://localhost:3000/users \
|
|
61
|
+
-H "Content-Type: application/json" \
|
|
62
|
+
-d '{"email":"user2@example.com","name":"Jane Doe"}'
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### Login (valid):
|
|
66
|
+
```bash
|
|
67
|
+
curl -X POST http://localhost:3000/auth/login \
|
|
68
|
+
-H "Content-Type: application/json" \
|
|
69
|
+
-d '{"email":"user@example.com","password":"password123"}'
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Watch the console for contract validation messages! ⚡
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
{
|
|
2
|
+
"method": "POST",
|
|
3
|
+
"path": "/auth/login",
|
|
4
|
+
"request": {
|
|
5
|
+
"body": {
|
|
6
|
+
"email": {
|
|
7
|
+
"type": "string",
|
|
8
|
+
"required": true
|
|
9
|
+
},
|
|
10
|
+
"password": {
|
|
11
|
+
"type": "string",
|
|
12
|
+
"required": true
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
},
|
|
16
|
+
"response": {
|
|
17
|
+
"200": {
|
|
18
|
+
"token": {
|
|
19
|
+
"type": "string"
|
|
20
|
+
},
|
|
21
|
+
"user": {
|
|
22
|
+
"id": {
|
|
23
|
+
"type": "string"
|
|
24
|
+
},
|
|
25
|
+
"email": {
|
|
26
|
+
"type": "string"
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
"errors": {
|
|
32
|
+
"401": {
|
|
33
|
+
"message": {
|
|
34
|
+
"type": "string"
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
{
|
|
2
|
+
"method": "POST",
|
|
3
|
+
"path": "/users",
|
|
4
|
+
"auth": "jwt",
|
|
5
|
+
"request": {
|
|
6
|
+
"body": {
|
|
7
|
+
"email": {
|
|
8
|
+
"type": "string",
|
|
9
|
+
"required": true
|
|
10
|
+
},
|
|
11
|
+
"password": {
|
|
12
|
+
"type": "string",
|
|
13
|
+
"minLength": 8,
|
|
14
|
+
"required": true
|
|
15
|
+
},
|
|
16
|
+
"name": {
|
|
17
|
+
"type": "string"
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
},
|
|
21
|
+
"response": {
|
|
22
|
+
"201": {
|
|
23
|
+
"id": {
|
|
24
|
+
"type": "string"
|
|
25
|
+
},
|
|
26
|
+
"email": {
|
|
27
|
+
"type": "string"
|
|
28
|
+
},
|
|
29
|
+
"name": {
|
|
30
|
+
"type": "string"
|
|
31
|
+
},
|
|
32
|
+
"createdAt": {
|
|
33
|
+
"type": "string"
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
"errors": {
|
|
38
|
+
"400": {
|
|
39
|
+
"message": {
|
|
40
|
+
"type": "string"
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
"409": {
|
|
44
|
+
"message": {
|
|
45
|
+
"type": "string"
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
const { loadContracts } = require('@contract-studio/core');
|
|
2
|
+
|
|
3
|
+
async function debug() {
|
|
4
|
+
try {
|
|
5
|
+
console.log('Loading contracts from ./contracts...');
|
|
6
|
+
const contracts = await loadContracts('./contracts');
|
|
7
|
+
console.log(`Found ${contracts.length} contracts:`, contracts.map(c => `${c.method} ${c.path}`));
|
|
8
|
+
} catch (error) {
|
|
9
|
+
console.error('Error loading contracts:', error);
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
debug();
|