@tinacms/cli 0.60.17 → 0.60.18

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/CHANGELOG.md CHANGED
@@ -1,5 +1,19 @@
1
1
  # tinacms-cli
2
2
 
3
+ ## 0.60.18
4
+
5
+ ### Patch Changes
6
+
7
+ - 79d112d79: Update cli to accept tinaCloudMediaStore flag and add to metadata during schema compilation
8
+ - 91d6e6758: revert platform aware paths in schema introduced in https://github.com/tinacms/tinacms/commit/558cc4368cd2a4b6e87dfb82bbfbb6f569f8a6f8
9
+ - b1240328d: Adds local server routes for handling media
10
+ - 91d6e6758: Fix issues with experimentalData on windows related to path separator inconsistency and interference with the .tina/**generated** folder
11
+ - Updated dependencies [79d112d79]
12
+ - Updated dependencies [3f46c6706]
13
+ - Updated dependencies [db9168578]
14
+ - Updated dependencies [91d6e6758]
15
+ - @tinacms/graphql@0.60.3
16
+
3
17
  ## 0.60.17
4
18
 
5
19
  ### Patch Changes
@@ -10,4 +10,4 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10
10
  See the License for the specific language governing permissions and
11
11
  limitations under the License.
12
12
  */
13
- export declare const defaultSchema: (sep: string) => string;
13
+ export declare const defaultSchema = "\nimport { defineSchema, defineConfig } from \"tinacms\";\n\nconst schema = defineSchema({\n collections: [\n {\n label: \"Blog Posts\",\n name: \"posts\",\n path: \"content/posts\",\n fields: [\n {\n type: \"string\",\n label: \"Title\",\n name: \"title\",\n },\n {\n type: \"rich-text\",\n label: \"Blog Post Body\",\n name: \"body\",\n isBody: true,\n templates: [\n {\n name: \"PageSection\",\n label: \"Page Section\",\n fields: [\n {\n type: \"string\",\n name: \"heading\",\n label: \"Heading\",\n },\n {\n type: \"string\",\n name: \"content\",\n label: \"Content\",\n ui: {\n component: \"textarea\"\n }\n }\n ],\n },\n ]\n },\n ],\n },\n ],\n});\n\nexport default schema\n\n// Your tina config\n// ==============\nconst branch = 'main'\n// When working locally, hit our local filesystem.\n// On a Vercel deployment, hit the Tina Cloud API\nconst apiURL =\n process.env.NODE_ENV == 'development'\n ? 'http://localhost:4001/graphql'\n : `https://content.tinajs.io/content/${process.env.NEXT_PUBLIC_TINA_CLIENT_ID}/github/${branch}`\n\nexport const tinaConfig = defineConfig({\n apiURL,\n schema,\n cmsCallback: (cms) => {\n // add your CMS callback code here (if you want)\n\n // The Route Mapper\n /**\n * 1. Import `tinacms` and `RouteMappingPlugin`\n **/\n import(\"tinacms\").then(({ RouteMappingPlugin }) => {\n /**\n * 2. Define the `RouteMappingPlugin` see https://tina.io/docs/tinacms-context/#the-routemappingplugin for more details\n **/\n const RouteMapping = new RouteMappingPlugin((collection, document) => {\n return undefined;\n });\n /**\n * 3. Add the `RouteMappingPlugin` to the `cms`.\n **/\n cms.plugins.add(RouteMapping);\n });\n\n return cms;\n },\n});\n";
@@ -15,10 +15,11 @@ interface Options {
15
15
  command?: string;
16
16
  watchFolders?: string[];
17
17
  experimentalData?: boolean;
18
+ tinaCloudMediaStore?: boolean;
18
19
  noWatch?: boolean;
19
20
  noSDK: boolean;
20
21
  noTelemetry: boolean;
21
22
  verbose?: boolean;
22
23
  }
23
- export declare function startServer(_ctx: any, _next: any, { port, command, noWatch, experimentalData, noSDK, noTelemetry, watchFolders, verbose, }: Options): Promise<void>;
24
+ export declare function startServer(_ctx: any, _next: any, { port, command, noWatch, experimentalData, tinaCloudMediaStore, noSDK, noTelemetry, watchFolders, verbose, }: Options): Promise<void>;
24
25
  export {};
@@ -10,7 +10,5 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10
10
  See the License for the specific language governing permissions and
11
11
  limitations under the License.
12
12
  */
13
- /// <reference types="node" />
14
- import http from 'http';
15
- declare const gqlServer: (database: any) => Promise<http.Server>;
13
+ import { gqlServer } from '../../server';
16
14
  export default gqlServer;
package/dist/index.js CHANGED
@@ -54,22 +54,112 @@ var __toModule = (module2) => {
54
54
  return __reExport(__markAsModule(__defProp(module2 != null ? __create(__getProtoOf(module2)) : {}, "default", module2 && module2.__esModule && "default" in module2 ? { get: () => module2.default, enumerable: true } : { value: module2, enumerable: true })), module2);
55
55
  };
56
56
 
57
- // pnp:/home/runner/work/tinacms/tinacms/packages/@tinacms/cli/src/cmds/start-server/server.ts
58
- var server_exports = {};
59
- __export(server_exports, {
60
- default: () => server_default
57
+ // pnp:/home/runner/work/tinacms/tinacms/packages/@tinacms/cli/src/server/models/media.ts
58
+ var import_fs_extra5, import_path6, MediaModel;
59
+ var init_media = __esm({
60
+ "pnp:/home/runner/work/tinacms/tinacms/packages/@tinacms/cli/src/server/models/media.ts"() {
61
+ import_fs_extra5 = __toModule(require("fs-extra"));
62
+ import_path6 = __toModule(require("path"));
63
+ MediaModel = class {
64
+ constructor({ basePath }) {
65
+ this.basePath = basePath;
66
+ }
67
+ async listMedia(args) {
68
+ try {
69
+ const folderPath = (0, import_path6.join)(this.basePath, args.searchPath);
70
+ const filesStr = await import_fs_extra5.default.readdir(folderPath);
71
+ const filesProm = filesStr.map(async (x) => {
72
+ const filePath = (0, import_path6.join)(folderPath, x);
73
+ const stat = await import_fs_extra5.default.stat(filePath);
74
+ const src = (0, import_path6.join)(args.searchPath, x);
75
+ return {
76
+ size: stat.size,
77
+ fileName: x,
78
+ src: "/" + src,
79
+ isFile: stat.isFile()
80
+ };
81
+ });
82
+ const files = await Promise.all(filesProm);
83
+ return {
84
+ files: files.filter((x) => x.isFile),
85
+ directories: files.filter((x) => !x.isFile).map((x) => x.src)
86
+ };
87
+ } catch (error) {
88
+ console.error(error);
89
+ return {
90
+ files: [],
91
+ directories: [],
92
+ error: error == null ? void 0 : error.toString()
93
+ };
94
+ }
95
+ }
96
+ async deleteMedia(args) {
97
+ try {
98
+ const file = (0, import_path6.join)(this.basePath, args.searchPath);
99
+ await import_fs_extra5.default.stat(file);
100
+ await import_fs_extra5.default.remove(file);
101
+ return { ok: true };
102
+ } catch (error) {
103
+ console.error(error);
104
+ return { ok: false, message: error == null ? void 0 : error.toString() };
105
+ }
106
+ }
107
+ };
108
+ }
109
+ });
110
+
111
+ // pnp:/home/runner/work/tinacms/tinacms/packages/@tinacms/cli/src/server/routes/index.ts
112
+ var import_express, import_path7, import_multer, mediaFolder, storage, upload, mediaModel, mediaRouter;
113
+ var init_routes = __esm({
114
+ "pnp:/home/runner/work/tinacms/tinacms/packages/@tinacms/cli/src/server/routes/index.ts"() {
115
+ import_express = __toModule(require("express"));
116
+ import_path7 = __toModule(require("path"));
117
+ import_multer = __toModule(require("multer"));
118
+ init_media();
119
+ mediaFolder = (0, import_path7.join)(process.cwd(), "public");
120
+ storage = import_multer.default.diskStorage({
121
+ destination: function(req, file, cb) {
122
+ cb(null, mediaFolder);
123
+ },
124
+ filename: function(req, _file, cb) {
125
+ const file = req.params[0];
126
+ cb(null, file);
127
+ }
128
+ });
129
+ upload = (0, import_multer.default)({ storage });
130
+ mediaModel = new MediaModel({ basePath: mediaFolder });
131
+ mediaRouter = (0, import_express.Router)();
132
+ mediaRouter.get("/list/*", async (req, res) => {
133
+ const folder = req.params[0];
134
+ const media = await mediaModel.listMedia({
135
+ searchPath: folder
136
+ });
137
+ res.json(media);
138
+ });
139
+ mediaRouter.delete("/delete/*", async (req, res) => {
140
+ const file = req.params[0];
141
+ const didDelete = await mediaModel.deleteMedia({ searchPath: file });
142
+ res.json(didDelete);
143
+ });
144
+ mediaRouter.post("/upload/*", upload.single("file"), function(req, res, next) {
145
+ res.json({ ok: true });
146
+ });
147
+ }
61
148
  });
62
- var import_cors, import_http, import_express, import_altair_express_middleware, import_body_parser, gqlServer, server_default;
149
+
150
+ // pnp:/home/runner/work/tinacms/tinacms/packages/@tinacms/cli/src/server/server.ts
151
+ var import_cors, import_http, import_express2, import_altair_express_middleware, import_body_parser, gqlServer;
63
152
  var init_server = __esm({
64
- "pnp:/home/runner/work/tinacms/tinacms/packages/@tinacms/cli/src/cmds/start-server/server.ts"() {
153
+ "pnp:/home/runner/work/tinacms/tinacms/packages/@tinacms/cli/src/server/server.ts"() {
65
154
  import_cors = __toModule(require("cors"));
66
155
  import_http = __toModule(require("http"));
67
- import_express = __toModule(require("express"));
156
+ import_express2 = __toModule(require("express"));
68
157
  import_altair_express_middleware = __toModule(require("altair-express-middleware"));
69
158
  import_body_parser = __toModule(require("body-parser"));
159
+ init_routes();
70
160
  gqlServer = async (database) => {
71
161
  const gqlPackage = require("@tinacms/graphql");
72
- const app = (0, import_express.default)();
162
+ const app = (0, import_express2.default)();
73
163
  const server = import_http.default.createServer(app);
74
164
  app.use((0, import_cors.default)());
75
165
  app.use(import_body_parser.default.json());
@@ -103,8 +193,28 @@ var init_server = __esm({
103
193
  });
104
194
  return res.json(result);
105
195
  });
196
+ app.use("/media", mediaRouter);
106
197
  return server;
107
198
  };
199
+ }
200
+ });
201
+
202
+ // pnp:/home/runner/work/tinacms/tinacms/packages/@tinacms/cli/src/server/index.ts
203
+ var init_server2 = __esm({
204
+ "pnp:/home/runner/work/tinacms/tinacms/packages/@tinacms/cli/src/server/index.ts"() {
205
+ init_server();
206
+ }
207
+ });
208
+
209
+ // pnp:/home/runner/work/tinacms/tinacms/packages/@tinacms/cli/src/cmds/start-server/server.ts
210
+ var server_exports = {};
211
+ __export(server_exports, {
212
+ default: () => server_default
213
+ });
214
+ var server_default;
215
+ var init_server3 = __esm({
216
+ "pnp:/home/runner/work/tinacms/tinacms/packages/@tinacms/cli/src/cmds/start-server/server.ts"() {
217
+ init_server2();
108
218
  server_default = gqlServer;
109
219
  }
110
220
  });
@@ -118,7 +228,7 @@ var commander = __toModule(require("commander"));
118
228
 
119
229
  // pnp:/home/runner/work/tinacms/tinacms/packages/@tinacms/cli/package.json
120
230
  var name = "@tinacms/cli";
121
- var version = "0.60.17";
231
+ var version = "0.60.18";
122
232
 
123
233
  // pnp:/home/runner/work/tinacms/tinacms/packages/@tinacms/cli/src/cmds/query-gen/attachSchema.ts
124
234
  var import_graphql = __toModule(require("@tinacms/graphql"));
@@ -1289,7 +1399,7 @@ var import_path5 = __toModule(require("path"));
1289
1399
  var import_esbuild = __toModule(require("esbuild"));
1290
1400
 
1291
1401
  // pnp:/home/runner/work/tinacms/tinacms/packages/@tinacms/cli/src/cmds/compile/defaultSchema.ts
1292
- var defaultSchema = (sep) => `
1402
+ var defaultSchema = `
1293
1403
  import { defineSchema, defineConfig } from "tinacms";
1294
1404
 
1295
1405
  const schema = defineSchema({
@@ -1297,7 +1407,7 @@ const schema = defineSchema({
1297
1407
  {
1298
1408
  label: "Blog Posts",
1299
1409
  name: "posts",
1300
- path: "content${sep}posts",
1410
+ path: "content/posts",
1301
1411
  fields: [
1302
1412
  {
1303
1413
  type: "string",
@@ -1454,7 +1564,7 @@ var compile = async (_ctx, _next, options) => {
1454
1564
  `));
1455
1565
  const file = import_path5.default.join(tinaPath, `schema.${schemaFileType2}`);
1456
1566
  await import_fs_extra4.default.ensureFile(file);
1457
- await import_fs_extra4.default.writeFile(file, defaultSchema(import_path5.default.sep));
1567
+ await import_fs_extra4.default.writeFile(file, defaultSchema);
1458
1568
  }
1459
1569
  try {
1460
1570
  await transpile(tinaPath, tinaTempPath, options.verbose);
@@ -1555,7 +1665,7 @@ var import_metrics3 = __toModule(require("@tinacms/metrics"));
1555
1665
  var import_chalk6 = __toModule(require("chalk"));
1556
1666
  var import_child_process = __toModule(require("child_process"));
1557
1667
  var import_chokidar = __toModule(require("chokidar"));
1558
- var import_path6 = __toModule(require("path"));
1668
+ var import_path8 = __toModule(require("path"));
1559
1669
  var lock = new AsyncLock();
1560
1670
  var gqlPackageFile = require.resolve("@tinacms/graphql");
1561
1671
  async function startServer(_ctx, _next, {
@@ -1563,6 +1673,7 @@ async function startServer(_ctx, _next, {
1563
1673
  command,
1564
1674
  noWatch,
1565
1675
  experimentalData,
1676
+ tinaCloudMediaStore: tinaCloudMediaStore2,
1566
1677
  noSDK,
1567
1678
  noTelemetry,
1568
1679
  watchFolders,
@@ -1611,11 +1722,17 @@ stack: ${code.stack || "No stack was provided"}`);
1611
1722
  lock.enable();
1612
1723
  try {
1613
1724
  if (!process.env.CI && !noWatch) {
1725
+ await store.close();
1614
1726
  await resetGeneratedFolder();
1727
+ await store.open();
1728
+ }
1729
+ const cliFlags = [];
1730
+ if (tinaCloudMediaStore2) {
1731
+ cliFlags.push("tinaCloudMediaStore");
1615
1732
  }
1616
1733
  const database2 = await (0, import_graphql10.createDatabase)({ store, bridge });
1617
1734
  await compile(null, null, { verbose });
1618
- const schema = await (0, import_graphql10.buildSchema)(rootPath2, database2);
1735
+ const schema = await (0, import_graphql10.buildSchema)(rootPath2, database2, cliFlags);
1619
1736
  await genTypes({ schema }, () => {
1620
1737
  }, { noSDK: noSDK2, verbose });
1621
1738
  } catch (error) {
@@ -1624,7 +1741,7 @@ stack: ${code.stack || "No stack was provided"}`);
1624
1741
  lock.disable();
1625
1742
  }
1626
1743
  };
1627
- const foldersToWatch = (watchFolders || []).map((x) => import_path6.default.join(rootPath2, x));
1744
+ const foldersToWatch = (watchFolders || []).map((x) => import_path8.default.join(rootPath2, x));
1628
1745
  if (!noWatch && !process.env.CI) {
1629
1746
  import_chokidar.default.watch([
1630
1747
  ...foldersToWatch,
@@ -1633,7 +1750,7 @@ stack: ${code.stack || "No stack was provided"}`);
1633
1750
  ignored: [
1634
1751
  "**/node_modules/**/*",
1635
1752
  "**/.next/**/*",
1636
- `${import_path6.default.resolve(rootPath2)}/.tina/__generated__/**/*`
1753
+ `${import_path8.default.resolve(rootPath2)}/.tina/__generated__/**/*`
1637
1754
  ]
1638
1755
  }).on("ready", async () => {
1639
1756
  if (verbose)
@@ -1678,7 +1795,7 @@ stack: ${code.stack || "No stack was provided"}`);
1678
1795
  };
1679
1796
  let isReady = false;
1680
1797
  const start = async () => {
1681
- const s = (init_server(), server_exports);
1798
+ const s = (init_server3(), server_exports);
1682
1799
  state.server = await s.default(database);
1683
1800
  state.server.listen(port, () => {
1684
1801
  const altairUrl = `http://localhost:${port}/altair/`;
@@ -1783,6 +1900,10 @@ var verboseOption = {
1783
1900
  name: "-v, --verbose",
1784
1901
  description: "increase verbosity of logged output"
1785
1902
  };
1903
+ var tinaCloudMediaStore = {
1904
+ name: "--tinaCloudMediaStore",
1905
+ description: "Automatically pushes updates from GitHub to the Tina Cloud Media Store"
1906
+ };
1786
1907
  var baseCmds = [
1787
1908
  {
1788
1909
  command: CMD_START_SERVER,
@@ -1791,6 +1912,7 @@ var baseCmds = [
1791
1912
  startServerPortOption,
1792
1913
  subCommand,
1793
1914
  experimentalDatalayer,
1915
+ tinaCloudMediaStore,
1794
1916
  noWatchOption,
1795
1917
  noSDKCodegenOption,
1796
1918
  noTelemetryOption,
@@ -1802,18 +1924,28 @@ var baseCmds = [
1802
1924
  {
1803
1925
  command: CMD_COMPILE_MODELS,
1804
1926
  description: "Compile schema into static files for the server",
1805
- options: [experimentalDatalayer, noTelemetryOption],
1927
+ options: [experimentalDatalayer, tinaCloudMediaStore, noTelemetryOption],
1806
1928
  action: (options) => chain([compile], options)
1807
1929
  },
1808
1930
  {
1809
1931
  command: CMD_GEN_TYPES,
1810
1932
  description: "Generate a GraphQL query for your site's schema, (and optionally Typescript types)",
1811
- options: [experimentalDatalayer, noSDKCodegenOption, noTelemetryOption],
1933
+ options: [
1934
+ experimentalDatalayer,
1935
+ tinaCloudMediaStore,
1936
+ noSDKCodegenOption,
1937
+ noTelemetryOption
1938
+ ],
1812
1939
  action: (options) => chain([attachSchema, genTypes], options)
1813
1940
  },
1814
1941
  {
1815
1942
  command: INIT,
1816
- options: [experimentalDatalayer, noTelemetryOption, schemaFileType],
1943
+ options: [
1944
+ experimentalDatalayer,
1945
+ tinaCloudMediaStore,
1946
+ noTelemetryOption,
1947
+ schemaFileType
1948
+ ],
1817
1949
  description: "Add Tina Cloud to an existing project",
1818
1950
  action: (options) => chain([
1819
1951
  checkDeps,
@@ -0,0 +1,13 @@
1
+ /**
2
+ Copyright 2021 Forestry.io Holdings, Inc.
3
+ Licensed under the Apache License, Version 2.0 (the "License");
4
+ you may not use this file except in compliance with the License.
5
+ You may obtain a copy of the License at
6
+ http://www.apache.org/licenses/LICENSE-2.0
7
+ Unless required by applicable law or agreed to in writing, software
8
+ distributed under the License is distributed on an "AS IS" BASIS,
9
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10
+ See the License for the specific language governing permissions and
11
+ limitations under the License.
12
+ */
13
+ export * from './server';
@@ -0,0 +1,41 @@
1
+ /**
2
+ Copyright 2021 Forestry.io Holdings, Inc.
3
+ Licensed under the Apache License, Version 2.0 (the "License");
4
+ you may not use this file except in compliance with the License.
5
+ You may obtain a copy of the License at
6
+ http://www.apache.org/licenses/LICENSE-2.0
7
+ Unless required by applicable law or agreed to in writing, software
8
+ distributed under the License is distributed on an "AS IS" BASIS,
9
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10
+ See the License for the specific language governing permissions and
11
+ limitations under the License.
12
+ */
13
+ interface MediaArgs {
14
+ searchPath: string;
15
+ }
16
+ interface File {
17
+ src: string;
18
+ fileName: string;
19
+ size: number;
20
+ }
21
+ interface ListMediaRes {
22
+ directories: string[];
23
+ files: File[];
24
+ cursor?: string;
25
+ error?: string;
26
+ }
27
+ declare type SuccessRecord = {
28
+ ok: true;
29
+ } | {
30
+ ok: false;
31
+ message: string;
32
+ };
33
+ export declare class MediaModel {
34
+ readonly basePath: string;
35
+ constructor({ basePath }: {
36
+ basePath: string;
37
+ });
38
+ listMedia(args: MediaArgs): Promise<ListMediaRes>;
39
+ deleteMedia(args: MediaArgs): Promise<SuccessRecord>;
40
+ }
41
+ export {};
@@ -0,0 +1,13 @@
1
+ /**
2
+ Copyright 2021 Forestry.io Holdings, Inc.
3
+ Licensed under the Apache License, Version 2.0 (the "License");
4
+ you may not use this file except in compliance with the License.
5
+ You may obtain a copy of the License at
6
+ http://www.apache.org/licenses/LICENSE-2.0
7
+ Unless required by applicable law or agreed to in writing, software
8
+ distributed under the License is distributed on an "AS IS" BASIS,
9
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10
+ See the License for the specific language governing permissions and
11
+ limitations under the License.
12
+ */
13
+ export declare const mediaRouter: import("express-serve-static-core").Router;
@@ -0,0 +1,15 @@
1
+ /**
2
+ Copyright 2021 Forestry.io Holdings, Inc.
3
+ Licensed under the Apache License, Version 2.0 (the "License");
4
+ you may not use this file except in compliance with the License.
5
+ You may obtain a copy of the License at
6
+ http://www.apache.org/licenses/LICENSE-2.0
7
+ Unless required by applicable law or agreed to in writing, software
8
+ distributed under the License is distributed on an "AS IS" BASIS,
9
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
10
+ See the License for the specific language governing permissions and
11
+ limitations under the License.
12
+ */
13
+ /// <reference types="node" />
14
+ import http from 'http';
15
+ export declare const gqlServer: (database: any) => Promise<http.Server>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tinacms/cli",
3
- "version": "0.60.17",
3
+ "version": "0.60.18",
4
4
  "main": "dist/index.js",
5
5
  "typings": "dist/index.d.ts",
6
6
  "files": [
@@ -35,6 +35,7 @@
35
35
  "@types/lodash": "^4.14.157",
36
36
  "@types/lodash.get": "^4.4.6",
37
37
  "@types/log4js": "^2.3.5",
38
+ "@types/multer": "^1.4.7",
38
39
  "@types/progress": "^2.0.3",
39
40
  "@types/prompts": "^2.0.13",
40
41
  "@types/yup": "^0.29.11",
@@ -58,7 +59,7 @@
58
59
  "@graphql-tools/graphql-file-loader": "^7.2.0",
59
60
  "@graphql-tools/load": "^7.3.2",
60
61
  "@tinacms/datalayer": "0.1.1",
61
- "@tinacms/graphql": "0.60.2",
62
+ "@tinacms/graphql": "0.60.3",
62
63
  "@tinacms/metrics": "0.0.3",
63
64
  "@tinacms/schema-tools": "0.0.4",
64
65
  "@yarnpkg/esbuild-plugin-pnp": "^2.0.1-rc.3",
@@ -82,6 +83,7 @@
82
83
  "lodash": "^4.17.19",
83
84
  "lodash.get": "^4.4.2",
84
85
  "log4js": "^6.4.0",
86
+ "multer": "^1.4.4",
85
87
  "normalize-path": "^3.0.0",
86
88
  "progress": "^2.0.3",
87
89
  "prompts": "^2.4.1",