@stamhoofd/backend-renderer 2.39.1 → 2.40.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.
@@ -0,0 +1,5 @@
1
+ import stamhoofdEslint from 'eslint-plugin-stamhoofd';
2
+
3
+ export default [
4
+ ...stamhoofdEslint.configs.backend,
5
+ ];
package/index.ts CHANGED
@@ -1,40 +1,42 @@
1
- require('@stamhoofd/backend-env').load({service: 'renderer'});
2
- import { CORSPreflightEndpoint, Router, RouterServer } from "@simonbackx/simple-endpoints";
3
- import { I18n } from "@stamhoofd/backend-i18n";
4
- import { CORSMiddleware, LogMiddleware } from "@stamhoofd/backend-middleware";
5
- import { loadLogger } from "@stamhoofd/logging";
6
-
7
- process.on("unhandledRejection", (error: Error) => {
8
- console.error("unhandledRejection");
1
+ import backendEnv from '@stamhoofd/backend-env';
2
+ backendEnv.load({ service: 'renderer' });
3
+
4
+ import { CORSPreflightEndpoint, Router, RouterServer } from '@simonbackx/simple-endpoints';
5
+ import { I18n } from '@stamhoofd/backend-i18n';
6
+ import { CORSMiddleware, LogMiddleware } from '@stamhoofd/backend-middleware';
7
+ import { loadLogger } from '@stamhoofd/logging';
8
+
9
+ process.on('unhandledRejection', (error: Error) => {
10
+ console.error('unhandledRejection');
9
11
  console.error(error.message, error.stack);
10
12
  process.exit(1);
11
13
  });
12
14
 
13
15
  // Set timezone!
14
- process.env.TZ = "UTC";
16
+ process.env.TZ = 'UTC';
15
17
 
16
18
  // Quick check
17
- if (new Date().getTimezoneOffset() != 0) {
18
- throw new Error("Process should always run in UTC timezone");
19
+ if (new Date().getTimezoneOffset() !== 0) {
20
+ throw new Error('Process should always run in UTC timezone');
19
21
  }
20
22
 
21
23
  const start = async () => {
22
- console.log('Started Renderer.')
24
+ console.log('Started Renderer.');
23
25
  loadLogger();
24
- await I18n.load()
26
+ await I18n.load();
25
27
  const router = new Router();
26
- await router.loadEndpoints(__dirname + "/src/endpoints");
27
- router.endpoints.push(new CORSPreflightEndpoint())
28
+ await router.loadEndpoints(__dirname + '/src/endpoints');
29
+ router.endpoints.push(new CORSPreflightEndpoint());
28
30
 
29
31
  const routerServer = new RouterServer(router);
30
- routerServer.verbose = false
31
-
32
+ routerServer.verbose = false;
33
+
32
34
  // Send the app version along
33
- routerServer.addRequestMiddleware(LogMiddleware)
34
- routerServer.addResponseMiddleware(LogMiddleware)
35
+ routerServer.addRequestMiddleware(LogMiddleware);
36
+ routerServer.addResponseMiddleware(LogMiddleware);
35
37
 
36
38
  // Add CORS headers
37
- routerServer.addResponseMiddleware(CORSMiddleware)
39
+ routerServer.addResponseMiddleware(CORSMiddleware);
38
40
 
39
41
  routerServer.listen(STAMHOOFD.PORT ?? 9090);
40
42
 
@@ -44,19 +46,20 @@ const start = async () => {
44
46
  }
45
47
 
46
48
  const shutdown = async () => {
47
- console.log("Shutting down...")
49
+ console.log('Shutting down...');
48
50
  // Disable keep alive
49
- routerServer.defaultHeaders = Object.assign(routerServer.defaultHeaders, { 'Connection': 'close' })
51
+ routerServer.defaultHeaders = Object.assign(routerServer.defaultHeaders, { Connection: 'close' });
50
52
  if (routerServer.server) {
51
53
  routerServer.server.headersTimeout = 5000;
52
54
  routerServer.server.keepAliveTimeout = 1;
53
55
  }
54
56
 
55
57
  try {
56
- await routerServer.close()
57
- console.log("HTTP server stopped");
58
- } catch (err) {
59
- console.error("Failed to stop HTTP server:");
58
+ await routerServer.close();
59
+ console.log('HTTP server stopped');
60
+ }
61
+ catch (err) {
62
+ console.error('Failed to stop HTTP server:');
60
63
  console.error(err);
61
64
  }
62
65
 
@@ -64,24 +67,24 @@ const start = async () => {
64
67
  process.exit(0);
65
68
  };
66
69
 
67
- process.on("SIGTERM", () => {
68
- console.info("SIGTERM signal received.");
70
+ process.on('SIGTERM', () => {
71
+ console.info('SIGTERM signal received.');
69
72
  shutdown().catch((e) => {
70
- console.error(e)
73
+ console.error(e);
71
74
  process.exit(1);
72
75
  });
73
76
  });
74
77
 
75
- process.on("SIGINT", () => {
76
- console.info("SIGINT signal received.");
78
+ process.on('SIGINT', () => {
79
+ console.info('SIGINT signal received.');
77
80
  shutdown().catch((e) => {
78
- console.error(e)
81
+ console.error(e);
79
82
  process.exit(1);
80
83
  });
81
84
  });
82
85
  };
83
86
 
84
- start().catch(error => {
85
- console.error("unhandledRejection", error);
87
+ start().catch((error) => {
88
+ console.error('unhandledRejection', error);
86
89
  process.exit(1);
87
90
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stamhoofd/backend-renderer",
3
- "version": "2.39.1",
3
+ "version": "2.40.0",
4
4
  "main": "./dist/index.js",
5
5
  "exports": {
6
6
  ".": {
@@ -14,7 +14,7 @@
14
14
  "build:full": "yarn clear && yarn build",
15
15
  "clear": "rm -rf ./dist",
16
16
  "start": "yarn build && node --enable-source-maps ./dist/index.js",
17
- "lint": "eslint . --ext .js,.jsx,.ts,.tsx"
17
+ "lint": "eslint"
18
18
  },
19
19
  "devDependencies": {
20
20
  "@types/formidable": "3.4.5",
@@ -31,5 +31,5 @@
31
31
  "mysql": "^2.18.1",
32
32
  "puppeteer": "22.12.0"
33
33
  },
34
- "gitHead": "13df02459d27104c9bf92ff3d905920cf81276c4"
34
+ "gitHead": "6839689f56361c6ba6f34f6113a5cdc4bbd7b209"
35
35
  }
@@ -1,18 +1,18 @@
1
- import { DecodedRequest, Endpoint, Request, Response } from "@simonbackx/simple-endpoints";
2
- import { SimpleError } from "@simonbackx/simple-errors";
3
- import { verifyInternalSignature } from "@stamhoofd/backend-env";
4
- import { QueueHandler } from "@stamhoofd/queues";
1
+ import { DecodedRequest, Endpoint, Request, Response } from '@simonbackx/simple-endpoints';
2
+ import { SimpleError } from '@simonbackx/simple-errors';
3
+ import { verifyInternalSignature } from '@stamhoofd/backend-env';
4
+ import { QueueHandler } from '@stamhoofd/queues';
5
5
  import formidable from 'formidable';
6
6
  import { firstValues } from 'formidable/src/helpers/firstValues.js';
7
- import { promises as fs } from "fs";
8
- import puppeteer, { Browser } from "puppeteer";
7
+ import { promises as fs } from 'fs';
8
+ import puppeteer, { Browser } from 'puppeteer';
9
9
 
10
- import { FileCache } from "../helpers/FileCache";
10
+ import { FileCache } from '../helpers/FileCache';
11
11
 
12
12
  type Params = Record<string, never>;
13
13
  type Body = undefined;
14
- type Query = undefined
15
- type ResponseBody = Buffer
14
+ type Query = undefined;
15
+ type ResponseBody = Buffer;
16
16
 
17
17
  /**
18
18
  * One endpoint to create, patch and delete groups. Usefull because on organization setup, we need to create multiple groups at once. Also, sometimes we need to link values and update multiple groups at once
@@ -20,11 +20,11 @@ type ResponseBody = Buffer
20
20
 
21
21
  export class HtmlToPdfEndpoint extends Endpoint<Params, Query, Body, ResponseBody> {
22
22
  protected doesMatch(request: Request): [true, Params] | [false] {
23
- if (request.method != "POST") {
23
+ if (request.method !== 'POST') {
24
24
  return [false];
25
25
  }
26
26
 
27
- const params = Endpoint.parseParameters(request.url, "/html-to-pdf", {});
27
+ const params = Endpoint.parseParameters(request.url, '/html-to-pdf', {});
28
28
 
29
29
  if (params) {
30
30
  return [true, params as Params];
@@ -33,161 +33,165 @@ export class HtmlToPdfEndpoint extends Endpoint<Params, Query, Body, ResponseBod
33
33
  }
34
34
 
35
35
  async handle(request: DecodedRequest<Params, Query, Body>) {
36
- const form = formidable({
37
- maxTotalFileSize: 20 * 1024 * 1024,
36
+ const form = formidable({
37
+ maxTotalFileSize: 20 * 1024 * 1024,
38
38
  keepExtensions: false,
39
- maxFiles: 1
39
+ maxFiles: 1,
40
40
  });
41
41
 
42
- const {html, cacheId, timestamp, signature} = await new Promise<{html: string, cacheId: string, timestamp: Date, signature: string}>((resolve, reject) => {
42
+ const { html, cacheId, timestamp, signature } = await new Promise<{ html: string; cacheId: string; timestamp: Date; signature: string }>((resolve, reject) => {
43
43
  if (!request.request.request) {
44
44
  reject(new SimpleError({
45
- code: "invalid_request",
46
- message: "Invalid request",
47
- statusCode: 500
45
+ code: 'invalid_request',
46
+ message: 'Invalid request',
47
+ statusCode: 500,
48
48
  }));
49
49
  return;
50
50
  }
51
51
 
52
52
  // eslint-disable-next-line @typescript-eslint/no-misused-promises
53
- form.parse(request.request.request, async (err, fieldsMultiple, files) => {
53
+ form.parse(request.request.request, async (err: Error, fieldsMultiple, files) => {
54
54
  if (err) {
55
55
  reject(err);
56
56
  return;
57
57
  }
58
58
  if (!files.html || files.html.length !== 1) {
59
59
  reject(new SimpleError({
60
- code: "missing_field",
61
- message: "Field html is required",
62
- field: "html"
63
- }))
64
- return
60
+ code: 'missing_field',
61
+ message: 'Field html is required',
62
+ field: 'html',
63
+ }));
64
+ return;
65
65
  }
66
66
  const fields = firstValues(form, fieldsMultiple);
67
67
 
68
- if (!fields.signature || typeof fields.signature !== "string") {
68
+ if (!fields.signature || typeof fields.signature !== 'string') {
69
69
  reject(new SimpleError({
70
- code: "missing_field",
71
- message: "Field signature is required",
72
- field: "signature"
73
- }))
74
- return
70
+ code: 'missing_field',
71
+ message: 'Field signature is required',
72
+ field: 'signature',
73
+ }));
74
+ return;
75
75
  }
76
- if (!fields.cacheId || typeof fields.cacheId !== "string") {
76
+ if (!fields.cacheId || typeof fields.cacheId !== 'string') {
77
77
  reject(new SimpleError({
78
- code: "missing_field",
79
- message: "Field cacheId is required",
80
- field: "cacheId"
81
- }))
82
- return
78
+ code: 'missing_field',
79
+ message: 'Field cacheId is required',
80
+ field: 'cacheId',
81
+ }));
82
+ return;
83
83
  }
84
- if (!fields.timestamp || typeof fields.timestamp !== "string") {
84
+ if (!fields.timestamp || typeof fields.timestamp !== 'string') {
85
85
  reject(new SimpleError({
86
- code: "missing_field",
87
- message: "Field timestamp is required",
88
- field: "timestamp"
89
- }))
90
- return
86
+ code: 'missing_field',
87
+ message: 'Field timestamp is required',
88
+ field: 'timestamp',
89
+ }));
90
+ return;
91
91
  }
92
92
 
93
93
  let html;
94
94
  try {
95
- html = await fs.readFile(files.html[0].filepath , 'utf8')
96
- } catch (e) {
95
+ html = await fs.readFile(files.html[0].filepath, 'utf8');
96
+ }
97
+ catch (e) {
97
98
  reject(new SimpleError({
98
- code: "invalid_field",
99
- message: "Could not read html",
100
- field: "html"
101
- }))
102
- return
99
+ code: 'invalid_field',
100
+ message: 'Could not read html',
101
+ field: 'html',
102
+ }));
103
+ return;
103
104
  }
104
105
 
105
106
  resolve({
106
107
  html,
107
108
  signature: fields.signature,
108
109
  cacheId: fields.cacheId,
109
- timestamp: new Date(parseInt(fields.timestamp as string))
110
- })
111
- return
110
+ timestamp: new Date(parseInt(fields.timestamp as string)),
111
+ });
112
+ return;
112
113
  });
113
114
  });
114
115
 
115
116
  // Verify signature first
116
117
  if (!verifyInternalSignature(signature, cacheId, timestamp.getTime().toString(), html)) {
117
118
  throw new SimpleError({
118
- code: "invalid_signature",
119
- message: "Invalid signature"
120
- })
119
+ code: 'invalid_signature',
120
+ message: 'Invalid signature',
121
+ });
121
122
  }
122
123
 
123
- let pdf: Buffer | null = null
124
+ let pdf: Buffer | null = null;
124
125
  try {
125
- pdf = await this.htmlToPdf(html, {retryCount: 2, startDate: new Date()})
126
- } catch (e) {
127
- console.error(e)
126
+ pdf = await this.htmlToPdf(html, { retryCount: 2, startDate: new Date() });
127
+ }
128
+ catch (e) {
129
+ console.error(e);
128
130
  }
129
131
  if (!pdf) {
130
132
  throw new SimpleError({
131
- code: "internal_error",
132
- message: "Could not generate pdf"
133
- })
133
+ code: 'internal_error',
134
+ message: 'Could not generate pdf',
135
+ });
134
136
  }
135
- await FileCache.write(cacheId, timestamp, pdf)
136
- const response = new Response(pdf)
137
- response.headers["Content-Type"] = "application/pdf"
138
- response.headers["Content-Length"] = pdf.byteLength.toString()
137
+ await FileCache.write(cacheId, timestamp, pdf);
138
+ const response = new Response(pdf);
139
+ response.headers['Content-Type'] = 'application/pdf';
140
+ response.headers['Content-Length'] = pdf.byteLength.toString();
139
141
  return response;
140
142
  }
141
143
 
142
- browsers: ({browser: Browser, count: number}|null)[] = [null, null, null, null]
143
- nextBrowserIndex = 0
144
+ browsers: ({ browser: Browser; count: number } | null)[] = [null, null, null, null];
145
+ nextBrowserIndex = 0;
144
146
 
145
147
  async useBrowser<T>(callback: (browser: Browser) => Promise<T>): Promise<T> {
146
148
  this.nextBrowserIndex++;
147
149
  if (this.nextBrowserIndex >= this.browsers.length) {
148
150
  this.nextBrowserIndex = 0;
149
151
  }
150
- return await QueueHandler.schedule("getBrowser" + this.nextBrowserIndex, async () => {
152
+ return await QueueHandler.schedule('getBrowser' + this.nextBrowserIndex, async () => {
151
153
  if (!this.browsers[this.nextBrowserIndex]) {
152
- this.browsers[this.nextBrowserIndex] = { browser: await puppeteer.launch({ pipe: true }), count: 0 }
154
+ this.browsers[this.nextBrowserIndex] = { browser: await puppeteer.launch({ pipe: true }), count: 0 };
153
155
  }
154
- const browser = this.browsers[this.nextBrowserIndex]!
156
+ const browser = this.browsers[this.nextBrowserIndex]!;
155
157
  if (browser.count > 50 || !browser.browser.isConnected()) {
156
158
  try {
157
159
  await browser.browser.close();
158
- } catch (e) {
159
- console.error(e)
160
160
  }
161
- this.browsers[this.nextBrowserIndex] = { browser: await puppeteer.launch({ pipe: true }), count: 0 }
161
+ catch (e) {
162
+ console.error(e);
163
+ }
164
+ this.browsers[this.nextBrowserIndex] = { browser: await puppeteer.launch({ pipe: true }), count: 0 };
162
165
  }
163
-
164
- return await callback(browser.browser)
166
+
167
+ return await callback(browser.browser);
165
168
  });
166
169
  }
167
170
 
168
171
  async clearBrowser(browser: Browser) {
169
172
  try {
170
173
  await browser.close();
171
- } catch (e) {
172
- console.error(e)
173
174
  }
174
- const i = this.browsers.findIndex(b => b?.browser === browser)
175
+ catch (e) {
176
+ console.error(e);
177
+ }
178
+ const i = this.browsers.findIndex(b => b?.browser === browser);
175
179
  if (i >= 0) {
176
- this.browsers[i] = null
180
+ this.browsers[i] = null;
177
181
  }
178
182
  }
179
183
 
180
184
  /**
181
185
  * This will move to a different external service
182
186
  */
183
- async htmlToPdf(html: string, options: {retryCount: number, startDate: Date}): Promise<Buffer | null> {
187
+ async htmlToPdf(html: string, options: { retryCount: number; startDate: Date }): Promise<Buffer | null> {
184
188
  const response = await this.useBrowser(async (browser) => {
185
189
  try {
186
190
  // Create a new page
187
191
  const page = await browser.newPage();
188
192
  await page.setJavaScriptEnabled(false);
189
193
  await page.emulateMediaType('screen');
190
- await page.setContent(html, { waitUntil: 'load' })
194
+ await page.setContent(html, { waitUntil: 'load' });
191
195
 
192
196
  // Downlaod the PDF
193
197
  const pdf = await page.pdf({
@@ -196,18 +200,19 @@ export class HtmlToPdfEndpoint extends Endpoint<Params, Query, Body, ResponseBod
196
200
  printBackground: true,
197
201
  format: 'A4',
198
202
  preferCSSPageSize: true,
199
- displayHeaderFooter: false
203
+ displayHeaderFooter: false,
200
204
  });
201
205
  await page.close();
202
206
  return pdf;
203
- } catch (e) {
204
- console.error('Failed to render document pdf', e)
207
+ }
208
+ catch (e) {
209
+ console.error('Failed to render document pdf', e);
205
210
  return null;
206
211
  }
207
- })
208
- if (response == null && options.retryCount > 0 && new Date().getTime() - options.startDate.getTime() < 15000) {
209
- // Retry
210
- return await this.htmlToPdf(html, {...options, retryCount: options.retryCount - 1})
212
+ });
213
+ if (response === null && options.retryCount > 0 && new Date().getTime() - options.startDate.getTime() < 15000) {
214
+ // Retry
215
+ return await this.htmlToPdf(html, { ...options, retryCount: options.retryCount - 1 });
211
216
  }
212
217
  return response;
213
218
  }
@@ -1,33 +1,33 @@
1
- import { AutoEncoder, DateDecoder, Decoder, field, StringDecoder } from "@simonbackx/simple-encoding";
2
- import { DecodedRequest, Endpoint, Request, Response } from "@simonbackx/simple-endpoints";
3
- import { SimpleError } from "@simonbackx/simple-errors";
1
+ import { AutoEncoder, DateDecoder, Decoder, field, StringDecoder } from '@simonbackx/simple-encoding';
2
+ import { DecodedRequest, Endpoint, Request, Response } from '@simonbackx/simple-endpoints';
3
+ import { SimpleError } from '@simonbackx/simple-errors';
4
4
 
5
- import { FileCache } from "../helpers/FileCache";
5
+ import { FileCache } from '../helpers/FileCache';
6
6
 
7
7
  type Params = Record<string, never>;
8
8
  class Query extends AutoEncoder {
9
9
  @field({ decoder: StringDecoder })
10
- cacheId: string
10
+ cacheId: string;
11
11
 
12
12
  @field({ decoder: DateDecoder })
13
- timestamp: Date
13
+ timestamp: Date;
14
14
  }
15
- type Body = undefined
16
- type ResponseBody = Buffer
15
+ type Body = undefined;
16
+ type ResponseBody = Buffer;
17
17
 
18
18
  /**
19
19
  * One endpoint to create, patch and delete groups. Usefull because on organization setup, we need to create multiple groups at once. Also, sometimes we need to link values and update multiple groups at once
20
20
  */
21
21
 
22
22
  export class PdfCacheEndpoint extends Endpoint<Params, Query, Body, ResponseBody> {
23
- queryDecoder = Query as Decoder<Query>
23
+ queryDecoder = Query as Decoder<Query>;
24
24
 
25
25
  protected doesMatch(request: Request): [true, Params] | [false] {
26
- if (request.method != "GET") {
26
+ if (request.method !== 'GET') {
27
27
  return [false];
28
28
  }
29
29
 
30
- const params = Endpoint.parseParameters(request.url, "/pdf-cache", {});
30
+ const params = Endpoint.parseParameters(request.url, '/pdf-cache', {});
31
31
 
32
32
  if (params) {
33
33
  return [true, params as Params];
@@ -36,17 +36,17 @@ export class PdfCacheEndpoint extends Endpoint<Params, Query, Body, ResponseBody
36
36
  }
37
37
 
38
38
  async handle(request: DecodedRequest<Params, Query, Body>) {
39
- const pdf = await FileCache.read(request.query.cacheId, request.query.timestamp)
39
+ const pdf = await FileCache.read(request.query.cacheId, request.query.timestamp);
40
40
  if (!pdf) {
41
41
  throw new SimpleError({
42
- code: "cache_not_found",
43
- message: "Not cached",
44
- statusCode: 404
45
- })
42
+ code: 'cache_not_found',
43
+ message: 'Not cached',
44
+ statusCode: 404,
45
+ });
46
46
  }
47
- const response = new Response(pdf)
48
- response.headers["Content-Type"] = "application/pdf"
49
- response.headers["Content-Length"] = pdf.byteLength.toString()
47
+ const response = new Response(pdf);
48
+ response.headers['Content-Type'] = 'application/pdf';
49
+ response.headers['Content-Length'] = pdf.byteLength.toString();
50
50
  return response;
51
51
  }
52
52
  }
@@ -3,45 +3,46 @@ import { promises as fs } from 'fs';
3
3
 
4
4
  export class FileCache {
5
5
  static async write(cacheId: string, timestamp: Date, data: Buffer) {
6
- if (cacheId.includes("/")) {
6
+ if (cacheId.includes('/')) {
7
7
  throw new SimpleError({
8
- code: "invalid_field",
9
- message: "Invalid cache id",
10
- field: "cacheId"
11
- })
8
+ code: 'invalid_field',
9
+ message: 'Invalid cache id',
10
+ field: 'cacheId',
11
+ });
12
12
  }
13
-
14
- const folder = STAMHOOFD.CACHE_PATH + "/" + cacheId;
15
- await fs.mkdir(folder, { recursive: true })
13
+
14
+ const folder = STAMHOOFD.CACHE_PATH + '/' + cacheId;
15
+ await fs.mkdir(folder, { recursive: true });
16
16
 
17
17
  // Emtpy folder
18
18
  const files = await fs.readdir(folder);
19
19
  for (const file of files) {
20
20
  const fileTimestamp = parseInt(file.substring(0, file.length - 4));
21
21
  if (fileTimestamp <= timestamp.getTime()) {
22
- await fs.unlink(folder + "/" + file);
22
+ await fs.unlink(folder + '/' + file);
23
23
  }
24
24
  }
25
25
 
26
- const path = folder + "/" + timestamp.getTime() + ".pdf";
26
+ const path = folder + '/' + timestamp.getTime() + '.pdf';
27
27
  await fs.writeFile(path, data);
28
28
  }
29
29
 
30
30
  static async read(cacheId: string, timestamp: Date): Promise<Buffer | null> {
31
- if (cacheId.includes("/")) {
31
+ if (cacheId.includes('/')) {
32
32
  throw new SimpleError({
33
- code: "invalid_field",
34
- message: "Invalid cache id",
35
- field: "cacheId"
36
- })
33
+ code: 'invalid_field',
34
+ message: 'Invalid cache id',
35
+ field: 'cacheId',
36
+ });
37
37
  }
38
38
 
39
- const folder = STAMHOOFD.CACHE_PATH + "/" + cacheId;
40
- const path = folder + "/" + timestamp.getTime() + ".pdf";
39
+ const folder = STAMHOOFD.CACHE_PATH + '/' + cacheId;
40
+ const path = folder + '/' + timestamp.getTime() + '.pdf';
41
41
  try {
42
- const data = await fs.readFile(path)
42
+ const data = await fs.readFile(path);
43
43
  return data;
44
- } catch {
44
+ }
45
+ catch {
45
46
  // ignore
46
47
  }
47
48
 
@@ -51,17 +52,19 @@ export class FileCache {
51
52
  const fileTimestamp = parseInt(file.substring(0, file.length - 4));
52
53
  if (fileTimestamp >= timestamp.getTime()) {
53
54
  try {
54
- const data = await fs.readFile(folder + "/" + file)
55
+ const data = await fs.readFile(folder + '/' + file);
55
56
  return data;
56
- } catch {
57
+ }
58
+ catch {
57
59
  // ignore
58
60
  }
59
61
  }
60
62
  }
61
- } catch {
63
+ }
64
+ catch {
62
65
  // ignore
63
66
  }
64
67
 
65
68
  return null;
66
69
  }
67
- }
70
+ }
package/stamhoofd.d.ts CHANGED
@@ -1,15 +1,14 @@
1
-
2
1
  export {};
3
2
 
4
3
  /**
5
- * Stamhoofd uses a global variable to store some configurations. We don't use process.env because we can only store
6
- * strings into those files. And we need objects for our localized domains (different domains for each locale).
4
+ * Stamhoofd uses a global variable to store some configurations. We don't use process.env because we can only store
5
+ * strings into those files. And we need objects for our localized domains (different domains for each locale).
7
6
  * Having to encode and decode those values would be inefficient.
8
- *
9
- * So we use our own global configuration variable: STAMHOOFD. Available everywhere and contains
10
- * other information depending on the environment (frontend/backend/shared). TypeScript will
7
+ *
8
+ * So we use our own global configuration variable: STAMHOOFD. Available everywhere and contains
9
+ * other information depending on the environment (frontend/backend/shared). TypeScript will
11
10
  * always suggest the possible keys.
12
11
  */
13
12
  declare global {
14
- const STAMHOOFD: RendererEnvironment
15
- }
13
+ const STAMHOOFD: RendererEnvironment;
14
+ }
package/.eslintrc.js DELETED
@@ -1,61 +0,0 @@
1
- module.exports = {
2
- root: true,
3
- ignorePatterns: ["dist/", "node_modules/"],
4
- parserOptions: {
5
- "ecmaVersion": 2017
6
- },
7
- env: {
8
- "es6": true,
9
- "node": true,
10
- },
11
- extends: [
12
- "eslint:recommended",
13
- ],
14
- plugins: [],
15
- rules: {
16
- "no-console": "off",
17
- "no-debugger": process.env.NODE_ENV === "production" ? "error" : "off",
18
- "sort-imports": "off",
19
- "import/order": "off"
20
- },
21
- overrides: [
22
- {
23
- // Rules for TypeScript and vue
24
- files: ["*.ts"],
25
- parser: "@typescript-eslint/parser",
26
- parserOptions: {
27
- project: ["./tsconfig.json"]
28
- },
29
- plugins: ["@typescript-eslint", "jest"],
30
- extends: [
31
- "eslint:recommended",
32
- "plugin:@typescript-eslint/eslint-recommended",
33
- "plugin:@typescript-eslint/recommended",
34
- "plugin:@typescript-eslint/recommended-requiring-type-checking",
35
- "plugin:jest/recommended",
36
- ],
37
- rules: {
38
- "no-console": "off",
39
- "no-debugger": process.env.NODE_ENV === "production" ? "error" : "off",
40
- "sort-imports": "off",
41
- "import/order": "off",
42
- "@typescript-eslint/explicit-function-return-type": "off",
43
- "@typescript-eslint/no-explicit-any": "off",
44
- "@typescript-eslint/no-unused-vars": ["warn", { argsIgnorePattern: "^_" }],
45
- "@typescript-eslint/no-namespace": "off",
46
- "@typescript-eslint/no-floating-promises": "error",
47
- "@typescript-eslint/no-misused-promises": "error",
48
- "@typescript-eslint/prefer-for-of": "warn",
49
- "@typescript-eslint/no-empty-interface": "off", // It is convenient to have placeholder interfaces
50
- "@typescript-eslint/no-this-alias": "off", // No idea why we need this. This breaks code that is just fine. Prohibit the use of function() instead of this rule
51
- "@typescript-eslint/unbound-method": "off", // Methods are automatically bound in vue, it would break removeEventListeners if we bound it every time unless we save every method in variables again...
52
- "@typescript-eslint/no-unsafe-assignment": "off", // This is impossible to use with dependencies that don't have types yet, such as tiptap
53
- "@typescript-eslint/no-unsafe-return": "off", // This is impossible to use with dependencies that don't have types yet, such as tiptap
54
- "@typescript-eslint/no-unsafe-call": "off", // This is impossible to use with dependencies that don't have types yet, such as tiptap
55
- "@typescript-eslint/no-unsafe-member-access": "off", // This is impossible to use with dependencies that don't have types yet, such as tiptap
56
- "@typescript-eslint/restrict-plus-operands": "off", // bullshit one
57
- "@typescript-eslint/explicit-module-boundary-types": "off",
58
- },
59
- }
60
- ]
61
- };