beavuck-time 2.2.0 → 2.3.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/.env CHANGED
@@ -1,21 +1,21 @@
1
1
  # CORS
2
2
  ## URL of this API
3
- HOST_URL=http://localhost:3000
3
+ BEAVUCK_TIME_HOST_URL=http://localhost:3000
4
4
  ## To allow requests from any origin, include * (not recommended)
5
- TRUSTED_ORIGINS=http://localhost:8477
5
+ BEAVUCK_TIME_TRUSTED_ORIGINS=http://localhost:8477
6
6
 
7
7
  # Server
8
8
  ## Port of this API: in a container, this is the internal port -- outside of a container, this is the external port. Default is 3000
9
- API_PORT=3000
9
+ BEAVUCK_TIME_API_PORT=3000
10
10
 
11
11
  # Rate limiting
12
12
  ## Requests per minute for each IP address. If not a strictly positive, "no limit". Default is -1
13
- RATE_LIMIT=-1
13
+ BEAVUCK_TIME_RATE_LIMIT=-1
14
14
 
15
15
  # Logging
16
16
  ## Level of detail in logs: error, warn, info, http, verbose, debug, silly. Default is info
17
- LOG_LEVEL=info
17
+ BEAVUCK_TIME_LOG_LEVEL=info
18
18
  ## Maximum number of logs to keep. This can be a number of files or number of days. If using days, add 'd' as the suffix. Default is 64
19
- MAX_LOG_FILES=64
19
+ BEAVUCK_TIME_MAX_LOG_FILES=64
20
20
  ## Maximum size of the file after which it will rotate. This can be a number of bytes, or units of kb, mb, and gb. If using the units, add 'k', 'm', or 'g' as the suffix. The units need to directly follow the number. Default is 1m
21
- MAX_SIZE_LOG_FILES=1m
21
+ BEAVUCK_TIME_MAX_SIZE_LOG_FILES=1m
package/.env.test CHANGED
@@ -9,22 +9,22 @@ DOTENV_PUBLIC_KEY_TEST="02d5c6b7efe5269d1fd3626adac3338f0971e58e2555e8e27c53a7e7
9
9
 
10
10
  # CORS
11
11
  ## URL of this API
12
- HOST_URL=encrypted:BG5D1BHPO/UlcKh8c1s4s2YDqFQ0yIiduOKDHAsc9GNlm4/BRSPwxHNka+jJopZp++w+nfARNbSJwdgBoZvlbjujb/E8uJ2CX4erxmh1j+HBpmri2ocBa04NnJodMojPkcuxJqP3RSKfh61u+Fo1oTpCoZ8yYg==
12
+ BEAVUCK_TIME_HOST_URL=encrypted:BG5D1BHPO/UlcKh8c1s4s2YDqFQ0yIiduOKDHAsc9GNlm4/BRSPwxHNka+jJopZp++w+nfARNbSJwdgBoZvlbjujb/E8uJ2CX4erxmh1j+HBpmri2ocBa04NnJodMojPkcuxJqP3RSKfh61u+Fo1oTpCoZ8yYg==
13
13
  ## To allow requests from any origin, include * (not recommended)
14
- TRUSTED_ORIGINS=encrypted:BE1fOSnJ8rnMU+A1orA9/Ujee4ypigUywnZ9g85l74XiNxEDoOdQmAIiSjYut+y/Y5b3VkqF+vBAgP++LYCMGTPoANWHgscZ+DAzsgqeFjsFp9WTKuWXxTeauI3HzLWI3v44o67oSZ1myWk9wsvc9WWwN4plrA==
14
+ BEAVUCK_TIME_TRUSTED_ORIGINS=encrypted:BE1fOSnJ8rnMU+A1orA9/Ujee4ypigUywnZ9g85l74XiNxEDoOdQmAIiSjYut+y/Y5b3VkqF+vBAgP++LYCMGTPoANWHgscZ+DAzsgqeFjsFp9WTKuWXxTeauI3HzLWI3v44o67oSZ1myWk9wsvc9WWwN4plrA==
15
15
 
16
16
  # Server
17
17
  ## Port of this API: in a container, this is the internal port -- outside of a container, this is the external port. Default is 3000
18
- API_PORT=encrypted:BGw4+UyXhxyfMzdxNjZBzTN/akEDL77i+XDqNRZA6w9ed7GYrQyYvuvEho+4VYir9T014sgLYRNeS09cR2mJV8pjyYWzHYhdXQyDeihUcNbLvIpfsZu7KH+aIeHaPx5YIRGJDSM=
18
+ BEAVUCK_TIME_API_PORT=encrypted:BGw4+UyXhxyfMzdxNjZBzTN/akEDL77i+XDqNRZA6w9ed7GYrQyYvuvEho+4VYir9T014sgLYRNeS09cR2mJV8pjyYWzHYhdXQyDeihUcNbLvIpfsZu7KH+aIeHaPx5YIRGJDSM=
19
19
 
20
20
  # Rate limiting
21
21
  ## Requests per minute for each IP address. If not a strictly positive, "no limit". Default is -1
22
- RATE_LIMIT=encrypted:BD1uTBsjTAjd+GYlZGM0S5DVCkmiOSEouDmLQj9XztlHpP2u8KyHxByIzUed8qkJXzbcf8zvTsANzY44V91m9UZZqXeZDOQlCqmn+ZpzmPDSA3VMUPzIdUpYF9DD7rWIgxvF
22
+ BEAVUCK_TIME_RATE_LIMIT=encrypted:BD1uTBsjTAjd+GYlZGM0S5DVCkmiOSEouDmLQj9XztlHpP2u8KyHxByIzUed8qkJXzbcf8zvTsANzY44V91m9UZZqXeZDOQlCqmn+ZpzmPDSA3VMUPzIdUpYF9DD7rWIgxvF
23
23
 
24
24
  # Logging
25
25
  ## Level of detail in logs: error, warn, info, http, verbose, debug, silly. Default is info
26
- LOG_LEVEL=encrypted:BGfqcxa9XJrMBk7U9QqkbfnXimot5dnz0kRroclEwtsY0JVc8VCw35idcSKpdS3jhCIxg0enNCZEbVMFMt6Q37yvYlIUqCKqk229moGTDSkQ2V/38pwnmzMS1LD/+nUH2yyFpWA=
26
+ BEAVUCK_TIME_LOG_LEVEL=encrypted:BGfqcxa9XJrMBk7U9QqkbfnXimot5dnz0kRroclEwtsY0JVc8VCw35idcSKpdS3jhCIxg0enNCZEbVMFMt6Q37yvYlIUqCKqk229moGTDSkQ2V/38pwnmzMS1LD/+nUH2yyFpWA=
27
27
  ## Maximum number of logs to keep. This can be a number of files or number of days. If using days, add 'd' as the suffix. Default is 64
28
- MAX_LOG_FILES=encrypted:BET35n9Sfhqkdahr+JCwV/1sfX5zCE2FmH4lFFOi/WUhg9Wi+DIm2NH2WqfHcYIiWcRRnqpr3f2gnXwLsmRMcSydk7gxuERgA+mn0F2ygzbjTQUw+6l3snLgHKskKTuuA1rO
28
+ BEAVUCK_TIME_MAX_LOG_FILES=encrypted:BET35n9Sfhqkdahr+JCwV/1sfX5zCE2FmH4lFFOi/WUhg9Wi+DIm2NH2WqfHcYIiWcRRnqpr3f2gnXwLsmRMcSydk7gxuERgA+mn0F2ygzbjTQUw+6l3snLgHKskKTuuA1rO
29
29
  ## Maximum size of the file after which it will rotate. This can be a number of bytes, or units of kb, mb, and gb. If using the units, add 'k', 'm', or 'g' as the suffix. The units need to directly follow the number. Default is 1m
30
- MAX_SIZE_LOG_FILES=encrypted:BJLXlbtMDxs5di0o+FRr6Im9gYs3GayVwjWomavHzCychYr9JZyOyMTrBN8YrusYoHklvEoHuGfIkUB1m8ErDEl8eJlJvaPZr30+NLPujWSrVwb1B9v8lBon2TfrDQulqSX6
30
+ BEAVUCK_TIME_MAX_SIZE_LOG_FILES=encrypted:BJLXlbtMDxs5di0o+FRr6Im9gYs3GayVwjWomavHzCychYr9JZyOyMTrBN8YrusYoHklvEoHuGfIkUB1m8ErDEl8eJlJvaPZr30+NLPujWSrVwb1B9v8lBon2TfrDQulqSX6
@@ -83,20 +83,20 @@ time:
83
83
  - 'SOME_PORT_NUMBER:3000'
84
84
  # HOST_PORT:CONTAINER_PORT (Since we are in a container, CONTAINER_PORT corresponds to the API_PORT variable below)
85
85
  environment:
86
- - HOST_URL: https://time-api.example.com
87
- # HOST_URL: That API's URL. Essential for CORS config.
88
- - TRUSTED_ORIGINS: https://my.app.com,https://my-other.app.com
89
- # TRUSTED_ORIGINS: To allow requests from any origin, include * (not recommended). If empty, will only allow requests from the HOST_URL's origin. Defaults to the HOST_URL's origin
90
- - API_PORT: 3000
91
- # API_PORT: Optional. Internal port when in a container. Defaults to 3000
92
- - RATE_LIMIT: 100
93
- # RATE_LIMIT: Optional. Max allowed number of requests per minute for each IP address. If negative or 0, no limit. Defaults to no limit
94
- - LOG_LEVEL: info
95
- # LOG_LEVEL: Optional. Logging levels include error, warn, info, http, verbose, debug, silly. Defaults to info
96
- - MAX_LOG_FILES: 64
97
- # MAX_LOG_FILES: Optional. Maximum number of logs to keep. This can be a number of files or number of days. If using days, add 'd' as the suffix. Default is 64
98
- - MAX_SIZE_LOG_FILES: 1m
99
- # MAX_SIZE_LOG_FILES: Optional. Maximum size of the file after which it will rotate. This can be a number of bytes, or units of kb, mb, and gb. If using the units, add 'k', 'm', or 'g' as the suffix. The units need to directly follow the number. Default is 1m
86
+ - BEAVUCK_TIME_HOST_URL: https://time-api.example.com
87
+ # BEAVUCK_TIME_HOST_URL: That API's URL. Essential for CORS config.
88
+ - BEAVUCK_TIME_TRUSTED_ORIGINS: https://my.app.com,https://my-other.app.com
89
+ # BEAVUCK_TIME_TRUSTED_ORIGINS: To allow requests from any origin, include * (not recommended). If empty, will only allow requests from the HOST_URL's origin. Defaults to the HOST_URL's origin
90
+ - BEAVUCK_TIME_API_PORT: 3000
91
+ # BEAVUCK_TIME_API_PORT: Optional. Internal port when in a container. Defaults to 3000
92
+ - BEAVUCK_TIME_RATE_LIMIT: 100
93
+ # BEAVUCK_TIME_RATE_LIMIT: Optional. Max allowed number of requests per minute for each IP address. If negative or 0, no limit. Defaults to no limit
94
+ - BEAVUCK_TIME_LOG_LEVEL: info
95
+ # BEAVUCK_TIME_LOG_LEVEL: Optional. Logging levels include error, warn, info, http, verbose, debug, silly. Defaults to info
96
+ - BEAVUCK_TIME_MAX_LOG_FILES: 64
97
+ # BEAVUCK_TIME_MAX_LOG_FILES: Optional. Maximum number of logs to keep. This can be a number of files or number of days. If using days, add 'd' as the suffix. Default is 64
98
+ - BEAVUCK_TIME_MAX_SIZE_LOG_FILES: 1m
99
+ # BEAVUCK_TIME_MAX_SIZE_LOG_FILES: Optional. Maximum size of the file after which it will rotate. This can be a number of bytes, or units of kb, mb, and gb. If using the units, add 'k', 'm', or 'g' as the suffix. The units need to directly follow the number. Default is 1m
100
100
  ```
101
101
 
102
102
  Here's the simple docker compose file I used to test this service locally:
@@ -108,9 +108,9 @@ services:
108
108
  ports:
109
109
  - '3000:3000'
110
110
  environment:
111
- HOST_URL: http://127.0.0.1:3000
112
- TRUSTED_ORIGINS: http://127.0.0.1:8000,http://localhost:8000
113
- LOG_LEVEL: debug
111
+ BEAVUCK_TIME_HOST_URL: http://127.0.0.1:3000
112
+ BEAVUCK_TIME_TRUSTED_ORIGINS: http://127.0.0.1:8000,http://localhost:8000
113
+ BEAVUCK_TIME_LOG_LEVEL: debug
114
114
  ```
115
115
 
116
116
  When you're ready, just run your services with:
@@ -145,15 +145,15 @@ variable.
145
145
 
146
146
  When you use the API, keep in mind what roles these headers play:
147
147
 
148
- | `"Origin:"` | `"Referrer:"`* | Result |
149
- | -------------------------------------------- | ------------------------------ | ------ |
150
- | Defined and API `TRUSTED_ORIGINS` set to `*` | Whatever | ✅ |
151
- | Trusted | Whatever | ✅ |
152
- | Same as this API's host | Whatever | ✅ |
153
- | Not defined | Same as this API's host | ✅ |
154
- | Defined and not trusted | Whatever | 🛑 |
155
- | Not defined | Not defined | 🛑 |
156
- | Not defined or not trusted | Different from this API's host | 🛑 |
148
+ | `"Origin:"` | `"Referrer:"`* | Result |
149
+ | --------------------------------------------------------- | ------------------------------ | ------ |
150
+ | Defined and API `BEAVUCK_TIME_TRUSTED_ORIGINS` set to `*` | Whatever | ✅ |
151
+ | Trusted | Whatever | ✅ |
152
+ | Same as this API's host | Whatever | ✅ |
153
+ | Not defined | Same as this API's host | ✅ |
154
+ | Defined and not trusted | Whatever | 🛑 |
155
+ | Not defined | Not defined | 🛑 |
156
+ | Not defined or not trusted | Different from this API's host | 🛑 |
157
157
  * AKA `Referer` (sic).
158
158
  ---
159
159
 
package/README.md CHANGED
@@ -49,14 +49,15 @@ Dockerized for easy deployment and scaling.
49
49
  ## 🔍 Where
50
50
 
51
51
  The code lives on [GitLab](https://gitlab.com/beavuck-services/time),
52
- and the Docker image is hosted on [Docker Hub](https://hub.docker.com/r/beavuck/time)
52
+ the Docker image is hosted on [Docker Hub](https://hub.docker.com/r/beavuck/time),
53
+ and it's also stored as a package on [NPM](https://www.npmjs.com/package/beavuck-time)
53
54
 
54
55
  ### 🦊 GitLab
55
56
 
56
- You can find the code on GitLab, where, once you have read the [CONTRIBUTING.md](CONTRIBUTING.md) file, you can also
57
+ You can find the code on GitLab, where, once you have read the [CONTRIBUTING.md](https://gitlab.com/beavuck-services/time/-/blob/main/CONTRIBUTING.md?ref_type=heads) file, you can also
57
58
  create issues and merge requests.
58
59
 
59
- Feel free to fork the repo and make your own changes at will, as per the [UNLICENSE](UNLICENSE).
60
+ Feel free to fork the repo and make your own changes at will, as per the [UNLICENSE](https://gitlab.com/beavuck-services/time/-/blob/main/UNLICENSE?ref_type=heads).
60
61
 
61
62
  ### 🐳 Docker Hub
62
63
 
@@ -68,12 +69,50 @@ When the time comes to go to production, to protect yourself from surprise break
68
69
  specific minor version tags, such as `beavuck/time:2.0` : those will not get breaking changes, but they will get
69
70
  security updates and bug fixes while they're active.
70
71
 
72
+ ### Ⓝ NPM
73
+
74
+ You can also use this service directly via npm:
75
+
76
+ ```bash
77
+ npm install beavuck-time
78
+ ```
79
+
80
+ #### Programmatically
81
+
82
+ Then, if you want to run this service programmatically in your Node.js project:
83
+
84
+ ```js
85
+ import { startServer } from 'beavuck-time'
86
+
87
+ startServer({
88
+ port: 3000,
89
+ hostUrl: 'https://time-api.example.com',
90
+ trustedOrigins: 'https://my.app.com,https://my-other.app.com'
91
+ })
92
+ ```
93
+
94
+ You can rely on environment variables (BEAVUCK_TIME_HOST_URL, etc.) instead of passing an options object. Refer to
95
+ the docker Compose example below to see an exhaustive list of available environment variables and what they do.
96
+
97
+ #### CLI
98
+
99
+ To run this service directly in your command line interface, just run:
100
+
101
+ ```bash
102
+ npx beavuck-time
103
+ ```
104
+
105
+ Refer to the docker Compose example below to see an exhaustive list of available environment variables and what they do.
106
+
71
107
  ---
72
108
 
73
109
  ## ⚙️ Usage
74
110
 
75
111
  ### 🪧 Set up (docker-compose example)
76
112
 
113
+ (The section below supposes you're using a Docker image. If using the npm package, you can set those environment variable
114
+ on the host directly, instead of doing so in the container like detailed below)
115
+
77
116
  To run the service in a docker-compose environment, add this in your `docker-compose.yml`'s services section:
78
117
 
79
118
  ```yaml
@@ -83,20 +122,20 @@ time:
83
122
  - 'SOME_PORT_NUMBER:3000'
84
123
  # HOST_PORT:CONTAINER_PORT (Since we are in a container, CONTAINER_PORT corresponds to the API_PORT variable below)
85
124
  environment:
86
- - HOST_URL: https://time-api.example.com
87
- # HOST_URL: That API's URL. Essential for CORS config.
88
- - TRUSTED_ORIGINS: https://my.app.com,https://my-other.app.com
89
- # TRUSTED_ORIGINS: To allow requests from any origin, include * (not recommended). If empty, will only allow requests from the HOST_URL's origin. Defaults to the HOST_URL's origin
90
- - API_PORT: 3000
91
- # API_PORT: Optional. Internal port when in a container. Defaults to 3000
92
- - RATE_LIMIT: 100
93
- # RATE_LIMIT: Optional. Max allowed number of requests per minute for each IP address. If negative or 0, no limit. Defaults to no limit
94
- - LOG_LEVEL: info
95
- # LOG_LEVEL: Optional. Logging levels include error, warn, info, http, verbose, debug, silly. Defaults to info
96
- - MAX_LOG_FILES: 64
97
- # MAX_LOG_FILES: Optional. Maximum number of logs to keep. This can be a number of files or number of days. If using days, add 'd' as the suffix. Default is 64
98
- - MAX_SIZE_LOG_FILES: 1m
99
- # MAX_SIZE_LOG_FILES: Optional. Maximum size of the file after which it will rotate. This can be a number of bytes, or units of kb, mb, and gb. If using the units, add 'k', 'm', or 'g' as the suffix. The units need to directly follow the number. Default is 1m
125
+ - BEAVUCK_TIME_HOST_URL: https://time-api.example.com
126
+ # BEAVUCK_TIME_HOST_URL: That API's URL. Essential for CORS config.
127
+ - BEAVUCK_TIME_TRUSTED_ORIGINS: https://my.app.com,https://my-other.app.com
128
+ # BEAVUCK_TIME_TRUSTED_ORIGINS: To allow requests from any origin, include * (not recommended). If empty, will only allow requests from the HOST_URL's origin. Defaults to the HOST_URL's origin
129
+ - BEAVUCK_TIME_API_PORT: 3000
130
+ # BEAVUCK_TIME_API_PORT: Optional. Internal port when in a container. Defaults to 3000
131
+ - BEAVUCK_TIME_RATE_LIMIT: 100
132
+ # BEAVUCK_TIME_RATE_LIMIT: Optional. Max allowed number of requests per minute for each IP address. If negative or 0, no limit. Defaults to no limit
133
+ - BEAVUCK_TIME_LOG_LEVEL: info
134
+ # BEAVUCK_TIME_LOG_LEVEL: Optional. Logging levels include error, warn, info, http, verbose, debug, silly. Defaults to info
135
+ - BEAVUCK_TIME_MAX_LOG_FILES: 64
136
+ # BEAVUCK_TIME_MAX_LOG_FILES: Optional. Maximum number of logs to keep. This can be a number of files or number of days. If using days, add 'd' as the suffix. Default is 64
137
+ - BEAVUCK_TIME_MAX_SIZE_LOG_FILES: 1m
138
+ # BEAVUCK_TIME_MAX_SIZE_LOG_FILES: Optional. Maximum size of the file after which it will rotate. This can be a number of bytes, or units of kb, mb, and gb. If using the units, add 'k', 'm', or 'g' as the suffix. The units need to directly follow the number. Default is 1m
100
139
  ```
101
140
 
102
141
  Here's the simple docker compose file I used to test this service locally:
@@ -108,9 +147,9 @@ services:
108
147
  ports:
109
148
  - '3000:3000'
110
149
  environment:
111
- HOST_URL: http://127.0.0.1:3000
112
- TRUSTED_ORIGINS: http://127.0.0.1:8000,http://localhost:8000
113
- LOG_LEVEL: debug
150
+ BEAVUCK_TIME_HOST_URL: http://127.0.0.1:3000
151
+ BEAVUCK_TIME_TRUSTED_ORIGINS: http://127.0.0.1:8000,http://localhost:8000
152
+ BEAVUCK_TIME_LOG_LEVEL: debug
114
153
  ```
115
154
 
116
155
  When you're ready, just run your services with:
@@ -145,15 +184,15 @@ variable.
145
184
 
146
185
  When you use the API, keep in mind what roles these headers play:
147
186
 
148
- | `"Origin:"` | `"Referrer:"`* | Result |
149
- | -------------------------------------------- | ------------------------------ | ------ |
150
- | Defined and API `TRUSTED_ORIGINS` set to `*` | Whatever | ✅ |
151
- | Trusted | Whatever | ✅ |
152
- | Same as this API's host | Whatever | ✅ |
153
- | Not defined | Same as this API's host | ✅ |
154
- | Defined and not trusted | Whatever | 🛑 |
155
- | Not defined | Not defined | 🛑 |
156
- | Not defined or not trusted | Different from this API's host | 🛑 |
187
+ | `"Origin:"` | `"Referrer:"`* | Result |
188
+ | --------------------------------------------------------- | ------------------------------ | ------ |
189
+ | Defined and API `BEAVUCK_TIME_TRUSTED_ORIGINS` set to `*` | Whatever | ✅ |
190
+ | Trusted | Whatever | ✅ |
191
+ | Same as this API's host | Whatever | ✅ |
192
+ | Not defined | Same as this API's host | ✅ |
193
+ | Defined and not trusted | Whatever | 🛑 |
194
+ | Not defined | Not defined | 🛑 |
195
+ | Not defined or not trusted | Different from this API's host | 🛑 |
157
196
 
158
197
  *AKA `Referer` (sic).
159
198
 
@@ -212,4 +251,4 @@ sequenceDiagram
212
251
 
213
252
  Have at it.
214
253
 
215
- This project uses the Unlicense. See the [UNLICENSE](UNLICENSE) file for details.
254
+ This project uses the Unlicense. See the [UNLICENSE](https://gitlab.com/beavuck-services/time/-/blob/main/UNLICENSE?ref_type=heads) file for details.
@@ -32,7 +32,7 @@
32
32
  },
33
33
  "info": {
34
34
  "title": "beavuck-time",
35
- "version": "2.2.0",
35
+ "version": "beta",
36
36
  "description": "Get time in ISO format, in UTC timezone, from a simple, lightweight node server",
37
37
  "license": {
38
38
  "name": "Unlicense"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "beavuck-time",
3
- "version": "2.2.0",
3
+ "version": "2.3.0",
4
4
  "description": "Get time in ISO format, in UTC timezone, from a simple, lightweight node server",
5
5
  "keywords": [
6
6
  "time",
@@ -21,6 +21,9 @@
21
21
  "author": "Alexis Drai",
22
22
  "type": "commonjs",
23
23
  "main": "build/api.js",
24
+ "bin": {
25
+ "beavuck-time": "./build/server.js"
26
+ },
24
27
  "scripts": {
25
28
  "run-integration-tests": "cd api-tests/bruno && npm install -g @usebruno/cli && bru run --env local --bail",
26
29
  "up-patch": "npm version patch --no-git-tag-version",
@@ -6,7 +6,7 @@ import {RFC_3339_FORMAT} from '../types/isoTimestamp'
6
6
  let callsMadeSoFar = 0
7
7
 
8
8
  function getSomeTrustedOrigin(): string {
9
- return process.env.TRUSTED_ORIGINS?.split(',')[0] ?? ''
9
+ return process.env.BEAVUCK_TIME_TRUSTED_ORIGINS?.split(',')[0] ?? ''
10
10
  }
11
11
 
12
12
  /**
@@ -44,7 +44,7 @@ describe('App Initialization', () => {
44
44
  })
45
45
 
46
46
  it('should allow requests with no origin header but a referrer header identical to server url', async () => {
47
- const REFERRER: string = process.env.HOST_URL!
47
+ const REFERRER: string = process.env.BEAVUCK_TIME_HOST_URL!
48
48
  const res = await request(api).get('/now').set('Referrer', REFERRER)
49
49
  expect(res.header['access-control-allow-origin']).toBeUndefined()
50
50
  expect(res.status).toBe(StatusCodes.OK)
@@ -52,7 +52,7 @@ describe('App Initialization', () => {
52
52
  })
53
53
 
54
54
  it('should allow requests with no origin header but a referer (sic) header identical to server url', async () => {
55
- const REFERER: string = process.env.HOST_URL!
55
+ const REFERER: string = process.env.BEAVUCK_TIME_HOST_URL!
56
56
  const res = await request(api).get('/now').set('Referer', REFERER)
57
57
  expect(res.header['access-control-allow-origin']).toBeUndefined()
58
58
  expect(res.status).toBe(StatusCodes.OK)
@@ -72,13 +72,13 @@ describe('App Initialization', () => {
72
72
  })
73
73
 
74
74
  it('should return 500 if HOST_URL is not set', async () => {
75
- const originalHostUrl = process.env.HOST_URL
76
- delete process.env.HOST_URL
75
+ const originalHostUrl = process.env.BEAVUCK_TIME_HOST_URL
76
+ delete process.env.BEAVUCK_TIME_HOST_URL
77
77
 
78
78
  const res = await request(api).get('/now')
79
79
  expect(res.status).toBe(StatusCodes.INTERNAL_SERVER_ERROR)
80
80
 
81
- process.env.HOST_URL = originalHostUrl
81
+ process.env.BEAVUCK_TIME_HOST_URL = originalHostUrl
82
82
  })
83
83
 
84
84
  it('should block requests with non-trusted referrer header if origin is not OK', async () => {
@@ -87,7 +87,7 @@ describe('App Initialization', () => {
87
87
  })
88
88
 
89
89
  it('should block requests that exceed the rate limit', async () => {
90
- const RATE_LIMIT = parseInt(process.env.RATE_LIMIT!, 10)
90
+ const RATE_LIMIT = parseInt(process.env.BEAVUCK_TIME_RATE_LIMIT!, 10)
91
91
  while (callsMadeSoFar <= RATE_LIMIT) {
92
92
  const {res} = await makeSuccessfulCallToNowEndpoint()
93
93
  if (callsMadeSoFar > RATE_LIMIT) {
@@ -39,7 +39,7 @@ export function getHostUrl(): URL | undefined {
39
39
  }
40
40
 
41
41
  export function initHostUrl(): void {
42
- HOST_URL = new URL(process.env.HOST_URL!)
42
+ HOST_URL = new URL(process.env.BEAVUCK_TIME_HOST_URL!)
43
43
  }
44
44
 
45
45
  export function getTrustedOrigins(): string[] {
@@ -50,7 +50,7 @@ export function getTrustedOrigins(): string[] {
50
50
  }
51
51
 
52
52
  export function initTrustedOrigins(): void {
53
- const trustedOrigins: string = process.env.TRUSTED_ORIGINS!
53
+ const trustedOrigins: string = process.env.BEAVUCK_TIME_TRUSTED_ORIGINS!
54
54
  TRUSTED_ORIGINS = trustedOrigins.split(',')
55
55
  }
56
56
 
@@ -7,9 +7,9 @@ import dotenvx from '@dotenvx/dotenvx'
7
7
  dotenvx.config()
8
8
 
9
9
  const LOGS_DIR = 'logs'
10
- const LOG_LEVEL: string = process.env.LOG_LEVEL ?? 'info'
11
- const MAX_LOG_FILES: string | number = process.env.MAX_LOG_FILES ?? 64
12
- const MAX_SIZE_LOG_FILES: string = process.env.MAX_SIZE_LOG_FILES ?? '1m'
10
+ const LOG_LEVEL: string = process.env.BEAVUCK_TIME_LOG_LEVEL ?? 'info'
11
+ const MAX_LOG_FILES: string | number = process.env.BEAVUCK_TIME_MAX_LOG_FILES ?? 64
12
+ const MAX_SIZE_LOG_FILES: string = process.env.BEAVUCK_TIME_MAX_SIZE_LOG_FILES ?? '1m'
13
13
 
14
14
  const dailyRotateFileTransport = new transports.DailyRotateFile({
15
15
  filename: `${LOGS_DIR}/%DATE%-combined.log`,
@@ -13,7 +13,7 @@ export const corsMiddleware = (
13
13
  res: express.Response,
14
14
  next: express.NextFunction,
15
15
  ) => {
16
- const HOST_URL = tryParseUrl(process.env.HOST_URL ?? '')
16
+ const HOST_URL = tryParseUrl(process.env.BEAVUCK_TIME_HOST_URL ?? '')
17
17
  // 'referer' is a misspelling that was kept for compatibility: https://en.wikipedia.org/wiki/HTTP_referer
18
18
  const referrerHeader: string | undefined =
19
19
  (req.headers.referrer as string) || req.headers.referer
@@ -3,7 +3,7 @@
3
3
  import rateLimit from 'express-rate-limit'
4
4
 
5
5
  const NO_RATE_LIMIT = '-1'
6
- const RATE_LIMIT = parseInt(process.env.RATE_LIMIT ?? NO_RATE_LIMIT, 10)
6
+ const RATE_LIMIT = parseInt(process.env.BEAVUCK_TIME_RATE_LIMIT ?? NO_RATE_LIMIT, 10)
7
7
 
8
8
  const SECONDS_IN_ONE_MINUTE = 60
9
9
  const MILLISECONDS_IN_ONE_SECOND = 1000
package/src/server.ts CHANGED
@@ -1,53 +1,83 @@
1
+ #!/usr/bin/env node
2
+
1
3
  // src/server.ts
2
4
 
3
5
  import {api} from './api'
4
6
  import {logger} from './config/logger'
5
7
  import {tryParseUrl} from './utils/urlUtil'
6
8
  import dotenvx from '@dotenvx/dotenvx'
9
+ import http from 'http'
7
10
 
8
11
  dotenvx.config()
9
12
 
10
- const API_PORT = process.env.API_PORT ?? 3000
11
-
12
- const HOST_URL = process.env.HOST_URL ?? ''
13
- const TRUSTED_ORIGINS = process.env.TRUSTED_ORIGINS ?? ''
13
+ type ServerOptions = {
14
+ port?: number
15
+ hostUrl?: string
16
+ trustedOrigins?: string
17
+ }
14
18
 
15
- const SIGTERM = 'SIGTERM'
16
- const SIGINT = 'SIGINT'
19
+ function validateEnv({
20
+ hostUrl,
21
+ trustedOrigins,
22
+ }: Required<Pick<ServerOptions, 'hostUrl' | 'trustedOrigins'>>) {
23
+ if (!hostUrl || !tryParseUrl(hostUrl)) {
24
+ logger.error('HOST_URL not set or is not a valid URL')
25
+ process.exit(1)
26
+ }
17
27
 
18
- if (!HOST_URL || !tryParseUrl(HOST_URL)) {
19
- logger.error('HOST_URL not set in environment variables (or is not a valid URL)')
20
- process.exit(1)
28
+ if (!trustedOrigins) {
29
+ logger.error('TRUSTED_ORIGINS not set')
30
+ process.exit(1)
31
+ }
21
32
  }
22
33
 
23
- if (!TRUSTED_ORIGINS) {
24
- logger.error('TRUSTED_ORIGINS not set in environment variables')
25
- process.exit(1)
26
- }
34
+ export function startServer(options: ServerOptions = {}): http.Server {
35
+ const API_PORT = options.port ?? process.env.BEAVUCK_TIME_API_PORT ?? 3000
36
+ const HOST_URL = options.hostUrl ?? process.env.BEAVUCK_TIME_HOST_URL ?? ''
37
+ const TRUSTED_ORIGINS =
38
+ options.trustedOrigins ?? process.env.BEAVUCK_TIME_TRUSTED_ORIGINS ?? ''
27
39
 
28
- const server = api.listen(API_PORT, () => {
29
- logger.info(
30
- `
40
+ validateEnv({hostUrl: HOST_URL, trustedOrigins: TRUSTED_ORIGINS})
41
+
42
+ const server = api.listen(API_PORT, () => {
43
+ logger.info(
44
+ `
31
45
  | | | | ,=.
32
46
  | |__ ___ __ ___ ___ _ ___| | __ ,=""""==.__.=" o".___
33
47
  | '_ \\ / _ \\/ _\` \\ \\ / / | | |/ __| |/ / ,=.==" ___/
34
48
  | |_) | __/ (_| |\\ V /| |_| | (__| < ,==.," , , \\,===""
35
49
  |_.__/ \\___|\\__,_| \\_/ \\__,_|\\___|_|\\_\\ < ,==) \\"'"=._.==) \\
36
50
  \`=='' \`" \`"
37
-
51
+
38
52
  Beavuck Time microservice started successfully
39
-
40
- Ready on API port ${API_PORT} (if this is running in a container, this port number is internal to the container)`,
41
- )
42
- })
43
-
44
- const gracefulShutdown = (signal: string) => {
45
- logger.info(`${signal} signal received: closing HTTP server`)
46
- server.close(() => {
47
- logger.info('HTTP server closed')
48
- process.exit(0)
53
+
54
+ Ready on API port ${API_PORT} (if this is running in a container, this port number is internal to the container)
55
+ `,
56
+ )
49
57
  })
58
+
59
+ server.on('error', (err: NodeJS.ErrnoException) => {
60
+ logger.error(`Beavuck Time Server error [${err.code}]: ${err.message}`)
61
+ process.exit(1)
62
+ })
63
+
64
+ const gracefulShutdown = (signal: string) => {
65
+ logger.info(`${signal} signal received: closing HTTP server`)
66
+ server.close(() => {
67
+ logger.info('HTTP server closed')
68
+ process.exit(0)
69
+ })
70
+ }
71
+
72
+ const SIGTERM = 'SIGTERM'
73
+ const SIGINT = 'SIGINT'
74
+ process.on(SIGTERM, () => gracefulShutdown(SIGTERM))
75
+ process.on(SIGINT, () => gracefulShutdown(SIGINT))
76
+
77
+ return server
50
78
  }
51
79
 
52
- process.on(SIGTERM, () => gracefulShutdown(SIGTERM))
53
- process.on(SIGINT, () => gracefulShutdown(SIGINT))
80
+ // Support running as standalone binary
81
+ if (require.main === module) {
82
+ startServer()
83
+ }
package/tsconfig.json CHANGED
@@ -2,7 +2,7 @@
2
2
  "compilerOptions": {
3
3
  /* Basic Options */
4
4
  "incremental": true,
5
- "target": "ES2023",
5
+ "target": "ESNext",
6
6
  "module": "commonjs",
7
7
  "outDir": "build",
8
8
  "rootDir": "src",