@verdaccio/local-storage 10.0.7 → 11.0.0-6-next.9

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,126 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.getFolders = getFolders;
7
+ exports.searchOnStorage = searchOnStorage;
8
+
9
+ var _path = require("path");
10
+
11
+ var _globby = _interopRequireDefault(require("globby"));
12
+
13
+ var _debug = _interopRequireDefault(require("debug"));
14
+
15
+ var _core = require("@verdaccio/core");
16
+
17
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
18
+
19
+ const debug = (0, _debug.default)('verdaccio:plugin:local-storage:utils');
20
+ /**
21
+ * Retrieve a list of absolute paths to all folders in the given storage path
22
+ * @param storagePath the base path of the storage
23
+ * @return a promise that resolves to an array of absolute paths
24
+ */
25
+
26
+ async function getFolders(storagePath, pattern = '*') {
27
+ // @ts-ignore - check why this fails, types are correct
28
+ const files = await (0, _globby.default)(pattern, {
29
+ // @ts-ignore
30
+ cwd: storagePath,
31
+ expandDirectories: true,
32
+ onlyDirectories: true,
33
+ onlyFiles: false,
34
+ // should not go deeper than the storage path (10 is reseaon for the storage))
35
+ deep: 10,
36
+ dot: false,
37
+ followSymbolicLinks: true,
38
+ caseSensitiveMatch: true,
39
+ unique: true // FIXME: add here list of forbiden patterns
40
+ // don't include scoped folders.
41
+ // ignore: [`@*`],
42
+
43
+ });
44
+ return files;
45
+ }
46
+ /**
47
+ * Search packages on the the storage. The storage could be
48
+ * - storage
49
+ * - pkg1
50
+ * - @company
51
+ * - pkg2 -> @scompany/pkg2
52
+ * - storage1
53
+ * - pkg2
54
+ * - pkg3
55
+ * - storage2
56
+ * - @scope
57
+ * - pkg4 > @scope/pkg4
58
+ * The search return a data structure like:
59
+ * [
60
+ * {
61
+ * name: 'pkg1', // package name could be @scope/pkg1
62
+ * path: absolute/path/package/name
63
+ * }
64
+ * ]
65
+ * @param {string} storagePath is the base path of the storage folder,
66
+ * inside could be packages, storages and @scope packages.
67
+ * @param {Set<string>} storages storages are defined peer package access pattern via `storage` property
68
+ * @param query is the search query from the user via npm search command.
69
+ * and are intended to organize packages in a tree structure.
70
+ * @returns {Promise<searchUtils.SearchItemPkg[]>}
71
+ */
72
+
73
+
74
+ async function searchOnStorage(storagePath, storages) {
75
+ const matchedStorages = Array.from(storages);
76
+ const storageFolders = Array.from(storages.keys()); // const getScopedFolders = async (pkgName) => {
77
+ // const scopedPackages = await getFolders(join(storagePath, pkgName), '*');
78
+ // const listScoped = scopedPackages.map((scoped) => ({
79
+ // name: `${pkgName}/${scoped}`,
80
+ // }));
81
+ // };
82
+
83
+ debug('search on %o', storagePath);
84
+ debug('storage folders %o', matchedStorages.length);
85
+ let results = []; // watch base path and ignore storage folders
86
+
87
+ const basePathFolders = (await getFolders(storagePath, '*')).filter(storageFolder => !storageFolders.includes(storageFolder));
88
+
89
+ for (let store of basePathFolders) {
90
+ if (_core.validatioUtils.isPackageNameScoped(store)) {
91
+ const scopedPackages = await getFolders((0, _path.join)(storagePath, store), '*');
92
+ const listScoped = scopedPackages.map(scoped => ({
93
+ name: `${store}/${scoped}`,
94
+ scoped: store
95
+ }));
96
+ results.push(...listScoped);
97
+ } else {
98
+ results.push({
99
+ name: store
100
+ });
101
+ }
102
+ } // iterate each storage folder
103
+
104
+
105
+ for (const store of storageFolders) {
106
+ const foldersOnStorage = await getFolders((0, _path.join)(storagePath, store), '*');
107
+
108
+ for (let pkgName of foldersOnStorage) {
109
+ if (_core.validatioUtils.isPackageNameScoped(pkgName)) {
110
+ const scopedPackages = await getFolders((0, _path.join)(storagePath, store, pkgName), '*');
111
+ const listScoped = scopedPackages.map(scoped => ({
112
+ name: `${pkgName}/${scoped}`,
113
+ scoped: pkgName
114
+ }));
115
+ results.push(...listScoped);
116
+ } else {
117
+ results.push({
118
+ name: pkgName
119
+ });
120
+ }
121
+ }
122
+ }
123
+
124
+ return results;
125
+ }
126
+ //# sourceMappingURL=dir-utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/dir-utils.ts"],"names":["debug","getFolders","storagePath","pattern","files","cwd","expandDirectories","onlyDirectories","onlyFiles","deep","dot","followSymbolicLinks","caseSensitiveMatch","unique","searchOnStorage","storages","matchedStorages","Array","from","storageFolders","keys","length","results","basePathFolders","filter","storageFolder","includes","store","validatioUtils","isPackageNameScoped","scopedPackages","listScoped","map","scoped","name","push","foldersOnStorage","pkgName"],"mappings":";;;;;;;;AAAA;;AACA;;AACA;;AACA;;;;AAEA,MAAMA,KAAK,GAAG,oBAAW,sCAAX,CAAd;AAEA;AACA;AACA;AACA;AACA;;AACO,eAAeC,UAAf,CAA0BC,WAA1B,EAA+CC,OAAO,GAAG,GAAzD,EAAiF;AACtF;AACA,QAAMC,KAAK,GAAG,MAAM,qBAAOD,OAAP,EAAgB;AAClC;AACAE,IAAAA,GAAG,EAAEH,WAF6B;AAGlCI,IAAAA,iBAAiB,EAAE,IAHe;AAIlCC,IAAAA,eAAe,EAAE,IAJiB;AAKlCC,IAAAA,SAAS,EAAE,KALuB;AAMlC;AACAC,IAAAA,IAAI,EAAE,EAP4B;AAQlCC,IAAAA,GAAG,EAAE,KAR6B;AASlCC,IAAAA,mBAAmB,EAAE,IATa;AAUlCC,IAAAA,kBAAkB,EAAE,IAVc;AAWlCC,IAAAA,MAAM,EAAE,IAX0B,CAYlC;AACA;AACA;;AAdkC,GAAhB,CAApB;AAgBA,SAAOT,KAAP;AACD;AAED;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;;AACO,eAAeU,eAAf,CACLZ,WADK,EAELa,QAFK,EAGiC;AACtC,QAAMC,eAAe,GAAGC,KAAK,CAACC,IAAN,CAAWH,QAAX,CAAxB;AACA,QAAMI,cAAc,GAAGF,KAAK,CAACC,IAAN,CAAWH,QAAQ,CAACK,IAAT,EAAX,CAAvB,CAFsC,CAGtC;AACA;AACA;AACA;AACA;AACA;;AACApB,EAAAA,KAAK,CAAC,cAAD,EAAiBE,WAAjB,CAAL;AACAF,EAAAA,KAAK,CAAC,oBAAD,EAAuBgB,eAAe,CAACK,MAAvC,CAAL;AACA,MAAIC,OAAoC,GAAG,EAA3C,CAXsC,CAYtC;;AACA,QAAMC,eAAe,GAAG,CAAC,MAAMtB,UAAU,CAACC,WAAD,EAAc,GAAd,CAAjB,EAAqCsB,MAArC,CACrBC,aAAD,IAAmB,CAACN,cAAc,CAACO,QAAf,CAAwBD,aAAxB,CADE,CAAxB;;AAIA,OAAK,IAAIE,KAAT,IAAkBJ,eAAlB,EAAmC;AACjC,QAAIK,qBAAeC,mBAAf,CAAmCF,KAAnC,CAAJ,EAA+C;AAC7C,YAAMG,cAAc,GAAG,MAAM7B,UAAU,CAAC,gBAAKC,WAAL,EAAkByB,KAAlB,CAAD,EAA2B,GAA3B,CAAvC;AACA,YAAMI,UAAU,GAAGD,cAAc,CAACE,GAAf,CAAoBC,MAAD,KAAa;AACjDC,QAAAA,IAAI,EAAG,GAAEP,KAAM,IAAGM,MAAO,EADwB;AAEjDA,QAAAA,MAAM,EAAEN;AAFyC,OAAb,CAAnB,CAAnB;AAIAL,MAAAA,OAAO,CAACa,IAAR,CAAa,GAAGJ,UAAhB;AACD,KAPD,MAOO;AACLT,MAAAA,OAAO,CAACa,IAAR,CAAa;AACXD,QAAAA,IAAI,EAAEP;AADK,OAAb;AAGD;AACF,GA9BqC,CAgCtC;;;AACA,OAAK,MAAMA,KAAX,IAAoBR,cAApB,EAAoC;AAClC,UAAMiB,gBAAgB,GAAG,MAAMnC,UAAU,CAAC,gBAAKC,WAAL,EAAkByB,KAAlB,CAAD,EAA2B,GAA3B,CAAzC;;AACA,SAAK,IAAIU,OAAT,IAAoBD,gBAApB,EAAsC;AACpC,UAAIR,qBAAeC,mBAAf,CAAmCQ,OAAnC,CAAJ,EAAiD;AAC/C,cAAMP,cAAc,GAAG,MAAM7B,UAAU,CAAC,gBAAKC,WAAL,EAAkByB,KAAlB,EAAyBU,OAAzB,CAAD,EAAoC,GAApC,CAAvC;AACA,cAAMN,UAAU,GAAGD,cAAc,CAACE,GAAf,CAAoBC,MAAD,KAAa;AACjDC,UAAAA,IAAI,EAAG,GAAEG,OAAQ,IAAGJ,MAAO,EADsB;AAEjDA,UAAAA,MAAM,EAAEI;AAFyC,SAAb,CAAnB,CAAnB;AAIAf,QAAAA,OAAO,CAACa,IAAR,CAAa,GAAGJ,UAAhB;AACD,OAPD,MAOO;AACLT,QAAAA,OAAO,CAACa,IAAR,CAAa;AACXD,UAAAA,IAAI,EAAEG;AADK,SAAb;AAGD;AACF;AACF;;AAED,SAAOf,OAAP;AACD","sourcesContent":["import { join } from 'path';\nimport globby from 'globby';\nimport buildDebug from 'debug';\nimport { searchUtils, validatioUtils } from '@verdaccio/core';\n\nconst debug = buildDebug('verdaccio:plugin:local-storage:utils');\n\n/**\n * Retrieve a list of absolute paths to all folders in the given storage path\n * @param storagePath the base path of the storage\n * @return a promise that resolves to an array of absolute paths\n */\nexport async function getFolders(storagePath: string, pattern = '*'): Promise<string[]> {\n // @ts-ignore - check why this fails, types are correct\n const files = await globby(pattern, {\n // @ts-ignore\n cwd: storagePath,\n expandDirectories: true,\n onlyDirectories: true,\n onlyFiles: false,\n // should not go deeper than the storage path (10 is reseaon for the storage))\n deep: 10,\n dot: false,\n followSymbolicLinks: true,\n caseSensitiveMatch: true,\n unique: true,\n // FIXME: add here list of forbiden patterns\n // don't include scoped folders.\n // ignore: [`@*`],\n });\n return files;\n}\n\n/**\n * Search packages on the the storage. The storage could be\n * - storage\n * - pkg1\n * - @company\n * - pkg2 -> @scompany/pkg2\n * - storage1\n * - pkg2\n * - pkg3\n * - storage2\n * - @scope\n * - pkg4 > @scope/pkg4\n * The search return a data structure like:\n * [\n * {\n * name: 'pkg1', // package name could be @scope/pkg1\n * path: absolute/path/package/name\n * }\n * ]\n * @param {string} storagePath is the base path of the storage folder,\n * inside could be packages, storages and @scope packages.\n * @param {Set<string>} storages storages are defined peer package access pattern via `storage` property\n * @param query is the search query from the user via npm search command.\n * and are intended to organize packages in a tree structure.\n * @returns {Promise<searchUtils.SearchItemPkg[]>}\n */\nexport async function searchOnStorage(\n storagePath: string,\n storages: Map<string, string>\n): Promise<searchUtils.SearchItemPkg[]> {\n const matchedStorages = Array.from(storages);\n const storageFolders = Array.from(storages.keys());\n // const getScopedFolders = async (pkgName) => {\n // const scopedPackages = await getFolders(join(storagePath, pkgName), '*');\n // const listScoped = scopedPackages.map((scoped) => ({\n // name: `${pkgName}/${scoped}`,\n // }));\n // };\n debug('search on %o', storagePath);\n debug('storage folders %o', matchedStorages.length);\n let results: searchUtils.SearchItemPkg[] = [];\n // watch base path and ignore storage folders\n const basePathFolders = (await getFolders(storagePath, '*')).filter(\n (storageFolder) => !storageFolders.includes(storageFolder)\n );\n\n for (let store of basePathFolders) {\n if (validatioUtils.isPackageNameScoped(store)) {\n const scopedPackages = await getFolders(join(storagePath, store), '*');\n const listScoped = scopedPackages.map((scoped) => ({\n name: `${store}/${scoped}`,\n scoped: store,\n }));\n results.push(...listScoped);\n } else {\n results.push({\n name: store,\n });\n }\n }\n\n // iterate each storage folder\n for (const store of storageFolders) {\n const foldersOnStorage = await getFolders(join(storagePath, store), '*');\n for (let pkgName of foldersOnStorage) {\n if (validatioUtils.isPackageNameScoped(pkgName)) {\n const scopedPackages = await getFolders(join(storagePath, store, pkgName), '*');\n const listScoped = scopedPackages.map((scoped) => ({\n name: `${pkgName}/${scoped}`,\n scoped: pkgName,\n }));\n results.push(...listScoped);\n } else {\n results.push({\n name: pkgName,\n });\n }\n }\n }\n\n return results;\n}\n"],"file":"dir-utils.js"}
package/build/fs.d.ts ADDED
@@ -0,0 +1,10 @@
1
+ /// <reference types="node" />
2
+ import fs from 'fs';
3
+ declare const mkdirPromise: typeof fs.mkdir.__promisify__;
4
+ declare const writeFilePromise: typeof fs.writeFile.__promisify__;
5
+ declare const readdirPromise: typeof fs.readdir.__promisify__;
6
+ declare const statPromise: typeof fs.stat.__promisify__;
7
+ declare const unlinkPromise: typeof fs.unlink.__promisify__;
8
+ declare const rmdirPromise: typeof fs.rmdir.__promisify__;
9
+ export declare const readFilePromise: (path: any) => Promise<string>;
10
+ export { mkdirPromise, writeFilePromise, readdirPromise, statPromise, unlinkPromise, rmdirPromise };
package/build/fs.js ADDED
@@ -0,0 +1,34 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.rmdirPromise = exports.unlinkPromise = exports.statPromise = exports.readdirPromise = exports.writeFilePromise = exports.mkdirPromise = exports.readFilePromise = void 0;
7
+
8
+ var _util = require("util");
9
+
10
+ var _fs = _interopRequireDefault(require("fs"));
11
+
12
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
13
+
14
+ // FUTURE: when v15 is min replace by fs/promises
15
+ const readFile = (0, _util.promisify)(_fs.default.readFile);
16
+ const mkdirPromise = (0, _util.promisify)(_fs.default.mkdir);
17
+ exports.mkdirPromise = mkdirPromise;
18
+ const writeFilePromise = (0, _util.promisify)(_fs.default.writeFile);
19
+ exports.writeFilePromise = writeFilePromise;
20
+ const readdirPromise = (0, _util.promisify)(_fs.default.readdir);
21
+ exports.readdirPromise = readdirPromise;
22
+ const statPromise = (0, _util.promisify)(_fs.default.stat);
23
+ exports.statPromise = statPromise;
24
+ const unlinkPromise = (0, _util.promisify)(_fs.default.unlink);
25
+ exports.unlinkPromise = unlinkPromise;
26
+ const rmdirPromise = (0, _util.promisify)(_fs.default.rmdir);
27
+ exports.rmdirPromise = rmdirPromise;
28
+
29
+ const readFilePromise = async path => {
30
+ return await readFile(path, 'utf8');
31
+ };
32
+
33
+ exports.readFilePromise = readFilePromise;
34
+ //# sourceMappingURL=fs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/fs.ts"],"names":["readFile","fs","mkdirPromise","mkdir","writeFilePromise","writeFile","readdirPromise","readdir","statPromise","stat","unlinkPromise","unlink","rmdirPromise","rmdir","readFilePromise","path"],"mappings":";;;;;;;AAAA;;AACA;;;;AAEA;AACA,MAAMA,QAAQ,GAAG,qBAAUC,YAAGD,QAAb,CAAjB;AACA,MAAME,YAAY,GAAG,qBAAUD,YAAGE,KAAb,CAArB;;AACA,MAAMC,gBAAgB,GAAG,qBAAUH,YAAGI,SAAb,CAAzB;;AACA,MAAMC,cAAc,GAAG,qBAAUL,YAAGM,OAAb,CAAvB;;AACA,MAAMC,WAAW,GAAG,qBAAUP,YAAGQ,IAAb,CAApB;;AACA,MAAMC,aAAa,GAAG,qBAAUT,YAAGU,MAAb,CAAtB;;AACA,MAAMC,YAAY,GAAG,qBAAUX,YAAGY,KAAb,CAArB;;;AAEO,MAAMC,eAAe,GAAG,MAAOC,IAAP,IAAgB;AAC7C,SAAO,MAAMf,QAAQ,CAACe,IAAD,EAAO,MAAP,CAArB;AACD,CAFM","sourcesContent":["import { promisify } from 'util';\nimport fs from 'fs';\n\n// FUTURE: when v15 is min replace by fs/promises\nconst readFile = promisify(fs.readFile);\nconst mkdirPromise = promisify(fs.mkdir);\nconst writeFilePromise = promisify(fs.writeFile);\nconst readdirPromise = promisify(fs.readdir);\nconst statPromise = promisify(fs.stat);\nconst unlinkPromise = promisify(fs.unlink);\nconst rmdirPromise = promisify(fs.rmdir);\n\nexport const readFilePromise = async (path) => {\n return await readFile(path, 'utf8');\n};\n\nexport { mkdirPromise, writeFilePromise, readdirPromise, statPromise, unlinkPromise, rmdirPromise };\n"],"file":"fs.js"}
File without changes
File without changes
File without changes
@@ -0,0 +1,40 @@
1
+ import { Config, IPackageStorage, LocalStorage, Logger } from '@verdaccio/types';
2
+ import { searchUtils, pluginUtils } from '@verdaccio/core';
3
+ import TokenActions from './token';
4
+ export declare const ERROR_DB_LOCKED = "Database is locked, please check error message printed during startup to prevent data loss";
5
+ declare type IPluginStorage = pluginUtils.IPluginStorage<{}>;
6
+ declare class LocalDatabase extends TokenActions implements IPluginStorage {
7
+ private readonly path;
8
+ private readonly logger;
9
+ readonly config: Config;
10
+ readonly storages: Map<string, string>;
11
+ data: LocalStorage | void;
12
+ locked: boolean;
13
+ constructor(config: Config, logger: Logger);
14
+ init(): Promise<void>;
15
+ getSecret(): Promise<string>;
16
+ setSecret(secret: string): Promise<void>;
17
+ add(name: string): Promise<void>;
18
+ /**
19
+ * The field storage could be absolute or relative.
20
+ * If relative, it will be resolved against the config path.
21
+ * If absolute, it will be returned as is.
22
+ **/
23
+ private getStoragePath;
24
+ private getBaseConfigPath;
25
+ /**
26
+ * Filter by query.
27
+ **/
28
+ filterByQuery(results: searchUtils.SearchItemPkg[], query: searchUtils.SearchQuery): Promise<searchUtils.SearchItemPkg[]>;
29
+ getScore(_pkg: searchUtils.SearchItemPkg): Promise<searchUtils.Score>;
30
+ search(query: searchUtils.SearchQuery): Promise<searchUtils.SearchItem[]>;
31
+ remove(name: string): Promise<void>;
32
+ get(): Promise<any>;
33
+ getPackageStorage(packageName: string): IPackageStorage;
34
+ clean(): Promise<void>;
35
+ private _getCustomPackageLocalStorages;
36
+ private _sync;
37
+ private _getLocalStoragePath;
38
+ private _fetchLocalPackages;
39
+ }
40
+ export default LocalDatabase;
@@ -0,0 +1,366 @@
1
+ "use strict";
2
+
3
+ require("core-js/modules/esnext.weak-map.delete-all.js");
4
+
5
+ Object.defineProperty(exports, "__esModule", {
6
+ value: true
7
+ });
8
+ exports.default = exports.ERROR_DB_LOCKED = void 0;
9
+
10
+ require("core-js/modules/esnext.map.delete-all.js");
11
+
12
+ require("core-js/modules/esnext.map.every.js");
13
+
14
+ require("core-js/modules/esnext.map.filter.js");
15
+
16
+ require("core-js/modules/esnext.map.find.js");
17
+
18
+ require("core-js/modules/esnext.map.find-key.js");
19
+
20
+ require("core-js/modules/esnext.map.includes.js");
21
+
22
+ require("core-js/modules/esnext.map.key-of.js");
23
+
24
+ require("core-js/modules/esnext.map.map-keys.js");
25
+
26
+ require("core-js/modules/esnext.map.map-values.js");
27
+
28
+ require("core-js/modules/esnext.map.merge.js");
29
+
30
+ require("core-js/modules/esnext.map.reduce.js");
31
+
32
+ require("core-js/modules/esnext.map.some.js");
33
+
34
+ require("core-js/modules/esnext.map.update.js");
35
+
36
+ var _path = _interopRequireDefault(require("path"));
37
+
38
+ var _debug = _interopRequireDefault(require("debug"));
39
+
40
+ var _lodash = _interopRequireDefault(require("lodash"));
41
+
42
+ var _core = require("@verdaccio/core");
43
+
44
+ var _utils = require("@verdaccio/utils");
45
+
46
+ var _localFs = _interopRequireWildcard(require("./local-fs"));
47
+
48
+ var _pkgUtils = require("./pkg-utils");
49
+
50
+ var _token = _interopRequireDefault(require("./token"));
51
+
52
+ var _fs = require("./fs");
53
+
54
+ var _dirUtils = require("./dir-utils");
55
+
56
+ var _utils2 = require("./utils");
57
+
58
+ var _process$env$VERDACCI;
59
+
60
+ function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function (nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
61
+
62
+ function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
63
+
64
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
65
+
66
+ function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
67
+
68
+ const DB_NAME = (_process$env$VERDACCI = process.env.VERDACCIO_STORAGE_NAME) !== null && _process$env$VERDACCI !== void 0 ? _process$env$VERDACCI : _core.fileUtils.Files.DatabaseName;
69
+ const debug = (0, _debug.default)('verdaccio:plugin:local-storage:experimental');
70
+ const ERROR_DB_LOCKED = 'Database is locked, please check error message printed during startup to prevent data loss';
71
+ exports.ERROR_DB_LOCKED = ERROR_DB_LOCKED;
72
+
73
+ class LocalDatabase extends _token.default {
74
+ constructor(config, logger) {
75
+ super(config);
76
+
77
+ _defineProperty(this, "path", void 0);
78
+
79
+ _defineProperty(this, "logger", void 0);
80
+
81
+ _defineProperty(this, "config", void 0);
82
+
83
+ _defineProperty(this, "storages", void 0);
84
+
85
+ _defineProperty(this, "data", void 0);
86
+
87
+ _defineProperty(this, "locked", void 0);
88
+
89
+ this.config = config;
90
+ this.logger = logger;
91
+ this.locked = false;
92
+ this.data = undefined;
93
+ this.path = (0, _utils2._dbGenPath)(DB_NAME, config);
94
+ this.storages = this._getCustomPackageLocalStorages();
95
+ debug('plugin storage path %o', this.path);
96
+ }
97
+
98
+ async init() {
99
+ debug('plugin init');
100
+ this.data = await this._fetchLocalPackages();
101
+ debug('local packages loaded');
102
+ await this._sync();
103
+ }
104
+
105
+ async getSecret() {
106
+ if (typeof this.data === 'undefined') {
107
+ throw Error('no data secret available');
108
+ }
109
+
110
+ return Promise.resolve(this.data.secret);
111
+ }
112
+
113
+ async setSecret(secret) {
114
+ if (typeof this.data === 'undefined') {
115
+ throw Error('no data secret available');
116
+ } else {
117
+ this.data.secret = secret;
118
+ }
119
+
120
+ await this._sync();
121
+ }
122
+
123
+ async add(name) {
124
+ if (typeof this.data === 'undefined') {
125
+ throw Error('no data secret available');
126
+ }
127
+
128
+ if (this.data.list.indexOf(name) === -1) {
129
+ this.data.list.push(name);
130
+ debug('the private package %s has been added', name);
131
+ await this._sync();
132
+ } else {
133
+ debug('the private package %s already exist on database', name);
134
+ return Promise.resolve();
135
+ }
136
+ }
137
+ /**
138
+ * The field storage could be absolute or relative.
139
+ * If relative, it will be resolved against the config path.
140
+ * If absolute, it will be returned as is.
141
+ **/
142
+
143
+
144
+ getStoragePath() {
145
+ const {
146
+ storage
147
+ } = this.config;
148
+
149
+ if (typeof storage !== 'string') {
150
+ throw new TypeError('storage field is mandatory');
151
+ }
152
+
153
+ const storagePath = _path.default.isAbsolute(storage) ? storage : _path.default.normalize(_path.default.join(this.getBaseConfigPath(), storage));
154
+ debug('storage path %o', storagePath);
155
+ return storagePath;
156
+ }
157
+
158
+ getBaseConfigPath() {
159
+ return _path.default.dirname(this.config.config_path);
160
+ }
161
+ /**
162
+ * Filter by query.
163
+ **/
164
+
165
+
166
+ async filterByQuery(results, query) {
167
+ // FUTURE: apply new filters, keyword, version, ...
168
+ return results.filter(item => {
169
+ var _item$name;
170
+
171
+ return (item === null || item === void 0 ? void 0 : (_item$name = item.name) === null || _item$name === void 0 ? void 0 : _item$name.match(query.text)) !== null;
172
+ });
173
+ } // eslint-disable-next-line @typescript-eslint/no-unused-vars
174
+
175
+
176
+ async getScore(_pkg) {
177
+ return Promise.resolve({
178
+ final: 1,
179
+ detail: {
180
+ maintenance: 0,
181
+ popularity: 1,
182
+ quality: 1
183
+ }
184
+ });
185
+ }
186
+
187
+ async search(query) {
188
+ const results = [];
189
+ const storagePath = this.getStoragePath();
190
+ const packagesOnStorage = await this.filterByQuery(await (0, _dirUtils.searchOnStorage)(storagePath, this.storages), query);
191
+ debug('packages found %o', packagesOnStorage.length);
192
+
193
+ for (let storage of packagesOnStorage) {
194
+ const score = await this.getScore(storage);
195
+ results.push({
196
+ package: storage,
197
+ // there is no particular reason to predefined scores
198
+ // could be improved by using
199
+ score
200
+ });
201
+ }
202
+
203
+ return results;
204
+ }
205
+
206
+ async remove(name) {
207
+ try {
208
+ if (typeof this.data === 'undefined') {
209
+ throw Error('no data secret available');
210
+ }
211
+
212
+ const data = await this.get();
213
+ const pkgName = data.indexOf(name);
214
+
215
+ if (pkgName !== -1) {
216
+ this.data.list.splice(pkgName, 1);
217
+ debug('remove package %o has been removed', name);
218
+ }
219
+
220
+ await this._sync();
221
+ } catch (err) {
222
+ this.logger.error({
223
+ err
224
+ }, 'remove the private package has failed @{err}');
225
+ throw _core.errorUtils.getInternalError('error remove private package');
226
+ }
227
+ }
228
+
229
+ async get() {
230
+ if (typeof this.data === 'undefined') {
231
+ throw Error('no data secret available');
232
+ }
233
+
234
+ const {
235
+ list
236
+ } = this.data;
237
+ const totalItems = list === null || list === void 0 ? void 0 : list.length;
238
+ debug('get full list of packages (%o) has been fetched', totalItems);
239
+ return Promise.resolve(list);
240
+ }
241
+
242
+ getPackageStorage(packageName) {
243
+ const packageAccess = (0, _utils.getMatchedPackagesSpec)(packageName, this.config.packages);
244
+
245
+ const packagePath = this._getLocalStoragePath(packageAccess ? packageAccess.storage : undefined);
246
+
247
+ debug('storage path selected: ', packagePath);
248
+
249
+ if (_lodash.default.isString(packagePath) === false) {
250
+ debug('the package %o has no storage defined ', packageName);
251
+ return;
252
+ }
253
+
254
+ const packageStoragePath = _path.default.join( // FIXME: use getBaseStoragePath instead
255
+ _path.default.resolve(_path.default.dirname(this.config.config_path || ''), packagePath), packageName);
256
+
257
+ debug('storage absolute path: ', packageStoragePath);
258
+ return new _localFs.default(packageStoragePath, this.logger);
259
+ }
260
+
261
+ async clean() {
262
+ await this._sync();
263
+ }
264
+
265
+ _getCustomPackageLocalStorages() {
266
+ const storages = new Map();
267
+ const {
268
+ packages
269
+ } = this.config;
270
+
271
+ if (packages) {
272
+ Object.keys(packages || {}).map(pkg => {
273
+ const {
274
+ storage
275
+ } = packages[pkg];
276
+
277
+ if (typeof storage === 'string') {
278
+ const storagePath = _path.default.join(this.getStoragePath(), storage);
279
+
280
+ debug('add custom storage for %s on %s', storage, storagePath);
281
+ storages.set(storage, storagePath);
282
+ }
283
+ });
284
+ }
285
+
286
+ return storages;
287
+ }
288
+
289
+ async _sync() {
290
+ debug('sync database started');
291
+
292
+ if (this.locked) {
293
+ this.logger.error(ERROR_DB_LOCKED);
294
+ throw new Error(ERROR_DB_LOCKED);
295
+ } // Uses sync to prevent ugly race condition
296
+
297
+
298
+ try {
299
+ const folderName = _path.default.dirname(this.path);
300
+
301
+ debug('creating folder %o', folderName);
302
+ await (0, _fs.mkdirPromise)(folderName, {
303
+ recursive: true
304
+ });
305
+ debug('creating folder %o created succeed', folderName);
306
+ } catch (err) {
307
+ this.logger.error({
308
+ err
309
+ }, 'sync create folder has failed with error: @{err}');
310
+ throw err;
311
+ }
312
+
313
+ try {
314
+ await (0, _fs.writeFilePromise)(this.path, JSON.stringify(this.data));
315
+ debug('sync write succeed');
316
+ return null;
317
+ } catch (err) {
318
+ this.logger.error({
319
+ err
320
+ }, 'sync database file failed: @{err}');
321
+ throw err;
322
+ }
323
+ }
324
+
325
+ _getLocalStoragePath(storage) {
326
+ const globalConfigStorage = this.getStoragePath();
327
+
328
+ if (_lodash.default.isNil(globalConfigStorage)) {
329
+ this.logger.error('property storage in config.yaml is required for using this plugin');
330
+ throw new Error('property storage in config.yaml is required for using this plugin');
331
+ } else {
332
+ if (typeof storage === 'string') {
333
+ return _path.default.join(globalConfigStorage, storage);
334
+ }
335
+
336
+ return globalConfigStorage;
337
+ }
338
+ }
339
+
340
+ async _fetchLocalPackages() {
341
+ try {
342
+ return await (0, _pkgUtils.loadPrivatePackages)(this.path, this.logger);
343
+ } catch (err) {
344
+ // readFileSync is platform specific, macOS, Linux and Windows thrown an error
345
+ // Only recreate if file not found to prevent data loss
346
+ this.logger.warn({
347
+ path: this.path
348
+ }, 'no private database found, recreating new one on @{path}');
349
+
350
+ if (err.code !== _localFs.noSuchFile) {
351
+ this.locked = true;
352
+ this.logger.error('Failed to read package database file, please check the error printed below:\n', `File Path: ${this.path}\n\n ${err.message}`);
353
+ }
354
+
355
+ return {
356
+ list: [],
357
+ secret: ''
358
+ };
359
+ }
360
+ }
361
+
362
+ }
363
+
364
+ var _default = LocalDatabase;
365
+ exports.default = _default;
366
+ //# sourceMappingURL=local-database.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/local-database.ts"],"names":["DB_NAME","process","env","VERDACCIO_STORAGE_NAME","fileUtils","Files","DatabaseName","debug","ERROR_DB_LOCKED","LocalDatabase","TokenActions","constructor","config","logger","locked","data","undefined","path","storages","_getCustomPackageLocalStorages","init","_fetchLocalPackages","_sync","getSecret","Error","Promise","resolve","secret","setSecret","add","name","list","indexOf","push","getStoragePath","storage","TypeError","storagePath","isAbsolute","normalize","join","getBaseConfigPath","dirname","config_path","filterByQuery","results","query","filter","item","match","text","getScore","_pkg","final","detail","maintenance","popularity","quality","search","packagesOnStorage","length","score","package","remove","get","pkgName","splice","err","error","errorUtils","getInternalError","totalItems","getPackageStorage","packageName","packageAccess","packages","packagePath","_getLocalStoragePath","_","isString","packageStoragePath","LocalDriver","clean","Map","Object","keys","map","pkg","set","folderName","recursive","JSON","stringify","globalConfigStorage","isNil","warn","code","noSuchFile","message"],"mappings":"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","sourcesContent":["import path from 'path';\n// import LRU from 'lru-cache';\nimport buildDebug from 'debug';\nimport _ from 'lodash';\nimport { Config, IPackageStorage, LocalStorage, Logger } from '@verdaccio/types';\nimport { errorUtils, searchUtils, pluginUtils, fileUtils } from '@verdaccio/core';\nimport { getMatchedPackagesSpec } from '@verdaccio/utils';\n\nimport LocalDriver, { noSuchFile } from './local-fs';\nimport { loadPrivatePackages } from './pkg-utils';\nimport TokenActions from './token';\nimport { mkdirPromise, writeFilePromise } from './fs';\nimport { searchOnStorage } from './dir-utils';\nimport { _dbGenPath } from './utils';\n\nconst DB_NAME = process.env.VERDACCIO_STORAGE_NAME ?? fileUtils.Files.DatabaseName;\n\nconst debug = buildDebug('verdaccio:plugin:local-storage:experimental');\n\nexport const ERROR_DB_LOCKED =\n 'Database is locked, please check error message printed during startup to prevent data loss';\n\ntype IPluginStorage = pluginUtils.IPluginStorage<{}>;\n\nclass LocalDatabase extends TokenActions implements IPluginStorage {\n private readonly path: string;\n private readonly logger: Logger;\n public readonly config: Config;\n public readonly storages: Map<string, string>;\n public data: LocalStorage | void;\n public locked: boolean;\n\n public constructor(config: Config, logger: Logger) {\n super(config);\n this.config = config;\n this.logger = logger;\n this.locked = false;\n this.data = undefined;\n this.path = _dbGenPath(DB_NAME, config);\n this.storages = this._getCustomPackageLocalStorages();\n debug('plugin storage path %o', this.path);\n }\n\n public async init(): Promise<void> {\n debug('plugin init');\n this.data = await this._fetchLocalPackages();\n debug('local packages loaded');\n await this._sync();\n }\n\n public async getSecret(): Promise<string> {\n if (typeof this.data === 'undefined') {\n throw Error('no data secret available');\n }\n\n return Promise.resolve(this.data.secret);\n }\n\n public async setSecret(secret: string): Promise<void> {\n if (typeof this.data === 'undefined') {\n throw Error('no data secret available');\n } else {\n this.data.secret = secret;\n }\n\n await this._sync();\n }\n\n public async add(name: string): Promise<void> {\n if (typeof this.data === 'undefined') {\n throw Error('no data secret available');\n }\n\n if (this.data.list.indexOf(name) === -1) {\n this.data.list.push(name);\n debug('the private package %s has been added', name);\n await this._sync();\n } else {\n debug('the private package %s already exist on database', name);\n return Promise.resolve();\n }\n }\n\n /**\n * The field storage could be absolute or relative.\n * If relative, it will be resolved against the config path.\n * If absolute, it will be returned as is.\n **/\n private getStoragePath() {\n const { storage } = this.config;\n if (typeof storage !== 'string') {\n throw new TypeError('storage field is mandatory');\n }\n\n const storagePath = path.isAbsolute(storage)\n ? storage\n : path.normalize(path.join(this.getBaseConfigPath(), storage));\n debug('storage path %o', storagePath);\n return storagePath;\n }\n\n private getBaseConfigPath(): string {\n return path.dirname(this.config.config_path);\n }\n\n /**\n * Filter by query.\n **/\n public async filterByQuery(results: searchUtils.SearchItemPkg[], query: searchUtils.SearchQuery) {\n // FUTURE: apply new filters, keyword, version, ...\n return results.filter((item: searchUtils.SearchItemPkg) => {\n return item?.name?.match(query.text) !== null;\n }) as searchUtils.SearchItemPkg[];\n }\n\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n public async getScore(_pkg: searchUtils.SearchItemPkg): Promise<searchUtils.Score> {\n return Promise.resolve({\n final: 1,\n detail: {\n maintenance: 0,\n popularity: 1,\n quality: 1,\n },\n });\n }\n\n public async search(query: searchUtils.SearchQuery): Promise<searchUtils.SearchItem[]> {\n const results: searchUtils.SearchItem[] = [];\n const storagePath = this.getStoragePath();\n const packagesOnStorage = await this.filterByQuery(\n await searchOnStorage(storagePath, this.storages),\n query\n );\n debug('packages found %o', packagesOnStorage.length);\n for (let storage of packagesOnStorage) {\n const score = await this.getScore(storage);\n results.push({\n package: storage,\n // there is no particular reason to predefined scores\n // could be improved by using\n score,\n });\n }\n return results;\n }\n\n public async remove(name: string): Promise<void> {\n try {\n if (typeof this.data === 'undefined') {\n throw Error('no data secret available');\n }\n\n const data = await this.get();\n\n const pkgName = data.indexOf(name);\n if (pkgName !== -1) {\n this.data.list.splice(pkgName, 1);\n debug('remove package %o has been removed', name);\n }\n await this._sync();\n } catch (err) {\n this.logger.error({ err }, 'remove the private package has failed @{err}');\n throw errorUtils.getInternalError('error remove private package');\n }\n }\n\n public async get(): Promise<any> {\n if (typeof this.data === 'undefined') {\n throw Error('no data secret available');\n }\n\n const { list } = this.data;\n const totalItems = list?.length;\n debug('get full list of packages (%o) has been fetched', totalItems);\n return Promise.resolve(list);\n }\n\n public getPackageStorage(packageName: string): IPackageStorage {\n const packageAccess = getMatchedPackagesSpec(packageName, this.config.packages);\n\n const packagePath: string = this._getLocalStoragePath(\n packageAccess ? packageAccess.storage : undefined\n );\n debug('storage path selected: ', packagePath);\n if (_.isString(packagePath) === false) {\n debug('the package %o has no storage defined ', packageName);\n return;\n }\n\n const packageStoragePath: string = path.join(\n // FIXME: use getBaseStoragePath instead\n path.resolve(path.dirname(this.config.config_path || ''), packagePath),\n packageName\n );\n\n debug('storage absolute path: ', packageStoragePath);\n\n return new LocalDriver(packageStoragePath, this.logger);\n }\n\n public async clean(): Promise<void> {\n await this._sync();\n }\n\n private _getCustomPackageLocalStorages(): Map<string, string> {\n const storages = new Map<string, string>();\n const { packages } = this.config;\n\n if (packages) {\n Object.keys(packages || {}).map((pkg) => {\n const { storage } = packages[pkg];\n if (typeof storage === 'string') {\n const storagePath = path.join(this.getStoragePath(), storage);\n debug('add custom storage for %s on %s', storage, storagePath);\n storages.set(storage, storagePath);\n }\n });\n }\n\n return storages;\n }\n\n private async _sync(): Promise<null> {\n debug('sync database started');\n\n if (this.locked) {\n this.logger.error(ERROR_DB_LOCKED);\n throw new Error(ERROR_DB_LOCKED);\n }\n // Uses sync to prevent ugly race condition\n try {\n const folderName = path.dirname(this.path);\n debug('creating folder %o', folderName);\n await mkdirPromise(folderName, { recursive: true });\n debug('creating folder %o created succeed', folderName);\n } catch (err) {\n this.logger.error({ err }, 'sync create folder has failed with error: @{err}');\n throw err;\n }\n\n try {\n await writeFilePromise(this.path, JSON.stringify(this.data));\n debug('sync write succeed');\n\n return null;\n } catch (err: any) {\n this.logger.error({ err }, 'sync database file failed: @{err}');\n throw err;\n }\n }\n\n private _getLocalStoragePath(storage: string | void): string {\n const globalConfigStorage = this.getStoragePath();\n if (_.isNil(globalConfigStorage)) {\n this.logger.error('property storage in config.yaml is required for using this plugin');\n throw new Error('property storage in config.yaml is required for using this plugin');\n } else {\n if (typeof storage === 'string') {\n return path.join(globalConfigStorage as string, storage as string);\n }\n\n return globalConfigStorage as string;\n }\n }\n\n private async _fetchLocalPackages(): Promise<LocalStorage> {\n try {\n return await loadPrivatePackages(this.path, this.logger);\n } catch (err: any) {\n // readFileSync is platform specific, macOS, Linux and Windows thrown an error\n // Only recreate if file not found to prevent data loss\n this.logger.warn(\n { path: this.path },\n 'no private database found, recreating new one on @{path}'\n );\n if (err.code !== noSuchFile) {\n this.locked = true;\n this.logger.error(\n 'Failed to read package database file, please check the error printed below:\\n',\n `File Path: ${this.path}\\n\\n ${err.message}`\n );\n }\n\n return { list: [], secret: '' };\n }\n }\n}\n\nexport default LocalDatabase;\n"],"file":"local-database.js"}