@fluidframework/fluid-runner 2.0.0-dev-rc.1.0.0.224419

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 (77) hide show
  1. package/.eslintrc.cjs +17 -0
  2. package/.mocharc.js +12 -0
  3. package/CHANGELOG.md +120 -0
  4. package/LICENSE +21 -0
  5. package/README.md +101 -0
  6. package/api-extractor-lint.json +13 -0
  7. package/api-extractor.json +17 -0
  8. package/api-report/fluid-runner.api.md +89 -0
  9. package/bin/fluid-runner +2 -0
  10. package/dist/codeLoaderBundle.d.ts +46 -0
  11. package/dist/codeLoaderBundle.d.ts.map +1 -0
  12. package/dist/codeLoaderBundle.js +25 -0
  13. package/dist/codeLoaderBundle.js.map +1 -0
  14. package/dist/exportFile.d.ts +33 -0
  15. package/dist/exportFile.d.ts.map +1 -0
  16. package/dist/exportFile.js +120 -0
  17. package/dist/exportFile.js.map +1 -0
  18. package/dist/fakeUrlResolver.d.ts +15 -0
  19. package/dist/fakeUrlResolver.d.ts.map +1 -0
  20. package/dist/fakeUrlResolver.js +43 -0
  21. package/dist/fakeUrlResolver.js.map +1 -0
  22. package/dist/fluid-runner-alpha.d.ts +79 -0
  23. package/dist/fluid-runner-beta.d.ts +52 -0
  24. package/dist/fluid-runner-public.d.ts +52 -0
  25. package/dist/fluid-runner-untrimmed.d.ts +175 -0
  26. package/dist/fluidRunner.d.ts +11 -0
  27. package/dist/fluidRunner.d.ts.map +1 -0
  28. package/dist/fluidRunner.js +126 -0
  29. package/dist/fluidRunner.js.map +1 -0
  30. package/dist/index.d.ts +12 -0
  31. package/dist/index.d.ts.map +1 -0
  32. package/dist/index.js +24 -0
  33. package/dist/index.js.map +1 -0
  34. package/dist/logger/baseFileLogger.d.ts +28 -0
  35. package/dist/logger/baseFileLogger.d.ts.map +1 -0
  36. package/dist/logger/baseFileLogger.js +76 -0
  37. package/dist/logger/baseFileLogger.js.map +1 -0
  38. package/dist/logger/csvFileLogger.d.ts +18 -0
  39. package/dist/logger/csvFileLogger.d.ts.map +1 -0
  40. package/dist/logger/csvFileLogger.js +64 -0
  41. package/dist/logger/csvFileLogger.js.map +1 -0
  42. package/dist/logger/fileLogger.d.ts +44 -0
  43. package/dist/logger/fileLogger.d.ts.map +1 -0
  44. package/dist/logger/fileLogger.js +18 -0
  45. package/dist/logger/fileLogger.js.map +1 -0
  46. package/dist/logger/jsonFileLogger.d.ts +14 -0
  47. package/dist/logger/jsonFileLogger.d.ts.map +1 -0
  48. package/dist/logger/jsonFileLogger.js +48 -0
  49. package/dist/logger/jsonFileLogger.js.map +1 -0
  50. package/dist/logger/loggerUtils.d.ts +44 -0
  51. package/dist/logger/loggerUtils.d.ts.map +1 -0
  52. package/dist/logger/loggerUtils.js +120 -0
  53. package/dist/logger/loggerUtils.js.map +1 -0
  54. package/dist/parseBundleAndExportFile.d.ts +13 -0
  55. package/dist/parseBundleAndExportFile.d.ts.map +1 -0
  56. package/dist/parseBundleAndExportFile.js +88 -0
  57. package/dist/parseBundleAndExportFile.js.map +1 -0
  58. package/dist/tsdoc-metadata.json +11 -0
  59. package/dist/utils.d.ts +33 -0
  60. package/dist/utils.d.ts.map +1 -0
  61. package/dist/utils.js +107 -0
  62. package/dist/utils.js.map +1 -0
  63. package/package.json +120 -0
  64. package/prettier.config.cjs +8 -0
  65. package/src/codeLoaderBundle.ts +63 -0
  66. package/src/exportFile.ts +148 -0
  67. package/src/fakeUrlResolver.ts +54 -0
  68. package/src/fluidRunner.ts +135 -0
  69. package/src/index.ts +18 -0
  70. package/src/logger/baseFileLogger.ts +58 -0
  71. package/src/logger/csvFileLogger.ts +40 -0
  72. package/src/logger/fileLogger.ts +51 -0
  73. package/src/logger/jsonFileLogger.ts +27 -0
  74. package/src/logger/loggerUtils.ts +108 -0
  75. package/src/parseBundleAndExportFile.ts +92 -0
  76. package/src/utils.ts +100 -0
  77. package/tsconfig.json +13 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"parseBundleAndExportFile.js","sourceRoot":"","sources":["../src/parseBundleAndExportFile.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;;;;;;;;;;;;;;;;;;;;;;;;AAEH,uCAAyB;AACzB,qEAAmE;AACnE,yDAA8E;AAC9E,6CAA8E;AAG9E,sDAAqF;AACrF,8CAA8C;AAC9C,mCAAyE;AAEzE,MAAM,yBAAyB,GAAG,4BAA4B,CAAC;AAE/D;;;;GAIG;AACI,KAAK,UAAU,wBAAwB,CAC7C,UAAkB,EAClB,SAAiB,EACjB,UAAkB,EAClB,aAAqB,EACrB,OAAgB,EAChB,gBAAoC,EACpC,OAAgB,EAChB,mBAA6B;IAE7B,MAAM,iBAAiB,GAAG,IAAA,6CAA+B,EAAC,aAAa,CAAC,CAAC;IACzE,IAAI,iBAAiB,EAAE;QACtB,MAAM,SAAS,GAAG,yBAAyB,CAAC;QAC5C,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,YAAY,EAAE,iBAAiB,EAAE,CAAC;KACtE;IACD,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,GAAG,IAAA,0BAAY,EAAC,aAAa,EAAE,gBAAgB,CAAC,CAAC;IAE7E,IAAI;QACH,OAAO,MAAM,kCAAgB,CAAC,cAAc,CAC3C,MAAM,EACN,EAAE,SAAS,EAAE,0BAA0B,EAAE,EACzC,KAAK,IAAI,EAAE;YACV,qGAAqG;YACrG,MAAM,gBAAgB,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;YAC7C,IAAI,CAAC,IAAA,qCAAkB,EAAC,gBAAgB,CAAC,EAAE;gBAC1C,MAAM,SAAS,GAAG,yBAAyB,CAAC;gBAC5C,MAAM,YAAY,GAAG,qDAAqD,CAAC;gBAC3E,MAAM,CAAC,cAAc,CAAC,EAAE,SAAS,EAAE,OAAO,EAAE,YAAY,EAAE,CAAC,CAAC;gBAC5D,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,YAAY,EAAE,CAAC;aACnD;YAED,MAAM,WAAW,GAAG,MAAM,gBAAgB,CAAC,WAAW,CAAC;YACvD,IAAI,CAAC,IAAA,uCAAoB,EAAC,WAAW,CAAC,EAAE;gBACvC,MAAM,SAAS,GAAG,yBAAyB,CAAC;gBAC5C,MAAM,YAAY,GACjB,uEAAuE,CAAC;gBACzE,MAAM,CAAC,cAAc,CAAC,EAAE,SAAS,EAAE,OAAO,EAAE,YAAY,EAAE,CAAC,CAAC;gBAC5D,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,YAAY,EAAE,CAAC;aACnD;YAED,MAAM,mBAAmB,GAAG,IAAA,8BAAsB,EAAC,SAAS,EAAE,UAAU,EAAE,OAAO,CAAC,CAAC;YACnF,IAAI,mBAAmB,EAAE;gBACxB,MAAM,SAAS,GAAG,yBAAyB,CAAC;gBAC5C,MAAM,CAAC,cAAc,CAAC,EAAE,SAAS,EAAE,OAAO,EAAE,mBAAmB,EAAE,CAAC,CAAC;gBACnE,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,YAAY,EAAE,mBAAmB,EAAE,CAAC;aACxE;YAED,EAAE,CAAC,aAAa,CACf,UAAU,EACV,MAAM,IAAA,sCAAyB,EAC9B,IAAA,8BAAsB,EAAC,SAAS,CAAC,EACjC,WAAW,EACX,MAAM,EACN,OAAO,EACP,OAAO,EACP,mBAAmB,CACnB,CACD,CAAC;YAEF,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,CAAC;QAC1B,CAAC,CACD,CAAC;KACF;IAAC,OAAO,KAAK,EAAE;QACf,MAAM,SAAS,GAAG,wBAAwB,CAAC;QAC3C,MAAM,CAAC,cAAc,CAAC,EAAE,SAAS,EAAE,EAAE,KAAK,CAAC,CAAC;QAC5C,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,SAAS,EAAE,YAAY,EAAE,kBAAkB,EAAE,KAAK,EAAE,CAAC;KAC9E;YAAS;QACT,MAAM,UAAU,CAAC,KAAK,EAAE,CAAC;KACzB;AACF,CAAC;AArED,4DAqEC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport * as fs from \"fs\";\nimport { PerformanceEvent } from \"@fluidframework/telemetry-utils\";\nimport { isCodeLoaderBundle, isFluidFileConverter } from \"./codeLoaderBundle\";\nimport { createContainerAndExecute, IExportFileResponse } from \"./exportFile\";\n/* eslint-disable import/no-internal-modules */\nimport { ITelemetryOptions } from \"./logger/fileLogger\";\nimport { createLogger, getTelemetryFileValidationError } from \"./logger/loggerUtils\";\n/* eslint-enable import/no-internal-modules */\nimport { getSnapshotFileContent, getArgsValidationError } from \"./utils\";\n\nconst clientArgsValidationError = \"Client_ArgsValidationError\";\n\n/**\n * Parse a provided JS bundle, execute code on Container based on ODSP snapshot, and write result to file\n * @param codeLoader - path to provided JS bundle that implements ICodeLoaderBundle (see codeLoaderBundle.ts)\n * @internal\n */\nexport async function parseBundleAndExportFile(\n\tcodeLoader: string,\n\tinputFile: string,\n\toutputFile: string,\n\ttelemetryFile: string,\n\toptions?: string,\n\ttelemetryOptions?: ITelemetryOptions,\n\ttimeout?: number,\n\tdisableNetworkFetch?: boolean,\n): Promise<IExportFileResponse> {\n\tconst telemetryArgError = getTelemetryFileValidationError(telemetryFile);\n\tif (telemetryArgError) {\n\t\tconst eventName = clientArgsValidationError;\n\t\treturn { success: false, eventName, errorMessage: telemetryArgError };\n\t}\n\tconst { fileLogger, logger } = createLogger(telemetryFile, telemetryOptions);\n\n\ttry {\n\t\treturn await PerformanceEvent.timedExecAsync(\n\t\t\tlogger,\n\t\t\t{ eventName: \"ParseBundleAndExportFile\" },\n\t\t\tasync () => {\n\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-require-imports, @typescript-eslint/no-var-requires\n\t\t\t\tconst codeLoaderBundle = require(codeLoader);\n\t\t\t\tif (!isCodeLoaderBundle(codeLoaderBundle)) {\n\t\t\t\t\tconst eventName = clientArgsValidationError;\n\t\t\t\t\tconst errorMessage = \"Code loader bundle is not of type ICodeLoaderBundle\";\n\t\t\t\t\tlogger.sendErrorEvent({ eventName, message: errorMessage });\n\t\t\t\t\treturn { success: false, eventName, errorMessage };\n\t\t\t\t}\n\n\t\t\t\tconst fluidExport = await codeLoaderBundle.fluidExport;\n\t\t\t\tif (!isFluidFileConverter(fluidExport)) {\n\t\t\t\t\tconst eventName = clientArgsValidationError;\n\t\t\t\t\tconst errorMessage =\n\t\t\t\t\t\t\"Fluid export from CodeLoaderBundle is not of type IFluidFileConverter\";\n\t\t\t\t\tlogger.sendErrorEvent({ eventName, message: errorMessage });\n\t\t\t\t\treturn { success: false, eventName, errorMessage };\n\t\t\t\t}\n\n\t\t\t\tconst argsValidationError = getArgsValidationError(inputFile, outputFile, timeout);\n\t\t\t\tif (argsValidationError) {\n\t\t\t\t\tconst eventName = clientArgsValidationError;\n\t\t\t\t\tlogger.sendErrorEvent({ eventName, message: argsValidationError });\n\t\t\t\t\treturn { success: false, eventName, errorMessage: argsValidationError };\n\t\t\t\t}\n\n\t\t\t\tfs.writeFileSync(\n\t\t\t\t\toutputFile,\n\t\t\t\t\tawait createContainerAndExecute(\n\t\t\t\t\t\tgetSnapshotFileContent(inputFile),\n\t\t\t\t\t\tfluidExport,\n\t\t\t\t\t\tlogger,\n\t\t\t\t\t\toptions,\n\t\t\t\t\t\ttimeout,\n\t\t\t\t\t\tdisableNetworkFetch,\n\t\t\t\t\t),\n\t\t\t\t);\n\n\t\t\t\treturn { success: true };\n\t\t\t},\n\t\t);\n\t} catch (error) {\n\t\tconst eventName = \"Client_UnexpectedError\";\n\t\tlogger.sendErrorEvent({ eventName }, error);\n\t\treturn { success: false, eventName, errorMessage: \"Unexpected error\", error };\n\t} finally {\n\t\tawait fileLogger.close();\n\t}\n}\n"]}
@@ -0,0 +1,11 @@
1
+ // This file is read by tools that parse documentation comments conforming to the TSDoc standard.
2
+ // It should be published with your NPM package. It should not be tracked by Git.
3
+ {
4
+ "tsdocVersion": "0.12",
5
+ "toolPackages": [
6
+ {
7
+ "packageName": "@microsoft/api-extractor",
8
+ "packageVersion": "7.38.3"
9
+ }
10
+ ]
11
+ }
@@ -0,0 +1,33 @@
1
+ /*!
2
+ * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
3
+ * Licensed under the MIT License.
4
+ */
5
+ /// <reference types="node" />
6
+ import { IFluidFileConverter } from "./codeLoaderBundle";
7
+ /**
8
+ * Is the given snapshot in JSON format
9
+ * @param content - snapshot file content
10
+ * @internal
11
+ */
12
+ export declare function isJsonSnapshot(content: Buffer): boolean;
13
+ /**
14
+ * Get the ODSP snapshot file content
15
+ * Works on both JSON and binary snapshot formats
16
+ * @param filePath - path to the ODSP snapshot file
17
+ * @internal
18
+ */
19
+ export declare function getSnapshotFileContent(filePath: string): string | Buffer;
20
+ /**
21
+ * Validate provided command line arguments
22
+ * @internal
23
+ */
24
+ export declare function validateCommandLineArgs(codeLoader?: string, fluidFileConverter?: IFluidFileConverter): string | undefined;
25
+ /**
26
+ * @internal
27
+ */
28
+ export declare function getArgsValidationError(inputFile: string, outputFile: string, timeout?: number): string | undefined;
29
+ /**
30
+ * @internal
31
+ */
32
+ export declare function timeoutPromise<T = void>(executor: (resolve: (value: T | PromiseLike<T>) => void, reject: (reason?: any) => void) => void, timeout: number): Promise<T>;
33
+ //# sourceMappingURL=utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA;;;GAGG;;AAGH,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAEzD;;;;GAIG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAEvD;AAED;;;;;GAKG;AACH,wBAAgB,sBAAsB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,GAAG,MAAM,CAIxE;AAED;;;GAGG;AACH,wBAAgB,uBAAuB,CACtC,UAAU,CAAC,EAAE,MAAM,EACnB,kBAAkB,CAAC,EAAE,mBAAmB,GACtC,MAAM,GAAG,SAAS,CAQpB;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CACrC,SAAS,EAAE,MAAM,EACjB,UAAU,EAAE,MAAM,EAClB,OAAO,CAAC,EAAE,MAAM,GACd,MAAM,GAAG,SAAS,CAoBpB;AAED;;GAEG;AACH,wBAAsB,cAAc,CAAC,CAAC,GAAG,IAAI,EAC5C,QAAQ,EAAE,CACT,OAAO,EAAE,CAAC,KAAK,EAAE,CAAC,GAAG,WAAW,CAAC,CAAC,CAAC,KAAK,IAAI,EAC5C,MAAM,EAAE,CAAC,MAAM,CAAC,EAAE,GAAG,KAAK,IAAI,KAC1B,IAAI,EACT,OAAO,EAAE,MAAM,GACb,OAAO,CAAC,CAAC,CAAC,CAeZ"}
package/dist/utils.js ADDED
@@ -0,0 +1,107 @@
1
+ "use strict";
2
+ /*!
3
+ * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
4
+ * Licensed under the MIT License.
5
+ */
6
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
7
+ if (k2 === undefined) k2 = k;
8
+ var desc = Object.getOwnPropertyDescriptor(m, k);
9
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
10
+ desc = { enumerable: true, get: function() { return m[k]; } };
11
+ }
12
+ Object.defineProperty(o, k2, desc);
13
+ }) : (function(o, m, k, k2) {
14
+ if (k2 === undefined) k2 = k;
15
+ o[k2] = m[k];
16
+ }));
17
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
18
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
19
+ }) : function(o, v) {
20
+ o["default"] = v;
21
+ });
22
+ var __importStar = (this && this.__importStar) || function (mod) {
23
+ if (mod && mod.__esModule) return mod;
24
+ var result = {};
25
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
26
+ __setModuleDefault(result, mod);
27
+ return result;
28
+ };
29
+ Object.defineProperty(exports, "__esModule", { value: true });
30
+ exports.timeoutPromise = exports.getArgsValidationError = exports.validateCommandLineArgs = exports.getSnapshotFileContent = exports.isJsonSnapshot = void 0;
31
+ const fs = __importStar(require("fs"));
32
+ /**
33
+ * Is the given snapshot in JSON format
34
+ * @param content - snapshot file content
35
+ * @internal
36
+ */
37
+ function isJsonSnapshot(content) {
38
+ return content.toString(undefined, 0, 1) === "{";
39
+ }
40
+ exports.isJsonSnapshot = isJsonSnapshot;
41
+ /**
42
+ * Get the ODSP snapshot file content
43
+ * Works on both JSON and binary snapshot formats
44
+ * @param filePath - path to the ODSP snapshot file
45
+ * @internal
46
+ */
47
+ function getSnapshotFileContent(filePath) {
48
+ // TODO: read file stream
49
+ const content = fs.readFileSync(filePath);
50
+ return isJsonSnapshot(content) ? content.toString() : content;
51
+ }
52
+ exports.getSnapshotFileContent = getSnapshotFileContent;
53
+ /**
54
+ * Validate provided command line arguments
55
+ * @internal
56
+ */
57
+ function validateCommandLineArgs(codeLoader, fluidFileConverter) {
58
+ if (codeLoader && fluidFileConverter !== undefined) {
59
+ return '"codeLoader" and "fluidFileConverter" cannot both be provided. See README for details.';
60
+ }
61
+ if (!codeLoader && fluidFileConverter === undefined) {
62
+ return '"codeLoader" must be provided if there is no explicit "fluidFileConverter". See README for details.';
63
+ }
64
+ return undefined;
65
+ }
66
+ exports.validateCommandLineArgs = validateCommandLineArgs;
67
+ /**
68
+ * @internal
69
+ */
70
+ function getArgsValidationError(inputFile, outputFile, timeout) {
71
+ // Validate input file
72
+ if (!inputFile) {
73
+ return "Input file name argument is missing.";
74
+ }
75
+ else if (!fs.existsSync(inputFile)) {
76
+ return "Input file does not exist.";
77
+ }
78
+ // Validate output file
79
+ if (!outputFile) {
80
+ return "Output file argument is missing.";
81
+ }
82
+ else if (fs.existsSync(outputFile)) {
83
+ return `Output file already exists [${outputFile}].`;
84
+ }
85
+ if (timeout !== undefined && (isNaN(timeout) || timeout < 0)) {
86
+ return "Invalid timeout";
87
+ }
88
+ return undefined;
89
+ }
90
+ exports.getArgsValidationError = getArgsValidationError;
91
+ /**
92
+ * @internal
93
+ */
94
+ async function timeoutPromise(executor, timeout) {
95
+ return new Promise((resolve, reject) => {
96
+ const timer = setTimeout(() => reject(new Error(`Timed out (${timeout}ms)`)), timeout);
97
+ executor((value) => {
98
+ clearTimeout(timer);
99
+ resolve(value);
100
+ }, (reason) => {
101
+ clearTimeout(timer);
102
+ reject(reason);
103
+ });
104
+ });
105
+ }
106
+ exports.timeoutPromise = timeoutPromise;
107
+ //# sourceMappingURL=utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;;;;;;;;;;;;;;;;;;;;;;;;AAEH,uCAAyB;AAGzB;;;;GAIG;AACH,SAAgB,cAAc,CAAC,OAAe;IAC7C,OAAO,OAAO,CAAC,QAAQ,CAAC,SAAS,EAAE,CAAC,EAAE,CAAC,CAAC,KAAK,GAAG,CAAC;AAClD,CAAC;AAFD,wCAEC;AAED;;;;;GAKG;AACH,SAAgB,sBAAsB,CAAC,QAAgB;IACtD,yBAAyB;IACzB,MAAM,OAAO,GAAG,EAAE,CAAC,YAAY,CAAC,QAAQ,CAAC,CAAC;IAC1C,OAAO,cAAc,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,OAAO,CAAC;AAC/D,CAAC;AAJD,wDAIC;AAED;;;GAGG;AACH,SAAgB,uBAAuB,CACtC,UAAmB,EACnB,kBAAwC;IAExC,IAAI,UAAU,IAAI,kBAAkB,KAAK,SAAS,EAAE;QACnD,OAAO,wFAAwF,CAAC;KAChG;IACD,IAAI,CAAC,UAAU,IAAI,kBAAkB,KAAK,SAAS,EAAE;QACpD,OAAO,qGAAqG,CAAC;KAC7G;IACD,OAAO,SAAS,CAAC;AAClB,CAAC;AAXD,0DAWC;AAED;;GAEG;AACH,SAAgB,sBAAsB,CACrC,SAAiB,EACjB,UAAkB,EAClB,OAAgB;IAEhB,sBAAsB;IACtB,IAAI,CAAC,SAAS,EAAE;QACf,OAAO,sCAAsC,CAAC;KAC9C;SAAM,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE;QACrC,OAAO,4BAA4B,CAAC;KACpC;IAED,uBAAuB;IACvB,IAAI,CAAC,UAAU,EAAE;QAChB,OAAO,kCAAkC,CAAC;KAC1C;SAAM,IAAI,EAAE,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE;QACrC,OAAO,+BAA+B,UAAU,IAAI,CAAC;KACrD;IAED,IAAI,OAAO,KAAK,SAAS,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,OAAO,GAAG,CAAC,CAAC,EAAE;QAC7D,OAAO,iBAAiB,CAAC;KACzB;IAED,OAAO,SAAS,CAAC;AAClB,CAAC;AAxBD,wDAwBC;AAED;;GAEG;AACI,KAAK,UAAU,cAAc,CACnC,QAGS,EACT,OAAe;IAEf,OAAO,IAAI,OAAO,CAAI,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACzC,MAAM,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,cAAc,OAAO,KAAK,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;QAEvF,QAAQ,CACP,CAAC,KAAK,EAAE,EAAE;YACT,YAAY,CAAC,KAAK,CAAC,CAAC;YACpB,OAAO,CAAC,KAAK,CAAC,CAAC;QAChB,CAAC,EACD,CAAC,MAAM,EAAE,EAAE;YACV,YAAY,CAAC,KAAK,CAAC,CAAC;YACpB,MAAM,CAAC,MAAM,CAAC,CAAC;QAChB,CAAC,CACD,CAAC;IACH,CAAC,CAAC,CAAC;AACJ,CAAC;AArBD,wCAqBC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport * as fs from \"fs\";\nimport { IFluidFileConverter } from \"./codeLoaderBundle\";\n\n/**\n * Is the given snapshot in JSON format\n * @param content - snapshot file content\n * @internal\n */\nexport function isJsonSnapshot(content: Buffer): boolean {\n\treturn content.toString(undefined, 0, 1) === \"{\";\n}\n\n/**\n * Get the ODSP snapshot file content\n * Works on both JSON and binary snapshot formats\n * @param filePath - path to the ODSP snapshot file\n * @internal\n */\nexport function getSnapshotFileContent(filePath: string): string | Buffer {\n\t// TODO: read file stream\n\tconst content = fs.readFileSync(filePath);\n\treturn isJsonSnapshot(content) ? content.toString() : content;\n}\n\n/**\n * Validate provided command line arguments\n * @internal\n */\nexport function validateCommandLineArgs(\n\tcodeLoader?: string,\n\tfluidFileConverter?: IFluidFileConverter,\n): string | undefined {\n\tif (codeLoader && fluidFileConverter !== undefined) {\n\t\treturn '\"codeLoader\" and \"fluidFileConverter\" cannot both be provided. See README for details.';\n\t}\n\tif (!codeLoader && fluidFileConverter === undefined) {\n\t\treturn '\"codeLoader\" must be provided if there is no explicit \"fluidFileConverter\". See README for details.';\n\t}\n\treturn undefined;\n}\n\n/**\n * @internal\n */\nexport function getArgsValidationError(\n\tinputFile: string,\n\toutputFile: string,\n\ttimeout?: number,\n): string | undefined {\n\t// Validate input file\n\tif (!inputFile) {\n\t\treturn \"Input file name argument is missing.\";\n\t} else if (!fs.existsSync(inputFile)) {\n\t\treturn \"Input file does not exist.\";\n\t}\n\n\t// Validate output file\n\tif (!outputFile) {\n\t\treturn \"Output file argument is missing.\";\n\t} else if (fs.existsSync(outputFile)) {\n\t\treturn `Output file already exists [${outputFile}].`;\n\t}\n\n\tif (timeout !== undefined && (isNaN(timeout) || timeout < 0)) {\n\t\treturn \"Invalid timeout\";\n\t}\n\n\treturn undefined;\n}\n\n/**\n * @internal\n */\nexport async function timeoutPromise<T = void>(\n\texecutor: (\n\t\tresolve: (value: T | PromiseLike<T>) => void,\n\t\treject: (reason?: any) => void,\n\t) => void,\n\ttimeout: number,\n): Promise<T> {\n\treturn new Promise<T>((resolve, reject) => {\n\t\tconst timer = setTimeout(() => reject(new Error(`Timed out (${timeout}ms)`)), timeout);\n\n\t\texecutor(\n\t\t\t(value) => {\n\t\t\t\tclearTimeout(timer);\n\t\t\t\tresolve(value);\n\t\t\t},\n\t\t\t(reason) => {\n\t\t\t\tclearTimeout(timer);\n\t\t\t\treject(reason);\n\t\t\t},\n\t\t);\n\t});\n}\n"]}
package/package.json ADDED
@@ -0,0 +1,120 @@
1
+ {
2
+ "name": "@fluidframework/fluid-runner",
3
+ "version": "2.0.0-dev-rc.1.0.0.224419",
4
+ "description": "Utility for running various functionality inside a Fluid Framework environment",
5
+ "homepage": "https://fluidframework.com",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "https://github.com/microsoft/FluidFramework.git",
9
+ "directory": "packages/tools/fluid-runner"
10
+ },
11
+ "license": "MIT",
12
+ "author": "Microsoft and contributors",
13
+ "type": "commonjs",
14
+ "exports": {
15
+ ".": {
16
+ "types": "./dist/index.d.ts",
17
+ "default": "./dist/index.js"
18
+ }
19
+ },
20
+ "main": "dist/index.js",
21
+ "types": "dist/index.d.ts",
22
+ "bin": {
23
+ "fluid-runner": "bin/fluid-runner"
24
+ },
25
+ "c8": {
26
+ "all": true,
27
+ "cache-dir": "nyc/.cache",
28
+ "exclude": [
29
+ "src/test/**/*.*ts",
30
+ "dist/test/**/*.*js"
31
+ ],
32
+ "exclude-after-remap": false,
33
+ "include": [
34
+ "src/**/*.*ts",
35
+ "dist/**/*.*js"
36
+ ],
37
+ "report-dir": "nyc/report",
38
+ "reporter": [
39
+ "cobertura",
40
+ "html",
41
+ "text"
42
+ ],
43
+ "temp-directory": "nyc/.nyc_output"
44
+ },
45
+ "dependencies": {
46
+ "@fluidframework/aqueduct": "2.0.0-dev-rc.1.0.0.224419",
47
+ "@fluidframework/container-definitions": "2.0.0-dev-rc.1.0.0.224419",
48
+ "@fluidframework/container-loader": "2.0.0-dev-rc.1.0.0.224419",
49
+ "@fluidframework/core-interfaces": "2.0.0-dev-rc.1.0.0.224419",
50
+ "@fluidframework/driver-definitions": "2.0.0-dev-rc.1.0.0.224419",
51
+ "@fluidframework/odsp-driver": "2.0.0-dev-rc.1.0.0.224419",
52
+ "@fluidframework/odsp-driver-definitions": "2.0.0-dev-rc.1.0.0.224419",
53
+ "@fluidframework/telemetry-utils": "2.0.0-dev-rc.1.0.0.224419",
54
+ "@microsoft/api-extractor": "^7.38.3",
55
+ "json2csv": "^5.0.7",
56
+ "yargs": "13.2.2"
57
+ },
58
+ "devDependencies": {
59
+ "@arethetypeswrong/cli": "^0.13.3",
60
+ "@fluid-tools/build-cli": "0.29.0-222379",
61
+ "@fluidframework/build-common": "^2.0.3",
62
+ "@fluidframework/build-tools": "0.29.0-222379",
63
+ "@fluidframework/eslint-config-fluid": "^3.1.0",
64
+ "@fluidframework/fluid-runner-previous": "npm:@fluidframework/fluid-runner@2.0.0-internal.7.2.0",
65
+ "@fluidframework/mocha-test-setup": "2.0.0-dev-rc.1.0.0.224419",
66
+ "@types/mocha": "^9.1.1",
67
+ "@types/node": "^18.19.0",
68
+ "@types/yargs": "^13",
69
+ "c8": "^7.7.1",
70
+ "cross-env": "^7.0.3",
71
+ "eslint": "~8.50.0",
72
+ "mocha": "^10.2.0",
73
+ "mocha-json-output-reporter": "^2.0.1",
74
+ "mocha-multi-reporters": "^1.5.1",
75
+ "moment": "^2.21.0",
76
+ "prettier": "~3.0.3",
77
+ "rimraf": "^4.4.0",
78
+ "typescript": "~5.1.6"
79
+ },
80
+ "fluidBuild": {
81
+ "tasks": {
82
+ "build:docs": {
83
+ "dependsOn": [
84
+ "...",
85
+ "api-extractor:commonjs"
86
+ ],
87
+ "script": false
88
+ }
89
+ }
90
+ },
91
+ "typeValidation": {
92
+ "broken": {}
93
+ },
94
+ "scripts": {
95
+ "api": "fluid-build . --task api",
96
+ "api-extractor:commonjs": "api-extractor run --local",
97
+ "build": "fluid-build . --task build",
98
+ "build:commonjs": "fluid-build . --task commonjs",
99
+ "build:compile": "fluid-build . --task compile",
100
+ "build:docs": "fluid-build . --task api",
101
+ "build:test": "tsc --project ./src/test/tsconfig.json",
102
+ "check:are-the-types-wrong": "attw --pack",
103
+ "ci:build:docs": "api-extractor run",
104
+ "clean": "rimraf --glob dist lib \"**/*.tsbuildinfo\" \"**/*.build.log\" nyc _api-extractor-temp",
105
+ "eslint": "eslint --format stylish src",
106
+ "eslint:fix": "eslint --format stylish src --fix --fix-type problem,suggestion,layout",
107
+ "format": "npm run prettier:fix",
108
+ "lint": "npm run prettier && npm run eslint",
109
+ "lint:fix": "npm run prettier:fix && npm run eslint:fix",
110
+ "prettier": "prettier --check . --cache --ignore-path ../../../.prettierignore",
111
+ "prettier:fix": "prettier --write . --cache --ignore-path ../../../.prettierignore",
112
+ "test": "npm run test:mocha",
113
+ "test:coverage": "c8 npm test",
114
+ "test:mocha": "mocha --ignore \"dist/test/types/*\" --recursive dist/test -r node_modules/@fluidframework/mocha-test-setup",
115
+ "test:mocha:verbose": "cross-env FLUID_TEST_VERBOSE=1 npm run test:mocha",
116
+ "tsc": "tsc",
117
+ "typetests:gen": "fluid-type-test-generator",
118
+ "typetests:prepare": "flub typetests --dir . --reset --previous --normalize"
119
+ }
120
+ }
@@ -0,0 +1,8 @@
1
+ /*!
2
+ * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
3
+ * Licensed under the MIT License.
4
+ */
5
+
6
+ module.exports = {
7
+ ...require("@fluidframework/build-common/prettier.config.cjs"),
8
+ };
@@ -0,0 +1,63 @@
1
+ /*!
2
+ * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
3
+ * Licensed under the MIT License.
4
+ */
5
+
6
+ import { ICodeDetailsLoader, IContainer } from "@fluidframework/container-definitions";
7
+ import { ITelemetryBaseLogger, FluidObject } from "@fluidframework/core-interfaces";
8
+
9
+ /**
10
+ * Contract that defines the necessary exports for the bundle provided at runtime
11
+ * For an example, see "src/test/sampleCodeLoaders/sampleCodeLoader.ts"
12
+ * @internal
13
+ */
14
+ export interface ICodeLoaderBundle {
15
+ /**
16
+ * Fluid export of all the required objects and functions
17
+ */
18
+ fluidExport: Promise<IFluidFileConverter>;
19
+ }
20
+
21
+ /**
22
+ * Instance that holds all the details for Fluid file conversion
23
+ * @alpha
24
+ */
25
+ export interface IFluidFileConverter {
26
+ /**
27
+ * Get code loader details to provide at Loader creation
28
+ * @param logger - created logger object to pass to code loader
29
+ */
30
+ getCodeLoader(logger: ITelemetryBaseLogger): Promise<ICodeDetailsLoader>;
31
+
32
+ /**
33
+ * Get scope object to provide at Loader creation
34
+ * @param logger - created logger object to pass to scope object
35
+ */
36
+ getScope?(logger: ITelemetryBaseLogger): Promise<FluidObject>;
37
+
38
+ /**
39
+ * Executes code on container and returns the result
40
+ * @param container - container created by this application
41
+ * @param options - additional options
42
+ */
43
+ execute(container: IContainer, options?: string): Promise<string>;
44
+ }
45
+
46
+ /**
47
+ * Type cast to ensure necessary methods are present in the provided bundle
48
+ * @param bundle - bundle provided to this application
49
+ */
50
+ export function isCodeLoaderBundle(bundle: any): bundle is ICodeLoaderBundle {
51
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-return
52
+ return bundle?.fluidExport && typeof bundle.fluidExport === "object";
53
+ }
54
+
55
+ export function isFluidFileConverter(obj: any): obj is IFluidFileConverter {
56
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-return
57
+ return (
58
+ obj?.getCodeLoader &&
59
+ typeof obj.getCodeLoader === "function" &&
60
+ obj.execute &&
61
+ typeof obj.execute === "function"
62
+ );
63
+ }
@@ -0,0 +1,148 @@
1
+ /*!
2
+ * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
3
+ * Licensed under the MIT License.
4
+ */
5
+
6
+ import * as fs from "fs";
7
+ import { ITelemetryLoggerExt, PerformanceEvent } from "@fluidframework/telemetry-utils";
8
+ import { LoaderHeader } from "@fluidframework/container-definitions";
9
+ import { Loader } from "@fluidframework/container-loader";
10
+ import { createLocalOdspDocumentServiceFactory } from "@fluidframework/odsp-driver";
11
+ import { IFluidFileConverter } from "./codeLoaderBundle";
12
+ import { FakeUrlResolver } from "./fakeUrlResolver";
13
+ import { getSnapshotFileContent, timeoutPromise, getArgsValidationError } from "./utils";
14
+ /* eslint-disable import/no-internal-modules */
15
+ import { ITelemetryOptions } from "./logger/fileLogger";
16
+ import { createLogger, getTelemetryFileValidationError } from "./logger/loggerUtils";
17
+ /* eslint-enable import/no-internal-modules */
18
+
19
+ /**
20
+ * @alpha
21
+ */
22
+ export type IExportFileResponse = IExportFileResponseSuccess | IExportFileResponseFailure;
23
+
24
+ interface IExportFileResponseSuccess {
25
+ success: true;
26
+ }
27
+
28
+ interface IExportFileResponseFailure {
29
+ success: false;
30
+ eventName: string;
31
+ errorMessage: string;
32
+ error?: any;
33
+ }
34
+
35
+ const clientArgsValidationError = "Client_ArgsValidationError";
36
+
37
+ /**
38
+ * Execute code on Container based on ODSP snapshot and write result to file
39
+ * @internal
40
+ */
41
+ export async function exportFile(
42
+ fluidFileConverter: IFluidFileConverter,
43
+ inputFile: string,
44
+ outputFile: string,
45
+ telemetryFile: string,
46
+ options?: string,
47
+ telemetryOptions?: ITelemetryOptions,
48
+ timeout?: number,
49
+ disableNetworkFetch?: boolean,
50
+ ): Promise<IExportFileResponse> {
51
+ const telemetryArgError = getTelemetryFileValidationError(telemetryFile);
52
+ if (telemetryArgError) {
53
+ const eventName = clientArgsValidationError;
54
+ return { success: false, eventName, errorMessage: telemetryArgError };
55
+ }
56
+ const { fileLogger, logger } = createLogger(telemetryFile, telemetryOptions);
57
+
58
+ try {
59
+ return await PerformanceEvent.timedExecAsync(
60
+ logger,
61
+ { eventName: "ExportFile" },
62
+ async () => {
63
+ const argsValidationError = getArgsValidationError(inputFile, outputFile, timeout);
64
+ if (argsValidationError) {
65
+ const eventName = clientArgsValidationError;
66
+ logger.sendErrorEvent({ eventName, message: argsValidationError });
67
+ return { success: false, eventName, errorMessage: argsValidationError };
68
+ }
69
+
70
+ fs.writeFileSync(
71
+ outputFile,
72
+ await createContainerAndExecute(
73
+ getSnapshotFileContent(inputFile),
74
+ fluidFileConverter,
75
+ logger,
76
+ options,
77
+ timeout,
78
+ disableNetworkFetch,
79
+ ),
80
+ );
81
+
82
+ return { success: true };
83
+ },
84
+ );
85
+ } catch (error) {
86
+ const eventName = "Client_UnexpectedError";
87
+ logger.sendErrorEvent({ eventName }, error);
88
+ return { success: false, eventName, errorMessage: "Unexpected error", error };
89
+ } finally {
90
+ await fileLogger.close();
91
+ }
92
+ }
93
+
94
+ /**
95
+ * Create the container based on an ODSP snapshot and execute code on it
96
+ * @returns result of execution
97
+ * @internal
98
+ */
99
+ export async function createContainerAndExecute(
100
+ localOdspSnapshot: string | Uint8Array,
101
+ fluidFileConverter: IFluidFileConverter,
102
+ logger: ITelemetryLoggerExt,
103
+ options?: string,
104
+ timeout?: number,
105
+ disableNetworkFetch: boolean = false,
106
+ ): Promise<string> {
107
+ const fn = async () => {
108
+ if (disableNetworkFetch) {
109
+ global.fetch = async () => {
110
+ throw new Error("Network fetch is not allowed");
111
+ };
112
+ }
113
+
114
+ const loader = new Loader({
115
+ urlResolver: new FakeUrlResolver(),
116
+ documentServiceFactory: createLocalOdspDocumentServiceFactory(localOdspSnapshot),
117
+ codeLoader: await fluidFileConverter.getCodeLoader(logger),
118
+ scope: await fluidFileConverter.getScope?.(logger),
119
+ logger,
120
+ });
121
+
122
+ const container = await loader.resolve({
123
+ url: "/fakeUrl/",
124
+ headers: {
125
+ [LoaderHeader.loadMode]: { opsBeforeReturn: "cached" },
126
+ },
127
+ });
128
+
129
+ return PerformanceEvent.timedExecAsync(logger, { eventName: "ExportFile" }, async () => {
130
+ try {
131
+ return await fluidFileConverter.execute(container, options);
132
+ } finally {
133
+ container.dispose();
134
+ }
135
+ });
136
+ };
137
+
138
+ // eslint-disable-next-line unicorn/prefer-ternary
139
+ if (timeout !== undefined) {
140
+ return timeoutPromise<string>((resolve, reject) => {
141
+ fn()
142
+ .then((value) => resolve(value))
143
+ .catch((error) => reject(error));
144
+ }, timeout);
145
+ } else {
146
+ return fn();
147
+ }
148
+ }
@@ -0,0 +1,54 @@
1
+ /*!
2
+ * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
3
+ * Licensed under the MIT License.
4
+ */
5
+
6
+ import { IRequest } from "@fluidframework/core-interfaces";
7
+ import {
8
+ IContainerPackageInfo,
9
+ IResolvedUrl,
10
+ IUrlResolver,
11
+ } from "@fluidframework/driver-definitions";
12
+ import { IOdspResolvedUrl } from "@fluidframework/odsp-driver-definitions";
13
+
14
+ const fakeId = "FakeUrlResolver";
15
+ const fakeUrl = "/FakeUrlResolver/";
16
+
17
+ /**
18
+ * Fake URL resolver that returns hard coded values on every request
19
+ * @internal
20
+ */
21
+ export class FakeUrlResolver implements IUrlResolver {
22
+ public async resolve(_request: IRequest): Promise<IResolvedUrl | undefined> {
23
+ const fakeOdspResolvedUrl: IOdspResolvedUrl = {
24
+ type: "fluid",
25
+ odspResolvedUrl: true,
26
+ id: fakeId,
27
+ siteUrl: fakeUrl,
28
+ driveId: fakeId,
29
+ itemId: fakeId,
30
+ url: fakeUrl,
31
+ hashedDocumentId: fakeId,
32
+ endpoints: {
33
+ snapshotStorageUrl: fakeUrl,
34
+ attachmentPOSTStorageUrl: fakeUrl,
35
+ attachmentGETStorageUrl: fakeUrl,
36
+ deltaStorageUrl: fakeUrl,
37
+ },
38
+ tokens: {},
39
+ fileName: fakeId,
40
+ summarizer: false,
41
+ fileVersion: fakeId,
42
+ };
43
+
44
+ return fakeOdspResolvedUrl;
45
+ }
46
+
47
+ public async getAbsoluteUrl(
48
+ _resolvedUrl: IResolvedUrl,
49
+ _relativeUrl: string,
50
+ _packageInfoSource?: IContainerPackageInfo,
51
+ ): Promise<string> {
52
+ return "";
53
+ }
54
+ }