ts-procedures 1.0.0 → 1.1.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 +10 -0
- package/build/errors.d.ts +16 -0
- package/build/errors.js +37 -0
- package/build/errors.js.map +1 -0
- package/build/exports.d.ts +6 -0
- package/build/exports.js +7 -0
- package/build/exports.js.map +1 -0
- package/build/implementations/http/express/example/factories.d.ts +97 -0
- package/build/implementations/http/express/example/factories.js +4 -0
- package/build/implementations/http/express/example/factories.js.map +1 -0
- package/build/implementations/http/express/example/procedures/auth.d.ts +1 -0
- package/build/implementations/http/express/example/procedures/auth.js +22 -0
- package/build/implementations/http/express/example/procedures/auth.js.map +1 -0
- package/build/implementations/http/express/example/procedures/users.d.ts +1 -0
- package/build/implementations/http/express/example/procedures/users.js +30 -0
- package/build/implementations/http/express/example/procedures/users.js.map +1 -0
- package/build/implementations/http/express/example/server.d.ts +3 -0
- package/build/implementations/http/express/example/server.js +49 -0
- package/build/implementations/http/express/example/server.js.map +1 -0
- package/build/implementations/http/express/example/server.test.d.ts +1 -0
- package/build/implementations/http/express/example/server.test.js +110 -0
- package/build/implementations/http/express/example/server.test.js.map +1 -0
- package/build/implementations/http/express/index.d.ts +34 -0
- package/build/implementations/http/express/index.js +75 -0
- package/build/implementations/http/express/index.js.map +1 -0
- package/build/implementations/http/express/index.test.d.ts +1 -0
- package/build/implementations/http/express/index.test.js +329 -0
- package/build/implementations/http/express/index.test.js.map +1 -0
- package/build/index.d.ts +71 -0
- package/build/index.js +80 -0
- package/build/index.js.map +1 -0
- package/build/index.test.d.ts +1 -0
- package/build/index.test.js +249 -0
- package/build/index.test.js.map +1 -0
- package/build/schema/compute-schema.d.ts +23 -0
- package/build/schema/compute-schema.js +28 -0
- package/build/schema/compute-schema.js.map +1 -0
- package/build/schema/compute-schema.test.d.ts +1 -0
- package/build/schema/compute-schema.test.js +107 -0
- package/build/schema/compute-schema.test.js.map +1 -0
- package/build/schema/extract-json-schema.d.ts +2 -0
- package/build/schema/extract-json-schema.js +12 -0
- package/build/schema/extract-json-schema.js.map +1 -0
- package/build/schema/extract-json-schema.test.d.ts +1 -0
- package/build/schema/extract-json-schema.test.js +23 -0
- package/build/schema/extract-json-schema.test.js.map +1 -0
- package/build/schema/parser.d.ts +21 -0
- package/build/schema/parser.js +70 -0
- package/build/schema/parser.js.map +1 -0
- package/build/schema/parser.test.d.ts +1 -0
- package/build/schema/parser.test.js +102 -0
- package/build/schema/parser.test.js.map +1 -0
- package/build/schema/resolve-schema-lib.d.ts +12 -0
- package/build/schema/resolve-schema-lib.js +11 -0
- package/build/schema/resolve-schema-lib.js.map +1 -0
- package/build/schema/resolve-schema-lib.test.d.ts +1 -0
- package/build/schema/resolve-schema-lib.test.js +17 -0
- package/build/schema/resolve-schema-lib.test.js.map +1 -0
- package/build/schema/types.d.ts +7 -0
- package/build/schema/types.js +2 -0
- package/build/schema/types.js.map +1 -0
- package/package.json +21 -9
- package/src/implementations/http/express/README.md +351 -0
- package/src/implementations/http/express/example/factories.ts +25 -0
- package/src/implementations/http/express/example/procedures/auth.ts +24 -0
- package/src/implementations/http/express/example/procedures/users.ts +32 -0
- package/src/implementations/http/express/example/server.test.ts +133 -0
- package/src/implementations/http/express/example/server.ts +67 -0
- package/src/implementations/http/express/index.test.ts +526 -0
- package/src/implementations/http/express/index.ts +108 -0
- package/src/index.test.ts +4 -2
- package/src/index.ts +9 -17
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import { describe, it, expect } from 'vitest'
|
|
2
|
+
import supertest from 'supertest'
|
|
3
|
+
import { app } from './server.js'
|
|
4
|
+
|
|
5
|
+
describe('Express Server Tests', () => {
|
|
6
|
+
describe('Public Endpoints', () => {
|
|
7
|
+
describe('POST /authenticate', () => {
|
|
8
|
+
it('should return token with valid credentials', async () => {
|
|
9
|
+
const response = await supertest(app)
|
|
10
|
+
.post('/authenticate')
|
|
11
|
+
.send({ username: 'john', password: 'secret123' })
|
|
12
|
+
|
|
13
|
+
expect(response.status).toBe(200)
|
|
14
|
+
expect(response.body).toEqual({ token: 'fake-jwt-token' })
|
|
15
|
+
})
|
|
16
|
+
|
|
17
|
+
it('should return 422 when username is missing', async () => {
|
|
18
|
+
const response = await supertest(app).post('/authenticate').send({ password: 'secret123' })
|
|
19
|
+
|
|
20
|
+
expect(response.status).toBe(422)
|
|
21
|
+
expect(response.body).toHaveProperty('error')
|
|
22
|
+
})
|
|
23
|
+
|
|
24
|
+
it('should return 422 when username is too short (minLength: 3)', async () => {
|
|
25
|
+
const response = await supertest(app)
|
|
26
|
+
.post('/authenticate')
|
|
27
|
+
.send({ username: 'ab', password: 'secret123' })
|
|
28
|
+
|
|
29
|
+
expect(response.status).toBe(422)
|
|
30
|
+
expect(response.body).toHaveProperty('error')
|
|
31
|
+
})
|
|
32
|
+
|
|
33
|
+
it('should return 422 when password is missing', async () => {
|
|
34
|
+
const response = await supertest(app).post('/authenticate').send({ username: 'john' })
|
|
35
|
+
|
|
36
|
+
expect(response.status).toBe(422)
|
|
37
|
+
expect(response.body).toHaveProperty('error')
|
|
38
|
+
})
|
|
39
|
+
|
|
40
|
+
it('should return 422 when password is too short (minLength: 6)', async () => {
|
|
41
|
+
const response = await supertest(app)
|
|
42
|
+
.post('/authenticate')
|
|
43
|
+
.send({ username: 'john', password: '12345' })
|
|
44
|
+
|
|
45
|
+
expect(response.status).toBe(422)
|
|
46
|
+
expect(response.body).toHaveProperty('error')
|
|
47
|
+
})
|
|
48
|
+
|
|
49
|
+
it('should return 422 when body is empty', async () => {
|
|
50
|
+
const response = await supertest(app).post('/authenticate').send({})
|
|
51
|
+
|
|
52
|
+
expect(response.status).toBe(422)
|
|
53
|
+
expect(response.body).toHaveProperty('error')
|
|
54
|
+
})
|
|
55
|
+
})
|
|
56
|
+
})
|
|
57
|
+
|
|
58
|
+
describe('Protected Endpoints', () => {
|
|
59
|
+
describe('GET /users/user-profile/:id', () => {
|
|
60
|
+
it('should return 401 when no authorization header is provided', async () => {
|
|
61
|
+
const response = await supertest(app).get('/users/user-profile/123')
|
|
62
|
+
|
|
63
|
+
expect(response.status).toBe(401)
|
|
64
|
+
expect(response.body).toEqual({ error: 'Unauthorized' })
|
|
65
|
+
})
|
|
66
|
+
|
|
67
|
+
it('should return 401 when authorization token is invalid', async () => {
|
|
68
|
+
const response = await supertest(app)
|
|
69
|
+
.get('/users/user-profile/123')
|
|
70
|
+
.set('Authorization', 'invalid-token')
|
|
71
|
+
|
|
72
|
+
expect(response.status).toBe(401)
|
|
73
|
+
expect(response.body).toEqual({ error: 'Unauthorized' })
|
|
74
|
+
})
|
|
75
|
+
|
|
76
|
+
it('should return user profile with valid token', async () => {
|
|
77
|
+
const response = await supertest(app)
|
|
78
|
+
.get('/users/user-profile/123')
|
|
79
|
+
.set('Authorization', 'valid-token')
|
|
80
|
+
|
|
81
|
+
expect(response.status).toBe(200)
|
|
82
|
+
expect(response.body).toEqual({
|
|
83
|
+
user: {
|
|
84
|
+
id: '123',
|
|
85
|
+
name: 'Jane Doe',
|
|
86
|
+
email: 'test@gmail.com',
|
|
87
|
+
},
|
|
88
|
+
})
|
|
89
|
+
})
|
|
90
|
+
|
|
91
|
+
it('should return user profile with different id from path', async () => {
|
|
92
|
+
const response = await supertest(app)
|
|
93
|
+
.get('/users/user-profile/abc')
|
|
94
|
+
.set('Authorization', 'valid-token')
|
|
95
|
+
|
|
96
|
+
expect(response.status).toBe(200)
|
|
97
|
+
expect(response.body).toEqual({
|
|
98
|
+
user: {
|
|
99
|
+
id: 'abc',
|
|
100
|
+
name: 'Jane Doe',
|
|
101
|
+
email: 'test@gmail.com',
|
|
102
|
+
},
|
|
103
|
+
})
|
|
104
|
+
})
|
|
105
|
+
})
|
|
106
|
+
})
|
|
107
|
+
|
|
108
|
+
describe('Response Structure', () => {
|
|
109
|
+
it('authenticate returns correct token structure', async () => {
|
|
110
|
+
const response = await supertest(app)
|
|
111
|
+
.post('/authenticate')
|
|
112
|
+
.send({ username: 'testuser', password: 'password123' })
|
|
113
|
+
|
|
114
|
+
expect(response.status).toBe(200)
|
|
115
|
+
expect(response.body).toHaveProperty('token')
|
|
116
|
+
expect(typeof response.body.token).toBe('string')
|
|
117
|
+
})
|
|
118
|
+
|
|
119
|
+
it('user profile returns correct nested user object with id, name, email', async () => {
|
|
120
|
+
const response = await supertest(app)
|
|
121
|
+
.get('/users/user-profile/test-id')
|
|
122
|
+
.set('Authorization', 'valid-token')
|
|
123
|
+
|
|
124
|
+
expect(response.status).toBe(200)
|
|
125
|
+
expect(response.body).toHaveProperty('user')
|
|
126
|
+
expect(response.body.user).toHaveProperty('id', 'test-id')
|
|
127
|
+
expect(response.body.user).toHaveProperty('name')
|
|
128
|
+
expect(response.body.user).toHaveProperty('email')
|
|
129
|
+
expect(typeof response.body.user.name).toBe('string')
|
|
130
|
+
expect(typeof response.body.user.email).toBe('string')
|
|
131
|
+
})
|
|
132
|
+
})
|
|
133
|
+
})
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import express from 'express'
|
|
2
|
+
import {
|
|
3
|
+
PublicFactory,
|
|
4
|
+
ProtectedFactory
|
|
5
|
+
} from './factories.js'
|
|
6
|
+
import { registerExpressRoutes } from '../index.js'
|
|
7
|
+
|
|
8
|
+
// Import procedures for their side effects (they register with the factories)
|
|
9
|
+
import './procedures/auth.js'
|
|
10
|
+
import './procedures/users.js'
|
|
11
|
+
|
|
12
|
+
const authTokenService = (authToken: string) => {
|
|
13
|
+
// Dummy implementation - replace with real token validation logic
|
|
14
|
+
return {
|
|
15
|
+
isValid: authToken === 'valid-token',
|
|
16
|
+
userId: authToken === 'valid-token' ? 'user-123' : null,
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export const app = express()
|
|
21
|
+
app.use(express.json())
|
|
22
|
+
|
|
23
|
+
registerExpressRoutes(
|
|
24
|
+
app,
|
|
25
|
+
{
|
|
26
|
+
getContext:async (req, res) => {
|
|
27
|
+
return {
|
|
28
|
+
ipAddress:'',
|
|
29
|
+
requestId:'',
|
|
30
|
+
headers:{},
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
},
|
|
34
|
+
PublicFactory.getProcedures()
|
|
35
|
+
)
|
|
36
|
+
|
|
37
|
+
registerExpressRoutes(
|
|
38
|
+
app,
|
|
39
|
+
{
|
|
40
|
+
getContext:async (req, res) => {
|
|
41
|
+
const authServiceResult = authTokenService(req.headers['authorization']?.toString() || '')
|
|
42
|
+
|
|
43
|
+
if (authServiceResult.isValid) {
|
|
44
|
+
return {
|
|
45
|
+
userId:authServiceResult.userId!,
|
|
46
|
+
ipAddress:'',
|
|
47
|
+
requestId:'',
|
|
48
|
+
headers:{}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
res.status(401).json({
|
|
53
|
+
error: 'Unauthorized'
|
|
54
|
+
})
|
|
55
|
+
throw new Error('Unauthorized')
|
|
56
|
+
}
|
|
57
|
+
},
|
|
58
|
+
ProtectedFactory.getProcedures()
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
// Only start server when run directly (not when imported for testing)
|
|
62
|
+
const isMainModule = import.meta.url.endsWith(process.argv[1]?.replace(/\\/g, '/') || '')
|
|
63
|
+
if (isMainModule) {
|
|
64
|
+
app.listen(4841, () => {
|
|
65
|
+
console.log('Server is running on http://localhost:4841')
|
|
66
|
+
})
|
|
67
|
+
}
|