@static-suite/static-suite-data-server 0.0.1 → 0.0.3

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 (146) hide show
  1. package/README.md +569 -107
  2. package/dist/http/README.md +569 -107
  3. package/dist/http/routes/dependency.d.ts +10 -0
  4. package/dist/http/routes/dependency.d.ts.map +1 -0
  5. package/dist/http/routes/dependency.js +71 -0
  6. package/dist/http/routes/dump.d.ts.map +1 -1
  7. package/dist/http/routes/dump.js +15 -10
  8. package/dist/http/routes/home.js +2 -1
  9. package/dist/http/routes/index.d.ts.map +1 -1
  10. package/dist/http/routes/index.js +8 -0
  11. package/dist/http/routes/status.d.ts.map +1 -1
  12. package/dist/http/routes/status.js +1 -6
  13. package/dist/http/views/dependencyIndex.pug +14 -0
  14. package/dist/lib/dataServer.d.ts +2 -1
  15. package/dist/lib/dataServer.d.ts.map +1 -1
  16. package/dist/lib/query/query.types.d.ts +2 -2
  17. package/dist/lib/query/query.types.d.ts.map +1 -1
  18. package/dist/lib/query/query.types.js +2 -2
  19. package/dist/lib/query/queryRunner.d.ts.map +1 -1
  20. package/dist/lib/query/queryRunner.js +3 -1
  21. package/dist/lib/store/dataDir/dataDir.types.d.ts +5 -5
  22. package/dist/lib/store/dataDir/dataDir.types.d.ts.map +1 -1
  23. package/dist/lib/store/dataDir/dataDirManager.d.ts.map +1 -1
  24. package/dist/lib/store/dataDir/dataDirManager.js +23 -12
  25. package/dist/lib/store/dependency/dependency.types.d.ts.map +1 -1
  26. package/dist/lib/store/dependency/dependencyFileHelper.d.ts +1 -1
  27. package/dist/lib/store/dependency/dependencyFileHelper.d.ts.map +1 -1
  28. package/dist/lib/store/dependency/dependencyFileHelper.js +5 -3
  29. package/dist/lib/store/dependency/dependencyManager.d.ts +12 -0
  30. package/dist/lib/store/dependency/dependencyManager.d.ts.map +1 -1
  31. package/dist/lib/store/dependency/dependencyManager.js +7 -5
  32. package/dist/lib/store/dependency/dependencyTagger.d.ts.map +1 -1
  33. package/dist/lib/store/dependency/dependencyTagger.js +3 -38
  34. package/dist/lib/store/diff/{diffManager.types.d.ts → diff.types.d.ts} +14 -6
  35. package/dist/lib/store/diff/diff.types.d.ts.map +1 -0
  36. package/dist/lib/store/{dependency/dependencyManager.types.js → diff/diff.types.js} +0 -0
  37. package/dist/lib/store/diff/diffManager.d.ts +1 -1
  38. package/dist/lib/store/diff/diffManager.d.ts.map +1 -1
  39. package/dist/lib/store/diff/diffManager.js +38 -81
  40. package/dist/lib/store/dump/{dumpManager.types.d.ts → dump.types.d.ts} +21 -8
  41. package/dist/lib/store/dump/dump.types.d.ts.map +1 -0
  42. package/dist/lib/store/{diff/diffManager.types.js → dump/dump.types.js} +0 -0
  43. package/dist/lib/store/dump/dumpManager.d.ts +1 -1
  44. package/dist/lib/store/dump/dumpManager.d.ts.map +1 -1
  45. package/dist/lib/store/dump/dumpManager.js +31 -56
  46. package/dist/lib/store/dump/dumpMetadataHelper.d.ts +7 -0
  47. package/dist/lib/store/dump/dumpMetadataHelper.d.ts.map +1 -0
  48. package/dist/lib/store/dump/dumpMetadataHelper.js +61 -0
  49. package/dist/lib/store/hook/hook.types.d.ts +49 -23
  50. package/dist/lib/store/hook/hook.types.d.ts.map +1 -1
  51. package/dist/lib/store/hook/hookManager.d.ts.map +1 -1
  52. package/dist/lib/store/hook/hookManager.js +19 -8
  53. package/dist/lib/store/store.d.ts.map +1 -1
  54. package/dist/lib/store/store.js +9 -4
  55. package/dist/lib/store/store.types.d.ts +14 -37
  56. package/dist/lib/store/store.types.d.ts.map +1 -1
  57. package/dist/lib/store/storeManager.d.ts.map +1 -1
  58. package/dist/lib/store/storeManager.js +20 -10
  59. package/dist/lib/store/workDir/storage/getChangedLinesBetween.d.ts +16 -0
  60. package/dist/lib/store/workDir/storage/getChangedLinesBetween.d.ts.map +1 -0
  61. package/dist/lib/store/workDir/storage/{getChangedLinesSince.js → getChangedLinesBetween.js} +22 -20
  62. package/dist/lib/store/workDir/storage/getDataFromLogLine.d.ts.map +1 -1
  63. package/dist/lib/store/workDir/storage/getDataFromLogLine.js +16 -3
  64. package/dist/lib/store/workDir/storage/index.d.ts +1 -1
  65. package/dist/lib/store/workDir/storage/index.d.ts.map +1 -1
  66. package/dist/lib/store/workDir/storage/index.js +1 -1
  67. package/dist/lib/store/workDir/workDir.types.d.ts +9 -1
  68. package/dist/lib/store/workDir/workDir.types.d.ts.map +1 -1
  69. package/dist/lib/store/workDir/workDirHelper.d.ts +13 -6
  70. package/dist/lib/store/workDir/workDirHelper.d.ts.map +1 -1
  71. package/dist/lib/store/workDir/workDirHelper.js +42 -11
  72. package/dist/lib/utils/fs/fsUtils.d.ts +6 -0
  73. package/dist/lib/utils/fs/fsUtils.d.ts.map +1 -1
  74. package/dist/lib/utils/fs/fsUtils.js +20 -1
  75. package/dist/lib/utils/module/moduleManager.d.ts.map +1 -1
  76. package/dist/lib/utils/module/moduleManager.js +5 -1
  77. package/dist/lib/utils/string/stringUtils.d.ts +14 -0
  78. package/dist/lib/utils/string/stringUtils.d.ts.map +1 -1
  79. package/dist/lib/utils/string/stringUtils.js +28 -1
  80. package/dist/static-suite-data-server.d.ts +19 -39
  81. package/package.json +3 -3
  82. package/src/http/routes/dependency.ts +91 -0
  83. package/src/http/routes/dump.ts +21 -10
  84. package/src/http/routes/home.ts +2 -2
  85. package/src/http/routes/index.ts +16 -0
  86. package/src/http/routes/status.ts +1 -9
  87. package/src/http/views/dependencyIndex.pug +14 -0
  88. package/src/lib/dataServer.ts +2 -0
  89. package/src/lib/query/query.types.ts +2 -2
  90. package/src/lib/query/queryRunner.ts +3 -1
  91. package/src/lib/store/dataDir/dataDir.types.ts +5 -5
  92. package/src/lib/store/dataDir/dataDirManager.ts +30 -14
  93. package/src/lib/store/dependency/dependency.types.ts +0 -5
  94. package/src/lib/store/dependency/dependencyFileHelper.ts +5 -3
  95. package/src/lib/store/dependency/dependencyManager.ts +6 -3
  96. package/src/lib/store/dependency/dependencyTagger.ts +3 -39
  97. package/src/lib/store/diff/{diffManager.types.ts → diff.types.ts} +14 -5
  98. package/src/lib/store/diff/diffManager.ts +45 -84
  99. package/src/lib/store/dump/{dumpManager.types.ts → dump.types.ts} +24 -7
  100. package/src/lib/store/dump/dumpManager.ts +40 -75
  101. package/src/lib/store/dump/dumpMetadataHelper.ts +73 -0
  102. package/src/lib/store/hook/hook.types.ts +58 -23
  103. package/src/lib/store/hook/hookManager.ts +24 -9
  104. package/src/lib/store/store.ts +9 -4
  105. package/src/lib/store/store.types.ts +16 -37
  106. package/src/lib/store/storeManager.ts +28 -12
  107. package/src/lib/store/workDir/__tests__/workDirHelper.test.ts +6 -1
  108. package/src/lib/store/workDir/storage/__tests__/{getChangedLinesSince.test.ts → getChangedLinesBetween.test.ts} +9 -4
  109. package/src/lib/store/workDir/storage/getChangedLinesBetween.ts +52 -0
  110. package/src/lib/store/workDir/storage/getDataFromLogLine.ts +22 -3
  111. package/src/lib/store/workDir/storage/index.ts +1 -1
  112. package/src/lib/store/workDir/workDir.types.ts +11 -1
  113. package/src/lib/store/workDir/workDirHelper.ts +45 -11
  114. package/src/lib/utils/fs/fsUtils.ts +18 -0
  115. package/src/lib/utils/module/moduleManager.ts +5 -1
  116. package/src/lib/utils/string/__tests__/stringUtils.test.ts +30 -1
  117. package/src/lib/utils/string/stringUtils.ts +32 -0
  118. package/dist/lib/query/queryRunner copy.d.ts +0 -3
  119. package/dist/lib/query/queryRunner copy.d.ts.map +0 -1
  120. package/dist/lib/query/queryRunner copy.js +0 -87
  121. package/dist/lib/store/dependency/dependencyManager copy.d.ts +0 -6
  122. package/dist/lib/store/dependency/dependencyManager copy.d.ts.map +0 -1
  123. package/dist/lib/store/dependency/dependencyManager copy.js +0 -91
  124. package/dist/lib/store/dependency/dependencyManager.types.d.ts +0 -48
  125. package/dist/lib/store/dependency/dependencyManager.types.d.ts.map +0 -1
  126. package/dist/lib/store/dependency/dependencyTagManager.d.ts +0 -6
  127. package/dist/lib/store/dependency/dependencyTagManager.d.ts.map +0 -1
  128. package/dist/lib/store/dependency/dependencyTagManager.js +0 -33
  129. package/dist/lib/store/diff/diffManager.types.d.ts.map +0 -1
  130. package/dist/lib/store/diff/tracker.d.ts +0 -3
  131. package/dist/lib/store/diff/tracker.d.ts.map +0 -1
  132. package/dist/lib/store/diff/tracker.js +0 -82
  133. package/dist/lib/store/diff/tracker.types.d.ts +0 -31
  134. package/dist/lib/store/diff/tracker.types.d.ts.map +0 -1
  135. package/dist/lib/store/diff/tracker.types.js +0 -2
  136. package/dist/lib/store/dump/dumpManager.types.d.ts.map +0 -1
  137. package/dist/lib/store/dump/dumpManager.types.js +0 -2
  138. package/dist/lib/store/include/includeIndex.d.ts +0 -6
  139. package/dist/lib/store/include/includeIndex.d.ts.map +0 -1
  140. package/dist/lib/store/include/includeIndex.js +0 -65
  141. package/dist/lib/store/include/includeIndex.types.d.ts +0 -29
  142. package/dist/lib/store/include/includeIndex.types.d.ts.map +0 -1
  143. package/dist/lib/store/include/includeIndex.types.js +0 -2
  144. package/dist/lib/store/workDir/storage/getChangedLinesSince.d.ts +0 -9
  145. package/dist/lib/store/workDir/storage/getChangedLinesSince.d.ts.map +0 -1
  146. package/src/lib/store/workDir/storage/getChangedLinesSince.ts +0 -47
@@ -1,6 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.getDataFromLogLine = void 0;
4
+ const logger_1 = require("@lib/utils/logger");
4
5
  /**
5
6
  * Extract information from Static Suite's log line.
6
7
  *
@@ -9,13 +10,25 @@ exports.getDataFromLogLine = void 0;
9
10
  * @returns An object with parsed data, or null if line format is not valid.
10
11
  */
11
12
  const getDataFromLogLine = (line) => {
12
- const matches = line.match(/^(\S+) (\S+) \[ID: ([^\]]+)] (.+)/);
13
+ const matches = line.match(/^(\S+) (\S+) \[ID: ([^\]]+)] (.+)$/);
13
14
  if (matches) {
14
15
  const uniqueId = matches[1];
15
16
  const operation = matches[2];
16
17
  const fileId = matches[3];
17
- const [fileLabel, uri] = matches[4].split(' | ');
18
- const [, uriTarget] = uri.split('://');
18
+ // Some lines contain more than one "|"
19
+ const labelUriParts = matches[4].split(' | ');
20
+ const uri = labelUriParts.pop();
21
+ const fileLabel = labelUriParts.join(' | ');
22
+ const uriTarget = uri?.split('://').pop();
23
+ if (!uniqueId ||
24
+ (operation !== 'write' && operation !== 'delete') ||
25
+ !fileId ||
26
+ !fileLabel ||
27
+ !uriTarget) {
28
+ const errorMessage = `Line ${line} meets parsing criteria but it contains invalid data. Regex match: ${JSON.stringify(matches)}`;
29
+ logger_1.logger.error(errorMessage);
30
+ throw Error(errorMessage);
31
+ }
19
32
  if (operation === 'write' || operation === 'delete') {
20
33
  return {
21
34
  uniqueId,
@@ -1,4 +1,4 @@
1
- export * from './getChangedLinesSince';
1
+ export * from './getChangedLinesBetween';
2
2
  export * from './getDataFromLogLine';
3
3
  export * from './getLogFile';
4
4
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/lib/store/workDir/storage/index.ts"],"names":[],"mappings":"AAKA,cAAc,wBAAwB,CAAC;AACvC,cAAc,sBAAsB,CAAC;AACrC,cAAc,cAAc,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../src/lib/store/workDir/storage/index.ts"],"names":[],"mappings":"AAKA,cAAc,0BAA0B,CAAC;AACzC,cAAc,sBAAsB,CAAC;AACrC,cAAc,cAAc,CAAC"}
@@ -15,6 +15,6 @@ These functions are separated from workDirHelper, since they are specific
15
15
  to the current storage backend (log files saved on disk) and they can change
16
16
  in the future.
17
17
  */
18
- __exportStar(require("./getChangedLinesSince"), exports);
18
+ __exportStar(require("./getChangedLinesBetween"), exports);
19
19
  __exportStar(require("./getDataFromLogLine"), exports);
20
20
  __exportStar(require("./getLogFile"), exports);
@@ -2,6 +2,14 @@
2
2
  * A group of changed files in Static Suite's data dir.
3
3
  */
4
4
  export declare type ChangedFiles = {
5
+ /**
6
+ * A unique id representing the date from which those changes are obtained.
7
+ */
8
+ fromUniqueId: string;
9
+ /**
10
+ * A unique id representing the date until which those changes are obtained.
11
+ */
12
+ toUniqueId: string;
5
13
  /**
6
14
  * A list of updated files (both newly added and changed files).
7
15
  */
@@ -16,7 +24,7 @@ export declare type ChangedFiles = {
16
24
  */
17
25
  export declare type LogLineData = {
18
26
  /**
19
- * The unique ID of the write/delete operation from Static Suite.
27
+ * The unique id of the write/delete operation from Static Suite.
20
28
  */
21
29
  uniqueId: string;
22
30
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"workDir.types.d.ts","sourceRoot":"","sources":["../../../../src/lib/store/workDir/workDir.types.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,oBAAY,YAAY,GAAG;IACzB;;OAEG;IACH,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB;;OAEG;IACH,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB,CAAC;AAEF;;GAEG;AACH,oBAAY,WAAW,GAAG;IACxB;;OAEG;IACH,QAAQ,EAAE,MAAM,CAAC;IAEjB;;OAEG;IACH,SAAS,EAAE,OAAO,GAAG,QAAQ,CAAC;IAE9B;;OAEG;IACH,IAAI,EAAE;QACJ;;WAEG;QACH,EAAE,EAAE,MAAM,CAAC;QAEX;;WAEG;QACH,KAAK,EAAE,MAAM,CAAC;QAEd;;WAEG;QACH,YAAY,EAAE,MAAM,CAAC;KACtB,CAAC;CACH,CAAC"}
1
+ {"version":3,"file":"workDir.types.d.ts","sourceRoot":"","sources":["../../../../src/lib/store/workDir/workDir.types.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,oBAAY,YAAY,GAAG;IACzB;;OAEG;IACH,YAAY,EAAE,MAAM,CAAC;IAErB;;OAEG;IACH,UAAU,EAAE,MAAM,CAAC;IAEnB;;OAEG;IACH,OAAO,EAAE,MAAM,EAAE,CAAC;IAClB;;OAEG;IACH,OAAO,EAAE,MAAM,EAAE,CAAC;CACnB,CAAC;AAEF;;GAEG;AACH,oBAAY,WAAW,GAAG;IACxB;;OAEG;IACH,QAAQ,EAAE,MAAM,CAAC;IAEjB;;OAEG;IACH,SAAS,EAAE,OAAO,GAAG,QAAQ,CAAC;IAE9B;;OAEG;IACH,IAAI,EAAE;QACJ;;WAEG;QACH,EAAE,EAAE,MAAM,CAAC;QAEX;;WAEG;QACH,KAAK,EAAE,MAAM,CAAC;QAEd;;WAEG;QACH,YAAY,EAAE,MAAM,CAAC;KACtB,CAAC;CACH,CAAC"}
@@ -1,20 +1,27 @@
1
1
  import { ChangedFiles } from './workDir.types';
2
+ /**
3
+ * The unique id of the Unix Epoch (00:00:00 UTC on 1 January 1970)
4
+ */
5
+ export declare const unixEpochUniqueId = "1970-01-01_00-00-00.000000__0000";
2
6
  export declare const workDirHelper: {
3
7
  /**
4
- * Gets date of last modification of work directory.
8
+ * Gets unique id of last modification of work directory.
5
9
  *
6
- * @returns The date of last modification of work directory, or null if directory not found.
10
+ * @returns The unique id of last modification of work directory, or null if directory not found.
7
11
  */
8
- getModificationDate: () => Date | null;
12
+ getModificationUniqueId: () => string | null;
9
13
  /**
10
14
  * Get changed files since a date.
11
15
  *
12
- * @param sinceDate - Date to search
16
+ * @param fromUniqueId - Date to search from.
17
+ * @param toUniqueId - Date to search to.
13
18
  *
14
- * @returns Object with two properties:
19
+ * @returns Object with four properties:
15
20
  * - updated: array of changed files.
16
21
  * - deleted: array of deleted files.
22
+ * - fromTimestamp
23
+ * - toTimestamp
17
24
  */
18
- getChangedFilesSince: (sinceDate: Date) => ChangedFiles;
25
+ getChangedFilesBetween: (fromUniqueId: string, toUniqueId: string) => ChangedFiles;
19
26
  };
20
27
  //# sourceMappingURL=workDirHelper.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"workDirHelper.d.ts","sourceRoot":"","sources":["../../../../src/lib/store/workDir/workDirHelper.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,YAAY,EAAe,MAAM,iBAAiB,CAAC;AAO5D,eAAO,MAAM,aAAa;IACxB;;;;OAIG;+BACsB,IAAI,GAAG,IAAI;IAKpC;;;;;;;;OAQG;sCAC+B,IAAI,KAAG,YAAY;CA6BtD,CAAC"}
1
+ {"version":3,"file":"workDirHelper.d.ts","sourceRoot":"","sources":["../../../../src/lib/store/workDir/workDirHelper.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,YAAY,EAAe,MAAM,iBAAiB,CAAC;AAO5D;;GAEG;AACH,eAAO,MAAM,iBAAiB,qCAAqC,CAAC;AAEpE,eAAO,MAAM,aAAa;IACxB;;;;OAIG;mCAC0B,MAAM,GAAG,IAAI;IAsB1C;;;;;;;;;;;OAWG;2CAEa,MAAM,cACR,MAAM,KACjB,YAAY;CAkChB,CAAC"}
@@ -1,30 +1,56 @@
1
1
  "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
2
5
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.workDirHelper = void 0;
4
- const fs_1 = require("@lib/utils/fs");
6
+ exports.workDirHelper = exports.unixEpochUniqueId = void 0;
7
+ const fs_1 = __importDefault(require("fs"));
5
8
  const logger_1 = require("@lib/utils/logger");
9
+ const string_1 = require("@lib/utils/string");
6
10
  const storage_1 = require("./storage");
11
+ /**
12
+ * The unique id of the Unix Epoch (00:00:00 UTC on 1 January 1970)
13
+ */
14
+ exports.unixEpochUniqueId = '1970-01-01_00-00-00.000000__0000';
7
15
  exports.workDirHelper = {
8
16
  /**
9
- * Gets date of last modification of work directory.
17
+ * Gets unique id of last modification of work directory.
10
18
  *
11
- * @returns The date of last modification of work directory, or null if directory not found.
19
+ * @returns The unique id of last modification of work directory, or null if directory not found.
12
20
  */
13
- getModificationDate: () => {
21
+ getModificationUniqueId: () => {
22
+ let modificationUniqueId = null;
14
23
  const logFile = (0, storage_1.getLogFile)();
15
- return logFile ? (0, fs_1.getModificationDate)(logFile) : null;
24
+ let allLines = [];
25
+ if (logFile) {
26
+ try {
27
+ allLines = fs_1.default.readFileSync(logFile).toString().trim().split('\n');
28
+ }
29
+ catch (e) {
30
+ logger_1.logger.error(`Error reading metadata log file located at ${`logFile`}: ${e}`);
31
+ }
32
+ const lastLine = allLines.slice(-1)[0];
33
+ const lastLineUniqueId = lastLine.substring(0, 32);
34
+ if ((0, string_1.isUniqueId)(lastLineUniqueId)) {
35
+ modificationUniqueId = lastLineUniqueId;
36
+ }
37
+ }
38
+ return modificationUniqueId;
16
39
  },
17
40
  /**
18
41
  * Get changed files since a date.
19
42
  *
20
- * @param sinceDate - Date to search
43
+ * @param fromUniqueId - Date to search from.
44
+ * @param toUniqueId - Date to search to.
21
45
  *
22
- * @returns Object with two properties:
46
+ * @returns Object with four properties:
23
47
  * - updated: array of changed files.
24
48
  * - deleted: array of deleted files.
49
+ * - fromTimestamp
50
+ * - toTimestamp
25
51
  */
26
- getChangedFilesSince: (sinceDate) => {
27
- const changedLines = (0, storage_1.getChangedLinesSince)(sinceDate);
52
+ getChangedFilesBetween: (fromUniqueId, toUniqueId) => {
53
+ const changedLines = (0, storage_1.getChangedLinesBetween)(fromUniqueId, toUniqueId);
28
54
  const lineData = {};
29
55
  changedLines.forEach(line => {
30
56
  const dataFromLogLine = (0, storage_1.getDataFromLogLine)(line);
@@ -47,6 +73,11 @@ exports.workDirHelper = {
47
73
  deleted.forEach(file => {
48
74
  logger_1.logger.debug(`Found deleted file "${file}"`);
49
75
  });
50
- return { updated, deleted };
76
+ return {
77
+ updated,
78
+ deleted,
79
+ fromUniqueId,
80
+ toUniqueId,
81
+ };
51
82
  },
52
83
  };
@@ -47,6 +47,12 @@ export declare const findFilesInDir: (dir: string, glob?: string, options?: fast
47
47
  * @returns The file's modification date as a Date object, or null on error
48
48
  */
49
49
  export declare const getModificationDate: (filePath: string) => Date | null;
50
+ /**
51
+ * Removes empty directories upwards.
52
+ *
53
+ * @param dir - Path to a directory
54
+ */
55
+ export declare const removeEmptyDirsUpwards: (dir: string) => void;
50
56
  /**
51
57
  * Watches for changes on a set of paths and attach listener to them
52
58
  *
@@ -1 +1 @@
1
- {"version":3,"file":"fsUtils.d.ts","sourceRoot":"","sources":["../../../../src/lib/utils/fs/fsUtils.ts"],"names":[],"mappings":"AACA,OAAW,EAAE,OAAO,IAAI,eAAe,EAAE,MAAM,WAAW,CAAC;AAI3D,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAEtC;;;;;;;;GAQG;AACH,eAAO,MAAM,UAAU,aAAc,MAAM,KAAG,OACd,CAAC;AAEjC;;;;;;GAMG;AACH,eAAO,MAAM,QAAQ,aAAc,MAAM,KAAG,MAAM,GAAG,IAWpD,CAAC;AAEF;;;;;;;;GAQG;AACH,eAAO,MAAM,cAAc,aAAc,MAAM,KAAG,QAUjD,CAAC;AAEF;;;;;;;;;GASG;AACH,eAAO,MAAM,cAAc,QACpB,MAAM,2BAEF,eAAe,KACvB,MAAM,EAQR,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,mBAAmB,aAAc,MAAM,KAAG,IAAI,GAAG,IAQ7D,CAAC;AAEF;;;;;;;;;;GAUG;AACH,eAAO,MAAM,KAAK,UACT,MAAM,EAAE,4DAC2C,MAAM,KAAK,IAAI,MACxE,IAyBF,CAAC"}
1
+ {"version":3,"file":"fsUtils.d.ts","sourceRoot":"","sources":["../../../../src/lib/utils/fs/fsUtils.ts"],"names":[],"mappings":"AAEA,OAAW,EAAE,OAAO,IAAI,eAAe,EAAE,MAAM,WAAW,CAAC;AAI3D,OAAO,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAEtC;;;;;;;;GAQG;AACH,eAAO,MAAM,UAAU,aAAc,MAAM,KAAG,OACd,CAAC;AAEjC;;;;;;GAMG;AACH,eAAO,MAAM,QAAQ,aAAc,MAAM,KAAG,MAAM,GAAG,IAWpD,CAAC;AAEF;;;;;;;;GAQG;AACH,eAAO,MAAM,cAAc,aAAc,MAAM,KAAG,QAUjD,CAAC;AAEF;;;;;;;;;GASG;AACH,eAAO,MAAM,cAAc,QACpB,MAAM,2BAEF,eAAe,KACvB,MAAM,EAQR,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,mBAAmB,aAAc,MAAM,KAAG,IAAI,GAAG,IAQ7D,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,sBAAsB,QAAS,MAAM,KAAG,IAUpD,CAAC;AAEF;;;;;;;;;;GAUG;AACH,eAAO,MAAM,KAAK,UACT,MAAM,EAAE,4DAC2C,MAAM,KAAK,IAAI,MACxE,IAyBF,CAAC"}
@@ -3,8 +3,9 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.watch = exports.getModificationDate = exports.findFilesInDir = exports.getFileContent = exports.readFile = exports.isJsonFile = void 0;
6
+ exports.watch = exports.removeEmptyDirsUpwards = exports.getModificationDate = exports.findFilesInDir = exports.getFileContent = exports.readFile = exports.isJsonFile = void 0;
7
7
  const fs_1 = __importDefault(require("fs"));
8
+ const path_1 = __importDefault(require("path"));
8
9
  const fast_glob_1 = __importDefault(require("fast-glob"));
9
10
  const chokidar_1 = __importDefault(require("chokidar"));
10
11
  const logger_1 = require("@lib/utils/logger");
@@ -98,6 +99,24 @@ const getModificationDate = (filePath) => {
98
99
  return modificationDate;
99
100
  };
100
101
  exports.getModificationDate = getModificationDate;
102
+ /**
103
+ * Removes empty directories upwards.
104
+ *
105
+ * @param dir - Path to a directory
106
+ */
107
+ const removeEmptyDirsUpwards = (dir) => {
108
+ const isEmpty = fs_1.default.readdirSync(dir).length === 0;
109
+ if (isEmpty) {
110
+ try {
111
+ fs_1.default.rmdirSync(dir);
112
+ }
113
+ catch (e) {
114
+ logger_1.logger.debug(`Error deleting empty directory "${dir}": ${e}`);
115
+ }
116
+ (0, exports.removeEmptyDirsUpwards)(path_1.default.dirname(dir));
117
+ }
118
+ };
119
+ exports.removeEmptyDirsUpwards = removeEmptyDirsUpwards;
101
120
  /**
102
121
  * Watches for changes on a set of paths and attach listener to them
103
122
  *
@@ -1 +1 @@
1
- {"version":3,"file":"moduleManager.d.ts","sourceRoot":"","sources":["../../../../src/lib/utils/module/moduleManager.ts"],"names":[],"mappings":"AA8CA;;;;;;;;;;GAUG;AACH,eAAO,MAAM,aAAa;IACxB;;;;;;;;;;;;;;;OAeG;6BACsB,MAAM;IAgB/B;;;;;;;;OAQG;yBACkB,MAAM;;UAAkC,IAAI;IASjE;;;;OAIG;uBACgB,MAAM,KAAG,IAAI;IAShC;;;;;;;;;;;;;OAaG;8BACqB,MAAM;CAO/B,CAAC"}
1
+ {"version":3,"file":"moduleManager.d.ts","sourceRoot":"","sources":["../../../../src/lib/utils/module/moduleManager.ts"],"names":[],"mappings":"AA8CA;;;;;;;;;;GAUG;AACH,eAAO,MAAM,aAAa;IACxB;;;;;;;;;;;;;;;OAeG;6BACsB,MAAM;IAoB/B;;;;;;;;OAQG;yBACkB,MAAM;;UAAkC,IAAI;IASjE;;;;OAIG;uBACgB,MAAM,KAAG,IAAI;IAShC;;;;;;;;;;;;;OAaG;8BACqB,MAAM;CAO/B,CAAC"}
@@ -86,7 +86,11 @@ exports.moduleManager = {
86
86
  throw e;
87
87
  }
88
88
  if (internalModuleCache[resolvedModulePath].onModuleLoad) {
89
- internalModuleCache[resolvedModulePath].onModuleLoad({ config: config_1.config, store: store_1.store });
89
+ internalModuleCache[resolvedModulePath].onModuleLoad({
90
+ config: config_1.config,
91
+ store: store_1.store,
92
+ logger: logger_1.logger,
93
+ });
90
94
  }
91
95
  logger_1.logger.debug(`Module ${resolvedModulePath} successfully loaded.`);
92
96
  return internalModuleCache[resolvedModulePath];
@@ -34,4 +34,18 @@ export declare const parseJsonString: (jsonString: string) => any;
34
34
  * @returns An object where its keys are the query arguments.
35
35
  */
36
36
  export declare const parseURLSearchParams: (queryString: string) => URLSearchParamsObject;
37
+ /**
38
+ * Parses a unique id from Static Suite and returns a Date.
39
+ *
40
+ * @param uniqueId - A unique id from Static Suite
41
+ *
42
+ * @returns A date from that unique id, or null if it can be parsed.
43
+ */
44
+ export declare const parseUniqueId: (uniqueId: string) => Date | null;
45
+ /**
46
+ * Checks that a string is a unique id.
47
+ *
48
+ * @param uniqueId - A unique id t be checked
49
+ */
50
+ export declare const isUniqueId: (uniqueId: string) => boolean;
37
51
  //# sourceMappingURL=stringUtils.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"stringUtils.d.ts","sourceRoot":"","sources":["../../../../src/lib/utils/string/stringUtils.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,qBAAqB,EAAE,MAAM,gBAAgB,CAAC;AAEvD;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,iBAAiB,OAAO,CAAC;AAEtC;;;;;;GAMG;AACH,eAAO,MAAM,eAAe,eAAgB,MAAM,KAAG,GAQpD,CAAC;AAEF;;;;;;;;;;GAUG;AACH,eAAO,MAAM,oBAAoB,gBAClB,MAAM,KAClB,qBAWF,CAAC"}
1
+ {"version":3,"file":"stringUtils.d.ts","sourceRoot":"","sources":["../../../../src/lib/utils/string/stringUtils.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,qBAAqB,EAAE,MAAM,gBAAgB,CAAC;AAEvD;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,iBAAiB,OAAO,CAAC;AAEtC;;;;;;GAMG;AACH,eAAO,MAAM,eAAe,eAAgB,MAAM,KAAG,GAQpD,CAAC;AAEF;;;;;;;;;;GAUG;AACH,eAAO,MAAM,oBAAoB,gBAClB,MAAM,KAClB,qBAWF,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,aAAa,aAAc,MAAM,KAAG,IAAI,GAAG,IAevD,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,UAAU,aAAc,MAAM,KAAG,OAC+B,CAAC"}
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.parseURLSearchParams = exports.parseJsonString = exports.VARIANT_SEPARATOR = void 0;
3
+ exports.isUniqueId = exports.parseUniqueId = exports.parseURLSearchParams = exports.parseJsonString = exports.VARIANT_SEPARATOR = void 0;
4
4
  const logger_1 = require("@lib/utils/logger");
5
5
  /**
6
6
  * Separator for variant data files saved to storage.
@@ -60,3 +60,30 @@ const parseURLSearchParams = (queryString) => {
60
60
  return obj;
61
61
  };
62
62
  exports.parseURLSearchParams = parseURLSearchParams;
63
+ /**
64
+ * Parses a unique id from Static Suite and returns a Date.
65
+ *
66
+ * @param uniqueId - A unique id from Static Suite
67
+ *
68
+ * @returns A date from that unique id, or null if it can be parsed.
69
+ */
70
+ const parseUniqueId = (uniqueId) => {
71
+ // todo - Do not use dates and use timestamps in all cases
72
+ // to avoid having to fix offsets.
73
+ const date = new Date();
74
+ const dateOffset = -(date.getTimezoneOffset() * 60 * 1000);
75
+ const dateString = uniqueId.replace(/(\d{4})-(\d{2})-(\d{2})_(\d{2})-(\d{2})-(\d{2})\.(\d{3}).*/, '$1-$2-$3T$4:$5:$6.$7');
76
+ const parsedDate = Date.parse(dateString);
77
+ if (!Number.isNaN(parsedDate)) {
78
+ return new Date(parsedDate + dateOffset);
79
+ }
80
+ return null;
81
+ };
82
+ exports.parseUniqueId = parseUniqueId;
83
+ /**
84
+ * Checks that a string is a unique id.
85
+ *
86
+ * @param uniqueId - A unique id t be checked
87
+ */
88
+ const isUniqueId = (uniqueId) => /(\d{4})-(\d{2})-(\d{2})_(\d{2})-(\d{2})-(\d{2})\.(\d{3}).*/.test(uniqueId);
89
+ exports.isUniqueId = isUniqueId;
@@ -7,6 +7,7 @@ import { QueryModule } from '@lib/query/query.types';
7
7
  import { QueryRunner } from '@lib/query/query.types';
8
8
  import { QuerySuccessfulResponse } from '@lib/query/query.types';
9
9
  import { Store } from '@lib/store/store.types';
10
+ import { TaskRunner } from '@lib/task/task.types';
10
11
 
11
12
  export { CacheStatus }
12
13
 
@@ -91,7 +92,7 @@ export declare type DataServerReturn = {
91
92
  /**
92
93
  * The task runner, to be able to run tasks on demand.
93
94
  */
94
- taskRunner: TaskRunner;
95
+ taskRunner: TaskRunner_2;
95
96
  };
96
97
 
97
98
  export { LogFile }
@@ -125,44 +126,17 @@ export { Store }
125
126
  */
126
127
  declare type Store_2 = {
127
128
  /**
128
- * Date to tell when was the store last synced.
129
- *
130
- * Every time the store is updated, syncDate is set with the last modification
131
- * date of the data directory, not the date when the store has finished updating.
132
- *
133
- * Given this scenario:
134
- * - Data directory modified at 12:30:00
135
- * - Syncing the store takes 3 seconds and finishes at 12:30:03
136
- *
137
- * ... syncDate will be 12:30:00, not 12:30:03.
138
- *
139
- * Doing it the other way round can cause data inconsistencies, because syncing files
140
- * to the store takes time, it is done sequentially, and in the meanwhile, other
141
- * modifications can happen:
142
- * - Store last syncDate is 12:29:00
143
- * - Data directory is modified at 12:30:00
144
- * - We ask for modified files after 12:29:00 and got 3 files (1.json, 2.json and 3.json)
145
- * - File "1.json" is processed and added to the store at 12:30:01
146
- * - While "2.json" is being processed and added to the store, data directory is modified
147
- * again at 12:30:02 and "1.json" is changed.
148
- * - File "3.json" is processed and added to the store at 12:30:03
149
- *
150
- * At this moment, there are two options:
129
+ * Initial unique id when the store was initially loaded.
130
+ */
131
+ initialUniqueId: string;
132
+ /**
133
+ * Current unique id to tell when was the store last synced.
151
134
  *
152
- * 1) Setting syncDate to the current date:
153
- * - Store syncDate is set to 12:30:03
154
- * - Data directory is modified again at 12:30:10 and only "3.json" is changed
155
- * - We ask for modified files after 12:30:03 and get only "3.json"
156
- * - Modification done at 12:30:02 to "1.json" is lost and cannot be recovered unless "1.json" is
157
- * modified again, or Data Server is restarted
135
+ * Every time the store is updated, this id is set with the last modification
136
+ * unique id of the data directory, not the date when the store has finished updating.
158
137
  *
159
- * 2) Setting syncDate to the last modification date of the data directory:
160
- * - Store syncDate is set to 12:30:00
161
- * - Data directory is modified again at 12:30:10 and only "3.json" is changed
162
- * - We ask for modified files after 12:30:00 and get "1.json" and "3.json"
163
- * - Modification done at 12:30:02 to "1.json" is properly processed
164
138
  */
165
- syncDate: Date | null;
139
+ currentUniqueId: string;
166
140
  /**
167
141
  * Map that holds all data for all files.
168
142
  *
@@ -188,7 +162,7 @@ declare type Store_2 = {
188
162
  */
189
163
  data: StoreData<string, any>;
190
164
  /**
191
- * A list of deleted files from store, to be able to track them.
165
+ * A list of deleted files since last reboot, to be able to track them.
192
166
  */
193
167
  deleted: Set<string>;
194
168
  /**
@@ -200,7 +174,7 @@ declare type Store_2 = {
200
174
  */
201
175
  url: Map<string, any>;
202
176
  /**
203
- * An index that holds all data for all files, keyed by their lang and uuid.
177
+ * An index that holds all data for all files, keyed by their langcode and UUID.
204
178
  */
205
179
  uuid: Map<string, any>;
206
180
  /**
@@ -251,6 +225,10 @@ declare interface StoreData<K, V> extends Map<K, V> {
251
225
  * Object holding a subset of items from the store.
252
226
  */
253
227
  declare type StoreSubset = {
228
+ /**
229
+ * Map of elements, with the filename as key
230
+ */
231
+ map: Map<string, any>;
254
232
  /**
255
233
  * Array of filenames in this subset.
256
234
  */
@@ -315,12 +293,14 @@ declare type TaskErrorResponse = {
315
293
  error: string;
316
294
  };
317
295
 
296
+ export { TaskRunner }
297
+
318
298
  /**
319
299
  * A service to handle the execution of tasks.
320
300
  *
321
301
  * @public
322
302
  */
323
- declare type TaskRunner = {
303
+ declare type TaskRunner_2 = {
324
304
  /**
325
305
  * Runs a task and returns its results with metadata.
326
306
  *
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@static-suite/static-suite-data-server",
3
- "version": "0.0.1",
3
+ "version": "0.0.3",
4
4
  "description": "A flexible, fast and developer friendly Data Server for Static Suite",
5
5
  "main": "./dist/lib/index.js",
6
6
  "typings": "./dist/lib/index.d.ts",
@@ -36,7 +36,7 @@
36
36
  },
37
37
  "scripts": {
38
38
  "dev": "tsc-watch --onSuccess \"yarn lint\"",
39
- "build": "yarn copy-http-files-to-src && yarn lint && tsc && yarn api-extractor run --local --verbose && yarn post-build && yarn copy-http-files-to-dist",
39
+ "build": "rm -Rf dist && yarn copy-http-files-to-src && yarn lint && tsc && yarn api-extractor run --local --verbose && yarn post-build && yarn copy-http-files-to-dist",
40
40
  "post-build": "yarn rimraf dist/**/*__tests__",
41
41
  "serve": "node ./dist/bin/serve.js http --port=57471 --data-dir=./src/__tests__/fixtures/data --work-dir=./src/__tests__/fixtures/work --query-dir=./src/__tests__/fixtures/query --hook-dir=./src/__tests__/fixtures/hook --task-dir=./src/__tests__/fixtures/task --run-mode=dev --log-level=debug",
42
42
  "lint": "eslint . --ext .ts",
@@ -99,4 +99,4 @@
99
99
  "pre-commit": "yarn build"
100
100
  }
101
101
  }
102
- }
102
+ }
@@ -0,0 +1,91 @@
1
+ // import microtime from 'microtime';
2
+ import { Request, Response } from 'express';
3
+ import { dataDirManager } from '@lib/store/dataDir';
4
+ import { jsonify } from '@lib/utils/object';
5
+ import {
6
+ dependencyManager,
7
+ getAllInvalidatedTags,
8
+ getTagParents,
9
+ } from '@lib/store/dependency/dependencyManager';
10
+ import {
11
+ dependencyTree,
12
+ getReversedDependencyTree,
13
+ invalidatedTags,
14
+ } from '@lib/store/dependency/dependencyTagger';
15
+
16
+ const dependencyIndex = (req: Request, res: Response): void => {
17
+ res.render('dependencyIndex', {
18
+ links: {
19
+ '/dependency/tree': 'Dependency tree',
20
+ '/dependency/tree/reversed': 'Reversed dependency tree',
21
+ '/dependency/invalidated/tags': 'Explicitly invalidated tags',
22
+ '/dependency/invalidated/tags/all': 'All invalidated tags in cascade',
23
+ '/dependency/invalidated/filepaths': 'Invalidated filepaths',
24
+ '/dependency/tag/parents': 'Tag parents',
25
+ },
26
+ });
27
+ };
28
+
29
+ const dependencyTreeRoute = (req: Request, res: Response): void => {
30
+ dataDirManager.update();
31
+ const args: any = req.query;
32
+ const response = args?.tag ? dependencyTree.get(args.tag) : dependencyTree;
33
+ res.status(200);
34
+ res.set({ 'Content-Type': 'application/json' });
35
+ res.send(jsonify(response));
36
+ };
37
+
38
+ const dependencyTreeReversed = (req: Request, res: Response): void => {
39
+ dataDirManager.update();
40
+ const reversedDependencyTree = getReversedDependencyTree();
41
+ const args: any = req.query;
42
+ const response = args?.tag
43
+ ? reversedDependencyTree.get(args.tag)
44
+ : reversedDependencyTree;
45
+ res.status(200);
46
+ res.set({ 'Content-Type': 'application/json' });
47
+ res.send(jsonify(response));
48
+ };
49
+
50
+ const dependencyExplicitlyInvalidatedTags = (
51
+ req: Request,
52
+ res: Response,
53
+ ): void => {
54
+ dataDirManager.update();
55
+ res.status(200);
56
+ res.set({ 'Content-Type': 'application/json' });
57
+ res.send(jsonify(invalidatedTags));
58
+ };
59
+
60
+ const dependencyAllInvalidatedTags = (req: Request, res: Response): void => {
61
+ dataDirManager.update();
62
+ res.status(200);
63
+ res.set({ 'Content-Type': 'application/json' });
64
+ res.send(getAllInvalidatedTags());
65
+ };
66
+
67
+ const dependencyInvalidatedFilepaths = (req: Request, res: Response): void => {
68
+ dataDirManager.update();
69
+ res.status(200);
70
+ res.set({ 'Content-Type': 'application/json' });
71
+ res.send(dependencyManager.getInvalidatedFilepaths());
72
+ };
73
+
74
+ const dependencyTagParents = (req: Request, res: Response): void => {
75
+ dataDirManager.update();
76
+ const args: any = req.query;
77
+ const response = args?.tag ? jsonify(getTagParents(args.tag)) : null;
78
+ res.status(200);
79
+ res.set({ 'Content-Type': 'application/json' });
80
+ res.send(response);
81
+ };
82
+
83
+ export {
84
+ dependencyIndex,
85
+ dependencyTreeRoute,
86
+ dependencyTreeReversed,
87
+ dependencyExplicitlyInvalidatedTags,
88
+ dependencyAllInvalidatedTags,
89
+ dependencyInvalidatedFilepaths,
90
+ dependencyTagParents,
91
+ };
@@ -5,7 +5,7 @@ import { jsonify } from '@lib/utils/object';
5
5
  import { config } from '@lib/config';
6
6
 
7
7
  const dumpIndex = (req: Request, res: Response): void => {
8
- res.render('statusIndex', {
8
+ res.render('dumpIndex', {
9
9
  links: {
10
10
  '/dump/incremental': 'Execute an incremental dump',
11
11
  '/dump/full': 'Execute a full dump',
@@ -15,18 +15,29 @@ const dumpIndex = (req: Request, res: Response): void => {
15
15
  });
16
16
  };
17
17
 
18
- const dumpIncremental = (req: Request, res: Response): void => {
19
- const dump = dumpManager.dump({ incremental: true });
18
+ const dumpAction = (
19
+ req: Request,
20
+ res: Response,
21
+ incremental: boolean,
22
+ ): void => {
23
+ const dump = dumpManager.dump({ incremental });
24
+ const dumpAsJson: any = jsonify(dump);
25
+ const args: any = req.query;
26
+ if (args?.noDiff !== undefined) {
27
+ delete dumpAsJson.diff;
28
+ }
29
+
20
30
  res.status(200);
21
31
  res.set({ 'Content-Type': 'application/json' });
22
- res.send(jsonify(dump));
32
+ res.send(dumpAsJson);
33
+ };
34
+
35
+ const dumpIncremental = (req: Request, res: Response): void => {
36
+ dumpAction(req, res, true);
23
37
  };
24
38
 
25
39
  const dumpFull = (req: Request, res: Response): void => {
26
- const dump = dumpManager.dump({ incremental: false });
27
- res.status(200);
28
- res.set({ 'Content-Type': 'application/json' });
29
- res.send(jsonify(dump));
40
+ dumpAction(req, res, false);
30
41
  };
31
42
 
32
43
  const getMetadata = () => {
@@ -44,8 +55,8 @@ const dumpMetadataShow = (req: Request, res: Response): void => {
44
55
 
45
56
  const dumpMetadataReset = (req: Request, res: Response): void => {
46
57
  const args: any = req.query;
47
- if (args?.timestamp) {
48
- dumpManager.reset(parseInt(args.timestamp, 10));
58
+ if (args?.uniqueId) {
59
+ dumpManager.reset(args.uniqueId);
49
60
  }
50
61
  res.status(200);
51
62
  res.set({ 'Content-Type': 'application/json' });
@@ -4,8 +4,8 @@ export const home = (req: Request, res: Response): void => {
4
4
  res.render('home', {
5
5
  links: {
6
6
  '/data': 'Browse all data loaded into the server',
7
- '/dump':
8
- 'Dump resolved data (includes and queries) into the dump directory',
7
+ '/dependency': 'Dependency data',
8
+ '/dump': 'Dump operations',
9
9
  '/query': 'List of available queries',
10
10
  '/task': 'List of available tasks',
11
11
  '/cache': 'List of available cache bins',