@pbvision/fastify-firestore-service 0.0.9 → 0.0.11

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pbvision/fastify-firestore-service",
3
- "version": "0.0.9",
3
+ "version": "0.0.11",
4
4
  "description": "Web Framework using Fastify and Firestore ORM",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",
@@ -46,8 +46,7 @@
46
46
  "@sentry/node": "^7.91.0",
47
47
  "fastify": "^4.10.0",
48
48
  "fastify-plugin": "^4.5.1",
49
- "got": "^14.0.0",
50
- "pino": "8.17.2",
49
+ "node-fetch": "^3.3.2",
51
50
  "word-wrap": "^1.2.3"
52
51
  },
53
52
  "devDependencies": {
@@ -61,6 +60,7 @@
61
60
  "eslint-config-standard": "17.1.0",
62
61
  "eslint-import-resolver-webpack": "^0.13.8",
63
62
  "eslint-plugin-import": "^2.22.0",
63
+ "eslint-plugin-n": "^16.6.2",
64
64
  "eslint-plugin-node": "^11.1.0",
65
65
  "eslint-plugin-promise": "^6.0.0",
66
66
  "eslint-plugin-standard": "^5.0.0",
@@ -69,6 +69,7 @@
69
69
  "license-webpack-plugin": "^4.0.2",
70
70
  "nodemon": "^3.0.2",
71
71
  "standard": "^17.1.0",
72
+ "superagent": "^8",
72
73
  "superagent-defaults": "^0.1.14",
73
74
  "supertest": "^6.3.3",
74
75
  "tui-jsdoc-template": "^1.2.2",
package/src/api/api.js CHANGED
@@ -3,7 +3,7 @@ import querystring from 'node:querystring'
3
3
 
4
4
  import S from '@pbvision/schema'
5
5
 
6
- import gotWrapper from '../got-wrapper.js'
6
+ import fetchWrapper from '../fetch-wrapper.js'
7
7
 
8
8
  import {
9
9
  BadRequestException,
@@ -117,15 +117,6 @@ class API {
117
117
  return undefined
118
118
  }
119
119
 
120
- /**
121
- * Returns the full HTTP path to this API.
122
- * @param {String} service The service this API belongs to.
123
- * @public
124
- */
125
- static getFullPath (service) {
126
- return `/${service}${this.PATH}`
127
- }
128
-
129
120
  /* istanbul ignore next */
130
121
  /**
131
122
  * A human-readable description of what this API does. It is only used when
@@ -362,8 +353,7 @@ class API {
362
353
  headers,
363
354
  method,
364
355
  url,
365
- searchParams: qsParams,
366
- throwHttpErrors: false
356
+ qsParams
367
357
  }
368
358
  // istanbul ignore if
369
359
  if (body) {
@@ -373,19 +363,22 @@ class API {
373
363
  request.json = body
374
364
  }
375
365
  }
376
- const resp = gotWrapper(request)
377
- const resolvedResp = await resp
366
+ const resp = await fetchWrapper(request)
378
367
  const ret = {
379
- code: resolvedResp.statusCode
368
+ code: resp.status,
369
+ isOk: resp.status >= 200 && resp.status <= 299
380
370
  }
381
- ret.isOk = (ret.code === 200)
382
371
  const respBody = await resp.text()
383
372
  if (respBody) {
384
- try {
385
- ret.data = JSON.parse(respBody)
386
- } catch (e) {
387
- // istanbul ignore next
388
- throw new Error(`JSON.parse failed on ${respBody} with reason ${e}.`)
373
+ if (resp.headers.get('content-type')?.startsWith('application/json')) {
374
+ try {
375
+ ret.data = JSON.parse(respBody)
376
+ } catch (e) {
377
+ // istanbul ignore next
378
+ throw new Error(`JSON.parse failed on ${respBody} with reason ${e}.`)
379
+ }
380
+ } else {
381
+ ret.data = respBody
389
382
  }
390
383
  }
391
384
  return ret
@@ -482,14 +475,14 @@ class API {
482
475
  * @package
483
476
  */
484
477
  static registerAPI (registrar) {
485
- const { app, service } = registrar
478
+ const { app } = registrar
486
479
  if (this.setup) {
487
480
  app.register(this.setup)
488
481
  }
489
482
  const cls = this
490
483
  app.register(async (fastify) => {
491
484
  try {
492
- await cls.registerAPIWithFastify(fastify, cls.getFullPath(service))
485
+ await cls.registerAPIWithFastify(fastify, cls.PATH)
493
486
  } catch (e) {
494
487
  if (e instanceof assert.AssertionError) {
495
488
  e.message = `${cls.name}: ${e.message}`
@@ -502,7 +495,7 @@ class API {
502
495
  if (this.CORS_ORIGIN) {
503
496
  // create an OPTIONS method API to support CORS preflight requests from
504
497
  // browsers
505
- const path = cls.getFullPath(service)
498
+ const path = cls.PATH
506
499
  const { params, querystring } = cls.swaggerSchema
507
500
  const schema = { hide: true, params, querystring }
508
501
  app.options(path, { schema: pruneUndefined(schema) },
@@ -0,0 +1,35 @@
1
+ import querystring from 'node:querystring'
2
+ import zlib from 'node:zlib'
3
+
4
+ import realFetch from 'node-fetch'
5
+
6
+ async function fetchWrapper (options, mockedFetch) {
7
+ const { compress = true, method = 'POST', url, qsParams, json } = options
8
+ let { body, headers } = options
9
+ headers = { ...headers } // copy the headers before we change them
10
+
11
+ // compress the body using brotli
12
+ if (json) {
13
+ headers['content-type'] = 'application/json'
14
+ body = JSON.stringify(options.json)
15
+ }
16
+ if (body && compress) {
17
+ body = zlib.brotliCompressSync(body)
18
+ headers['content-encoding'] = 'br'
19
+ }
20
+
21
+ // istanbul ignore next
22
+ const fetch = mockedFetch ?? fetchWrapper.__mock ?? realFetch
23
+
24
+ // compute the full URL including search params
25
+ let fullURL = url
26
+ if (qsParams) {
27
+ const qsStr = querystring.stringify(qsParams)
28
+ if (qsStr) {
29
+ fullURL += `?${qsStr}`
30
+ }
31
+ }
32
+ return fetch(fullURL, { body, headers, method, compress: false })
33
+ }
34
+
35
+ export default fetchWrapper
package/test/base-test.js CHANGED
@@ -48,23 +48,34 @@ class BaseAppTest extends BaseTest {
48
48
  }
49
49
  }
50
50
 
51
+ function makeHeadersObj (headers) {
52
+ return {
53
+ get: name => headers[name]
54
+ }
55
+ }
56
+
51
57
  // the promise input conveniently matches the promise produced by supertest
52
58
  // so you can pass the output of app.post(), etc. as the promise here as is
53
59
  function makeGotMockValueFromPromise (promise) {
54
60
  const mockValue = new Promise(resolve => {
55
61
  promise.then(desiredHttpResponse => {
56
62
  let body = desiredHttpResponse.text || desiredHttpResponse.body || ''
63
+ const headers = {}
57
64
  if (typeof body !== 'string') {
58
65
  body = JSON.stringify(body)
66
+ headers['content-type'] = 'application/json'
59
67
  }
60
- mockValue.text = async () => body
61
- resolve({ statusCode: desiredHttpResponse.status || 200 })
68
+ resolve({
69
+ status: desiredHttpResponse.status || 200,
70
+ headers: makeHeadersObj(headers),
71
+ text: async () => body
72
+ })
62
73
  })
63
74
  })
64
75
  return mockValue
65
76
  }
66
77
 
67
- function makeGotMockValue (body, statusCode, callback) {
78
+ function makeGotMockValue (body, status, callback) {
68
79
  const mockValue = new Promise(resolve => {
69
80
  // setTimeout is used so that this promise does not synchronously resolve
70
81
  // because unmocked got will NEVER return synchronously. This ensures
@@ -73,21 +84,23 @@ function makeGotMockValue (body, statusCode, callback) {
73
84
  // instead of only rejecting later when await'ed).
74
85
  // https://github.com/facebook/jest/issues/6028 (since jest 21.x)
75
86
  setTimeout(() => {
76
- mockValue.text = async () => {
77
- if (callback) {
78
- callback()
79
- }
80
- if (typeof body === 'string') {
81
- return body
87
+ const headers = {}
88
+ resolve({
89
+ status,
90
+ headers: makeHeadersObj(headers),
91
+ text: async () => {
92
+ if (callback) {
93
+ callback()
94
+ }
95
+ if (typeof body === 'string') {
96
+ return body
97
+ }
98
+ headers['content-type'] = 'application/json'
99
+ return JSON.stringify(body)
82
100
  }
83
- return JSON.stringify(body)
84
- }
85
- resolve({ statusCode })
101
+ })
86
102
  }, 0)
87
103
  })
88
- mockValue.text = async () => {
89
- throw new Error('cannot use text() before calling await() on the response')
90
- }
91
104
  return mockValue
92
105
  }
93
106
 
@@ -109,11 +122,12 @@ function mockGot () {
109
122
  */
110
123
  gotMock.mockRespWithCallback = (...callbacks) => {
111
124
  gotMock.mockImplementation(request => {
125
+ const { url, ...options } = request
112
126
  for (const callback of callbacks) {
113
127
  const desiredHTTPResponse = callback(request)
114
128
  if (desiredHTTPResponse === true) {
115
129
  const unmockedGot = jest.requireActual('../src/got')
116
- return unmockedGot(request)
130
+ return unmockedGot(url, options)
117
131
  }
118
132
  if (desiredHTTPResponse) {
119
133
  if (desiredHTTPResponse.then) {
@@ -1,34 +0,0 @@
1
- import zlib from 'node:zlib'
2
-
3
- import realGot from 'got'
4
-
5
- function gotWrapper (options, mockedGot) {
6
- options = {
7
- decompress: true,
8
- ...options
9
- }
10
- if (options.compress) {
11
- // make a copy of the headers obj before we make changes to it
12
- const headers = {
13
- ...options.headers
14
- }
15
- options.headers = headers
16
- if (options.body) {
17
- options.body = zlib.brotliCompressSync(options.body)
18
- }
19
- if (options.json) {
20
- headers['content-type'] = 'application/json'
21
- options.body = zlib.brotliCompressSync(JSON.stringify(options.json))
22
- delete options.json
23
- }
24
-
25
- if (options.body) {
26
- headers['content-encoding'] = 'br'
27
- }
28
- }
29
- // istanbul ignore next
30
- const got = mockedGot ?? gotWrapper.__mocked_got ?? realGot
31
- return got(options)
32
- }
33
-
34
- export default gotWrapper