@nx/js 16.4.0-beta.1 → 16.4.0-beta.13

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 (67) hide show
  1. package/babel.js +3 -1
  2. package/executors.json +1 -0
  3. package/generators.json +12 -0
  4. package/migrations.json +12 -0
  5. package/package.json +6 -5
  6. package/plugins/jest/local-registry.d.ts +1 -0
  7. package/plugins/jest/local-registry.js +4 -0
  8. package/src/executors/node/node.impl.d.ts +1 -0
  9. package/src/executors/node/node.impl.js +59 -11
  10. package/src/executors/tsc/lib/batch/build-task-info-per-tsconfig-map.d.ts +5 -0
  11. package/src/executors/tsc/lib/batch/build-task-info-per-tsconfig-map.js +59 -0
  12. package/src/executors/tsc/lib/batch/index.d.ts +4 -0
  13. package/src/executors/tsc/lib/batch/index.js +7 -0
  14. package/src/executors/tsc/lib/batch/normalize-tasks-options.d.ts +3 -0
  15. package/src/executors/tsc/lib/batch/normalize-tasks-options.js +14 -0
  16. package/src/executors/tsc/lib/batch/types.d.ts +17 -0
  17. package/src/executors/tsc/lib/batch/types.js +2 -0
  18. package/src/executors/tsc/lib/batch/watch.d.ts +3 -0
  19. package/src/executors/tsc/lib/batch/watch.js +63 -0
  20. package/src/executors/tsc/lib/get-custom-transformers-factory.d.ts +3 -0
  21. package/src/executors/tsc/lib/get-custom-transformers-factory.js +13 -0
  22. package/src/executors/tsc/lib/get-task-options.d.ts +8 -0
  23. package/src/executors/tsc/lib/get-task-options.js +51 -0
  24. package/src/executors/tsc/lib/get-tsconfig.d.ts +4 -0
  25. package/src/executors/tsc/lib/get-tsconfig.js +138 -0
  26. package/src/executors/tsc/lib/index.d.ts +4 -0
  27. package/src/executors/tsc/lib/index.js +7 -0
  28. package/src/executors/tsc/lib/normalize-options.d.ts +2 -0
  29. package/src/executors/tsc/lib/normalize-options.js +32 -0
  30. package/src/executors/tsc/lib/typescript-compilation.d.ts +29 -0
  31. package/src/executors/tsc/lib/typescript-compilation.js +206 -0
  32. package/src/executors/tsc/lib/typescript-diagnostic-reporters.d.ts +3 -0
  33. package/src/executors/tsc/lib/typescript-diagnostic-reporters.js +37 -0
  34. package/src/executors/tsc/tsc.batch-impl.d.ts +5 -0
  35. package/src/executors/tsc/tsc.batch-impl.js +137 -0
  36. package/src/executors/tsc/tsc.impl.d.ts +0 -1
  37. package/src/executors/tsc/tsc.impl.js +4 -39
  38. package/src/executors/verdaccio/verdaccio.impl.d.ts +1 -0
  39. package/src/executors/verdaccio/verdaccio.impl.js +93 -45
  40. package/src/generators/library/library.js +2 -10
  41. package/src/generators/library/schema.json +7 -6
  42. package/src/generators/setup-build/generator.d.ts +5 -0
  43. package/src/generators/setup-build/generator.js +133 -0
  44. package/src/generators/setup-build/schema.d.ts +7 -0
  45. package/src/generators/setup-build/schema.json +42 -0
  46. package/src/generators/setup-verdaccio/files/config.yml +5 -6
  47. package/src/generators/setup-verdaccio/generator.js +5 -1
  48. package/src/index.d.ts +1 -0
  49. package/src/index.js +1 -0
  50. package/src/plugins/jest/start-local-registry.d.ts +12 -0
  51. package/src/plugins/jest/start-local-registry.js +61 -0
  52. package/src/utils/add-babel-inputs.d.ts +1 -0
  53. package/src/utils/add-babel-inputs.js +2 -0
  54. package/src/utils/add-local-registry-scripts.d.ts +5 -0
  55. package/src/utils/add-local-registry-scripts.js +57 -0
  56. package/src/utils/assets/copy-assets-handler.d.ts +5 -1
  57. package/src/utils/assets/copy-assets-handler.js +34 -23
  58. package/src/utils/compiler-helper-dependency.d.ts +2 -1
  59. package/src/utils/compiler-helper-dependency.js +13 -2
  60. package/src/utils/inline.d.ts +1 -1
  61. package/src/utils/inline.js +3 -3
  62. package/src/utils/minimal-publish-script.js +2 -5
  63. package/src/utils/schema.d.ts +3 -2
  64. package/src/utils/swc/add-swc-config.d.ts +1 -1
  65. package/src/utils/versions.d.ts +1 -1
  66. package/src/utils/versions.js +1 -1
  67. package/src/generators/setup-verdaccio/files/htpasswd +0 -1
@@ -0,0 +1,61 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.startLocalRegistry = void 0;
4
+ const child_process_1 = require("child_process");
5
+ /**
6
+ * This function is used to start a local registry for testing purposes.
7
+ * @param localRegistryTarget the target to run to start the local registry e.g. workspace:local-registry
8
+ * @param storage the storage location for the local registry
9
+ * @param verbose whether to log verbose output
10
+ */
11
+ function startLocalRegistry({ localRegistryTarget, storage, verbose, }) {
12
+ if (!localRegistryTarget) {
13
+ throw new Error(`localRegistryTarget is required`);
14
+ }
15
+ return new Promise((resolve, reject) => {
16
+ var _a, _b;
17
+ const childProcess = (0, child_process_1.fork)(require.resolve('nx'), [
18
+ ...`run ${localRegistryTarget} --location none --clear true`.split(' '),
19
+ ...(storage ? [`--storage`, storage] : []),
20
+ ], { stdio: 'pipe' });
21
+ const listener = (data) => {
22
+ var _a, _b, _c;
23
+ if (verbose) {
24
+ process.stdout.write(data);
25
+ }
26
+ if (data.toString().includes('http://localhost:')) {
27
+ const port = parseInt((_b = (_a = data.toString().match(/localhost:(?<port>\d+)/)) === null || _a === void 0 ? void 0 : _a.groups) === null || _b === void 0 ? void 0 : _b.port);
28
+ console.log('Local registry started on port ' + port);
29
+ const registry = `http://localhost:${port}`;
30
+ process.env.npm_config_registry = registry;
31
+ process.env.YARN_REGISTRY = registry;
32
+ (0, child_process_1.execSync)(`npm config set //localhost:${port}/:_authToken "secretVerdaccioToken"`);
33
+ console.log('Set npm and yarn config registry to ' + registry);
34
+ resolve(() => {
35
+ childProcess.kill();
36
+ (0, child_process_1.execSync)(`npm config delete //localhost:${port}/:_authToken`);
37
+ });
38
+ (_c = childProcess === null || childProcess === void 0 ? void 0 : childProcess.stdout) === null || _c === void 0 ? void 0 : _c.off('data', listener);
39
+ }
40
+ };
41
+ (_a = childProcess === null || childProcess === void 0 ? void 0 : childProcess.stdout) === null || _a === void 0 ? void 0 : _a.on('data', listener);
42
+ (_b = childProcess === null || childProcess === void 0 ? void 0 : childProcess.stderr) === null || _b === void 0 ? void 0 : _b.on('data', (data) => {
43
+ process.stderr.write(data);
44
+ });
45
+ childProcess.on('error', (err) => {
46
+ console.log('local registry error', err);
47
+ reject(err);
48
+ });
49
+ childProcess.on('exit', (code) => {
50
+ console.log('local registry exit', code);
51
+ if (code !== 0) {
52
+ reject(code);
53
+ }
54
+ else {
55
+ resolve(() => { });
56
+ }
57
+ });
58
+ });
59
+ }
60
+ exports.startLocalRegistry = startLocalRegistry;
61
+ exports.default = startLocalRegistry;
@@ -1,2 +1,3 @@
1
1
  import { Tree } from '@nx/devkit';
2
+ /** @deprecated Do not use this function as the root babel.config.json file is no longer needed */
2
3
  export declare function addBabelInputs(tree: Tree): void;
@@ -2,6 +2,8 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.addBabelInputs = void 0;
4
4
  const devkit_1 = require("@nx/devkit");
5
+ /** @deprecated Do not use this function as the root babel.config.json file is no longer needed */
6
+ // TODO(jack): Remove This in Nx 17 once we don't need to support Nx 15 anymore. Currently this function is used in v15 migrations.
5
7
  function addBabelInputs(tree) {
6
8
  var _a;
7
9
  const nxJson = (0, devkit_1.readNxJson)(tree);
@@ -0,0 +1,5 @@
1
+ import { type Tree } from '@nx/devkit';
2
+ export declare function addLocalRegistryScripts(tree: Tree): {
3
+ startLocalRegistryPath: string;
4
+ stopLocalRegistryPath: string;
5
+ };
@@ -0,0 +1,57 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.addLocalRegistryScripts = void 0;
4
+ const devkit_1 = require("@nx/devkit");
5
+ const startLocalRegistryScript = (localRegistryTarget) => `
6
+ /**
7
+ * This script starts a local registry for e2e testing purposes.
8
+ * It is meant to be called in jest's globalSetup.
9
+ */
10
+ import { startLocalRegistry } from '@nx/js/plugins/jest/local-registry';
11
+ import { execFileSync } from 'child_process';
12
+
13
+ export default async () => {
14
+ // local registry target to run
15
+ const localRegistryTarget = '${localRegistryTarget}';
16
+ // storage folder for the local registry
17
+ const storage = './tmp/local-registry/storage';
18
+
19
+ global.stopLocalRegistry = await startLocalRegistry({
20
+ localRegistryTarget,
21
+ storage,
22
+ verbose: false,
23
+ });
24
+ const nx = require.resolve('nx');
25
+ execFileSync(
26
+ nx,
27
+ ['run-many', '--targets', 'publish', '--ver', '1.0.0', '--tag', 'e2e'],
28
+ { env: process.env, stdio: 'inherit' }
29
+ );
30
+ };
31
+ `;
32
+ const stopLocalRegistryScript = `
33
+ /**
34
+ * This script stops the local registry for e2e testing purposes.
35
+ * It is meant to be called in jest's globalTeardown.
36
+ */
37
+
38
+ export default () => {
39
+ if (global.stopLocalRegistry) {
40
+ global.stopLocalRegistry();
41
+ }
42
+ };
43
+ `;
44
+ function addLocalRegistryScripts(tree) {
45
+ const startLocalRegistryPath = 'tools/scripts/start-local-registry.ts';
46
+ const stopLocalRegistryPath = 'tools/scripts/stop-local-registry.ts';
47
+ const projectConfiguration = (0, devkit_1.readJson)(tree, 'project.json');
48
+ const localRegistryTarget = `${projectConfiguration.name}:local-registry`;
49
+ if (!tree.exists(startLocalRegistryPath)) {
50
+ tree.write(startLocalRegistryPath, startLocalRegistryScript(localRegistryTarget));
51
+ }
52
+ if (!tree.exists(stopLocalRegistryPath)) {
53
+ tree.write(stopLocalRegistryPath, stopLocalRegistryScript);
54
+ }
55
+ return { startLocalRegistryPath, stopLocalRegistryPath };
56
+ }
57
+ exports.addLocalRegistryScripts = addLocalRegistryScripts;
@@ -1,4 +1,5 @@
1
1
  import { AssetGlob } from './assets';
2
+ import { ChangedFile } from 'nx/src/daemon/client/client';
2
3
  export type FileEventType = 'create' | 'update' | 'delete';
3
4
  export interface FileEvent {
4
5
  type: FileEventType;
@@ -22,7 +23,10 @@ export declare class CopyAssetsHandler {
22
23
  private readonly callback;
23
24
  constructor(opts: CopyAssetHandlerOptions);
24
25
  processAllAssetsOnce(): Promise<void>;
26
+ processAllAssetsOnceSync(): void;
25
27
  watchAndProcessOnAssetChange(): Promise<() => void>;
26
- private processEvents;
28
+ processWatchEvents(events: ChangedFile[]): Promise<void>;
29
+ private filesToEvent;
30
+ private normalizeAssetPattern;
27
31
  }
28
32
  export {};
@@ -74,35 +74,27 @@ class CopyAssetsHandler {
74
74
  processAllAssetsOnce() {
75
75
  return tslib_1.__awaiter(this, void 0, void 0, function* () {
76
76
  yield Promise.all(this.assetGlobs.map((ag) => tslib_1.__awaiter(this, void 0, void 0, function* () {
77
- let pattern;
78
- if (typeof ag === 'string') {
79
- pattern = ag;
80
- }
81
- else {
82
- pattern = ag.pattern;
83
- }
77
+ const pattern = this.normalizeAssetPattern(ag);
84
78
  // fast-glob only supports Unix paths
85
79
  const files = yield fg(pattern.replace(/\\/g, '/'), {
86
80
  cwd: this.rootDir,
87
81
  dot: true, // enable hidden files
88
82
  });
89
- this.callback(files.reduce((acc, src) => {
90
- var _a;
91
- if (!((_a = ag.ignore) === null || _a === void 0 ? void 0 : _a.some((ig) => minimatch(src, ig))) &&
92
- !this.ignore.ignores(src)) {
93
- const relPath = path.relative(ag.input, src);
94
- const dest = relPath.startsWith('..') ? src : relPath;
95
- acc.push({
96
- type: 'create',
97
- src: path.join(this.rootDir, src),
98
- dest: path.join(this.rootDir, ag.output, dest),
99
- });
100
- }
101
- return acc;
102
- }, []));
83
+ this.callback(this.filesToEvent(files, ag));
103
84
  })));
104
85
  });
105
86
  }
87
+ processAllAssetsOnceSync() {
88
+ this.assetGlobs.forEach((ag) => {
89
+ const pattern = this.normalizeAssetPattern(ag);
90
+ // fast-glob only supports Unix paths
91
+ const files = fg.sync(pattern.replace(/\\/g, '/'), {
92
+ cwd: this.rootDir,
93
+ dot: true, // enable hidden files
94
+ });
95
+ this.callback(this.filesToEvent(files, ag));
96
+ });
97
+ }
106
98
  watchAndProcessOnAssetChange() {
107
99
  return tslib_1.__awaiter(this, void 0, void 0, function* () {
108
100
  const unregisterFileWatcher = yield client_1.daemonClient.registerFileWatcher({
@@ -118,13 +110,13 @@ class CopyAssetsHandler {
118
110
  devkit_1.logger.error(`Watch error: ${(_a = err === null || err === void 0 ? void 0 : err.message) !== null && _a !== void 0 ? _a : 'Unknown'}`);
119
111
  }
120
112
  else {
121
- this.processEvents(data.changedFiles);
113
+ this.processWatchEvents(data.changedFiles);
122
114
  }
123
115
  });
124
116
  return () => unregisterFileWatcher();
125
117
  });
126
118
  }
127
- processEvents(events) {
119
+ processWatchEvents(events) {
128
120
  var _a;
129
121
  return tslib_1.__awaiter(this, void 0, void 0, function* () {
130
122
  const fileEvents = [];
@@ -150,5 +142,24 @@ class CopyAssetsHandler {
150
142
  this.callback(fileEvents);
151
143
  });
152
144
  }
145
+ filesToEvent(files, assetGlob) {
146
+ return files.reduce((acc, src) => {
147
+ var _a;
148
+ if (!((_a = assetGlob.ignore) === null || _a === void 0 ? void 0 : _a.some((ig) => minimatch(src, ig))) &&
149
+ !this.ignore.ignores(src)) {
150
+ const relPath = path.relative(assetGlob.input, src);
151
+ const dest = relPath.startsWith('..') ? src : relPath;
152
+ acc.push({
153
+ type: 'create',
154
+ src: path.join(this.rootDir, src),
155
+ dest: path.join(this.rootDir, assetGlob.output, dest),
156
+ });
157
+ }
158
+ return acc;
159
+ }, []);
160
+ }
161
+ normalizeAssetPattern(assetEntry) {
162
+ return typeof assetEntry === 'string' ? assetEntry : assetEntry.pattern;
163
+ }
153
164
  }
154
165
  exports.CopyAssetsHandler = CopyAssetsHandler;
@@ -1,4 +1,4 @@
1
- import { ProjectGraph, ProjectGraphDependency } from '@nx/devkit';
1
+ import { type ProjectGraph, type ProjectGraphDependency } from '@nx/devkit';
2
2
  import { DependentBuildableProjectNode } from './buildable-libs-utils';
3
3
  export declare enum HelperDependency {
4
4
  tsc = "npm:tslib",
@@ -11,6 +11,7 @@ export declare enum HelperDependency {
11
11
  * @param {HelperDependency} helperDependency
12
12
  * @param {string} configPath
13
13
  * @param {DependentBuildableProjectNode[]} dependencies
14
+ * @param {ProjectGraph} projectGraph
14
15
  * @param {boolean=false} returnDependencyIfFound
15
16
  */
16
17
  export declare function getHelperDependency(helperDependency: HelperDependency, configPath: string, dependencies: DependentBuildableProjectNode[], projectGraph: ProjectGraph, returnDependencyIfFound?: boolean): DependentBuildableProjectNode | null;
@@ -9,7 +9,7 @@ var HelperDependency;
9
9
  (function (HelperDependency) {
10
10
  HelperDependency["tsc"] = "npm:tslib";
11
11
  HelperDependency["swc"] = "npm:@swc/helpers";
12
- })(HelperDependency = exports.HelperDependency || (exports.HelperDependency = {}));
12
+ })(HelperDependency || (exports.HelperDependency = HelperDependency = {}));
13
13
  const jsExecutors = {
14
14
  '@nx/js:tsc': {
15
15
  helperDependency: HelperDependency.tsc,
@@ -27,6 +27,7 @@ const jsExecutors = {
27
27
  * @param {HelperDependency} helperDependency
28
28
  * @param {string} configPath
29
29
  * @param {DependentBuildableProjectNode[]} dependencies
30
+ * @param {ProjectGraph} projectGraph
30
31
  * @param {boolean=false} returnDependencyIfFound
31
32
  */
32
33
  function getHelperDependency(helperDependency, configPath, dependencies, projectGraph, returnDependencyIfFound = false) {
@@ -50,7 +51,17 @@ function getHelperDependency(helperDependency, configPath, dependencies, project
50
51
  }
51
52
  if (!isHelperNeeded)
52
53
  return null;
53
- const libNode = projectGraph.externalNodes[helperDependency];
54
+ let libNode = projectGraph[helperDependency];
55
+ // If libNode is not found due to the version suffix from pnpm lockfile, try to match it by package name.
56
+ if (!libNode) {
57
+ for (const nodeName of Object.keys(projectGraph.externalNodes)) {
58
+ const node = projectGraph.externalNodes[nodeName];
59
+ if (`npm:${node.data.packageName}` === helperDependency) {
60
+ libNode = node;
61
+ break;
62
+ }
63
+ }
64
+ }
54
65
  if (!libNode) {
55
66
  devkit_1.logger.warn(`Your library compilation option specifies that the compiler external helper (${helperDependency.split(':')[1]}) is needed but it is not installed.`);
56
67
  return null;
@@ -13,7 +13,7 @@ export interface InlineProjectGraph {
13
13
  dependencies: Record<string, string[]>;
14
14
  }
15
15
  export declare function isInlineGraphEmpty(inlineGraph: InlineProjectGraph): boolean;
16
- export declare function handleInliningBuild(context: ExecutorContext, options: NormalizedExecutorOptions, tsConfigPath: string): InlineProjectGraph;
16
+ export declare function handleInliningBuild(context: ExecutorContext, options: NormalizedExecutorOptions, tsConfigPath: string, projectName?: string): InlineProjectGraph;
17
17
  export declare function postProcessInlinedDependencies(outputPath: string, parentOutputPath: string, inlineGraph: InlineProjectGraph): void;
18
18
  export declare function getRootTsConfigPath(context: ExecutorContext): string | null;
19
19
  export {};
@@ -9,11 +9,11 @@ function isInlineGraphEmpty(inlineGraph) {
9
9
  return Object.keys(inlineGraph.nodes).length === 0;
10
10
  }
11
11
  exports.isInlineGraphEmpty = isInlineGraphEmpty;
12
- function handleInliningBuild(context, options, tsConfigPath) {
12
+ function handleInliningBuild(context, options, tsConfigPath, projectName = context.projectName) {
13
13
  var _a;
14
14
  const tsConfigJson = (0, devkit_1.readJsonFile)(tsConfigPath);
15
15
  const pathAliases = ((_a = tsConfigJson['compilerOptions']) === null || _a === void 0 ? void 0 : _a['paths']) || readBasePathAliases(context);
16
- const inlineGraph = createInlineGraph(context, options, pathAliases);
16
+ const inlineGraph = createInlineGraph(context, options, pathAliases, projectName);
17
17
  if (isInlineGraphEmpty(inlineGraph)) {
18
18
  return inlineGraph;
19
19
  }
@@ -81,7 +81,7 @@ function projectNodeToInlineProjectNode(projectNode, pathAlias = '', buildOutput
81
81
  buildOutputPath,
82
82
  };
83
83
  }
84
- function createInlineGraph(context, options, pathAliases, projectName = context.projectName, inlineGraph = emptyInlineGraph()) {
84
+ function createInlineGraph(context, options, pathAliases, projectName, inlineGraph = emptyInlineGraph()) {
85
85
  var _a;
86
86
  var _b;
87
87
  if (options.external == null)
@@ -13,14 +13,13 @@ const publishScriptContent = `
13
13
 
14
14
  import { execSync } from 'child_process';
15
15
  import { readFileSync, writeFileSync } from 'fs';
16
- import chalk from 'chalk';
17
16
 
18
17
  import devkit from '@nx/devkit';
19
18
  const { readCachedProjectGraph } = devkit;
20
19
 
21
20
  function invariant(condition, message) {
22
21
  if (!condition) {
23
- console.error(chalk.bold.red(message));
22
+ console.error(message);
24
23
  process.exit(1);
25
24
  }
26
25
  }
@@ -59,9 +58,7 @@ try {
59
58
  json.version = version;
60
59
  writeFileSync(\`package.json\`, JSON.stringify(json, null, 2));
61
60
  } catch (e) {
62
- console.error(
63
- chalk.bold.red(\`Error reading package.json file from library build output.\`)
64
- );
61
+ console.error(\`Error reading package.json file from library build output.\`);
65
62
  }
66
63
 
67
64
  // Execute "npm publish" to publish
@@ -50,11 +50,12 @@ export interface ExecutorOptions {
50
50
  }
51
51
 
52
52
  export interface NormalizedExecutorOptions extends ExecutorOptions {
53
- root?: string;
54
- sourceRoot?: string;
53
+ rootDir: string;
55
54
  projectRoot: string;
56
55
  mainOutputPath: string;
57
56
  files: Array<FileInputOutput>;
57
+ root?: string;
58
+ sourceRoot?: string;
58
59
  }
59
60
 
60
61
  export interface SwcExecutorOptions extends ExecutorOptions {
@@ -1,3 +1,3 @@
1
- import { Tree } from '@nx/devkit';
1
+ import { type Tree } from '@nx/devkit';
2
2
  export declare const defaultExclude: string[];
3
3
  export declare function addSwcConfig(tree: Tree, projectDir: string, type?: 'commonjs' | 'es6'): void;
@@ -8,7 +8,7 @@ export declare const swcNodeVersion = "~1.4.2";
8
8
  export declare const tsLibVersion = "^2.3.0";
9
9
  export declare const typesNodeVersion = "18.7.1";
10
10
  export declare const verdaccioVersion = "^5.0.4";
11
- export declare const typescriptVersion = "~5.0.2";
11
+ export declare const typescriptVersion = "~5.1.3";
12
12
  /**
13
13
  * The minimum version is currently determined from the lowest version
14
14
  * that's supported by the lowest Angular supported version, e.g.
@@ -12,7 +12,7 @@ exports.tsLibVersion = '^2.3.0';
12
12
  exports.typesNodeVersion = '18.7.1';
13
13
  exports.verdaccioVersion = '^5.0.4';
14
14
  // Typescript
15
- exports.typescriptVersion = '~5.0.2';
15
+ exports.typescriptVersion = '~5.1.3';
16
16
  /**
17
17
  * The minimum version is currently determined from the lowest version
18
18
  * that's supported by the lowest Angular supported version, e.g.
@@ -1 +0,0 @@
1
- test:$6FrCaT/v0dwE:autocreated 2020-03-25T19:10:50.254Z