te.js 2.0.0 → 2.0.3

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.
@@ -1,2 +0,0 @@
1
- process.env.REDIS_URL = 'redis://localhost:6379';
2
- import('./index.js');
@@ -1,35 +0,0 @@
1
- import { Target, TejError } from 'te.js';
2
- import * as cacheService from '../services/cache.service.js';
3
-
4
- const cache = new Target('/cache');
5
-
6
- // Middleware: require Redis to be available
7
- cache.midair((ammo, next) => {
8
- if (!cacheService.isAvailable()) {
9
- throw new TejError(503, 'Cache service unavailable. Set REDIS_URL to enable Redis.');
10
- }
11
- next();
12
- });
13
-
14
- cache.register('/:key', async (ammo) => {
15
- if (!ammo.GET) return ammo.notAllowed();
16
-
17
- const { key } = ammo.payload;
18
- const value = await cacheService.get(key);
19
-
20
- if (value === null) return ammo.notFound();
21
-
22
- ammo.fire({ key, value });
23
- });
24
-
25
- cache.register('/', async (ammo) => {
26
- if (!ammo.POST) return ammo.notAllowed();
27
-
28
- const { key, value, ttl } = ammo.payload;
29
- if (!key || value === undefined) {
30
- throw new TejError(400, 'key and value are required');
31
- }
32
-
33
- await cacheService.set(key, value, ttl ? parseInt(ttl, 10) : undefined);
34
- ammo.fire(201, { message: 'Cached successfully', key });
35
- });
@@ -1,16 +0,0 @@
1
- import { Target, listAllEndpoints } from 'te.js';
2
-
3
- const target = new Target();
4
-
5
- target.register('/', (ammo) => {
6
- ammo.defaultEntry();
7
- });
8
-
9
- target.register('/health', (ammo) => {
10
- ammo.fire({ status: 'ok', timestamp: new Date().toISOString() });
11
- });
12
-
13
- target.register('/routes', (ammo) => {
14
- const grouped = listAllEndpoints(true);
15
- ammo.fire(grouped);
16
- });
@@ -1,60 +0,0 @@
1
- import { Target, TejError, TejFileUploader } from 'te.js';
2
- import userService from '../services/user.service.js';
3
-
4
- const users = new Target('/users');
5
-
6
- const uploader = new TejFileUploader({
7
- destination: 'public/uploads',
8
- maxFileSize: 5 * 1024 * 1024, // 5MB
9
- });
10
-
11
- users.register('/', (ammo) => {
12
- if (ammo.GET) {
13
- return ammo.fire(userService.list());
14
- }
15
- if (ammo.POST) {
16
- const user = userService.create(ammo.payload);
17
- if (!user) {
18
- throw new TejError(400, 'name and email are required');
19
- }
20
- return ammo.fire(201, user);
21
- }
22
- ammo.notAllowed();
23
- });
24
-
25
- users.register('/:id', (ammo) => {
26
- const { id } = ammo.payload;
27
- const user = userService.getById(id);
28
-
29
- if (ammo.GET) {
30
- if (!user) return ammo.notFound();
31
- return ammo.fire(user);
32
- }
33
- if (ammo.PUT) {
34
- if (!user) return ammo.notFound();
35
- const updated = userService.update(id, ammo.payload);
36
- return ammo.fire(updated);
37
- }
38
- if (ammo.DELETE) {
39
- if (!userService.delete(id)) return ammo.notFound();
40
- return ammo.fire(204);
41
- }
42
-
43
- ammo.notAllowed();
44
- });
45
-
46
- users.register('/:id/updateProfileImage', uploader.file('image'), (ammo) => {
47
- const { image } = ammo.payload;
48
- ammo.fire(200, {
49
- message: 'Profile image updated successfully!',
50
- file: image,
51
- });
52
- });
53
-
54
- users.register('/:id/uploadDocuments', uploader.files('documents'), (ammo) => {
55
- const { documents } = ammo.payload;
56
- ammo.fire(200, {
57
- message: `${documents?.length ?? 0} document(s) uploaded`,
58
- files: documents,
59
- });
60
- });
@@ -1,22 +0,0 @@
1
- {
2
- "port": 1403,
3
- "log": {
4
- "http_requests": true,
5
- "exceptions": true
6
- },
7
- "dir": {
8
- "targets": "targets"
9
- },
10
- "body": {
11
- "max_size": 5242880,
12
- "timeout": 15000
13
- },
14
- "docs": {
15
- "dirTargets": "targets",
16
- "output": "./openapi.json",
17
- "title": "Example API",
18
- "version": "1.0.0",
19
- "level": 1,
20
- "productionBranch": "main"
21
- }
22
- }
@@ -1,44 +0,0 @@
1
- /**
2
- * Unit tests for auto-docs handler-analyzer (detectMethods, analyzeHandler).
3
- */
4
- import { describe, it, expect } from 'vitest';
5
- import { detectMethods, analyzeHandler, ALL_METHODS } from '../../auto-docs/analysis/handler-analyzer.js';
6
-
7
- describe('handler-analyzer', () => {
8
- describe('detectMethods', () => {
9
- it('returns all methods when handler is not a function', () => {
10
- expect(detectMethods(null)).toEqual(ALL_METHODS);
11
- expect(detectMethods(undefined)).toEqual(ALL_METHODS);
12
- });
13
-
14
- it('detects GET when handler uses ammo.GET', () => {
15
- const handler = (ammo) => { if (ammo.GET) ammo.fire(200, {}); };
16
- expect(detectMethods(handler)).toContain('GET');
17
- });
18
-
19
- it('detects POST and GET when handler checks both', () => {
20
- const handler = (ammo) => {
21
- if (ammo.GET) ammo.fire(200, {});
22
- if (ammo.POST) ammo.fire(201, {});
23
- };
24
- const detected = detectMethods(handler);
25
- expect(detected).toContain('GET');
26
- expect(detected).toContain('POST');
27
- });
28
-
29
- it('returns all methods when no method checks found (method-agnostic)', () => {
30
- const handler = () => {};
31
- expect(detectMethods(handler)).toEqual(ALL_METHODS);
32
- });
33
- });
34
-
35
- describe('analyzeHandler', () => {
36
- it('returns object with methods array', () => {
37
- const handler = (ammo) => { if (ammo.GET) ammo.fire(200); };
38
- const result = analyzeHandler(handler);
39
- expect(result).toHaveProperty('methods');
40
- expect(Array.isArray(result.methods)).toBe(true);
41
- expect(result.methods).toContain('GET');
42
- });
43
- });
44
- });
@@ -1,103 +0,0 @@
1
- /**
2
- * Unit tests for auto-docs openapi/generator pure functions.
3
- */
4
- import { describe, it, expect } from 'vitest';
5
- import {
6
- toOpenAPIPath,
7
- getPathParameters,
8
- getQueryParameters,
9
- buildSchemaFromMetadata,
10
- buildResponses,
11
- buildOperation,
12
- mergeMetadata,
13
- } from '../../auto-docs/openapi/generator.js';
14
-
15
- describe('openapi-generator', () => {
16
- describe('toOpenAPIPath', () => {
17
- it('converts :param to {param}', () => {
18
- expect(toOpenAPIPath('/users/:id')).toBe('/users/{id}');
19
- });
20
- it('converts multiple params', () => {
21
- expect(toOpenAPIPath('/users/:userId/posts/:postId')).toBe('/users/{userId}/posts/{postId}');
22
- });
23
- it('returns / for empty or non-string', () => {
24
- expect(toOpenAPIPath('')).toBe('/');
25
- expect(toOpenAPIPath(null)).toBe('/');
26
- });
27
- });
28
-
29
- describe('getPathParameters', () => {
30
- it('extracts path params from te.js path', () => {
31
- const params = getPathParameters('/users/:id');
32
- expect(params).toHaveLength(1);
33
- expect(params[0]).toMatchObject({ name: 'id', in: 'path', required: true, schema: { type: 'string' } });
34
- });
35
- it('returns empty array for path without params', () => {
36
- expect(getPathParameters('/users')).toEqual([]);
37
- });
38
- });
39
-
40
- describe('getQueryParameters', () => {
41
- it('builds query params from metadata', () => {
42
- const queryMeta = { limit: { type: 'integer', required: false }, q: { type: 'string', required: true } };
43
- const params = getQueryParameters(queryMeta);
44
- expect(params).toHaveLength(2);
45
- expect(params.find((p) => p.name === 'limit')).toMatchObject({ in: 'query', required: false });
46
- expect(params.find((p) => p.name === 'q')).toMatchObject({ in: 'query', required: true });
47
- });
48
- it('returns empty array for invalid meta', () => {
49
- expect(getQueryParameters(null)).toEqual([]);
50
- });
51
- });
52
-
53
- describe('buildSchemaFromMetadata', () => {
54
- it('builds OpenAPI schema from field meta', () => {
55
- const meta = { name: { type: 'string' }, email: { type: 'string', format: 'email', required: true } };
56
- const schema = buildSchemaFromMetadata(meta);
57
- expect(schema.type).toBe('object');
58
- expect(schema.properties.name.type).toBe('string');
59
- expect(schema.properties.email.format).toBe('email');
60
- expect(schema.required).toContain('email');
61
- });
62
- });
63
-
64
- describe('buildResponses', () => {
65
- it('returns 200 Success when responseMeta empty', () => {
66
- const r = buildResponses(null);
67
- expect(r['200']).toEqual({ description: 'Success' });
68
- });
69
- it('builds responses from metadata', () => {
70
- const meta = { 200: { description: 'OK' }, 201: { description: 'Created' } };
71
- const r = buildResponses(meta);
72
- expect(r['200'].description).toBe('OK');
73
- expect(r['201'].description).toBe('Created');
74
- });
75
- });
76
-
77
- describe('buildOperation', () => {
78
- it('builds operation with summary and responses', () => {
79
- const meta = { summary: 'Get user', response: { 200: { description: 'OK' } } };
80
- const pathParams = [];
81
- const op = buildOperation('get', meta, pathParams);
82
- expect(op.summary).toBe('Get user');
83
- expect(op.responses['200'].description).toBe('OK');
84
- });
85
- });
86
-
87
- describe('mergeMetadata', () => {
88
- it('prefers explicit when preferEnhanced false', () => {
89
- const explicit = { summary: 'A', description: 'B' };
90
- const enhanced = { summary: 'C', description: 'D' };
91
- const merged = mergeMetadata(explicit, enhanced, { preferEnhanced: false });
92
- expect(merged.summary).toBe('A');
93
- expect(merged.description).toBe('B');
94
- });
95
- it('prefers enhanced when preferEnhanced true', () => {
96
- const explicit = { summary: 'A' };
97
- const enhanced = { summary: 'C', description: 'D' };
98
- const merged = mergeMetadata(explicit, enhanced, { preferEnhanced: true });
99
- expect(merged.summary).toBe('C');
100
- expect(merged.description).toBe('D');
101
- });
102
- });
103
- });
@@ -1,63 +0,0 @@
1
- /**
2
- * Unit tests for auto-docs llm/parse (extractJSON, extractJSONArray, reconcileOrderedTags).
3
- */
4
- import { describe, it, expect } from 'vitest';
5
- import {
6
- extractJSON,
7
- extractJSONArray,
8
- reconcileOrderedTags,
9
- } from '../../auto-docs/llm/parse.js';
10
-
11
- describe('llm/parse', () => {
12
- describe('extractJSON', () => {
13
- it('extracts object from plain JSON string', () => {
14
- const str = '{"name":"Users","description":"CRUD"}';
15
- expect(extractJSON(str)).toEqual({ name: 'Users', description: 'CRUD' });
16
- });
17
- it('extracts first object from text with markdown', () => {
18
- const str = 'Here is the result:\n```json\n{"summary":"Get item"}\n```';
19
- expect(extractJSON(str)).toEqual({ summary: 'Get item' });
20
- });
21
- it('returns null for empty or no object', () => {
22
- expect(extractJSON('')).toBeNull();
23
- expect(extractJSON('no brace here')).toBeNull();
24
- });
25
- });
26
-
27
- describe('extractJSONArray', () => {
28
- it('extracts array from string', () => {
29
- const str = '["Users", "Auth", "Health"]';
30
- expect(extractJSONArray(str)).toEqual(['Users', 'Auth', 'Health']);
31
- });
32
- it('returns null when no array', () => {
33
- expect(extractJSONArray('')).toBeNull();
34
- expect(extractJSONArray('nothing')).toBeNull();
35
- });
36
- });
37
-
38
- describe('reconcileOrderedTags', () => {
39
- it('reorders tags by orderedTagNames', () => {
40
- const tags = [
41
- { name: 'Health', description: '...' },
42
- { name: 'Users', description: '...' },
43
- { name: 'Auth', description: '...' },
44
- ];
45
- const ordered = reconcileOrderedTags(['Users', 'Auth', 'Health'], tags);
46
- expect(ordered.map((t) => t.name)).toEqual(['Users', 'Auth', 'Health']);
47
- });
48
- it('appends tags not in orderedTagNames', () => {
49
- const tags = [
50
- { name: 'Users' },
51
- { name: 'Other' },
52
- ];
53
- const ordered = reconcileOrderedTags(['Users'], tags);
54
- expect(ordered.map((t) => t.name)).toEqual(['Users', 'Other']);
55
- });
56
- it('returns copy of tags when orderedTagNames empty', () => {
57
- const tags = [{ name: 'A' }];
58
- const ordered = reconcileOrderedTags([], tags);
59
- expect(ordered).toEqual([{ name: 'A' }]);
60
- expect(ordered).not.toBe(tags);
61
- });
62
- });
63
- });
@@ -1,58 +0,0 @@
1
- /**
2
- * Unit tests for auto-docs source-resolver (extractRelativeImports, resolveTargetFilePath, formatDependencyContext).
3
- */
4
- import { describe, it, expect } from 'vitest';
5
- import path from 'node:path';
6
- import {
7
- extractRelativeImports,
8
- resolveTargetFilePath,
9
- formatDependencyContext,
10
- } from '../../auto-docs/analysis/source-resolver.js';
11
-
12
- describe('source-resolver', () => {
13
- describe('extractRelativeImports', () => {
14
- it('extracts relative import paths', () => {
15
- const source = `import x from './foo.js';\nimport { y } from '../bar.js';`;
16
- const imports = extractRelativeImports(source);
17
- expect(imports).toContain('./foo.js');
18
- expect(imports).toContain('../bar.js');
19
- });
20
- it('ignores absolute or node imports', () => {
21
- const source = `import path from 'path';\nimport x from './local.js';`;
22
- const imports = extractRelativeImports(source);
23
- expect(imports).toEqual(['./local.js']);
24
- });
25
- it('returns unique paths', () => {
26
- const source = `import a from './foo.js';\nimport b from './foo.js';`;
27
- expect(extractRelativeImports(source)).toHaveLength(1);
28
- });
29
- });
30
-
31
- describe('resolveTargetFilePath', () => {
32
- it('joins dirTargets with groupId and .target.js', () => {
33
- const resolved = resolveTargetFilePath('users', 'targets');
34
- expect(resolved).toMatch(/targets[\\/]users\.target\.js$/);
35
- });
36
- it('converts groupId slashes to path sep', () => {
37
- const resolved = resolveTargetFilePath('subdir/users', 'targets');
38
- expect(resolved).toMatch(/subdir[\\/]users\.target\.js$/);
39
- });
40
- });
41
-
42
- describe('formatDependencyContext', () => {
43
- it('returns empty string for empty sources', () => {
44
- expect(formatDependencyContext(new Map(), null)).toBe('');
45
- });
46
- it('formats map of path -> source with labels', () => {
47
- const sources = new Map([
48
- ['/cwd/targets/users.target.js', 'const x = 1;'],
49
- ['/cwd/services/user.js', 'const y = 2;'],
50
- ]);
51
- const targetPath = '/cwd/targets/users.target.js';
52
- const out = formatDependencyContext(sources, targetPath, 1000);
53
- expect(out).toContain('Target');
54
- expect(out).toContain('const x = 1;');
55
- expect(out).toContain('const y = 2;');
56
- });
57
- });
58
- });
@@ -1,37 +0,0 @@
1
- /**
2
- * Test Helpers Index
3
- * Central export for all test utilities and mocks
4
- */
5
-
6
- // HTTP Mocks
7
- export {
8
- MockRequest,
9
- MockResponse,
10
- createMockRequest,
11
- createMockResponse,
12
- createMockPair,
13
- createJsonRequest,
14
- createFormRequest,
15
- createMultipartRequest,
16
- createMultipartBody,
17
- } from './mock-http.js';
18
-
19
- // Test Utilities
20
- export {
21
- createTestAmmo,
22
- createEnhancedAmmo,
23
- createTestRegistry,
24
- createMockEndpoint,
25
- createMockMiddleware,
26
- createExpressStyleMiddleware,
27
- sleep,
28
- waitFor,
29
- createMockDbConnection,
30
- createMockFile,
31
- createMockStorage,
32
- assertResponse,
33
- mockConsole,
34
- captureResponse,
35
- } from './test-utils.js';
36
-
37
-