@furystack/rest-service 9.0.0 → 9.0.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.
Files changed (126) hide show
  1. package/esm/actions/login.d.ts +0 -1
  2. package/esm/actions/login.d.ts.map +1 -1
  3. package/esm/actions/login.js +0 -1
  4. package/esm/actions/login.js.map +1 -1
  5. package/esm/add-cors-header.d.ts +14 -0
  6. package/esm/add-cors-header.d.ts.map +1 -0
  7. package/esm/add-cors-header.js +23 -0
  8. package/esm/add-cors-header.js.map +1 -0
  9. package/esm/add-cors-header.spec.js +7 -8
  10. package/esm/add-cors-header.spec.js.map +1 -1
  11. package/esm/api-manager.d.ts.map +1 -1
  12. package/esm/api-manager.js +4 -5
  13. package/esm/api-manager.js.map +1 -1
  14. package/esm/endpoint-generators/create-delete-endpoint.d.ts +0 -1
  15. package/esm/endpoint-generators/create-delete-endpoint.d.ts.map +1 -1
  16. package/esm/endpoint-generators/create-delete-endpoint.js +0 -1
  17. package/esm/endpoint-generators/create-delete-endpoint.js.map +1 -1
  18. package/esm/endpoint-generators/create-delete-endpoint.spec.js +4 -2
  19. package/esm/endpoint-generators/create-delete-endpoint.spec.js.map +1 -1
  20. package/esm/endpoint-generators/create-get-collection-endpoint.d.ts +0 -1
  21. package/esm/endpoint-generators/create-get-collection-endpoint.d.ts.map +1 -1
  22. package/esm/endpoint-generators/create-get-collection-endpoint.js +0 -1
  23. package/esm/endpoint-generators/create-get-collection-endpoint.js.map +1 -1
  24. package/esm/endpoint-generators/create-get-collection-endpoint.spec.js +16 -10
  25. package/esm/endpoint-generators/create-get-collection-endpoint.spec.js.map +1 -1
  26. package/esm/endpoint-generators/create-get-entity-endpoint.d.ts +0 -1
  27. package/esm/endpoint-generators/create-get-entity-endpoint.d.ts.map +1 -1
  28. package/esm/endpoint-generators/create-get-entity-endpoint.js +0 -1
  29. package/esm/endpoint-generators/create-get-entity-endpoint.js.map +1 -1
  30. package/esm/endpoint-generators/create-get-entity-endpoint.spec.js +10 -6
  31. package/esm/endpoint-generators/create-get-entity-endpoint.spec.js.map +1 -1
  32. package/esm/endpoint-generators/create-patch-endpoint.d.ts +0 -1
  33. package/esm/endpoint-generators/create-patch-endpoint.d.ts.map +1 -1
  34. package/esm/endpoint-generators/create-patch-endpoint.js +2 -2
  35. package/esm/endpoint-generators/create-patch-endpoint.js.map +1 -1
  36. package/esm/endpoint-generators/create-patch-endpoint.spec.js +4 -2
  37. package/esm/endpoint-generators/create-patch-endpoint.spec.js.map +1 -1
  38. package/esm/endpoint-generators/create-post-endpoint.d.ts +0 -1
  39. package/esm/endpoint-generators/create-post-endpoint.d.ts.map +1 -1
  40. package/esm/endpoint-generators/create-post-endpoint.js +2 -2
  41. package/esm/endpoint-generators/create-post-endpoint.js.map +1 -1
  42. package/esm/endpoint-generators/create-post-endpoint.spec.js +4 -2
  43. package/esm/endpoint-generators/create-post-endpoint.spec.js.map +1 -1
  44. package/esm/endpoint-generators/utils.d.ts.map +1 -1
  45. package/esm/endpoint-generators/utils.js +0 -2
  46. package/esm/endpoint-generators/utils.js.map +1 -1
  47. package/esm/helpers.d.ts.map +1 -1
  48. package/esm/helpers.js +1 -1
  49. package/esm/helpers.js.map +1 -1
  50. package/esm/http-authentication-settings.d.ts +1 -1
  51. package/esm/http-authentication-settings.d.ts.map +1 -1
  52. package/esm/http-authentication-settings.js.map +1 -1
  53. package/esm/http-user-context.d.ts +7 -6
  54. package/esm/http-user-context.d.ts.map +1 -1
  55. package/esm/http-user-context.js +17 -5
  56. package/esm/http-user-context.js.map +1 -1
  57. package/esm/http-user-context.spec.js +60 -2
  58. package/esm/http-user-context.spec.js.map +1 -1
  59. package/esm/incoming-message-extensions.d.ts +0 -2
  60. package/esm/incoming-message-extensions.d.ts.map +1 -1
  61. package/esm/incoming-message-extensions.js +1 -10
  62. package/esm/incoming-message-extensions.js.map +1 -1
  63. package/esm/index.d.ts +2 -2
  64. package/esm/index.d.ts.map +1 -1
  65. package/esm/index.js +2 -2
  66. package/esm/index.js.map +1 -1
  67. package/esm/models/default-session.d.ts.map +1 -1
  68. package/esm/models/default-session.js +0 -8
  69. package/esm/models/default-session.js.map +1 -1
  70. package/esm/read-post-body.d.ts +12 -0
  71. package/esm/read-post-body.d.ts.map +1 -0
  72. package/esm/read-post-body.js +33 -0
  73. package/esm/read-post-body.js.map +1 -0
  74. package/esm/request-action-implementation.d.ts +4 -4
  75. package/esm/request-action-implementation.d.ts.map +1 -1
  76. package/esm/rest-service.integration.spec.js +24 -33
  77. package/esm/rest-service.integration.spec.js.map +1 -1
  78. package/esm/rest.integration.test.js +1 -1
  79. package/esm/static-server-manager.d.ts.map +1 -1
  80. package/esm/static-server-manager.js +0 -1
  81. package/esm/static-server-manager.js.map +1 -1
  82. package/esm/static-server-manager.spec.js +2 -15
  83. package/esm/static-server-manager.spec.js.map +1 -1
  84. package/esm/validate.d.ts +3 -1
  85. package/esm/validate.d.ts.map +1 -1
  86. package/esm/validate.integration.spec.js +6 -2
  87. package/esm/validate.integration.spec.js.map +1 -1
  88. package/package.json +13 -13
  89. package/src/actions/login.ts +0 -1
  90. package/src/add-cors-header.spec.ts +7 -8
  91. package/src/add-cors-header.ts +32 -0
  92. package/src/api-manager.ts +5 -5
  93. package/src/endpoint-generators/create-delete-endpoint.spec.ts +4 -2
  94. package/src/endpoint-generators/create-delete-endpoint.ts +0 -1
  95. package/src/endpoint-generators/create-get-collection-endpoint.spec.ts +16 -10
  96. package/src/endpoint-generators/create-get-collection-endpoint.ts +0 -1
  97. package/src/endpoint-generators/create-get-entity-endpoint.spec.ts +10 -6
  98. package/src/endpoint-generators/create-get-entity-endpoint.ts +0 -1
  99. package/src/endpoint-generators/create-patch-endpoint.spec.ts +4 -2
  100. package/src/endpoint-generators/create-patch-endpoint.ts +2 -2
  101. package/src/endpoint-generators/create-post-endpoint.spec.ts +4 -2
  102. package/src/endpoint-generators/create-post-endpoint.ts +2 -2
  103. package/src/endpoint-generators/utils.ts +2 -2
  104. package/src/helpers.ts +1 -1
  105. package/src/http-authentication-settings.ts +1 -2
  106. package/src/http-user-context.spec.ts +79 -2
  107. package/src/http-user-context.ts +29 -10
  108. package/src/incoming-message-extensions.ts +0 -15
  109. package/src/index.ts +2 -2
  110. package/src/models/default-session.ts +2 -2
  111. package/src/read-post-body.ts +36 -0
  112. package/src/rest-service.integration.spec.ts +24 -38
  113. package/src/rest.integration.test.ts +1 -1
  114. package/src/static-server-manager.spec.ts +2 -18
  115. package/src/static-server-manager.ts +1 -1
  116. package/src/validate.integration.spec.ts +9 -2
  117. package/esm/incoming-message-extensions.spec.d.ts +0 -2
  118. package/esm/incoming-message-extensions.spec.d.ts.map +0 -1
  119. package/esm/incoming-message-extensions.spec.js +0 -38
  120. package/esm/incoming-message-extensions.spec.js.map +0 -1
  121. package/esm/utils.d.ts +0 -25
  122. package/esm/utils.d.ts.map +0 -1
  123. package/esm/utils.js +0 -70
  124. package/esm/utils.js.map +0 -1
  125. package/src/incoming-message-extensions.spec.ts +0 -42
  126. package/src/utils.ts +0 -68
@@ -1,20 +1,5 @@
1
- import http from 'http'
2
- import { Utils } from './utils.js'
3
-
4
1
  declare module 'http' {
5
2
  export interface IncomingMessage {
6
- readPostBodyRaw: () => Promise<string>
7
- readPostBody: <T>() => Promise<T>
8
3
  postBody: unknown
9
4
  }
10
5
  }
11
-
12
- http.IncomingMessage.prototype.readPostBody = async function <T>() {
13
- const utils = new Utils()
14
- return await utils.readPostBody<T>(this)
15
- }
16
-
17
- http.IncomingMessage.prototype.readPostBodyRaw = async function () {
18
- const utils = new Utils()
19
- return await utils.readPostBodyRaw(this)
20
- }
package/src/index.ts CHANGED
@@ -1,18 +1,18 @@
1
1
  export * from './helpers.js'
2
+ export * from './add-cors-header.js'
2
3
  export * from './api-manager.js'
3
4
  export * from './actions/index.js'
4
5
  export * from './authenticate.js'
5
6
  export * from './authorize.js'
6
7
  export * from './http-authentication-settings.js'
7
8
  export * from './http-user-context.js'
8
- export * from './incoming-message-extensions.js'
9
9
  export * from './server-manager.js'
10
10
  export * from './server-response-extensions.js'
11
- export * from './utils.js'
12
11
  export * from './models/index.js'
13
12
  export * from './endpoint-generators/index.js'
14
13
  export * from './schema-validator/index.js'
15
14
  export * from './request-action-implementation.js'
16
15
  export * from './validate.js'
17
16
  export * from './mime-types.js'
17
+ export * from './read-post-body.js'
18
18
  export * from './static-server-manager.js'
@@ -5,10 +5,10 @@ export class DefaultSession {
5
5
  /**
6
6
  * The generated session identifier
7
7
  */
8
- public sessionId!: string
8
+ declare sessionId: string
9
9
 
10
10
  /**
11
11
  * The user's login name for the session
12
12
  */
13
- public username!: string
13
+ declare username: string
14
14
  }
@@ -0,0 +1,36 @@
1
+ import type { IncomingMessage } from 'http'
2
+ import './incoming-message-extensions.js'
3
+
4
+ export const readPostBodyRaw = async (incomingMessage: IncomingMessage) => {
5
+ if (!incomingMessage.readable) {
6
+ throw Error('Incoming message is not readable')
7
+ }
8
+
9
+ let body = ''
10
+ await new Promise<void>((resolve, reject) => {
11
+ incomingMessage.on('readable', () => {
12
+ const data = incomingMessage.read()
13
+ if (data) {
14
+ body += data
15
+ }
16
+ })
17
+ incomingMessage.on('end', () => {
18
+ resolve()
19
+ })
20
+ incomingMessage.on('error', (err) => {
21
+ reject(err)
22
+ })
23
+ })
24
+ return body
25
+ }
26
+
27
+ /**
28
+ * Reads the post's body and returns a promise with a parsed value
29
+ * @param incomingMessage The incoming message instance
30
+ * @returns the parsed object from the post body
31
+ */
32
+ export const readPostBody = async <T>(incomingMessage: IncomingMessage): Promise<T> => {
33
+ const body = incomingMessage.postBody || JSON.parse(await readPostBodyRaw(incomingMessage))
34
+ incomingMessage.postBody = body
35
+ return body
36
+ }
@@ -11,10 +11,6 @@ import { describe, it, expect } from 'vitest'
11
11
  import { serializeValue } from '@furystack/rest'
12
12
  import { getPort } from '@furystack/core/port-generator'
13
13
 
14
- class UserWithPassword extends User {
15
- password!: string
16
- }
17
-
18
14
  interface IntegrationTestApi extends RestApi {
19
15
  GET: {
20
16
  '/isAuthenticated': { result: { isAuthenticated: boolean } }
@@ -29,23 +25,22 @@ interface IntegrationTestApi extends RestApi {
29
25
  }
30
26
  }
31
27
 
32
- const prepareInjector = async (i: Injector) => {
28
+ const createIntegrationApi = async () => {
29
+ const i = new Injector()
33
30
  const port = getPort()
34
- const hostName = 'localhost'
35
31
  const root = 'test-api'
36
32
 
37
33
  addStore(i, new InMemoryStore({ model: User, primaryKey: 'username' })).addStore(
38
34
  new InMemoryStore({ model: DefaultSession, primaryKey: 'sessionId' }),
39
35
  )
40
36
  useHttpAuthentication(i, {
41
- getUserStore: (sm) => sm.getStoreFor(UserWithPassword, 'username'),
37
+ getUserStore: (sm) => sm.getStoreFor(User, 'username'),
42
38
  getSessionStore: (sm) => sm.getStoreFor(DefaultSession, 'sessionId'),
43
39
  })
44
40
  await useRestService<IntegrationTestApi>({
45
41
  injector: i,
46
42
  root,
47
- port: getPort(),
48
- hostName,
43
+ port,
49
44
  cors: {
50
45
  credentials: true,
51
46
  origins: ['http://localhost:8080'],
@@ -71,23 +66,22 @@ const prepareInjector = async (i: Injector) => {
71
66
  })
72
67
 
73
68
  return {
74
- apiUrl: `http://${hostName}:${port}/${root}`,
69
+ apiUrl: `http://127.0.0.1:${port}/${root}`,
75
70
  port,
76
- hostName,
71
+ dispose: i.dispose.bind(i),
77
72
  }
78
73
  }
79
74
 
80
75
  describe('@furystack/rest-service inregration tests', () => {
81
76
  it('Should be started and disposed', async () => {
82
- await usingAsync(new Injector(), async (i) => {
83
- await prepareInjector(i)
84
- })
77
+ await usingAsync(await createIntegrationApi(), async () => {})
85
78
  })
86
79
 
87
80
  it('Should respond with 404 when a route is not found', async () => {
88
- await usingAsync(new Injector(), async (i) => {
89
- const { apiUrl } = await prepareInjector(i)
90
- const result = await fetch(PathHelper.joinPaths(apiUrl, 'some-route-that-does-not-exists'))
81
+ await usingAsync(await createIntegrationApi(), async ({ apiUrl }) => {
82
+ const result = await fetch(PathHelper.joinPaths(apiUrl, 'some-route-that-does-not-exists'), {
83
+ method: 'GET',
84
+ })
91
85
  expect(result.ok).toBe(false)
92
86
  expect(result.status).toBe(404)
93
87
  const responseText = await result.json()
@@ -96,8 +90,7 @@ describe('@furystack/rest-service inregration tests', () => {
96
90
  })
97
91
 
98
92
  it('Should respond with 401 for unauthorized request errors', async () => {
99
- await usingAsync(new Injector(), async (i) => {
100
- const { apiUrl } = await prepareInjector(i)
93
+ await usingAsync(await createIntegrationApi(), async ({ apiUrl }) => {
101
94
  const result = await fetch(PathHelper.joinPaths(apiUrl, 'currentUser'))
102
95
  expect(result.ok).toBe(false)
103
96
  expect(result.status).toBe(401)
@@ -107,8 +100,7 @@ describe('@furystack/rest-service inregration tests', () => {
107
100
  })
108
101
 
109
102
  it('Should respond with 401 for unauthorized request errors', async () => {
110
- await usingAsync(new Injector(), async (i) => {
111
- const { apiUrl } = await prepareInjector(i)
103
+ await usingAsync(await createIntegrationApi(), async ({ apiUrl }) => {
112
104
  const result = await fetch(PathHelper.joinPaths(apiUrl, 'currentUser'))
113
105
  expect(result.ok).toBe(false)
114
106
  expect(result.status).toBe(401)
@@ -118,8 +110,7 @@ describe('@furystack/rest-service inregration tests', () => {
118
110
  })
119
111
 
120
112
  it('Should respond with the correct result body', async () => {
121
- await usingAsync(new Injector(), async (i) => {
122
- const { apiUrl } = await prepareInjector(i)
113
+ await usingAsync(await createIntegrationApi(), async ({ apiUrl }) => {
123
114
  const response = await fetch(PathHelper.joinPaths(apiUrl, 'isAuthenticated'))
124
115
  expect(response.status).toBe(200)
125
116
  const result = await response.json()
@@ -128,9 +119,8 @@ describe('@furystack/rest-service inregration tests', () => {
128
119
  })
129
120
 
130
121
  it('Should be able to read query parameters', async () => {
131
- await usingAsync(new Injector(), async (i) => {
132
- const { apiUrl } = await prepareInjector(i)
133
-
122
+ await usingAsync(await createIntegrationApi(), async ({ apiUrl }) => {
123
+ console.log('apiUrl', apiUrl)
134
124
  const response = await fetch(PathHelper.joinPaths(apiUrl, `testQuery?param1=${serializeValue('foo')}`))
135
125
  expect(response.status).toBe(200)
136
126
  const result = await response.json()
@@ -139,9 +129,7 @@ describe('@furystack/rest-service inregration tests', () => {
139
129
  })
140
130
 
141
131
  it('Should be able to read url parameters', async () => {
142
- await usingAsync(new Injector(), async (i) => {
143
- const { apiUrl } = await prepareInjector(i)
144
-
132
+ await usingAsync(await createIntegrationApi(), async ({ apiUrl }) => {
145
133
  const response = await fetch(PathHelper.joinPaths(apiUrl, 'testUrlParams/bar'))
146
134
  expect(response.status).toBe(200)
147
135
  const result = await response.json()
@@ -150,9 +138,7 @@ describe('@furystack/rest-service inregration tests', () => {
150
138
  })
151
139
 
152
140
  it('Should be able to read post body', async () => {
153
- await usingAsync(new Injector(), async (i) => {
154
- const { apiUrl } = await prepareInjector(i)
155
-
141
+ await usingAsync(await createIntegrationApi(), async ({ apiUrl }) => {
156
142
  const response = await fetch(PathHelper.joinPaths(apiUrl, 'testPostBody'), {
157
143
  method: 'POST',
158
144
  body: JSON.stringify({ value: 'baz' }),
@@ -164,20 +150,20 @@ describe('@furystack/rest-service inregration tests', () => {
164
150
  })
165
151
 
166
152
  it('Should respond with OK to OPTIONS requests', async () => {
167
- await usingAsync(new Injector(), async (i) => {
168
- const { apiUrl } = await prepareInjector(i)
169
-
153
+ await usingAsync(await createIntegrationApi(), async ({ apiUrl }) => {
170
154
  const response = await fetch(PathHelper.joinPaths(apiUrl, 'testPostBody'), {
171
155
  method: 'OPTIONS',
156
+ }).catch((e) => {
157
+ console.log(e)
158
+ throw e
172
159
  })
173
160
  expect(response.status).toBe(200)
174
161
  })
175
162
  })
176
163
 
177
164
  it('Should reject requests outside of the API Root', async () => {
178
- await usingAsync(new Injector(), async (i) => {
179
- const { hostName, port } = await prepareInjector(i)
180
- await expect(fetch(PathHelper.joinPaths(`http://${hostName}:${port}`, 'not-my-api-root'))).rejects.toThrowError(
165
+ await usingAsync(await createIntegrationApi(), async ({ port }) => {
166
+ await expect(fetch(PathHelper.joinPaths(`http://127.0.0.1:${port}`, 'not-my-api-root'))).rejects.toThrowError(
181
167
  'fetch failed',
182
168
  )
183
169
  })
@@ -56,7 +56,7 @@ const createEchoApiServer = async () => {
56
56
  },
57
57
  })
58
58
  const client = createClient<EchoApi>({
59
- endpointUrl: `http://localhost:${port}/api`,
59
+ endpointUrl: `http://127.0.0.1:${port}/api`,
60
60
  })
61
61
  return {
62
62
  dispose: injector.dispose.bind(injector),
@@ -3,23 +3,7 @@ import { sleepAsync, usingAsync } from '@furystack/utils'
3
3
  import { ServerManager } from './server-manager.js'
4
4
  import { StaticServerManager } from './static-server-manager.js'
5
5
  import { describe, it, expect, vi } from 'vitest'
6
-
7
- /**
8
- * Generator for an incremental port number
9
- * @param initialPort The initial port number
10
- * @yields a port for testing
11
- * @returns The Port number
12
- */
13
- function* portGenerator(initialPort = 17000) {
14
- let port = initialPort
15
-
16
- while (true) {
17
- yield port++
18
- }
19
- return port
20
- }
21
-
22
- const getPort = () => portGenerator().next().value
6
+ import { getPort } from '@furystack/core/port-generator'
23
7
 
24
8
  describe('StaticServerManager', () => {
25
9
  describe('Top level routing', () => {
@@ -33,7 +17,7 @@ describe('StaticServerManager', () => {
33
17
  port,
34
18
  })
35
19
 
36
- const result = await fetch(`http://localhost:${port}/not-found.html`)
20
+ const result = await fetch(`http://127.0.0.1:${port}/not-found.html`)
37
21
  expect(result.ok).toBe(false)
38
22
  expect(result.status).toBe(404)
39
23
  expect(result?.headers.get('content-type')).toBe('text/plain')
@@ -18,7 +18,7 @@ export interface StaticServerOptions {
18
18
  @Injectable({ lifetime: 'singleton' })
19
19
  export class StaticServerManager {
20
20
  @Injected(ServerManager)
21
- private readonly serverManager!: ServerManager
21
+ private declare readonly serverManager: ServerManager
22
22
 
23
23
  private async sendFile({
24
24
  fullPath,
@@ -8,13 +8,19 @@ import type { ValidationApi } from './validate.integration.schema.js'
8
8
  import { useRestService } from './helpers.js'
9
9
  import { describe, it, expect } from 'vitest'
10
10
  import { getPort } from '@furystack/core/port-generator'
11
+ import { getStoreManager, InMemoryStore, User } from '@furystack/core'
12
+ import { DefaultSession } from './models/default-session.js'
11
13
 
12
14
  // To recreate: yarn ts-json-schema-generator -f tsconfig.json --no-type-check -p packages/rest-service/src/validate.integration.schema.ts -o packages/rest-service/src/validate.integration.spec.schema.json
13
15
 
14
16
  const createValidateApi = async () => {
15
17
  const injector = new Injector()
16
18
  const port = getPort()
17
- useRestService<ValidationApi>({
19
+
20
+ getStoreManager(injector).addStore(new InMemoryStore({ model: User, primaryKey: 'username' }))
21
+ getStoreManager(injector).addStore(new InMemoryStore({ model: DefaultSession, primaryKey: 'sessionId' }))
22
+
23
+ await useRestService<ValidationApi>({
18
24
  injector,
19
25
  api: {
20
26
  GET: {
@@ -54,8 +60,9 @@ const createValidateApi = async () => {
54
60
  root: '/api',
55
61
  })
56
62
  const client = createClient<ValidationApi>({
57
- endpointUrl: `http://localhost:${port}/api`,
63
+ endpointUrl: `http://127.0.0.1:${port}/api`,
58
64
  })
65
+
59
66
  return {
60
67
  dispose: injector.dispose.bind(injector),
61
68
  client,
@@ -1,2 +0,0 @@
1
- import './incoming-message-extensions';
2
- //# sourceMappingURL=incoming-message-extensions.spec.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"incoming-message-extensions.spec.d.ts","sourceRoot":"","sources":["../src/incoming-message-extensions.spec.ts"],"names":[],"mappings":"AACA,OAAO,+BAA+B,CAAA"}
@@ -1,38 +0,0 @@
1
- import { IncomingMessage } from 'http';
2
- import './incoming-message-extensions';
3
- import { Socket } from 'net';
4
- import { describe, it, expect } from 'vitest';
5
- describe('IncomingMessage extensions', () => {
6
- describe('readPostBody', () => {
7
- it('Should be extended', () => {
8
- const socket = new Socket();
9
- const msg = new IncomingMessage(socket);
10
- expect(typeof msg.readPostBody).toBe('function');
11
- });
12
- it('Should read the raw post body', async () => {
13
- const exampleValue = { value: Math.random().toString() };
14
- const socket = new Socket();
15
- const msg = new IncomingMessage(socket);
16
- setTimeout(() => {
17
- msg.read = () => JSON.stringify(exampleValue);
18
- msg.emit('readable');
19
- msg.emit('end');
20
- }, 10);
21
- const result = await msg.readPostBodyRaw();
22
- expect(result).toEqual(JSON.stringify(exampleValue));
23
- });
24
- it('Should read the post body', async () => {
25
- const exampleValue = { value: Math.random().toString() };
26
- const socket = new Socket();
27
- const msg = new IncomingMessage(socket);
28
- setTimeout(() => {
29
- msg.read = () => JSON.stringify(exampleValue);
30
- msg.emit('readable');
31
- msg.emit('end');
32
- }, 10);
33
- const result = await msg.readPostBody();
34
- expect(result).toEqual(exampleValue);
35
- });
36
- });
37
- });
38
- //# sourceMappingURL=incoming-message-extensions.spec.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"incoming-message-extensions.spec.js","sourceRoot":"","sources":["../src/incoming-message-extensions.spec.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,MAAM,CAAA;AACtC,OAAO,+BAA+B,CAAA;AACtC,OAAO,EAAE,MAAM,EAAE,MAAM,KAAK,CAAA;AAC5B,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AAE7C,QAAQ,CAAC,4BAA4B,EAAE,GAAG,EAAE;IAC1C,QAAQ,CAAC,cAAc,EAAE,GAAG,EAAE;QAC5B,EAAE,CAAC,oBAAoB,EAAE,GAAG,EAAE;YAC5B,MAAM,MAAM,GAAG,IAAI,MAAM,EAAE,CAAA;YAC3B,MAAM,GAAG,GAAG,IAAI,eAAe,CAAC,MAAM,CAAC,CAAA;YACvC,MAAM,CAAC,OAAO,GAAG,CAAC,YAAY,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAA;QAClD,CAAC,CAAC,CAAA;QAEF,EAAE,CAAC,+BAA+B,EAAE,KAAK,IAAI,EAAE;YAC7C,MAAM,YAAY,GAAG,EAAE,KAAK,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,EAAE,CAAA;YACxD,MAAM,MAAM,GAAG,IAAI,MAAM,EAAE,CAAA;YAC3B,MAAM,GAAG,GAAG,IAAI,eAAe,CAAC,MAAM,CAAC,CAAA;YACvC,UAAU,CAAC,GAAG,EAAE;gBACd,GAAG,CAAC,IAAI,GAAG,GAAG,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,YAAY,CAAC,CAAA;gBAC7C,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC,CAAA;gBACpB,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;YACjB,CAAC,EAAE,EAAE,CAAC,CAAA;YAEN,MAAM,MAAM,GAAG,MAAM,GAAG,CAAC,eAAe,EAAE,CAAA;YAC1C,MAAM,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC,SAAS,CAAC,YAAY,CAAC,CAAC,CAAA;QACtD,CAAC,CAAC,CAAA;QAEF,EAAE,CAAC,2BAA2B,EAAE,KAAK,IAAI,EAAE;YACzC,MAAM,YAAY,GAAG,EAAE,KAAK,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,EAAE,CAAA;YACxD,MAAM,MAAM,GAAG,IAAI,MAAM,EAAE,CAAA;YAC3B,MAAM,GAAG,GAAG,IAAI,eAAe,CAAC,MAAM,CAAC,CAAA;YACvC,UAAU,CAAC,GAAG,EAAE;gBACd,GAAG,CAAC,IAAI,GAAG,GAAG,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,YAAY,CAAC,CAAA;gBAC7C,GAAG,CAAC,IAAI,CAAC,UAAU,CAAC,CAAA;gBACpB,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;YACjB,CAAC,EAAE,EAAE,CAAC,CAAA;YAEN,MAAM,MAAM,GAAG,MAAM,GAAG,CAAC,YAAY,EAAE,CAAA;YACvC,MAAM,CAAC,MAAM,CAAC,CAAC,OAAO,CAAC,YAAY,CAAC,CAAA;QACtC,CAAC,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA"}
package/esm/utils.d.ts DELETED
@@ -1,25 +0,0 @@
1
- /// <reference path="server-response-extensions.d.ts" />
2
- /// <reference path="incoming-message-extensions.d.ts" />
3
- /// <reference types="node/http.js" />
4
- import type { IncomingMessage, ServerResponse } from 'http';
5
- import type { CorsOptions } from './models/cors-options.js';
6
- /**
7
- * A collection of various HTTP API related utilities
8
- */
9
- export declare class Utils {
10
- readPostBodyRaw(incomingMessage: IncomingMessage): Promise<string>;
11
- /**
12
- * Reads the post's body and returns a promise with a parsed value
13
- * @param incomingMessage The incoming message instance
14
- * @returns the parsed object from the post body
15
- */
16
- readPostBody<T>(incomingMessage: IncomingMessage): Promise<T>;
17
- /**
18
- * Adds the specified CORS headers to the response
19
- * @param options The CORS Options object
20
- * @param incomingMessage The incoming message instance
21
- * @param serverResponse The outgoing response instance
22
- */
23
- addCorsHeaders(options: CorsOptions, incomingMessage: IncomingMessage, serverResponse: ServerResponse): void;
24
- }
25
- //# sourceMappingURL=utils.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":";;;AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,MAAM,CAAA;AAE3D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAA;AAE3D;;GAEG;AACH,qBACa,KAAK;IACH,eAAe,CAAC,eAAe,EAAE,eAAe;IAuB7D;;;;OAIG;IACU,YAAY,CAAC,CAAC,EAAE,eAAe,EAAE,eAAe,GAAG,OAAO,CAAC,CAAC,CAAC;IAM1E;;;;;OAKG;IACI,cAAc,CAAC,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,eAAe,EAAE,cAAc,EAAE,cAAc;CAkB7G"}
package/esm/utils.js DELETED
@@ -1,70 +0,0 @@
1
- var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
- var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
- if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
- else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
- return c > 3 && r && Object.defineProperty(target, key, r), r;
6
- };
7
- import { Injectable } from '@furystack/inject';
8
- /**
9
- * A collection of various HTTP API related utilities
10
- */
11
- let Utils = class Utils {
12
- async readPostBodyRaw(incomingMessage) {
13
- if (!incomingMessage.readable) {
14
- throw Error('Incoming message is not readable');
15
- }
16
- let body = '';
17
- await new Promise((resolve, reject) => {
18
- incomingMessage.on('readable', () => {
19
- const data = incomingMessage.read();
20
- if (data) {
21
- body += data;
22
- }
23
- });
24
- incomingMessage.on('end', () => {
25
- resolve();
26
- });
27
- incomingMessage.on('error', (err) => {
28
- reject(err);
29
- });
30
- });
31
- return body;
32
- }
33
- /**
34
- * Reads the post's body and returns a promise with a parsed value
35
- * @param incomingMessage The incoming message instance
36
- * @returns the parsed object from the post body
37
- */
38
- async readPostBody(incomingMessage) {
39
- const body = incomingMessage.postBody || JSON.parse(await this.readPostBodyRaw(incomingMessage));
40
- incomingMessage.postBody = body;
41
- return body;
42
- }
43
- /**
44
- * Adds the specified CORS headers to the response
45
- * @param options The CORS Options object
46
- * @param incomingMessage The incoming message instance
47
- * @param serverResponse The outgoing response instance
48
- */
49
- addCorsHeaders(options, incomingMessage, serverResponse) {
50
- if (incomingMessage.headers &&
51
- incomingMessage.headers.origin !== incomingMessage.headers.host &&
52
- options.origins.some((origin) => origin === incomingMessage.headers.origin)) {
53
- serverResponse.setHeader('Access-Control-Allow-Origin', incomingMessage.headers.origin);
54
- if (options.credentials) {
55
- serverResponse.setHeader('Access-Control-Allow-Credentials', 'true');
56
- }
57
- if (options.headers && options.headers.length) {
58
- serverResponse.setHeader('Access-Control-Allow-Headers', options.headers.join(', '));
59
- }
60
- if (options.methods && options.methods.length) {
61
- serverResponse.setHeader('Access-Control-Allow-Methods', options.methods.join(', '));
62
- }
63
- }
64
- }
65
- };
66
- Utils = __decorate([
67
- Injectable({ lifetime: 'transient' })
68
- ], Utils);
69
- export { Utils };
70
- //# sourceMappingURL=utils.js.map
package/esm/utils.js.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":";;;;;;AACA,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAA;AAG9C;;GAEG;AAEI,IAAM,KAAK,GAAX,MAAM,KAAK;IACT,KAAK,CAAC,eAAe,CAAC,eAAgC;QAC3D,IAAI,CAAC,eAAe,CAAC,QAAQ,EAAE,CAAC;YAC9B,MAAM,KAAK,CAAC,kCAAkC,CAAC,CAAA;QACjD,CAAC;QAED,IAAI,IAAI,GAAG,EAAE,CAAA;QACb,MAAM,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YAC1C,eAAe,CAAC,EAAE,CAAC,UAAU,EAAE,GAAG,EAAE;gBAClC,MAAM,IAAI,GAAG,eAAe,CAAC,IAAI,EAAE,CAAA;gBACnC,IAAI,IAAI,EAAE,CAAC;oBACT,IAAI,IAAI,IAAI,CAAA;gBACd,CAAC;YACH,CAAC,CAAC,CAAA;YACF,eAAe,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE;gBAC7B,OAAO,EAAE,CAAA;YACX,CAAC,CAAC,CAAA;YACF,eAAe,CAAC,EAAE,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE;gBAClC,MAAM,CAAC,GAAG,CAAC,CAAA;YACb,CAAC,CAAC,CAAA;QACJ,CAAC,CAAC,CAAA;QACF,OAAO,IAAI,CAAA;IACb,CAAC;IAED;;;;OAIG;IACI,KAAK,CAAC,YAAY,CAAI,eAAgC;QAC3D,MAAM,IAAI,GAAG,eAAe,CAAC,QAAQ,IAAI,IAAI,CAAC,KAAK,CAAC,MAAM,IAAI,CAAC,eAAe,CAAC,eAAe,CAAC,CAAC,CAAA;QAChG,eAAe,CAAC,QAAQ,GAAG,IAAI,CAAA;QAC/B,OAAO,IAAI,CAAA;IACb,CAAC;IAED;;;;;OAKG;IACI,cAAc,CAAC,OAAoB,EAAE,eAAgC,EAAE,cAA8B;QAC1G,IACE,eAAe,CAAC,OAAO;YACvB,eAAe,CAAC,OAAO,CAAC,MAAM,KAAK,eAAe,CAAC,OAAO,CAAC,IAAI;YAC/D,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,KAAK,eAAe,CAAC,OAAO,CAAC,MAAM,CAAC,EAC3E,CAAC;YACD,cAAc,CAAC,SAAS,CAAC,6BAA6B,EAAE,eAAe,CAAC,OAAO,CAAC,MAAgB,CAAC,CAAA;YACjG,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC;gBACxB,cAAc,CAAC,SAAS,CAAC,kCAAkC,EAAE,MAAM,CAAC,CAAA;YACtE,CAAC;YACD,IAAI,OAAO,CAAC,OAAO,IAAI,OAAO,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC;gBAC9C,cAAc,CAAC,SAAS,CAAC,8BAA8B,EAAE,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAA;YACtF,CAAC;YACD,IAAI,OAAO,CAAC,OAAO,IAAI,OAAO,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC;gBAC9C,cAAc,CAAC,SAAS,CAAC,8BAA8B,EAAE,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAA;YACtF,CAAC;QACH,CAAC;IACH,CAAC;CACF,CAAA;AA3DY,KAAK;IADjB,UAAU,CAAC,EAAE,QAAQ,EAAE,WAAW,EAAE,CAAC;GACzB,KAAK,CA2DjB"}
@@ -1,42 +0,0 @@
1
- import { IncomingMessage } from 'http'
2
- import './incoming-message-extensions'
3
- import { Socket } from 'net'
4
- import { describe, it, expect } from 'vitest'
5
-
6
- describe('IncomingMessage extensions', () => {
7
- describe('readPostBody', () => {
8
- it('Should be extended', () => {
9
- const socket = new Socket()
10
- const msg = new IncomingMessage(socket)
11
- expect(typeof msg.readPostBody).toBe('function')
12
- })
13
-
14
- it('Should read the raw post body', async () => {
15
- const exampleValue = { value: Math.random().toString() }
16
- const socket = new Socket()
17
- const msg = new IncomingMessage(socket)
18
- setTimeout(() => {
19
- msg.read = () => JSON.stringify(exampleValue)
20
- msg.emit('readable')
21
- msg.emit('end')
22
- }, 10)
23
-
24
- const result = await msg.readPostBodyRaw()
25
- expect(result).toEqual(JSON.stringify(exampleValue))
26
- })
27
-
28
- it('Should read the post body', async () => {
29
- const exampleValue = { value: Math.random().toString() }
30
- const socket = new Socket()
31
- const msg = new IncomingMessage(socket)
32
- setTimeout(() => {
33
- msg.read = () => JSON.stringify(exampleValue)
34
- msg.emit('readable')
35
- msg.emit('end')
36
- }, 10)
37
-
38
- const result = await msg.readPostBody()
39
- expect(result).toEqual(exampleValue)
40
- })
41
- })
42
- })
package/src/utils.ts DELETED
@@ -1,68 +0,0 @@
1
- import type { IncomingMessage, ServerResponse } from 'http'
2
- import { Injectable } from '@furystack/inject'
3
- import type { CorsOptions } from './models/cors-options.js'
4
-
5
- /**
6
- * A collection of various HTTP API related utilities
7
- */
8
- @Injectable({ lifetime: 'transient' })
9
- export class Utils {
10
- public async readPostBodyRaw(incomingMessage: IncomingMessage) {
11
- if (!incomingMessage.readable) {
12
- throw Error('Incoming message is not readable')
13
- }
14
-
15
- let body = ''
16
- await new Promise<void>((resolve, reject) => {
17
- incomingMessage.on('readable', () => {
18
- const data = incomingMessage.read()
19
- if (data) {
20
- body += data
21
- }
22
- })
23
- incomingMessage.on('end', () => {
24
- resolve()
25
- })
26
- incomingMessage.on('error', (err) => {
27
- reject(err)
28
- })
29
- })
30
- return body
31
- }
32
-
33
- /**
34
- * Reads the post's body and returns a promise with a parsed value
35
- * @param incomingMessage The incoming message instance
36
- * @returns the parsed object from the post body
37
- */
38
- public async readPostBody<T>(incomingMessage: IncomingMessage): Promise<T> {
39
- const body = incomingMessage.postBody || JSON.parse(await this.readPostBodyRaw(incomingMessage))
40
- incomingMessage.postBody = body
41
- return body
42
- }
43
-
44
- /**
45
- * Adds the specified CORS headers to the response
46
- * @param options The CORS Options object
47
- * @param incomingMessage The incoming message instance
48
- * @param serverResponse The outgoing response instance
49
- */
50
- public addCorsHeaders(options: CorsOptions, incomingMessage: IncomingMessage, serverResponse: ServerResponse) {
51
- if (
52
- incomingMessage.headers &&
53
- incomingMessage.headers.origin !== incomingMessage.headers.host &&
54
- options.origins.some((origin) => origin === incomingMessage.headers.origin)
55
- ) {
56
- serverResponse.setHeader('Access-Control-Allow-Origin', incomingMessage.headers.origin as string)
57
- if (options.credentials) {
58
- serverResponse.setHeader('Access-Control-Allow-Credentials', 'true')
59
- }
60
- if (options.headers && options.headers.length) {
61
- serverResponse.setHeader('Access-Control-Allow-Headers', options.headers.join(', '))
62
- }
63
- if (options.methods && options.methods.length) {
64
- serverResponse.setHeader('Access-Control-Allow-Methods', options.methods.join(', '))
65
- }
66
- }
67
- }
68
- }