page2pdf_server 1.1.2 → 2.0.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.
Files changed (70) hide show
  1. package/README.md +6 -5
  2. package/package.json +5 -70
  3. package/src/index.ts +10 -18
  4. package/src/types.d.ts +161 -97
  5. package/.github/ISSUE_TEMPLATE/bug_report.md +0 -28
  6. package/.github/ISSUE_TEMPLATE/feature_request.md +0 -15
  7. package/.github/ISSUE_TEMPLATE/refactoring.md +0 -15
  8. package/.github/PULL_REQUEST_TEMPLATE.md +0 -18
  9. package/.github/stale.yml +0 -17
  10. package/.github/workflows/cd.yml +0 -75
  11. package/.github/workflows/ci.yml +0 -36
  12. package/.prettierrc +0 -8
  13. package/.vscode/settings.json +0 -3
  14. package/config/default.json +0 -10
  15. package/config/development.json +0 -3
  16. package/config/production.json +0 -3
  17. package/config/test.json +0 -3
  18. package/ecosystem.config.js +0 -41
  19. package/jest.config.js +0 -35
  20. package/nodemon.json +0 -6
  21. package/src/CSS/345/205/274/345/256/271/346/200/247.txt +0 -125
  22. package/src/__tests__/UrltoPdf/generatePdf.test.d.ts +0 -1
  23. package/src/__tests__/UrltoPdf/generatePdf.test.ts +0 -207
  24. package/src/__tests__/UrltoPdf/pdfSplit.test.d.ts +0 -1
  25. package/src/__tests__/UrltoPdf/pdfSplit.test.ts +0 -69
  26. package/src/__tests__/helpers/index.d.ts +0 -2
  27. package/src/__tests__/helpers/index.ts +0 -21
  28. package/src/__tests__/home.test.d.ts +0 -1
  29. package/src/__tests__/home.test.ts +0 -77
  30. package/src/app.ts +0 -49
  31. package/src/components/home/controller.ts +0 -32
  32. package/src/components/home/index.ts +0 -4
  33. package/src/components/home/pdfController.ts +0 -118
  34. package/src/components/home/services.ts +0 -31
  35. package/src/components/home/splitController.ts +0 -134
  36. package/src/components/home/validators.ts +0 -12
  37. package/src/configEnv/index.ts +0 -62
  38. package/src/db/home.ts +0 -14
  39. package/src/helpers/apiResponse.ts +0 -10
  40. package/src/helpers/dataSanitizers.ts +0 -33
  41. package/src/helpers/error/ApiError.ts +0 -25
  42. package/src/helpers/error/ForbiddenError.ts +0 -15
  43. package/src/helpers/error/NotFoundException.ts +0 -15
  44. package/src/helpers/error/TimeOutError.ts +0 -20
  45. package/src/helpers/error/UnauthorizedError.ts +0 -15
  46. package/src/helpers/error/ValidationError.ts +0 -20
  47. package/src/helpers/error/index.ts +0 -15
  48. package/src/helpers/index.ts +0 -2
  49. package/src/helpers/loggers.ts +0 -75
  50. package/src/middlewares/errorHandler.ts +0 -52
  51. package/src/new_tab1.mhtml +0 -722
  52. package/src/routes/index.ts +0 -22
  53. package/src/server.ts +0 -30
  54. package/src/testCSS.html +0 -241
  55. package/src/types/global.d.ts +0 -13
  56. package/src/types/request/config.ts +0 -70
  57. package/src/types/request/home.ts +0 -3
  58. package/src/types/request/split.ts +0 -18
  59. package/src/types/response/AppInformation.ts +0 -9
  60. package/src/types/response/index.ts +0 -5
  61. package/src/utils/array.ts +0 -19
  62. package/src/utils/auth.ts +0 -12
  63. package/src/utils/crypt.ts +0 -25
  64. package/src/utils/filter.ts +0 -59
  65. package/src/utils/object.ts +0 -58
  66. package/src/utils/pdfgen.ts +0 -1045
  67. package/src/utils/url.ts +0 -54
  68. package/src//346/265/213/350/257/225.txt +0 -268
  69. package/test//346/211/223/345/215/260/346/234/215/345/212/241.http +0 -17
  70. package//346/226/207/344/271/246/346/211/223/345/215/260/350/275/254/346/215/242/345/231/250.bat +0 -2
@@ -1,22 +0,0 @@
1
- import { Router } from "express";
2
- import {
3
- HomeController,
4
- appKeyValidator,
5
- PdfController,
6
- SplitController,
7
- } from "../components/home";
8
- import { sanitizer } from "../helpers";
9
-
10
- const router = Router();
11
-
12
- router.get("/", sanitizer(appKeyValidator), HomeController.getAppInfo);
13
- //正常都用一个的 post传输的数据量比get大得多;
14
- //基本都统一入口:
15
- router.post("/pdf", sanitizer(appKeyValidator), PdfController.postMakePdf);
16
-
17
- //为了支持拆分pdf操作:
18
- router.post("/split", sanitizer(appKeyValidator), SplitController.postSplitPdf);
19
-
20
- export default router;
21
-
22
- //厂家的文档: https://pdf-lib.js.org/ https://www.npmjs.com/package/pdf-lib
package/src/server.ts DELETED
@@ -1,30 +0,0 @@
1
- import { Server, createServer } from "http";
2
- import e from "express";
3
- // @ts-ignore
4
- import config from "config";
5
- import { exitLog } from "./helpers";
6
- import CONFIG from "./configEnv";
7
- //自定义服务端口:
8
- const server_port = config.get("server_port");
9
-
10
- export const startServer = (app: e.Application): Server => {
11
- const httpServer = createServer(app);
12
-
13
- process
14
- .on("SIGINT", () => exitLog(null, "SIGINT"))
15
- .on("SIGQUIT", () => exitLog(null, "SIGQUIT"))
16
- .on("SIGTERM", () => exitLog(null, "SIGTERM"))
17
- .on("uncaughtException", (err) => exitLog(err, "uncaughtException"))
18
- .on("beforeExit", () => exitLog(null, "beforeExit"))
19
- .on("exit", () => exitLog(null, "exit"));
20
-
21
- //自定义用server_port替代掉 CONFIG.APP.PORT;
22
-
23
- return httpServer.listen({ port: server_port }, (): void => {
24
- process.stdout.write(`⚙️ Application Environment: ${CONFIG.APP.ENV}\n`);
25
- process.stdout.write(`⏱ Started on: ${Date.now()}\n`);
26
- process.stdout.write(
27
- `🚀 文书打印转换器启动好 http://localhost:${server_port}\n`,
28
- );
29
- });
30
- };
package/src/testCSS.html DELETED
@@ -1,241 +0,0 @@
1
- <!DOCTYPE html>
2
- <html>
3
- <head>
4
- <meta charset="utf-8">
5
- <meta name="robots" content="noindex, nofollow">
6
- <style>
7
- body {
8
- padding: 0;
9
- margin: 0;
10
- }
11
-
12
- svg:not(:root) {
13
- display: block;
14
- }
15
-
16
- .playable-code {
17
- background-color: #f4f7f8;
18
- border: none;
19
- border-left: 6px solid #558abb;
20
- border-width: medium medium medium 6px;
21
- color: #4d4e53;
22
- height: 100px;
23
- width: 90%;
24
- padding: 10px 10px 0;
25
- }
26
-
27
- .playable-canvas {
28
- border: 1px solid #4d4e53;
29
- border-radius: 2px;
30
- }
31
-
32
- .playable-buttons {
33
- text-align: right;
34
- width: 90%;
35
- padding: 5px 10px 5px 26px;
36
- }
37
- </style>
38
-
39
- <style>
40
- fieldset {
41
- display: flex;
42
- flex-direction: row;
43
- justify-content: space-between;
44
- gap: 1rem;
45
- width: fit-content;
46
- }
47
-
48
- @page toc {
49
- size: a4 portrait;
50
- @top-middle {
51
- content: "Table of contents";
52
- }
53
- }
54
-
55
- @page foreword {
56
- size: a4 portrait;
57
- @top-middle {
58
- content: "Foreword";
59
- }
60
- }
61
-
62
- @page introduction {
63
- size: a4 portrait;
64
- @top-middle {
65
- content: "Introduction";
66
- }
67
- }
68
-
69
- @page conclusion {
70
- size: a4 portrait;
71
- @top-middle {
72
- content: "Conclusion";
73
- }
74
- }
75
-
76
- @page chapter {
77
- size: a4 landscape;
78
- @top-middle {
79
- content: "Chapter";
80
- }
81
- }
82
-
83
- @media print {
84
- fieldset {
85
- display: none;
86
- }
87
- section {
88
- font-size: 2rem;
89
- font-family: Roboto;
90
- }
91
- .chapter {
92
- border: tomato 2px solid;
93
- }
94
- [data-print="grouped"] > #toc,
95
- [data-print="paged"] > #toc {
96
- page: toc;
97
- font-family: Courier;
98
- }
99
- [data-print="grouped"] > #foreword,
100
- [data-print="paged"] > #foreword {
101
- page: foreword;
102
- font-family: Courier;
103
- }
104
- [data-print="grouped"] > #introduction,
105
- [data-print="paged"] > #introduction {
106
- page: introduction;
107
- font-family: Courier;
108
- }
109
- [data-print="grouped"] > #conclusion,
110
- [data-print="paged"] > #conclusion {
111
- page: conclusion;
112
- font-family: Courier;
113
- }
114
- [data-print="grouped"] > .chapter,
115
- [data-print="paged"] > .chapter {
116
- page: chapter;
117
- }
118
- [data-print="paged"] > .chapter {
119
- border: none;
120
- break-after: page;
121
- }
122
- .chapter > ul {
123
- columns: 2;
124
- }
125
- }
126
-
127
- </style>
128
-
129
- <title>page - named_page_example - code sample</title>
130
-
131
- </head>
132
- <body>
133
-
134
- <!-- print options 文档看 https://developer.mozilla.org/en-US/docs/Web/CSS/page#named_page_example
135
- [data-print="paged"] > .chapter { 属性选择符号?
136
- -->
137
-
138
- <fieldset id="printStyle">
139
- <legend>How would you like to print</legend>
140
- <label for="single"
141
- ><input type="radio" id="single" name="type" value="single" checked />No
142
- Pages</label
143
- >
144
- <label for="grouped"
145
- ><input type="radio" id="grouped" name="type" value="grouped" />Pages with
146
- Grouped Chapters</label
147
- >
148
- <label for="paged"
149
- ><input type="radio" id="paged" name="type" value="paged" />Chapters
150
- Paged</label
151
- >
152
- <button id="print">Print</button>
153
- </fieldset>
154
- <!-- Content to be printed -->
155
- <article id="print-area" data-print="single">
156
- <section id="toc">
157
- <h2>Table of contents</h2>
158
- <ul>
159
- <li>Foreword</li>
160
- <li>Introduction</li>
161
- <li>Chapter One - named pages</li>
162
- <li>Chapter Two - page orientation</li>
163
- <li>Chapter Three - page margins</li>
164
- <li>Conclusion</li>
165
- </ul>
166
- </section>
167
- <section id="foreword">
168
- <h2>Foreword</h2>
169
- <p>
170
- This book is all about how the CSS <code>@page</code> at-rule can help
171
- with printing HTML books.
172
- </p>
173
- </section>
174
- <section id="introduction">
175
- <h2>Introduction</h2>
176
- <p>
177
- This book is a concept to show how an <em>HTML</em> document can easily be
178
- printed out in pages.
179
- </p>
180
- </section>
181
- <section id="chapter1" class="chapter">
182
- <h2>Named pages</h2>
183
- <p>Lorem ipsum</p>
184
- </section>
185
- <section id="chapter2" class="chapter">
186
- <h2>Page Orientation</h2>
187
- <p>Lorem ipsum</p>
188
- </section>
189
- <section id="chapter3" class="chapter">
190
- <h2>Page Margins</h2>
191
- <p>There are 16 page margins that can be set:</p>
192
- <ul>
193
- <li>@top-left-corner</li>
194
- <li>@top-left</li>
195
- <li>@top-middle</li>
196
- <li>@top-right</li>
197
- <li>@top-right-corner</li>
198
- <li>@left-top</li>
199
- <li>@left-middle</li>
200
- <li>@left-bottom</li>
201
- <li>@right-top</li>
202
- <li>@right-middle</li>
203
- <li>@right-bottom</li>
204
- <li>@bottom-left-corner</li>
205
- <li>@bottom-left</li>
206
- <li>@bottom-middle</li>
207
- <li>@bottom-right</li>
208
- <li>@bottom-right-corner</li>
209
- </ul>
210
- <p>They can be used to show what appears in these parts of the margin</p>
211
- </section>
212
- <section id="conclusion">
213
- <h2>Conclusion</h2>
214
- <p>Now go ahead and write books.</p>
215
- </section>
216
- </article>
217
-
218
-
219
-
220
- <script>
221
- const printArea = document.querySelector("#print-area");
222
- const printButton = document.querySelector("#print");
223
- const printOption = document.querySelector("#printStyle");
224
- printOption.addEventListener("change", (event) => {
225
- //对调paged single: ?? .dataset.print如何变身 data-print="single"属性值的??
226
- if (event.target.value === "single") {
227
- printArea.dataset.print = "paged";
228
- } else if (event.target.value === "grouped") {
229
- printArea.dataset.print = "grouped";
230
- } else {
231
- printArea.dataset.print = "single";
232
- }
233
- });
234
- printButton.addEventListener("click", () => {
235
- window.print();
236
- });
237
-
238
- </script>
239
-
240
- </body>
241
- </html>
@@ -1,13 +0,0 @@
1
- import { Request, Response, NextFunction } from "express";
2
-
3
- declare global {
4
- type TodoType = any;
5
- type Req = Request;
6
- type Res = Response;
7
- type NextFn = NextFunction;
8
- type ResponseData<T> = {
9
- opcode: number;
10
- message: string;
11
- data?: T;
12
- };
13
- }
@@ -1,70 +0,0 @@
1
- /*看 Page.printToPDF()文档说明的: 可以使用的注入参数:
2
- date: formatted print date
3
- title: document title
4
- url: document location
5
- pageNumber: current page number
6
- totalPages: total pages in the document
7
- For example, <span class=title></span> would generate span containing the title.
8
- */
9
-
10
- /**页眉页脚声明;前提条件是页眉页脚htm描述里面: 上一个版本保留字 ${pageNumber} ${totalPages}
11
- * 不应该把 -NOT_DISPLAY- ~pageNumber~ ~totalPages~ 这三个 保留字字符串当作普通文字输出的。
12
- * 前端发送数据包时刻,页眉页脚的脚本需要在 HTML转JSON 工具网站 进行转换处理后的;网站地址 https://uutool.cn/html2json/ 转换htm模板后是数组[string]
13
- * 实际上也就进行拆分多行字符串拼接数组,还有把html语法中的 ""引号 进行转义 style="position: 变成 style=\\\"position: 处置的。
14
- * */
15
- export interface HeadFooter {
16
- //每一个URL独立设置的 页眉 的 : 若是配置值=null 表示不要打印本页眉: 针对本url。
17
- //双面打印:右手边位置的,或单面打印使用
18
- head?: string | string[] | null;
19
- //每一个页 页脚的
20
- //每一个URL独立设置的 页脚的 : 若是配置值=null 表示不要打印本页脚的, 针对本url。
21
- //双面打印:右手边位置的,或单面打印使用
22
- foot?: string | string[] | null; //实际前端发过来却是[string]的也可以啊。
23
- /**可注入3个参数"特殊标记字符串"如下: 服务端依据参数来对注入的html进行修改的。
24
- * ~pageNumber~
25
- * ~totalPages~
26
- * -NOT_DISPLAY- 有页码才能显示,无页码就隐藏的标记。
27
- * 这三个分别代表 页码 总页数 以及页码<div style=""></div>中的可替代占位位置。
28
- * 其它2个替换成数字号码。
29
- * */
30
- //双面打印:左手边位置的
31
- headL?: string | string[] | null;
32
- //双面打印:左手边位置的
33
- footL?: string | string[] | null;
34
- }
35
-
36
- /**实际在第二步骤也即汇总阶段:页眉页脚的生成底下的参数size,landscape,reverseRanges,marginLeft,marginRight几个都不会涉及到了。
37
- * */
38
- export interface PartHeadFooter extends HeadFooter {
39
- //纸张大小: 纸张大小尺寸+布局方向是自定义系列的:
40
- //a5 a4 a3 b5 b4 jis-b5 jis-b4 letter legal ledger auto 等常见的名字, 默认是 "a4 portrait"
41
- //中国:默认值改成是 a4 portrait
42
- size: string;
43
- //W3C标准纸张大小,横着的吗; 但是非标准尺寸的#自定义的没有这个选择参数的!。 默认是 "portrait"
44
- landscape: boolean;
45
- //背景, 默认 =false
46
- printBackground: boolean;
47
-
48
- //底下的这四个参数默认都=1cm (~0.4 inches); 若要做配置的必须是英寸为单位的数字, 【单位 注意】
49
- marginTop?: number;
50
- marginBottom?: number;
51
- //就算纸张是横屏的:Chrome生成页眉页脚的位置实际也没牵涉到marginLeft,marginRight;
52
- marginLeft?: number;
53
- marginRight?: number;
54
- //默认全部打印的,#可自定义部分页面输出的。 Paper ranges to print, one based, e.g., '1-5, 8, 11-13'.
55
- pageRanges?: string;
56
- }
57
-
58
- /**配置自定义地非标准纸张尺寸, 横竖纸张要独立配置。
59
- * */
60
- export interface MyPaperSize {
61
- //自定义的尺寸名称 ,前端发送数据包时用这个名字 替换通常的 a4 a5 a3等,纸张横的竖的要定义两个标签。
62
- name: string;
63
- //W3C @page size{}语境中配的描述串。 如下:"4in 6in", 前面4英寸宽度的纸张。
64
- //{"name":"D8", "css": "4in 6in","w": 4,"h": 6},
65
- css: string;
66
- //纸张 4 英寸宽度 "w": 4,
67
- w: number;
68
- //纸张高度: 英寸单位的,必须和css参数确保一致性。
69
- h: number;
70
- }
@@ -1,3 +0,0 @@
1
- import CONFIG from "../../configEnv";
2
-
3
- export type getAppInfoQuery = `${Lowercase<keyof typeof CONFIG.APP>}`;
@@ -1,18 +0,0 @@
1
- /**拆分大的pdf文件,输出部分页数的小的pdf
2
- * 支持按pdf纸张页面进行重新排序, 部分提取页数。
3
- * */
4
- export interface SplitConfig {
5
- //等待拆分大的df文件名, 需要加 .pdf结尾的;只能是pdf文档!
6
- input: string;
7
- //每一个独立的pdf生成:
8
- files: [SplitPdfFile];
9
- }
10
-
11
- export interface SplitPdfFile {
12
- //定义部分页面输出的。 Paper ranges to print, one based, e.g., '1-5, 8, 11-13'.
13
- pageRanges: string;
14
- //输出本地工作目录的文件名, 不需要加 .pdf结尾的。
15
- //【特别】必须配置唯一性 的本地 工作目录的文件名,同名的被直接覆盖了。
16
- //拆分提取的pdf输出页面顺序是依据pageRanges所选定的顺序来输出的,不是原本pdf的顺序。
17
- out: string;
18
- }
@@ -1,9 +0,0 @@
1
- /**
2
- * Application Information response strucuture.
3
- */
4
- interface AppInformation {
5
- NAME: string;
6
- VERSION: string;
7
- }
8
-
9
- export default AppInformation;
@@ -1,5 +0,0 @@
1
- export interface ApiSuccessResponse<T> {
2
- status: number;
3
- message: string;
4
- data?: T;
5
- }
@@ -1,19 +0,0 @@
1
- import { differenceWith, isEqual } from "lodash-es";
2
-
3
- export interface ArrayDifference {
4
- added: any[];
5
- removed: any[];
6
- }
7
-
8
- /**
9
- *
10
- * @param {any[]} arr1
11
- * @param {any[]} arr2
12
- * @returns {ArrayDifference}
13
- */
14
- export const diff = (arr1: any[], arr2: any[]): ArrayDifference => {
15
- const added = differenceWith(arr2, arr1, isEqual);
16
- const removed = differenceWith(arr1, arr2, isEqual);
17
-
18
- return { added, removed };
19
- };
package/src/utils/auth.ts DELETED
@@ -1,12 +0,0 @@
1
- /**
2
- * @description hide password content with '*'
3
- * @param {object} bodyData
4
- * @returns bodyData with formatted 'password'
5
- */
6
- export const hidePassword = (bodyData: Record<string, any>) => {
7
- if (bodyData.hasOwnProperty("password")) {
8
- bodyData.password = "********";
9
- }
10
-
11
- return bodyData;
12
- };
@@ -1,25 +0,0 @@
1
- // import bcrypt from "bcrypt";
2
-
3
- /**
4
- * @description Create a bcrypt hash for a string.
5
- * @param {string} value
6
- * @returns {Promise<any>}
7
- */
8
- // export const hash = async (value: string): Promise<any> => {
9
- // const saltRounds = parseInt(CONFIG.AUTH.SALT_ROUNDS, 10);
10
- //
11
- // return bcrypt.hash(value, saltRounds);
12
- // };
13
-
14
- /**
15
- * @description Compare a string with the hash.
16
- * @param {string} value
17
- * @param {string} hashedValue
18
- * @returns {Promise<boolean>}
19
- */
20
- // export const compare = async (
21
- // value: string,
22
- // hashedValue: string,
23
- // ): Promise<boolean> => {
24
- // return bcrypt.compare(value, hashedValue);
25
- // };
@@ -1,59 +0,0 @@
1
- /**
2
- * Converts empty value to null.
3
- *
4
- * @param obj
5
- * @returns {*}
6
- */
7
- export const emptyToNull = (obj: any): any => {
8
- if (isScalarType(obj)) {
9
- return obj;
10
- }
11
-
12
- if (Array.isArray(obj)) {
13
- return obj.map(emptyToNull);
14
- }
15
-
16
- const result: any = {};
17
-
18
- for (const key of Object.keys(obj)) {
19
- const value = obj[key];
20
-
21
- if (typeof value === "object") {
22
- result[key] = emptyToNull(value);
23
- } else {
24
- result[key] = nullIfEmpty(value);
25
- }
26
- }
27
-
28
- return result;
29
- };
30
-
31
- /**
32
- * Returns if scalar type.
33
- *
34
- * @param obj
35
- * @returns {boolean}
36
- */
37
- const isScalarType = (obj: any) => {
38
- return (
39
- typeof obj !== "object" ||
40
- obj instanceof String ||
41
- obj instanceof Number ||
42
- obj instanceof Boolean ||
43
- obj === null
44
- );
45
- };
46
-
47
- /**
48
- * Changes empty value to null.
49
- *
50
- * @param value
51
- * @returns {*}
52
- */
53
- const nullIfEmpty = (value: any) => {
54
- if (typeof value !== "string") {
55
- return value;
56
- }
57
-
58
- return value.trim() === "" ? null : value;
59
- };
@@ -1,58 +0,0 @@
1
- import { differenceBy, intersectionBy } from "lodash-es";
2
-
3
- /**
4
- * Get the copy of object without attributes.
5
- *
6
- * @param {Object} obj
7
- * @param {Array} attrsToExclude
8
- * @return {Object}
9
- */
10
- export const withoutAttrs = (obj: any, attrsToExclude: any[]) => {
11
- const result: any = {};
12
-
13
- Object.keys(obj).forEach((key: string) => {
14
- if (!attrsToExclude.includes(key)) {
15
- result[key] = obj[key];
16
- }
17
- });
18
-
19
- return result;
20
- };
21
-
22
- /**
23
- * Get the copy of object with only specified attributes.
24
- *
25
- * @param {Object} obj
26
- * @param {Array} attrs
27
- * @return {Object}
28
- */
29
- export const withOnlyAttrs = (obj: any, attrs: any[]) => {
30
- const result: any = {};
31
-
32
- Object.keys(obj).forEach((key) => {
33
- if (attrs.includes(key)) {
34
- result[key] = obj[key];
35
- }
36
- });
37
-
38
- return result;
39
- };
40
-
41
- /**
42
- * Compare array of two objects and find data that needs to be create, update
43
- * and delete.
44
- *
45
- * @param {Array} list1
46
- * @param {Array} list2
47
- * @param {String} key
48
- * @returns {Object}
49
- */
50
- export const difference = (list1: any[], list2: any[], key = "id") => {
51
- return {
52
- create: list2
53
- .filter((obj) => obj.hasOwnProperty(key) && obj[key] === null)
54
- .map((obj) => withoutAttrs(obj, [key])),
55
- update: intersectionBy(list2, list1, key),
56
- destroy: differenceBy(list1, list2, key).map((obj: any) => obj[key]),
57
- };
58
- };