@fluidframework/tool-utils 2.118.1 → 3.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -1,12 +1,42 @@
1
1
  # @fluidframework/tool-utils
2
2
 
3
- ## 2.118.0
3
+ ## 3.0.0
4
4
 
5
- Dependency updates only.
5
+ ### Minor Changes
6
6
 
7
- ## 2.117.0
7
+ - Removal of direct CommonJS support ([#28124](https://github.com/microsoft/FluidFramework/pull/28124)) [0f84e3b8878](https://github.com/microsoft/FluidFramework/commit/0f84e3b8878a5e75b2253976d98fd963bbd9db88)
8
8
 
9
- Dependency updates only.
9
+ Direct `require()` import is no longer directly supported.
10
+ Package is transpiled as ECMAScript Module.
11
+
12
+ See [Removal of direct CommonJS support in v3.0](https://github.com/microsoft/FluidFramework/issues/27444) for more information.
13
+
14
+ - Require modern TypeScript module resolution ([#27970](https://github.com/microsoft/FluidFramework/pull/27970)) [325e2016ca9](https://github.com/microsoft/FluidFramework/commit/325e2016ca9978d4a1f7552c97ba34feac9df41f)
15
+
16
+ Fluid Framework Client packages no longer include type declaration compatibility entrypoints for TypeScript's legacy Node10 resolution mode (`"moduleResolution": "node"` or `"node10"`).
17
+ Applications upgrading to Fluid Framework 3.0 must use one of the following supported configurations:
18
+ - `"module": "Node16"` with `"moduleResolution": "Node16"`
19
+ - `"module": "NodeNext"` with `"moduleResolution": "NodeNext"`
20
+ - `"module": "ESNext"` with `"moduleResolution": "Bundler"`
21
+
22
+ Existing public package entrypoints exposed through `package.json` exports, including `/alpha`, `/beta`, and `/legacy`, remain available under supported module resolution modes.
23
+
24
+ See [Removal of Node10 resolutions in v3.0](https://github.com/microsoft/FluidFramework/issues/27457) for more information.
25
+
26
+ - Client packages now target ES2022 ([#27846](https://github.com/microsoft/FluidFramework/pull/27846)) [91c78541bdd](https://github.com/microsoft/FluidFramework/commit/91c78541bddcbca5d6c5f357b023eeaee617d885)
27
+
28
+ The TypeScript compilation `target` and `lib` for the Fluid Framework client packages have been raised from ES2021/ES2020 to **ES2022**.
29
+ The published JavaScript now uses ES2022 language features (with correspondingly less down-leveling), so consuming these packages requires a runtime that supports ES2022.
30
+ All actively supported Node.js versions and evergreen browsers already meet this requirement.
31
+
32
+ Note that Fluid Framework has not officially supported targets older than ES2022 since before 2.0: this is documented in [ClientRequirements.md](https://github.com/microsoft/FluidFramework/blob/main/ClientRequirements.md) as well as the README for every client package.
33
+
34
+ It is possible this change could impact users of less up to date JavaScript runtimes.
35
+ Impacted users can use a tool like [babel](https://babeljs.io/) to transpile out unsupported language features.
36
+
37
+ - Build with TypeScript 6 ([#28052](https://github.com/microsoft/FluidFramework/pull/28052)) [7ab015c49de](https://github.com/microsoft/FluidFramework/commit/7ab015c49deec84833cdfe1fb5e1606b901f6e81)
38
+
39
+ FluidFramework Client SDK is now built using TypeScript 6. Consumers should build with TypeScript v6 or v7 or compatible tooling.
10
40
 
11
41
  ## 2.116.0
12
42
 
package/README.md CHANGED
@@ -9,15 +9,15 @@ Shared utilities for tools.
9
9
 
10
10
  ## Using Fluid Framework libraries
11
11
 
12
- When taking a dependency on a Fluid Framework library's public APIs, we recommend using a `^` (caret) version range, such as `^1.3.4`.
13
- While Fluid Framework libraries may use different ranges with interdependencies between other Fluid Framework libraries,
14
- library consumers should always prefer `^`.
12
+ For a dependency on a Fluid Framework library's public APIs, we recommend a `^` (caret) version range.
13
+ For example, use `^1.3.4`.
15
14
 
16
- If using any of Fluid Framework's unstable APIs (for example, its `beta` APIs), we recommend using a more constrained version range, such as `~`.
15
+ For a dependency on an unstable API, such as a `beta` API, we recommend a more restrictive version range.
16
+ For example, use a `~` version range.
17
17
 
18
18
  ## Installation
19
19
 
20
- To get started, install the package by running the following command:
20
+ Run this command to install the package:
21
21
 
22
22
  ```bash
23
23
  npm i @fluidframework/tool-utils
@@ -25,7 +25,7 @@ npm i @fluidframework/tool-utils
25
25
 
26
26
  ## API Documentation
27
27
 
28
- API documentation for **@fluidframework/tool-utils** is available at <https://fluidframework.com/docs/apis/tool-utils>.
28
+ Read the **@fluidframework/tool-utils** API documentation at <https://fluidframework.com/docs/apis/tool-utils>.
29
29
 
30
30
  <!-- prettier-ignore-end -->
31
31
 
@@ -38,62 +38,69 @@ API documentation for **@fluidframework/tool-utils** is available at <https://fl
38
38
 
39
39
  ## Minimum Client Requirements
40
40
 
41
- These are the platform requirements for the current version of Fluid Framework Client Packages.
42
- These requirements err on the side of being too strict since within a major version they can be relaxed over time, but not made stricter.
43
- For Long Term Support (LTS) versions this can require supporting these platforms for several years.
41
+ Fluid Framework client libraries support the platforms in this document.
42
+ These requirements are intentionally restrictive.
43
+ Within a major version series, we can relax these requirements, but we cannot make them stricter.
44
+ For a Long Term Support (LTS) version, we might need to support these platforms for several years.
44
45
 
45
- It is likely that other configurations will work, but they are not supported: if they stop working, we do not consider that a bug.
46
- If you would benefit from support for something not listed here, file an issue and the product team will evaluate your request.
47
- When making such a request please include if the configuration already works (and thus the request is just that it becomes officially supported), or if changes are required to get it working.
46
+ Other configurations can work, but Fluid Framework does not support them.
47
+ If an unsupported configuration stops working, we do not classify this as a bug.
48
+ To request support for a configuration that is not listed, file an issue.
49
+ The product team will evaluate your request.
50
+ In the issue, specify the current status of the configuration:
51
+
52
+ - The configuration works but needs official support.
53
+ - The configuration does not work and requires changes.
48
54
 
49
55
  ### Supported Runtimes
50
56
 
51
- - NodeJs ^22.22.2 except that we will drop support for it [when NodeJs 22 loses its upstream support on 2027-04-30](https://github.com/nodejs/release#release-schedule), and will support a newer LTS version of NodeJS at least 1 year before 22 is end-of-life.
52
- - Running Fluid in a Node.js environment with the `--no-experimental-fetch` flag is not supported.
53
- - Modern browsers supporting the es2022 standard library: in response to asks we can add explicit support for using babel to polyfill to target specific standards or runtimes (meaning we can avoid/remove use of things that don't polyfill robustly, but otherwise target modern standards).
57
+ - Fluid Framework supports Node.js versions 22 and 24 while they receive [upstream support](https://nodejs.org/en/about/previous-releases).
58
+ - Fluid Framework will stop support for version 22 [when upstream support ends on 2027-04-30](https://github.com/nodejs/release#release-schedule).
59
+ - Fluid Framework does not support Node.js with the `--no-experimental-fetch` flag.
60
+ - Fluid Framework supports modern browsers that support the ES2022 standard library.
54
61
 
55
62
  ### Supported Tools
56
63
 
57
- - TypeScript 5.4:
58
- - All [`strict`](https://www.typescriptlang.org/tsconfig) options are supported.
59
- - [`strictNullChecks`](https://www.typescriptlang.org/tsconfig) is required.
60
- - [Configuration options deprecated in 5.0](https://github.com/microsoft/TypeScript/issues/51909) are not supported.
61
- - `exactOptionalPropertyTypes` is currently not fully supported.
62
- If used, narrowing members of Fluid Framework types types using `in`, `Reflect.has`, `Object.hasOwn` or `Object.prototype.hasOwnProperty` should be avoided as they may incorrectly exclude `undefined` from the possible values in some cases.
64
+ - [TypeScript 6.0](https://typescriptdocs.com/release-notes/TypeScript%206.0):
65
+ - Fluid Framework supports all [`strict`](https://www.typescriptlang.org/tsconfig) options.
66
+ - Set the build targets (`lib`, `target`) to `ES2022` or later.
67
+ - Enable [`strictNullChecks`](https://www.typescriptlang.org/tsconfig).
68
+ - Fluid Framework does not support [configuration options deprecated in TypeScript 6.0](https://typescriptdocs.com/release-notes/TypeScript%206.0#breaking-changes-and-deprecations-in-typescript-6-0).
69
+ - Fluid Framework does not fully support `exactOptionalPropertyTypes`.
70
+ If you enable this option, do not use `in`, `Reflect.has`, `Object.hasOwn`, or `Object.prototype.hasOwnProperty` to narrow members of Fluid Framework types.
71
+ These methods can incorrectly exclude `undefined` from the possible values.
63
72
  - [webpack](https://webpack.js.org/) 5
64
- - We are not intending to be prescriptive about what bundler to use.
65
- Other bundlers which can handle ES Modules should work, but webpack is the only one we actively test.
73
+ - We do not require a specific bundler.
74
+ Other bundlers that handle ES Modules can work, but we actively test only webpack.
66
75
 
67
76
  ### Module Resolution
68
77
 
69
- [`Node16`, `NodeNext`, or `Bundler`](https://www.typescriptlang.org/tsconfig#moduleResolution) resolution should be used with TypeScript compilerOptions to follow the [Node.js v12+ ESM Resolution and Loading algorithm](https://nodejs.github.io/nodejs.dev/en/api/v20/esm/#resolution-and-loading-algorithm).
70
- Node10 resolution is not supported as it does not support Fluid Framework's API structuring pattern that is used to distinguish stable APIs from those that are in development.
78
+ In TypeScript `compilerOptions`, use [`Node16`, `Node20`, `NodeNext`, or `Bundler`](https://www.typescriptlang.org/tsconfig#moduleResolution) module resolution.
79
+ These settings follow the [Node.js v12+ ESM Resolution and Loading algorithm](https://nodejs.github.io/nodejs.dev/en/api/v20/esm/#resolution-and-loading-algorithm).
80
+
81
+ Do not use `Node10` module resolution.
71
82
 
72
83
  ### Module Formats
73
84
 
74
85
  - ES Modules:
75
- ES Modules are the preferred way to consume our client packages (including in NodeJs) and consuming our client packages from ES Modules is fully supported.
76
- - CommonJs:
77
- Consuming our client packages as CommonJs is supported only in NodeJS and only for the cases listed below.
78
- This is done to accommodate some workflows without good ES Module support.
79
- If you have a workflow you would like included in this list, file an issue.
80
- Once this list of workflows motivating CommonJS support is empty, we may drop support for CommonJS one year after notice of the change is posted here.
81
-
82
- - Testing with Jest (which lacks [stable ESM support](https://jestjs.io/docs/ecmascript-modules) due to [unstable APIs in NodeJs](https://github.com/nodejs/node/issues/37648))
86
+ Use ES Modules to consume Fluid Framework client packages, including in Node.js.
87
+ - CommonJS:
88
+ Fluid Framework does not officially support CommonJS in version 3.0 or later.
83
89
 
84
90
  ## Contribution Guidelines
85
91
 
86
- There are many ways to [contribute](https://github.com/microsoft/FluidFramework/blob/main/CONTRIBUTING.md) to Fluid.
92
+ You can [contribute](https://github.com/microsoft/FluidFramework/blob/main/CONTRIBUTING.md) to Fluid Framework in these ways:
87
93
 
88
- - Participate in Q&A in our [GitHub Discussions](https://github.com/microsoft/FluidFramework/discussions).
89
- - [Submit bugs](https://github.com/microsoft/FluidFramework/issues) and help us verify fixes as they are checked in.
90
- - Review the [source code changes](https://github.com/microsoft/FluidFramework/pulls).
94
+ - Answer questions in [GitHub Discussions](https://github.com/microsoft/FluidFramework/discussions).
95
+ - [Submit bug reports](https://github.com/microsoft/FluidFramework/issues) and help verify fixes.
96
+ - Review [source code changes](https://github.com/microsoft/FluidFramework/pulls).
91
97
  - [Contribute bug fixes](https://github.com/microsoft/FluidFramework/blob/main/CONTRIBUTING.md).
92
98
 
93
- Detailed instructions for working in the repo can be found in the [Wiki](https://github.com/microsoft/FluidFramework/blob/main/docs/content/Home.md).
99
+ For detailed instructions, read the [repo documentation](https://github.com/microsoft/FluidFramework/blob/main/docs/content/Home.md).
94
100
 
95
- This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/).
96
- For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.
101
+ This project follows the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/).
102
+ For more information, read the [Code of Conduct frequently asked questions](https://opensource.microsoft.com/codeofconduct/faq/).
103
+ For questions or comments, contact [opencode@microsoft.com](mailto:opencode@microsoft.com).
97
104
 
98
105
  This project may contain Microsoft trademarks or logos for Microsoft projects, products, or services.
99
106
  Use of these trademarks or logos must follow Microsoft’s [Trademark & Brand Guidelines](https://www.microsoft.com/trademarks).
@@ -101,13 +108,9 @@ Use of Microsoft trademarks or logos in modified versions of this project must n
101
108
 
102
109
  ## Help
103
110
 
104
- Not finding what you're looking for in this README?
105
- Check out [fluidframework.com](https://fluidframework.com/docs/).
106
-
107
- Still not finding what you're looking for?
108
- Please [file an issue](https://github.com/microsoft/FluidFramework/blob/main/docs/content/Contributing/Submitting-Bugs-and-Feature-Requests.md).
111
+ Read the [Fluid Framework documentation](https://fluidframework.com/docs/) for information about Fluid Framework concepts and APIs.
109
112
 
110
- Thank you!
113
+ To request information that the documentation does not contain, [create an issue](https://github.com/microsoft/FluidFramework/blob/main/docs/content/Contributing/Submitting-Bugs-and-Feature-Requests.md).
111
114
 
112
115
  ## Trademark
113
116
 
@@ -1,4 +1,4 @@
1
1
  {
2
2
  "$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json",
3
- "extends": "../../../common/build/build-common/api-extractor-base.esm.no-legacy.json"
3
+ "extends": "<projectFolder>/../../../common/build/build-common/api-extractor-model.esm.json"
4
4
  }
@@ -0,0 +1,5 @@
1
+ {
2
+ "$schema": "https://developer.microsoft.com/json-schemas/api-extractor/v7/api-extractor.schema.json",
3
+ "extends": "<projectFolder>/../../../common/build/build-common/api-extractor-report-base.esm.json",
4
+ "mainEntryPointFilePath": "<projectFolder>/lib/public.d.ts"
5
+ }
@@ -7,7 +7,9 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
7
7
  return (mod && mod.__esModule) ? mod : { "default": mod };
8
8
  };
9
9
  Object.defineProperty(exports, "__esModule", { value: true });
10
- exports.lockRC = exports.saveRC = exports.loadRC = void 0;
10
+ exports.loadRC = loadRC;
11
+ exports.saveRC = saveRC;
12
+ exports.lockRC = lockRC;
11
13
  const node_fs_1 = __importDefault(require("node:fs"));
12
14
  const node_os_1 = __importDefault(require("node:os"));
13
15
  const node_path_1 = __importDefault(require("node:path"));
@@ -38,7 +40,6 @@ async function loadRC() {
38
40
  }
39
41
  return {};
40
42
  }
41
- exports.loadRC = loadRC;
42
43
  /**
43
44
  * Saves the Fluid tool resources to `.fluidtoolrc` in the current user's home directory.
44
45
  *
@@ -66,7 +67,6 @@ async function saveRC(rc) {
66
67
  await writeFile(fileName, Buffer.from(content, "utf8"), { mode: 0o600 });
67
68
  await chmod(fileName, 0o600);
68
69
  }
69
- exports.saveRC = saveRC;
70
70
  /**
71
71
  * Acquires the inter-process lock for `.fluidtoolrc` in the current user's home directory.
72
72
  *
@@ -88,5 +88,4 @@ async function lockRC() {
88
88
  realpath: false,
89
89
  });
90
90
  }
91
- exports.lockRC = lockRC;
92
91
  //# sourceMappingURL=fluidToolRc.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"fluidToolRc.js","sourceRoot":"","sources":["../src/fluidToolRc.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;;;;AAEH,sDAAyB;AACzB,sDAAyB;AACzB,0DAA6B;AAC7B,0DAA6B;AAG7B,qDAAuC;AA2BvC,MAAM,aAAa,GAAG,GAAW,EAAE,CAAC,mBAAI,CAAC,IAAI,CAAC,iBAAE,CAAC,OAAO,EAAE,EAAE,cAAc,CAAC,CAAC;AAE5E;;;;;;;GAOG;AACI,KAAK,UAAU,MAAM;IAC3B,MAAM,QAAQ,GAAG,mBAAI,CAAC,SAAS,CAAC,iBAAE,CAAC,QAAQ,CAAC,CAAC;IAC7C,MAAM,MAAM,GAAG,mBAAI,CAAC,SAAS,CAAC,iBAAE,CAAC,MAAM,CAAC,CAAC;IACzC,MAAM,QAAQ,GAAG,aAAa,EAAE,CAAC;IACjC,IAAI,MAAM,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC5B,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,QAAQ,CAAC,CAAC;QACrC,IAAI,CAAC;YACJ,+DAA+D;YAC/D,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC;QACzC,CAAC;QAAC,MAAM,CAAC;YACR,UAAU;QACX,CAAC;IACF,CAAC;IACD,OAAO,EAAE,CAAC;AACX,CAAC;AAdD,wBAcC;AAED;;;;;;;;;;;GAWG;AACI,KAAK,UAAU,MAAM,CAAC,EAAc;IAC1C,MAAM,SAAS,GAAG,mBAAI,CAAC,SAAS,CAAC,iBAAE,CAAC,SAAS,CAAC,CAAC;IAC/C,MAAM,KAAK,GAAG,mBAAI,CAAC,SAAS,CAAC,iBAAE,CAAC,KAAK,CAAC,CAAC;IACvC,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC,EAAE,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC;IACjD,MAAM,QAAQ,GAAG,aAAa,EAAE,CAAC;IACjC,qFAAqF;IACrF,0FAA0F;IAC1F,uFAAuF;IACvF,yFAAyF;IACzF,6FAA6F;IAC7F,+FAA+F;IAC/F,2FAA2F;IAC3F,MAAM,SAAS,CAAC,QAAQ,EAAE,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IACzE,MAAM,KAAK,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;AAC9B,CAAC;AAdD,wBAcC;AAED;;;;;;;;;;;GAWG;AACI,KAAK,UAAU,MAAM;IAC3B,OAAO,IAAA,sBAAI,EAAC,aAAa,EAAE,EAAE;QAC5B,OAAO,EAAE;YACR,OAAO,EAAE,IAAI;SACb;QACD,KAAK,EAAE,KAAK;QACZ,QAAQ,EAAE,KAAK;KACf,CAAC,CAAC;AACJ,CAAC;AARD,wBAQC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport fs from \"node:fs\";\nimport os from \"node:os\";\nimport path from \"node:path\";\nimport util from \"node:util\";\n\nimport type { IOdspTokens } from \"@fluidframework/odsp-doclib-utils/internal\";\nimport { lock } from \"proper-lockfile\";\n\n/**\n * @internal\n */\nexport interface IAsyncCache<TKey, TValue> {\n\tget(key: TKey): Promise<TValue | undefined>;\n\tsave(key: TKey, value: TValue): Promise<void>;\n\tlock<T>(callback: () => Promise<T>): Promise<T>;\n}\n\n/**\n * @internal\n */\nexport interface IResources {\n\ttokens?: {\n\t\tversion?: number;\n\t\tdata: Record<\n\t\t\tstring,\n\t\t\t{\n\t\t\t\tstorage?: IOdspTokens;\n\t\t\t\tpush?: IOdspTokens;\n\t\t\t}\n\t\t>;\n\t};\n}\n\nconst getRCFileName = (): string => path.join(os.homedir(), \".fluidtoolrc\");\n\n/**\n * Loads the Fluid tool resource cache from `.fluidtoolrc` in the current user's home directory.\n *\n * @returns The parsed resources, or an empty object if the file does not exist or contains invalid\n * JSON.\n * @throws If the file exists but cannot be read.\n * @internal\n */\nexport async function loadRC(): Promise<IResources> {\n\tconst readFile = util.promisify(fs.readFile);\n\tconst exists = util.promisify(fs.exists);\n\tconst fileName = getRCFileName();\n\tif (await exists(fileName)) {\n\t\tconst buf = await readFile(fileName);\n\t\ttry {\n\t\t\t// eslint-disable-next-line @typescript-eslint/no-unsafe-return\n\t\t\treturn JSON.parse(buf.toString(\"utf8\"));\n\t\t} catch {\n\t\t\t// Nothing\n\t\t}\n\t}\n\treturn {};\n}\n\n/**\n * Saves the Fluid tool resources to `.fluidtoolrc` in the current user's home directory.\n *\n * On POSIX filesystems, successful completion ensures the file has owner-only read/write\n * permissions. Windows continues to rely on the access controls inherited from the user's home\n * directory.\n *\n * @param rc - The resources to serialize and save.\n * @throws If serialization, writing, or updating the file permissions fails. A permission-update\n * failure occurs after the new contents have already been written.\n * @internal\n */\nexport async function saveRC(rc: IResources): Promise<void> {\n\tconst writeFile = util.promisify(fs.writeFile);\n\tconst chmod = util.promisify(fs.chmod);\n\tconst content = JSON.stringify(rc, undefined, 2);\n\tconst fileName = getRCFileName();\n\t// This per-user file holds ODSP access tokens and may also hold development secrets.\n\t// On POSIX filesystems, `mode` creates a new file as owner-readable/writable only (0600).\n\t// Because `mode` does not change an existing file, chmod also repairs caches that were\n\t// previously created with broader permissions. On Windows, these calls normally succeed,\n\t// but Node only uses the write bit: 0600 keeps the file writable without restricting who can\n\t// read it. Confidentiality therefore depends on ACLs inherited from the user's home directory.\n\t// If the filesystem rejects chmod, saveRC rejects after the file has already been written.\n\tawait writeFile(fileName, Buffer.from(content, \"utf8\"), { mode: 0o600 });\n\tawait chmod(fileName, 0o600);\n}\n\n/**\n * Acquires the inter-process lock for `.fluidtoolrc` in the current user's home directory.\n *\n * The lock may be acquired before the resource file exists. While another process holds the lock,\n * acquisition retries indefinitely. Locks whose modification time has not been updated for 60\n * seconds are considered stale.\n *\n * @returns An asynchronous callback that releases the lock. The caller must invoke it after\n * completing the protected operation, including when that operation fails.\n * @throws If a filesystem error prevents the lock from being acquired.\n * @internal\n */\nexport async function lockRC(): Promise<() => Promise<void>> {\n\treturn lock(getRCFileName(), {\n\t\tretries: {\n\t\t\tforever: true,\n\t\t},\n\t\tstale: 60000,\n\t\trealpath: false,\n\t});\n}\n"]}
1
+ {"version":3,"file":"fluidToolRc.js","sourceRoot":"","sources":["../src/fluidToolRc.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;;;AA6CH,wBAcC;AAcD,wBAcC;AAcD,wBAQC;AA3GD,sDAAyB;AACzB,sDAAyB;AACzB,0DAA6B;AAC7B,0DAA6B;AAG7B,qDAAuC;AA2BvC,MAAM,aAAa,GAAG,GAAW,EAAE,CAAC,mBAAI,CAAC,IAAI,CAAC,iBAAE,CAAC,OAAO,EAAE,EAAE,cAAc,CAAC,CAAC;AAE5E;;;;;;;GAOG;AACI,KAAK,UAAU,MAAM;IAC3B,MAAM,QAAQ,GAAG,mBAAI,CAAC,SAAS,CAAC,iBAAE,CAAC,QAAQ,CAAC,CAAC;IAC7C,MAAM,MAAM,GAAG,mBAAI,CAAC,SAAS,CAAC,iBAAE,CAAC,MAAM,CAAC,CAAC;IACzC,MAAM,QAAQ,GAAG,aAAa,EAAE,CAAC;IACjC,IAAI,MAAM,MAAM,CAAC,QAAQ,CAAC,EAAE,CAAC;QAC5B,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,QAAQ,CAAC,CAAC;QACrC,IAAI,CAAC;YACJ,+DAA+D;YAC/D,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC;QACzC,CAAC;QAAC,MAAM,CAAC;YACR,UAAU;QACX,CAAC;IACF,CAAC;IACD,OAAO,EAAE,CAAC;AACX,CAAC;AAED;;;;;;;;;;;GAWG;AACI,KAAK,UAAU,MAAM,CAAC,EAAc;IAC1C,MAAM,SAAS,GAAG,mBAAI,CAAC,SAAS,CAAC,iBAAE,CAAC,SAAS,CAAC,CAAC;IAC/C,MAAM,KAAK,GAAG,mBAAI,CAAC,SAAS,CAAC,iBAAE,CAAC,KAAK,CAAC,CAAC;IACvC,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC,EAAE,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC;IACjD,MAAM,QAAQ,GAAG,aAAa,EAAE,CAAC;IACjC,qFAAqF;IACrF,0FAA0F;IAC1F,uFAAuF;IACvF,yFAAyF;IACzF,6FAA6F;IAC7F,+FAA+F;IAC/F,2FAA2F;IAC3F,MAAM,SAAS,CAAC,QAAQ,EAAE,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAC;IACzE,MAAM,KAAK,CAAC,QAAQ,EAAE,KAAK,CAAC,CAAC;AAC9B,CAAC;AAED;;;;;;;;;;;GAWG;AACI,KAAK,UAAU,MAAM;IAC3B,OAAO,IAAA,sBAAI,EAAC,aAAa,EAAE,EAAE;QAC5B,OAAO,EAAE;YACR,OAAO,EAAE,IAAI;SACb;QACD,KAAK,EAAE,KAAK;QACZ,QAAQ,EAAE,KAAK;KACf,CAAC,CAAC;AACJ,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport fs from \"node:fs\";\nimport os from \"node:os\";\nimport path from \"node:path\";\nimport util from \"node:util\";\n\nimport type { IOdspTokens } from \"@fluidframework/odsp-doclib-utils/internal\";\nimport { lock } from \"proper-lockfile\";\n\n/**\n * @internal\n */\nexport interface IAsyncCache<TKey, TValue> {\n\tget(key: TKey): Promise<TValue | undefined>;\n\tsave(key: TKey, value: TValue): Promise<void>;\n\tlock<T>(callback: () => Promise<T>): Promise<T>;\n}\n\n/**\n * @internal\n */\nexport interface IResources {\n\ttokens?: {\n\t\tversion?: number;\n\t\tdata: Record<\n\t\t\tstring,\n\t\t\t{\n\t\t\t\tstorage?: IOdspTokens;\n\t\t\t\tpush?: IOdspTokens;\n\t\t\t}\n\t\t>;\n\t};\n}\n\nconst getRCFileName = (): string => path.join(os.homedir(), \".fluidtoolrc\");\n\n/**\n * Loads the Fluid tool resource cache from `.fluidtoolrc` in the current user's home directory.\n *\n * @returns The parsed resources, or an empty object if the file does not exist or contains invalid\n * JSON.\n * @throws If the file exists but cannot be read.\n * @internal\n */\nexport async function loadRC(): Promise<IResources> {\n\tconst readFile = util.promisify(fs.readFile);\n\tconst exists = util.promisify(fs.exists);\n\tconst fileName = getRCFileName();\n\tif (await exists(fileName)) {\n\t\tconst buf = await readFile(fileName);\n\t\ttry {\n\t\t\t// eslint-disable-next-line @typescript-eslint/no-unsafe-return\n\t\t\treturn JSON.parse(buf.toString(\"utf8\"));\n\t\t} catch {\n\t\t\t// Nothing\n\t\t}\n\t}\n\treturn {};\n}\n\n/**\n * Saves the Fluid tool resources to `.fluidtoolrc` in the current user's home directory.\n *\n * On POSIX filesystems, successful completion ensures the file has owner-only read/write\n * permissions. Windows continues to rely on the access controls inherited from the user's home\n * directory.\n *\n * @param rc - The resources to serialize and save.\n * @throws If serialization, writing, or updating the file permissions fails. A permission-update\n * failure occurs after the new contents have already been written.\n * @internal\n */\nexport async function saveRC(rc: IResources): Promise<void> {\n\tconst writeFile = util.promisify(fs.writeFile);\n\tconst chmod = util.promisify(fs.chmod);\n\tconst content = JSON.stringify(rc, undefined, 2);\n\tconst fileName = getRCFileName();\n\t// This per-user file holds ODSP access tokens and may also hold development secrets.\n\t// On POSIX filesystems, `mode` creates a new file as owner-readable/writable only (0600).\n\t// Because `mode` does not change an existing file, chmod also repairs caches that were\n\t// previously created with broader permissions. On Windows, these calls normally succeed,\n\t// but Node only uses the write bit: 0600 keeps the file writable without restricting who can\n\t// read it. Confidentiality therefore depends on ACLs inherited from the user's home directory.\n\t// If the filesystem rejects chmod, saveRC rejects after the file has already been written.\n\tawait writeFile(fileName, Buffer.from(content, \"utf8\"), { mode: 0o600 });\n\tawait chmod(fileName, 0o600);\n}\n\n/**\n * Acquires the inter-process lock for `.fluidtoolrc` in the current user's home directory.\n *\n * The lock may be acquired before the resource file exists. While another process holds the lock,\n * acquisition retries indefinitely. Locks whose modification time has not been updated for 60\n * seconds are considered stale.\n *\n * @returns An asynchronous callback that releases the lock. The caller must invoke it after\n * completing the protected operation, including when that operation fails.\n * @throws If a filesystem error prevents the lock from being acquired.\n * @internal\n */\nexport async function lockRC(): Promise<() => Promise<void>> {\n\treturn lock(getRCFileName(), {\n\t\tretries: {\n\t\t\tforever: true,\n\t\t},\n\t\tstale: 60000,\n\t\trealpath: false,\n\t});\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"odspTokenManager.d.ts","sourceRoot":"","sources":["../src/odspTokenManager.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EACX,mBAAmB,EACnB,WAAW,EACX,MAAM,4CAA4C,CAAC;AAIpD,OAAO,KAAK,EAAE,WAAW,EAAc,MAAM,kBAAkB,CAAC;AAMhE;;GAEG;AACH,eAAO,MAAM,yBAAyB,QAAO,mBAQ3C,CAAC;AAEH;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAChC,IAAI,EAAE,KAAK,CAAC;IACZ,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,aAAa,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;CAC/D;AAED;;GAEG;AACH,MAAM,WAAW,yBAAyB;IACzC,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACtB;AAsBD;;GAEG;AACH,qBAAa,gBAAgB;IAK3B,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAC;IAJ7B,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAkC;IAC/D,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAkC;IAC5D,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAe;gBAExB,UAAU,CAAC,iEAAqD;IAGrE,iBAAiB,CAC7B,GAAG,EAAE,yBAAyB,EAC9B,KAAK,EAAE,WAAW,GAChB,OAAO,CAAC,IAAI,CAAC;YAMF,4BAA4B;IAU7B,aAAa,CACzB,WAAW,EAAE,gBAAgB,EAC7B,YAAY,UAAQ,EACpB,WAAW,UAAQ,GACjB,OAAO,CAAC,WAAW,CAAC;IAKV,aAAa,CACzB,WAAW,EAAE,gBAAgB,EAC7B,YAAY,UAAQ,EACpB,WAAW,UAAQ,GACjB,OAAO,CAAC,WAAW,CAAC;YAKT,iBAAiB;IAiB/B,OAAO,CAAC,MAAM,CAAC,WAAW;YAUZ,SAAS;YAgCT,aAAa;IA4C3B,OAAO,CAAC,qBAAqB;IAiB7B,OAAO,CAAC,gBAAgB;CA4BxB;AAaD;;GAEG;AACH,eAAO,MAAM,eAAe,EAAE,WAAW,CAAC,yBAAyB,EAAE,WAAW,CA8B/E,CAAC"}
1
+ {"version":3,"file":"odspTokenManager.d.ts","sourceRoot":"","sources":["../src/odspTokenManager.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EACX,mBAAmB,EACnB,WAAW,EACX,MAAM,4CAA4C,CAAC;AAIpD,OAAO,KAAK,EAAE,WAAW,EAAc,MAAM,kBAAkB,CAAC;AAMhE;;GAEG;AACH,eAAO,MAAM,yBAAyB,QAAO,mBAQ3C,CAAC;AAEH;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAChC,IAAI,EAAE,KAAK,CAAC;IACZ,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,aAAa,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;CAC/D;AAED;;GAEG;AACH,MAAM,WAAW,yBAAyB;IACzC,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACtB;AAsBD;;GAEG;AACH,qBAAa,gBAAgB;IAK3B,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAC;IAJ7B,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAkC;IAC/D,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAkC;IAC5D,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAe;gBAExB,UAAU,CAAC,EAAE,WAAW,CAAC,yBAAyB,EAAE,WAAW,CAAC,YAAA;IAGrE,iBAAiB,CAC7B,GAAG,EAAE,yBAAyB,EAC9B,KAAK,EAAE,WAAW,GAChB,OAAO,CAAC,IAAI,CAAC;YAMF,4BAA4B;IAU7B,aAAa,CACzB,WAAW,EAAE,gBAAgB,EAC7B,YAAY,UAAQ,EACpB,WAAW,UAAQ,GACjB,OAAO,CAAC,WAAW,CAAC;IAKV,aAAa,CACzB,WAAW,EAAE,gBAAgB,EAC7B,YAAY,UAAQ,EACpB,WAAW,UAAQ,GACjB,OAAO,CAAC,WAAW,CAAC;YAKT,iBAAiB;IAiB/B,OAAO,CAAC,MAAM,CAAC,WAAW;YAUZ,SAAS;YAgCT,aAAa;IA4C3B,OAAO,CAAC,qBAAqB;IAiB7B,OAAO,CAAC,gBAAgB;CA4BxB;AAaD;;GAEG;AACH,eAAO,MAAM,eAAe,EAAE,WAAW,CAAC,yBAAyB,EAAE,WAAW,CA8B/E,CAAC"}
@@ -44,11 +44,12 @@ const cacheKeyToString = (key) => {
44
44
  * @internal
45
45
  */
46
46
  class OdspTokenManager {
47
+ tokenCache;
48
+ storageCache = new Map();
49
+ pushCache = new Map();
50
+ cacheMutex = new async_mutex_1.Mutex();
47
51
  constructor(tokenCache) {
48
52
  this.tokenCache = tokenCache;
49
- this.storageCache = new Map();
50
- this.pushCache = new Map();
51
- this.cacheMutex = new async_mutex_1.Mutex();
52
53
  }
53
54
  async updateTokensCache(key, value) {
54
55
  await this.cacheMutex.runExclusive(async () => {
@@ -1 +1 @@
1
- {"version":3,"file":"odspTokenManager.js","sourceRoot":"","sources":["../src/odspTokenManager.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport type {\n\tIPublicClientConfig,\n\tIOdspTokens,\n} from \"@fluidframework/odsp-doclib-utils/internal\";\nimport { Mutex } from \"async-mutex\";\n\nimport { debug } from \"./debug.js\";\nimport type { IAsyncCache, IResources } from \"./fluidToolRc.js\";\nimport { loadRC, lockRC, saveRC } from \"./fluidToolRc.js\";\nimport { redactTokens } from \"./redactTokens.js\";\n\n// TODO: Add documentation\n// eslint-disable-next-line jsdoc/require-description\n/**\n * @internal\n */\nexport const getMicrosoftConfiguration = (): IPublicClientConfig => ({\n\tget clientId(): string {\n\t\t// eslint-disable-next-line @typescript-eslint/strict-boolean-expressions\n\t\tif (!process.env.login__microsoft__clientId) {\n\t\t\tthrow new Error(\"Client ID environment variable not set: login__microsoft__clientId.\");\n\t\t}\n\t\treturn process.env.login__microsoft__clientId;\n\t},\n});\n\n/**\n * @internal\n */\nexport interface LoginCredentials {\n\ttype: \"fic\";\n\tusername: string;\n\tfetchToken(scopeEndpoint: \"push\" | \"storage\"): Promise<string>;\n}\n\n/**\n * @internal\n */\nexport interface IOdspTokenManagerCacheKey {\n\treadonly isPush: boolean;\n\treadonly user: string;\n}\n\nconst isValidAndNotExpiredToken = (tokens: IOdspTokens): boolean => {\n\t// Return false for undefined or empty tokens.\n\tif (!tokens.accessToken || tokens.accessToken.length === 0) {\n\t\treturn false;\n\t}\n\n\tif (tokens.receivedAt === undefined || tokens.expiresIn === undefined) {\n\t\t// If we don't have receivedAt or expiresIn, we treat the token as expired.\n\t\treturn false;\n\t}\n\n\tconst expiresAt = tokens.receivedAt + tokens.expiresIn;\n\t// Give it a 60s buffer\n\treturn expiresAt - 60 >= Date.now() / 1000;\n};\n\nconst cacheKeyToString = (key: IOdspTokenManagerCacheKey): string => {\n\treturn `${key.user}${key.isPush ? \"[Push]\" : \"\"}`;\n};\n\n/**\n * @internal\n */\nexport class OdspTokenManager {\n\tprivate readonly storageCache = new Map<string, IOdspTokens>();\n\tprivate readonly pushCache = new Map<string, IOdspTokens>();\n\tprivate readonly cacheMutex = new Mutex();\n\tpublic constructor(\n\t\tprivate readonly tokenCache?: IAsyncCache<IOdspTokenManagerCacheKey, IOdspTokens>,\n\t) {}\n\n\tpublic async updateTokensCache(\n\t\tkey: IOdspTokenManagerCacheKey,\n\t\tvalue: IOdspTokens,\n\t): Promise<void> {\n\t\tawait this.cacheMutex.runExclusive(async () => {\n\t\t\tawait this.updateTokensCacheWithoutLock(key, value);\n\t\t});\n\t}\n\n\tprivate async updateTokensCacheWithoutLock(\n\t\tkey: IOdspTokenManagerCacheKey,\n\t\tvalue: IOdspTokens,\n\t): Promise<void> {\n\t\tdebug(`${cacheKeyToString(key)}: Saving tokens`);\n\t\tconst memoryCache = key.isPush ? this.pushCache : this.storageCache;\n\t\tmemoryCache.set(key.user, value);\n\t\tawait this.tokenCache?.save(key, value);\n\t}\n\n\tpublic async getOdspTokens(\n\t\tcredentials: LoginCredentials,\n\t\tforceRefresh = false,\n\t\tforceReauth = false,\n\t): Promise<IOdspTokens> {\n\t\tdebug(\"Getting odsp tokens\");\n\t\treturn this.getTokens(false, credentials, forceRefresh, forceReauth);\n\t}\n\n\tpublic async getPushTokens(\n\t\tcredentials: LoginCredentials,\n\t\tforceRefresh = false,\n\t\tforceReauth = false,\n\t): Promise<IOdspTokens> {\n\t\tdebug(\"Getting push tokens\");\n\t\treturn this.getTokens(true, credentials, forceRefresh, forceReauth);\n\t}\n\n\tprivate async getTokenFromCache(\n\t\tcacheKey: IOdspTokenManagerCacheKey,\n\t): Promise<IOdspTokens | undefined> {\n\t\tconst memoryCache = cacheKey.isPush ? this.pushCache : this.storageCache;\n\t\tconst memoryToken = memoryCache.get(cacheKey.user);\n\t\tif (memoryToken) {\n\t\t\tdebug(`${cacheKeyToString(cacheKey)}: Token found in memory `);\n\t\t\treturn memoryToken;\n\t\t}\n\t\tconst fileToken = await this.tokenCache?.get(cacheKey);\n\t\tif (fileToken) {\n\t\t\tdebug(`${cacheKeyToString(cacheKey)}: Token found in file`);\n\t\t\tmemoryCache.set(cacheKey.user, fileToken);\n\t\t\treturn fileToken;\n\t\t}\n\t}\n\n\tprivate static getCacheKey(\n\t\tisPush: boolean,\n\t\tcredentials: LoginCredentials,\n\t): IOdspTokenManagerCacheKey {\n\t\treturn {\n\t\t\tisPush,\n\t\t\tuser: credentials.username,\n\t\t};\n\t}\n\n\tprivate async getTokens(\n\t\tisPush: boolean,\n\t\tcredentials: LoginCredentials,\n\t\tforceRefresh: boolean,\n\t\tforceReauth: boolean,\n\t): Promise<IOdspTokens> {\n\t\tconst invokeGetTokensCore = async (): Promise<IOdspTokens> => {\n\t\t\t// Don't solely rely on tokenCache lock, ensure serialized execution of\n\t\t\t// cache update to avoid multiple fetch.\n\t\t\treturn this.cacheMutex.runExclusive(async () => {\n\t\t\t\treturn this.getTokensCore(isPush, credentials, forceRefresh, forceReauth);\n\t\t\t});\n\t\t};\n\t\tif (!forceReauth && !forceRefresh) {\n\t\t\t// check and return if it exists without lock\n\t\t\tconst cacheKey = OdspTokenManager.getCacheKey(isPush, credentials);\n\t\t\tconst tokensFromCache = await this.getTokenFromCache(cacheKey);\n\t\t\tif (tokensFromCache) {\n\t\t\t\tif (isValidAndNotExpiredToken(tokensFromCache)) {\n\t\t\t\t\tdebug(`${cacheKeyToString(cacheKey)}: Token reused from cache `);\n\t\t\t\t\treturn tokensFromCache;\n\t\t\t\t}\n\t\t\t\tdebug(`${cacheKeyToString(cacheKey)}: Token expired from cache `);\n\t\t\t}\n\t\t}\n\t\tif (this.tokenCache) {\n\t\t\t// check with lock, used to prevent concurrent auth attempts\n\t\t\treturn this.tokenCache.lock(invokeGetTokensCore);\n\t\t}\n\t\treturn invokeGetTokensCore();\n\t}\n\n\tprivate async getTokensCore(\n\t\tisPush: boolean,\n\t\tcredentials: LoginCredentials,\n\t\tforceRefresh: boolean,\n\t\tforceReauth: boolean,\n\t): Promise<IOdspTokens> {\n\t\tconst cacheKey = OdspTokenManager.getCacheKey(isPush, credentials);\n\t\tlet tokens: IOdspTokens | undefined;\n\t\tif (!forceReauth) {\n\t\t\t// check the cache again under the lock (if it is there)\n\t\t\tconst tokensFromCache = await this.getTokenFromCache(cacheKey);\n\t\t\tif (tokensFromCache) {\n\t\t\t\tif (forceRefresh || !isValidAndNotExpiredToken(tokensFromCache)) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst scopeEndpoint = isPush ? \"push\" : \"storage\";\n\t\t\t\t\t\tconst newTokenData = await credentials.fetchToken(scopeEndpoint);\n\t\t\t\t\t\ttokens = this.ficTokenToIOdspTokens(newTokenData, isPush);\n\t\t\t\t\t\tawait this.updateTokensCacheWithoutLock(cacheKey, tokens);\n\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\tdebug(`${cacheKeyToString(cacheKey)}: Error in refreshing token. ${error}`);\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\ttokens = tokensFromCache;\n\t\t\t\t\tdebug(`${cacheKeyToString(cacheKey)}: Token reused from locked cache `);\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (tokens) {\n\t\t\t\treturn tokens;\n\t\t\t}\n\t\t}\n\n\t\tconst tokenData = await credentials.fetchToken(isPush ? \"push\" : \"storage\");\n\t\ttokens = this.ficTokenToIOdspTokens(tokenData, isPush);\n\n\t\tif (!isValidAndNotExpiredToken(tokens)) {\n\t\t\tthrow new Error(\n\t\t\t\t`Acquired invalid tokens for ${cacheKeyToString(cacheKey)}. ${redactTokens(tokens)}`,\n\t\t\t);\n\t\t}\n\n\t\tawait this.updateTokensCacheWithoutLock(cacheKey, tokens);\n\t\treturn tokens;\n\t}\n\n\tprivate ficTokenToIOdspTokens(token: string, isPush: boolean): IOdspTokens {\n\t\t// eslint-disable-next-line unicorn/prefer-ternary -- using if statement for clarity\n\t\tif (isPush) {\n\t\t\t// Push tokens are not standard JWTs. With direct token exchange, the second leg includes information about expiry.\n\t\t\t// This is not available in the FIC flow, but in direct token exchange we request tokens with 1 hour expiry so default to that.\n\t\t\t// At worst this should result in some higher latency when a token is returned from the cache when it should really be\n\t\t\t// refreshed immediately (as attempting to use such a token will trigger a token refresh flow indirectly).\n\t\t\treturn {\n\t\t\t\taccessToken: token,\n\t\t\t\treceivedAt: Math.floor(Date.now() / 1000),\n\t\t\t\texpiresIn: 3600,\n\t\t\t};\n\t\t} else {\n\t\t\treturn this.jwtToIOdspTokens(token);\n\t\t}\n\t}\n\n\tprivate jwtToIOdspTokens(token: string): IOdspTokens {\n\t\tlet receivedAt: number;\n\t\tlet expiresIn: number;\n\t\tconst payloadSegment = token.split(\".\")[1];\n\t\tif (payloadSegment === undefined) {\n\t\t\tthrow new Error(\"Invalid JWT format\");\n\t\t}\n\t\tconst payload = JSON.parse(Buffer.from(payloadSegment, \"base64url\").toString(\"utf8\")) as {\n\t\t\tiat?: number;\n\t\t\texp?: number;\n\t\t};\n\t\tif (typeof payload.iat === \"number\") {\n\t\t\treceivedAt = payload.iat;\n\t\t} else {\n\t\t\tthrow new TypeError(\"JWT payload lacks valid iat claim.\");\n\t\t}\n\t\tif (typeof payload.exp === \"number\" && typeof payload.iat === \"number\") {\n\t\t\texpiresIn = payload.exp - payload.iat;\n\t\t} else {\n\t\t\tthrow new TypeError(\"JWT payload lacks valid exp claim.\");\n\t\t}\n\n\t\treturn {\n\t\t\taccessToken: token,\n\t\t\treceivedAt,\n\t\t\texpiresIn,\n\t\t};\n\t}\n}\n\nasync function loadAndPatchRC(): Promise<IResources> {\n\tconst rc = await loadRC();\n\tif (rc.tokens && rc.tokens.version === undefined) {\n\t\t// Clean up older versions\n\t\tdelete rc.tokens;\n\t\t// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-explicit-any\n\t\tdelete (rc as any).pushTokens;\n\t}\n\treturn rc;\n}\n\n/**\n * @internal\n */\nexport const odspTokensCache: IAsyncCache<IOdspTokenManagerCacheKey, IOdspTokens> = {\n\tasync get(key: IOdspTokenManagerCacheKey): Promise<IOdspTokens | undefined> {\n\t\tconst rc = await loadAndPatchRC();\n\t\treturn rc.tokens?.data[key.user]?.[key.isPush ? \"push\" : \"storage\"];\n\t},\n\tasync save(key: IOdspTokenManagerCacheKey, tokens: IOdspTokens): Promise<void> {\n\t\tconst rc = await loadAndPatchRC();\n\t\t// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing -- using ??= could change behavior if value is falsy\n\t\tif (!rc.tokens) {\n\t\t\trc.tokens = {\n\t\t\t\tversion: 1,\n\t\t\t\tdata: {},\n\t\t\t};\n\t\t}\n\t\tlet prevTokens = rc.tokens.data[key.user];\n\t\tif (!prevTokens) {\n\t\t\tprevTokens = {};\n\t\t\trc.tokens.data[key.user] = prevTokens;\n\t\t}\n\t\tprevTokens[key.isPush ? \"push\" : \"storage\"] = tokens;\n\t\treturn saveRC(rc);\n\t},\n\tasync lock<T>(callback: () => Promise<T>): Promise<T> {\n\t\tconst release = await lockRC();\n\t\ttry {\n\t\t\treturn await callback();\n\t\t} finally {\n\t\t\tawait release();\n\t\t}\n\t},\n};\n"]}
1
+ {"version":3,"file":"odspTokenManager.js","sourceRoot":"","sources":["../src/odspTokenManager.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport type {\n\tIPublicClientConfig,\n\tIOdspTokens,\n} from \"@fluidframework/odsp-doclib-utils/internal\";\nimport { Mutex } from \"async-mutex\";\n\nimport { debug } from \"./debug.js\";\nimport type { IAsyncCache, IResources } from \"./fluidToolRc.js\";\nimport { loadRC, lockRC, saveRC } from \"./fluidToolRc.js\";\nimport { redactTokens } from \"./redactTokens.js\";\n\n// TODO: Add documentation\n// eslint-disable-next-line jsdoc/require-description\n/**\n * @internal\n */\nexport const getMicrosoftConfiguration = (): IPublicClientConfig => ({\n\tget clientId(): string {\n\t\t// eslint-disable-next-line @typescript-eslint/strict-boolean-expressions\n\t\tif (!process.env.login__microsoft__clientId) {\n\t\t\tthrow new Error(\"Client ID environment variable not set: login__microsoft__clientId.\");\n\t\t}\n\t\treturn process.env.login__microsoft__clientId;\n\t},\n});\n\n/**\n * @internal\n */\nexport interface LoginCredentials {\n\ttype: \"fic\";\n\tusername: string;\n\tfetchToken(scopeEndpoint: \"push\" | \"storage\"): Promise<string>;\n}\n\n/**\n * @internal\n */\nexport interface IOdspTokenManagerCacheKey {\n\treadonly isPush: boolean;\n\treadonly user: string;\n}\n\nconst isValidAndNotExpiredToken = (tokens: IOdspTokens): boolean => {\n\t// Return false for undefined or empty tokens.\n\tif (!tokens.accessToken || tokens.accessToken.length === 0) {\n\t\treturn false;\n\t}\n\n\tif (tokens.receivedAt === undefined || tokens.expiresIn === undefined) {\n\t\t// If we don't have receivedAt or expiresIn, we treat the token as expired.\n\t\treturn false;\n\t}\n\n\tconst expiresAt = tokens.receivedAt + tokens.expiresIn;\n\t// Give it a 60s buffer\n\treturn expiresAt - 60 >= Date.now() / 1000;\n};\n\nconst cacheKeyToString = (key: IOdspTokenManagerCacheKey): string => {\n\treturn `${key.user}${key.isPush ? \"[Push]\" : \"\"}`;\n};\n\n/**\n * @internal\n */\nexport class OdspTokenManager {\n\tprivate readonly storageCache = new Map<string, IOdspTokens>();\n\tprivate readonly pushCache = new Map<string, IOdspTokens>();\n\tprivate readonly cacheMutex = new Mutex();\n\tpublic constructor(\n\t\tprivate readonly tokenCache?: IAsyncCache<IOdspTokenManagerCacheKey, IOdspTokens>,\n\t) {}\n\n\tpublic async updateTokensCache(\n\t\tkey: IOdspTokenManagerCacheKey,\n\t\tvalue: IOdspTokens,\n\t): Promise<void> {\n\t\tawait this.cacheMutex.runExclusive(async () => {\n\t\t\tawait this.updateTokensCacheWithoutLock(key, value);\n\t\t});\n\t}\n\n\tprivate async updateTokensCacheWithoutLock(\n\t\tkey: IOdspTokenManagerCacheKey,\n\t\tvalue: IOdspTokens,\n\t): Promise<void> {\n\t\tdebug(`${cacheKeyToString(key)}: Saving tokens`);\n\t\tconst memoryCache = key.isPush ? this.pushCache : this.storageCache;\n\t\tmemoryCache.set(key.user, value);\n\t\tawait this.tokenCache?.save(key, value);\n\t}\n\n\tpublic async getOdspTokens(\n\t\tcredentials: LoginCredentials,\n\t\tforceRefresh = false,\n\t\tforceReauth = false,\n\t): Promise<IOdspTokens> {\n\t\tdebug(\"Getting odsp tokens\");\n\t\treturn this.getTokens(false, credentials, forceRefresh, forceReauth);\n\t}\n\n\tpublic async getPushTokens(\n\t\tcredentials: LoginCredentials,\n\t\tforceRefresh = false,\n\t\tforceReauth = false,\n\t): Promise<IOdspTokens> {\n\t\tdebug(\"Getting push tokens\");\n\t\treturn this.getTokens(true, credentials, forceRefresh, forceReauth);\n\t}\n\n\tprivate async getTokenFromCache(\n\t\tcacheKey: IOdspTokenManagerCacheKey,\n\t): Promise<IOdspTokens | undefined> {\n\t\tconst memoryCache = cacheKey.isPush ? this.pushCache : this.storageCache;\n\t\tconst memoryToken = memoryCache.get(cacheKey.user);\n\t\tif (memoryToken) {\n\t\t\tdebug(`${cacheKeyToString(cacheKey)}: Token found in memory `);\n\t\t\treturn memoryToken;\n\t\t}\n\t\tconst fileToken = await this.tokenCache?.get(cacheKey);\n\t\tif (fileToken) {\n\t\t\tdebug(`${cacheKeyToString(cacheKey)}: Token found in file`);\n\t\t\tmemoryCache.set(cacheKey.user, fileToken);\n\t\t\treturn fileToken;\n\t\t}\n\t}\n\n\tprivate static getCacheKey(\n\t\tisPush: boolean,\n\t\tcredentials: LoginCredentials,\n\t): IOdspTokenManagerCacheKey {\n\t\treturn {\n\t\t\tisPush,\n\t\t\tuser: credentials.username,\n\t\t};\n\t}\n\n\tprivate async getTokens(\n\t\tisPush: boolean,\n\t\tcredentials: LoginCredentials,\n\t\tforceRefresh: boolean,\n\t\tforceReauth: boolean,\n\t): Promise<IOdspTokens> {\n\t\tconst invokeGetTokensCore = async (): Promise<IOdspTokens> => {\n\t\t\t// Don't solely rely on tokenCache lock, ensure serialized execution of\n\t\t\t// cache update to avoid multiple fetch.\n\t\t\treturn this.cacheMutex.runExclusive(async () => {\n\t\t\t\treturn this.getTokensCore(isPush, credentials, forceRefresh, forceReauth);\n\t\t\t});\n\t\t};\n\t\tif (!forceReauth && !forceRefresh) {\n\t\t\t// check and return if it exists without lock\n\t\t\tconst cacheKey = OdspTokenManager.getCacheKey(isPush, credentials);\n\t\t\tconst tokensFromCache = await this.getTokenFromCache(cacheKey);\n\t\t\tif (tokensFromCache) {\n\t\t\t\tif (isValidAndNotExpiredToken(tokensFromCache)) {\n\t\t\t\t\tdebug(`${cacheKeyToString(cacheKey)}: Token reused from cache `);\n\t\t\t\t\treturn tokensFromCache;\n\t\t\t\t}\n\t\t\t\tdebug(`${cacheKeyToString(cacheKey)}: Token expired from cache `);\n\t\t\t}\n\t\t}\n\t\tif (this.tokenCache) {\n\t\t\t// check with lock, used to prevent concurrent auth attempts\n\t\t\treturn this.tokenCache.lock(invokeGetTokensCore);\n\t\t}\n\t\treturn invokeGetTokensCore();\n\t}\n\n\tprivate async getTokensCore(\n\t\tisPush: boolean,\n\t\tcredentials: LoginCredentials,\n\t\tforceRefresh: boolean,\n\t\tforceReauth: boolean,\n\t): Promise<IOdspTokens> {\n\t\tconst cacheKey = OdspTokenManager.getCacheKey(isPush, credentials);\n\t\tlet tokens: IOdspTokens | undefined;\n\t\tif (!forceReauth) {\n\t\t\t// check the cache again under the lock (if it is there)\n\t\t\tconst tokensFromCache = await this.getTokenFromCache(cacheKey);\n\t\t\tif (tokensFromCache) {\n\t\t\t\tif (forceRefresh || !isValidAndNotExpiredToken(tokensFromCache)) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst scopeEndpoint = isPush ? \"push\" : \"storage\";\n\t\t\t\t\t\tconst newTokenData = await credentials.fetchToken(scopeEndpoint);\n\t\t\t\t\t\ttokens = this.ficTokenToIOdspTokens(newTokenData, isPush);\n\t\t\t\t\t\tawait this.updateTokensCacheWithoutLock(cacheKey, tokens);\n\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\tdebug(`${cacheKeyToString(cacheKey)}: Error in refreshing token. ${error}`);\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\ttokens = tokensFromCache;\n\t\t\t\t\tdebug(`${cacheKeyToString(cacheKey)}: Token reused from locked cache `);\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (tokens) {\n\t\t\t\treturn tokens;\n\t\t\t}\n\t\t}\n\n\t\tconst tokenData = await credentials.fetchToken(isPush ? \"push\" : \"storage\");\n\t\ttokens = this.ficTokenToIOdspTokens(tokenData, isPush);\n\n\t\tif (!isValidAndNotExpiredToken(tokens)) {\n\t\t\tthrow new Error(\n\t\t\t\t`Acquired invalid tokens for ${cacheKeyToString(cacheKey)}. ${redactTokens(tokens)}`,\n\t\t\t);\n\t\t}\n\n\t\tawait this.updateTokensCacheWithoutLock(cacheKey, tokens);\n\t\treturn tokens;\n\t}\n\n\tprivate ficTokenToIOdspTokens(token: string, isPush: boolean): IOdspTokens {\n\t\t// eslint-disable-next-line unicorn/prefer-ternary -- using if statement for clarity\n\t\tif (isPush) {\n\t\t\t// Push tokens are not standard JWTs. With direct token exchange, the second leg includes information about expiry.\n\t\t\t// This is not available in the FIC flow, but in direct token exchange we request tokens with 1 hour expiry so default to that.\n\t\t\t// At worst this should result in some higher latency when a token is returned from the cache when it should really be\n\t\t\t// refreshed immediately (as attempting to use such a token will trigger a token refresh flow indirectly).\n\t\t\treturn {\n\t\t\t\taccessToken: token,\n\t\t\t\treceivedAt: Math.floor(Date.now() / 1000),\n\t\t\t\texpiresIn: 3600,\n\t\t\t};\n\t\t} else {\n\t\t\treturn this.jwtToIOdspTokens(token);\n\t\t}\n\t}\n\n\tprivate jwtToIOdspTokens(token: string): IOdspTokens {\n\t\tlet receivedAt: number;\n\t\tlet expiresIn: number;\n\t\tconst payloadSegment = token.split(\".\")[1];\n\t\tif (payloadSegment === undefined) {\n\t\t\tthrow new Error(\"Invalid JWT format\");\n\t\t}\n\t\tconst payload = JSON.parse(Buffer.from(payloadSegment, \"base64url\").toString(\"utf8\")) as {\n\t\t\tiat?: number;\n\t\t\texp?: number;\n\t\t};\n\t\tif (typeof payload.iat === \"number\") {\n\t\t\treceivedAt = payload.iat;\n\t\t} else {\n\t\t\tthrow new TypeError(\"JWT payload lacks valid iat claim.\");\n\t\t}\n\t\tif (typeof payload.exp === \"number\" && typeof payload.iat === \"number\") {\n\t\t\texpiresIn = payload.exp - payload.iat;\n\t\t} else {\n\t\t\tthrow new TypeError(\"JWT payload lacks valid exp claim.\");\n\t\t}\n\n\t\treturn {\n\t\t\taccessToken: token,\n\t\t\treceivedAt,\n\t\t\texpiresIn,\n\t\t};\n\t}\n}\n\nasync function loadAndPatchRC(): Promise<IResources> {\n\tconst rc = await loadRC();\n\tif (rc.tokens && rc.tokens.version === undefined) {\n\t\t// Clean up older versions\n\t\tdelete rc.tokens;\n\t\t// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-explicit-any\n\t\tdelete (rc as any).pushTokens;\n\t}\n\treturn rc;\n}\n\n/**\n * @internal\n */\nexport const odspTokensCache: IAsyncCache<IOdspTokenManagerCacheKey, IOdspTokens> = {\n\tasync get(key: IOdspTokenManagerCacheKey): Promise<IOdspTokens | undefined> {\n\t\tconst rc = await loadAndPatchRC();\n\t\treturn rc.tokens?.data[key.user]?.[key.isPush ? \"push\" : \"storage\"];\n\t},\n\tasync save(key: IOdspTokenManagerCacheKey, tokens: IOdspTokens): Promise<void> {\n\t\tconst rc = await loadAndPatchRC();\n\t\t// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing -- using ??= could change behavior if value is falsy\n\t\tif (!rc.tokens) {\n\t\t\trc.tokens = {\n\t\t\t\tversion: 1,\n\t\t\t\tdata: {},\n\t\t\t};\n\t\t}\n\t\tlet prevTokens = rc.tokens.data[key.user];\n\t\tif (!prevTokens) {\n\t\t\tprevTokens = {};\n\t\t\trc.tokens.data[key.user] = prevTokens;\n\t\t}\n\t\tprevTokens[key.isPush ? \"push\" : \"storage\"] = tokens;\n\t\treturn saveRC(rc);\n\t},\n\tasync lock<T>(callback: () => Promise<T>): Promise<T> {\n\t\tconst release = await lockRC();\n\t\ttry {\n\t\t\treturn await callback();\n\t\t} finally {\n\t\t\tawait release();\n\t\t}\n\t},\n};\n"]}
@@ -5,5 +5,5 @@
5
5
  * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY
6
6
  */
7
7
  export declare const pkgName = "@fluidframework/tool-utils";
8
- export declare const pkgVersion = "2.118.1";
8
+ export declare const pkgVersion = "3.0.1";
9
9
  //# sourceMappingURL=packageVersion.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"packageVersion.d.ts","sourceRoot":"","sources":["../src/packageVersion.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,eAAO,MAAM,OAAO,+BAA+B,CAAC;AACpD,eAAO,MAAM,UAAU,YAAY,CAAC"}
1
+ {"version":3,"file":"packageVersion.d.ts","sourceRoot":"","sources":["../src/packageVersion.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,eAAO,MAAM,OAAO,+BAA+B,CAAC;AACpD,eAAO,MAAM,UAAU,UAAU,CAAC"}
@@ -8,5 +8,5 @@
8
8
  Object.defineProperty(exports, "__esModule", { value: true });
9
9
  exports.pkgVersion = exports.pkgName = void 0;
10
10
  exports.pkgName = "@fluidframework/tool-utils";
11
- exports.pkgVersion = "2.118.1";
11
+ exports.pkgVersion = "3.0.1";
12
12
  //# sourceMappingURL=packageVersion.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"packageVersion.js","sourceRoot":"","sources":["../src/packageVersion.ts"],"names":[],"mappings":";AAAA;;;;;GAKG;;;AAEU,QAAA,OAAO,GAAG,4BAA4B,CAAC;AACvC,QAAA,UAAU,GAAG,SAAS,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n *\n * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY\n */\n\nexport const pkgName = \"@fluidframework/tool-utils\";\nexport const pkgVersion = \"2.118.1\";\n"]}
1
+ {"version":3,"file":"packageVersion.js","sourceRoot":"","sources":["../src/packageVersion.ts"],"names":[],"mappings":";AAAA;;;;;GAKG;;;AAEU,QAAA,OAAO,GAAG,4BAA4B,CAAC;AACvC,QAAA,UAAU,GAAG,OAAO,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n *\n * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY\n */\n\nexport const pkgName = \"@fluidframework/tool-utils\";\nexport const pkgVersion = \"3.0.1\";\n"]}
@@ -4,7 +4,7 @@
4
4
  * Licensed under the MIT License.
5
5
  */
6
6
  Object.defineProperty(exports, "__esModule", { value: true });
7
- exports.redactTokens = void 0;
7
+ exports.redactTokens = redactTokens;
8
8
  const describeSecret = (secret) => secret === undefined ? "absent" : `present(len=${secret.length})`;
9
9
  /**
10
10
  * Produce a log-safe, non-secret description of an {@link IOdspTokens} object.
@@ -21,5 +21,4 @@ function redactTokens(tokens) {
21
21
  `receivedAt:${tokens.receivedAt ?? "undefined"}, ` +
22
22
  `expiresIn:${tokens.expiresIn ?? "undefined"} }`);
23
23
  }
24
- exports.redactTokens = redactTokens;
25
24
  //# sourceMappingURL=redactTokens.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"redactTokens.js","sourceRoot":"","sources":["../src/redactTokens.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAIH,MAAM,cAAc,GAAG,CAAC,MAA0B,EAAU,EAAE,CAC7D,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,eAAe,MAAM,CAAC,MAAM,GAAG,CAAC;AAEnE;;;;;GAKG;AACH,SAAgB,YAAY,CAAC,MAAwC;IACpE,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;QAC1B,OAAO,kBAAkB,CAAC;IAC3B,CAAC;IACD,OAAO,CACN,wBAAwB,cAAc,CAAC,MAAM,CAAC,WAAW,CAAC,IAAI;QAC9D,gBAAgB,cAAc,CAAC,MAAM,CAAC,YAAY,CAAC,IAAI;QACvD,cAAc,MAAM,CAAC,UAAU,IAAI,WAAW,IAAI;QAClD,aAAa,MAAM,CAAC,SAAS,IAAI,WAAW,IAAI,CAChD,CAAC;AACH,CAAC;AAVD,oCAUC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport type { IOdspTokens } from \"@fluidframework/odsp-doclib-utils/internal\";\n\nconst describeSecret = (secret: string | undefined): string =>\n\tsecret === undefined ? \"absent\" : `present(len=${secret.length})`;\n\n/**\n * Produce a log-safe, non-secret description of an {@link IOdspTokens} object.\n *\n * Emits only the presence, length, and timing of the token fields — never the token values\n * themselves — so it is safe to embed in error messages and logs (which flow verbatim to telemetry).\n */\nexport function redactTokens(tokens: Partial<IOdspTokens> | undefined): string {\n\tif (tokens === undefined) {\n\t\treturn \"tokens=undefined\";\n\t}\n\treturn (\n\t\t`tokens={ accessToken:${describeSecret(tokens.accessToken)}, ` +\n\t\t`refreshToken:${describeSecret(tokens.refreshToken)}, ` +\n\t\t`receivedAt:${tokens.receivedAt ?? \"undefined\"}, ` +\n\t\t`expiresIn:${tokens.expiresIn ?? \"undefined\"} }`\n\t);\n}\n"]}
1
+ {"version":3,"file":"redactTokens.js","sourceRoot":"","sources":["../src/redactTokens.ts"],"names":[],"mappings":";AAAA;;;GAGG;;AAaH,oCAUC;AAnBD,MAAM,cAAc,GAAG,CAAC,MAA0B,EAAU,EAAE,CAC7D,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAC,eAAe,MAAM,CAAC,MAAM,GAAG,CAAC;AAEnE;;;;;GAKG;AACH,SAAgB,YAAY,CAAC,MAAwC;IACpE,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;QAC1B,OAAO,kBAAkB,CAAC;IAC3B,CAAC;IACD,OAAO,CACN,wBAAwB,cAAc,CAAC,MAAM,CAAC,WAAW,CAAC,IAAI;QAC9D,gBAAgB,cAAc,CAAC,MAAM,CAAC,YAAY,CAAC,IAAI;QACvD,cAAc,MAAM,CAAC,UAAU,IAAI,WAAW,IAAI;QAClD,aAAa,MAAM,CAAC,SAAS,IAAI,WAAW,IAAI,CAChD,CAAC;AACH,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport type { IOdspTokens } from \"@fluidframework/odsp-doclib-utils/internal\";\n\nconst describeSecret = (secret: string | undefined): string =>\n\tsecret === undefined ? \"absent\" : `present(len=${secret.length})`;\n\n/**\n * Produce a log-safe, non-secret description of an {@link IOdspTokens} object.\n *\n * Emits only the presence, length, and timing of the token fields — never the token values\n * themselves — so it is safe to embed in error messages and logs (which flow verbatim to telemetry).\n */\nexport function redactTokens(tokens: Partial<IOdspTokens> | undefined): string {\n\tif (tokens === undefined) {\n\t\treturn \"tokens=undefined\";\n\t}\n\treturn (\n\t\t`tokens={ accessToken:${describeSecret(tokens.accessToken)}, ` +\n\t\t`refreshToken:${describeSecret(tokens.refreshToken)}, ` +\n\t\t`receivedAt:${tokens.receivedAt ?? \"undefined\"}, ` +\n\t\t`expiresIn:${tokens.expiresIn ?? \"undefined\"} }`\n\t);\n}\n"]}
@@ -4,7 +4,8 @@
4
4
  * Licensed under the MIT License.
5
5
  */
6
6
  Object.defineProperty(exports, "__esModule", { value: true });
7
- exports.getNormalizedSnapshot = exports.legacyCatchUpBlobName = exports.gcBlobPrefix = void 0;
7
+ exports.legacyCatchUpBlobName = exports.gcBlobPrefix = void 0;
8
+ exports.getNormalizedSnapshot = getNormalizedSnapshot;
8
9
  const internal_1 = require("@fluidframework/driver-definitions/internal");
9
10
  const internal_2 = require("@fluidframework/driver-utils/internal");
10
11
  /**
@@ -180,7 +181,6 @@ function getNormalizedSnapshot(snapshot, config) {
180
181
  id: snapshot.id,
181
182
  };
182
183
  }
183
- exports.getNormalizedSnapshot = getNormalizedSnapshot;
184
184
  function normalizeMatrix(value) {
185
185
  const rows = value.entries.find((e) => e.path === "rows");
186
186
  if (!rows || !("entries" in rows.value)) {
@@ -1 +1 @@
1
- {"version":3,"file":"snapshotNormalizer.js","sourceRoot":"","sources":["../src/snapshotNormalizer.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport type {\n\tISequencedDocumentMessage,\n\tITree,\n\tITreeEntry,\n} from \"@fluidframework/driver-definitions/internal\";\nimport { TreeEntry } from \"@fluidframework/driver-definitions/internal\";\nimport {\n\tAttachmentTreeEntry,\n\tBlobTreeEntry,\n\tTreeTreeEntry,\n} from \"@fluidframework/driver-utils/internal\";\n\n/**\n * The name of the metadata blob added to the root of the container runtime.\n */\nconst metadataBlobName = \".metadata\";\n\n/**\n * The prefix that all GC blob names start with.\n *\n * @internal\n */\nexport const gcBlobPrefix = \"__gc\";\n\n/**\n * The name of the legacy catch-up ops blob in Merge Tree.\n * @internal\n */\nexport const legacyCatchUpBlobName = \"catchupOps\";\n\n/**\n * @internal\n */\nexport interface ISnapshotNormalizerConfig {\n\t// The paths of blobs whose contents should be normalized.\n\tblobsToNormalize?: string[];\n\t/**\n\t * channel types who's content (non-attribute) blobs will be excluded.\n\t * this is used to exclude the content of channels who's content cannot be compared\n\t * as the content is non-deterministic between snapshot at the same sequence number.\n\t */\n\texcludedChannelContentTypes?: string[];\n}\n\nconst sortStringified = (elem1: unknown, elem2: unknown): number => {\n\tconst serializedElem1 = JSON.stringify(elem1);\n\tconst serializedElem2 = JSON.stringify(elem2);\n\treturn serializedElem1.localeCompare(serializedElem2);\n};\n\n/**\n * Function that deep sorts an array. It handles cases where array elements are objects or arrays.\n * @returns the sorted array.\n */\nfunction getDeepSortedArray(array: unknown[]): unknown[] {\n\tconst sortedArray: unknown[] = [];\n\t// Sort arrays and objects, if any, in the array.\n\tfor (const element of array) {\n\t\tif (Array.isArray(element)) {\n\t\t\tsortedArray.push(getDeepSortedArray(element));\n\t\t} else if (element instanceof Object) {\n\t\t\tsortedArray.push(getDeepSortedObject(element));\n\t\t} else {\n\t\t\tsortedArray.push(element);\n\t\t}\n\t}\n\n\t// Now that all the arrays and objects in this array's elements have been sorted, sort it by comparing each\n\t// element's stringified version.\n\treturn sortedArray.sort(sortStringified);\n}\n\n/**\n * Function that deep sorts an object. It handles cases where object properties are arrays or objects.\n * @returns the sorted object.\n */\nfunction getDeepSortedObject<T extends object>(obj: T): T {\n\t// eslint-disable-next-line @typescript-eslint/consistent-type-assertions\n\tconst sortedObj: T = {} as T;\n\t// Sort the object keys first. Then sort arrays and objects, if any, in the object.\n\tconst keys = Object.keys(obj).sort();\n\tfor (const key of keys) {\n\t\tconst value: unknown = obj[key];\n\t\tif (Array.isArray(value)) {\n\t\t\tsortedObj[key] = getDeepSortedArray(value);\n\t\t} else if (value instanceof Object) {\n\t\t\tsortedObj[key] = getDeepSortedObject(value);\n\t\t} else {\n\t\t\tsortedObj[key] = value;\n\t\t}\n\t}\n\n\treturn sortedObj;\n}\n\n/**\n * Function that normalizes a blob's content. If the content is an object or an array, deep sorts them.\n * Special handling for certain runtime blobs, such as the \"gc\" blob.\n * @returns the normalized blob content.\n */\nfunction getNormalizedBlobContent(blobContent: string, blobName: string): string {\n\tlet content = blobContent;\n\tif (blobName.startsWith(gcBlobPrefix)) {\n\t\t// The following code parses JSON and makes some assumptions about the type of data within. There does not appear to\n\t\t// be a better type than `any` to use here, so the lint rules are disabled.\n\n\t\t/* eslint-disable @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access */\n\n\t\t// GC blobs may contain `unreferencedTimestampMs` for node that became unreferenced. This is the timestamp\n\t\t// of the last op processed or current timestamp and can differ between clients depending on when GC was run.\n\t\t// So, remove it for the purposes of comparing snapshots.\n\t\tconst gcState: any = JSON.parse(content);\n\t\t// eslint-disable-next-line @typescript-eslint/no-unsafe-argument\n\t\tfor (const [, data] of Object.entries(gcState.gcNodes)) {\n\t\t\tdelete (data as any).unreferencedTimestampMs;\n\t\t}\n\t\tcontent = JSON.stringify(gcState);\n\t}\n\n\t/**\n\t * The legacy catch-up ops blob in merge tree DDS contains sequenced messages. These ops used to have metadata property.\n\t * However, we stopped sending the metadata property to DDS because it was a Runtime layer concept. Remove the metadata\n\t * property from the ops because latest snapshots won't have the metadata property.\n\t */\n\tif (blobName === legacyCatchUpBlobName) {\n\t\ttry {\n\t\t\tconst catchupOps = JSON.parse(content) as ISequencedDocumentMessage[];\n\t\t\tif (catchupOps !== undefined && catchupOps.length > 0) {\n\t\t\t\tfor (const [index, op] of catchupOps.entries()) {\n\t\t\t\t\top.metadata = undefined;\n\t\t\t\t\tcatchupOps[index] = op;\n\t\t\t\t}\n\t\t\t}\n\t\t\tcontent = JSON.stringify(catchupOps);\n\t\t} catch {\n\t\t\t// Do nothing\n\t\t}\n\t}\n\n\t/**\n\t * The metadata blob has \"summaryNumber\" or \"summaryCount\" that tells which summary this is for a container. It can\n\t * be different in summaries of two clients even if they are generated at the same sequence#. For instance, at seq#\n\t * 1000, if one client has summarized 10 times and other has summarizer 15 times, summaryNumber will be different\n\t * for them. So, update \"summaryNumber\" to 0 for purposes of comparing snapshots.\n\t */\n\tif (blobName === metadataBlobName) {\n\t\tconst metadata = JSON.parse(content);\n\t\tif (metadata.summaryNumber !== undefined) {\n\t\t\tmetadata.summaryNumber = 0;\n\t\t}\n\t\tif (metadata.summaryCount !== undefined) {\n\t\t\tmetadata.summaryCount = 0;\n\t\t}\n\t\t// \"telemetryDocumentId\" is not a deterministic property (random guid), so we need to set it to something consistent\n\t\tif (metadata.telemetryDocumentId !== undefined) {\n\t\t\tmetadata.telemetryDocumentId = \"x\";\n\t\t}\n\t\t// default was not written before, now it's written in.\n\t\tif (metadata.documentSchema !== undefined) {\n\t\t\tmetadata.documentSchema = undefined;\n\t\t}\n\t\tcontent = JSON.stringify(metadata);\n\t}\n\n\t// Deep sort the content if it's parseable.\n\ttry {\n\t\tlet contentObj = JSON.parse(content);\n\t\tif (Array.isArray(contentObj)) {\n\t\t\tcontentObj = getDeepSortedArray(contentObj);\n\t\t} else if (contentObj instanceof Object) {\n\t\t\tcontentObj = getDeepSortedObject(contentObj);\n\t\t}\n\t\tcontent = JSON.stringify(contentObj);\n\t} catch {\n\t\t// Do nothing\n\t}\n\n\t/* eslint-enable @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access */\n\n\treturn content;\n}\n\n/**\n * Helper function that normalizes the given snapshot tree. It sorts objects and arrays in the snapshot. It also\n * normalizes certain blob contents for which the order of content does not matter. For example, garbage collection\n * blobs contains objects / arrays whose element order do not matter.\n * @param snapshot - The snapshot tree to normalize.\n * @param config - Configs to use when normalizing snapshot. For example, it can contain paths of blobs whose contents\n * should be normalized as well.\n * @returns a copy of the normalized snapshot tree.\n * @internal\n */\nexport function getNormalizedSnapshot(\n\tsnapshot: ITree,\n\tconfig?: ISnapshotNormalizerConfig,\n): ITree {\n\t// Merge blobs to normalize in the config with runtime blobs to normalize. The contents of these blobs will be\n\t// parsed and deep sorted.\n\tconst normalizedEntries: ITreeEntry[] = [];\n\n\t// The metadata blob in the root of the summary tree needs to be normalized.\n\tconst blobsToNormalize = [metadataBlobName, ...(config?.blobsToNormalize ?? [])];\n\tfor (const entry of snapshot.entries) {\n\t\tnormalizedEntries.push(normalizeEntry(entry, { ...config, blobsToNormalize }));\n\t}\n\n\t// Sort the tree entries based on their path.\n\tnormalizedEntries.sort((a, b) => a.path.localeCompare(b.path));\n\n\treturn {\n\t\tentries: normalizedEntries,\n\t\tid: snapshot.id,\n\t};\n}\n\nfunction normalizeMatrix(value: ITree): ITree {\n\tconst rows = value.entries.find((e) => e.path === \"rows\");\n\n\tif (!rows || !(\"entries\" in rows.value)) {\n\t\treturn value;\n\t}\n\n\tconst segments = rows.value.entries.find((e) => e.path === \"segments\");\n\n\tif (!segments || !(\"entries\" in segments.value)) {\n\t\treturn value;\n\t}\n\n\tconst header = segments.value.entries.find((e) => e.path === \"header\");\n\n\tif (!header || !(\"contents\" in header.value)) {\n\t\treturn value;\n\t}\n\n\tif (!header?.value.contents.includes(\"removedClientId\")) {\n\t\treturn value;\n\t}\n\n\t/* eslint-disable @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access */\n\n\tconst contents = JSON.parse(header?.value.contents);\n\n\tfor (const segment of contents.segments) {\n\t\tif (\"removedClientId\" in segment) {\n\t\t\tsegment.removedClientId = undefined;\n\t\t}\n\n\t\tif (\"removedClientIds\" in segment) {\n\t\t\tsegment.removedClientIds = undefined;\n\t\t}\n\t}\n\n\theader.value.contents = JSON.stringify(contents);\n\n\t/* eslint-enable @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access */\n\n\treturn value;\n}\n\nfunction normalizeEntry(\n\tentry: ITreeEntry,\n\tconfig: ISnapshotNormalizerConfig | undefined,\n): ITreeEntry {\n\tswitch (entry.type) {\n\t\tcase TreeEntry.Blob: {\n\t\t\tlet contents = entry.value.contents;\n\t\t\t// If this blob has to be normalized, it's a GC or legacy catchup blob, parse and sort the blob contents first.\n\t\t\tif (\n\t\t\t\t(config?.blobsToNormalize?.includes(entry.path) ?? false) ||\n\t\t\t\tentry.path.startsWith(gcBlobPrefix) ||\n\t\t\t\tentry.path === legacyCatchUpBlobName\n\t\t\t) {\n\t\t\t\tcontents = getNormalizedBlobContent(contents, entry.path);\n\t\t\t}\n\t\t\treturn new BlobTreeEntry(entry.path, contents);\n\t\t}\n\t\tcase TreeEntry.Tree: {\n\t\t\tif (config?.excludedChannelContentTypes !== undefined) {\n\t\t\t\tfor (const maybeAttributes of entry.value.entries) {\n\t\t\t\t\tif (\n\t\t\t\t\t\tmaybeAttributes.type === TreeEntry.Blob &&\n\t\t\t\t\t\tmaybeAttributes.path === \".attributes\"\n\t\t\t\t\t) {\n\t\t\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n\t\t\t\t\t\tconst parsed: { type?: string } = JSON.parse(maybeAttributes.value.contents);\n\t\t\t\t\t\tif (parsed.type === \"https://graph.microsoft.com/types/sharedmatrix\") {\n\t\t\t\t\t\t\treturn new TreeTreeEntry(\n\t\t\t\t\t\t\t\tentry.path,\n\t\t\t\t\t\t\t\tnormalizeMatrix(getNormalizedSnapshot(entry.value, config)),\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (\n\t\t\t\t\t\t\tparsed.type !== undefined &&\n\t\t\t\t\t\t\tconfig.excludedChannelContentTypes.includes(parsed.type)\n\t\t\t\t\t\t) {\n\t\t\t\t\t\t\t// remove everything to match the unknown channel\n\t\t\t\t\t\t\treturn new TreeTreeEntry(entry.path, { entries: [maybeAttributes] });\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn new TreeTreeEntry(entry.path, getNormalizedSnapshot(entry.value, config));\n\t\t}\n\t\tcase TreeEntry.Attachment: {\n\t\t\treturn new AttachmentTreeEntry(entry.path, entry.value.id);\n\t\t}\n\n\t\tdefault: {\n\t\t\tthrow new Error(\"Unknown entry type\");\n\t\t}\n\t}\n}\n"]}
1
+ {"version":3,"file":"snapshotNormalizer.js","sourceRoot":"","sources":["../src/snapshotNormalizer.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport type {\n\tISequencedDocumentMessage,\n\tITree,\n\tITreeEntry,\n} from \"@fluidframework/driver-definitions/internal\";\nimport { TreeEntry } from \"@fluidframework/driver-definitions/internal\";\nimport {\n\tAttachmentTreeEntry,\n\tBlobTreeEntry,\n\tTreeTreeEntry,\n} from \"@fluidframework/driver-utils/internal\";\n\n/**\n * The name of the metadata blob added to the root of the container runtime.\n */\nconst metadataBlobName = \".metadata\";\n\n/**\n * The prefix that all GC blob names start with.\n *\n * @internal\n */\nexport const gcBlobPrefix = \"__gc\";\n\n/**\n * The name of the legacy catch-up ops blob in Merge Tree.\n * @internal\n */\nexport const legacyCatchUpBlobName = \"catchupOps\";\n\n/**\n * @internal\n */\nexport interface ISnapshotNormalizerConfig {\n\t// The paths of blobs whose contents should be normalized.\n\tblobsToNormalize?: string[];\n\t/**\n\t * channel types who's content (non-attribute) blobs will be excluded.\n\t * this is used to exclude the content of channels who's content cannot be compared\n\t * as the content is non-deterministic between snapshot at the same sequence number.\n\t */\n\texcludedChannelContentTypes?: string[];\n}\n\nconst sortStringified = (elem1: unknown, elem2: unknown): number => {\n\tconst serializedElem1 = JSON.stringify(elem1);\n\tconst serializedElem2 = JSON.stringify(elem2);\n\treturn serializedElem1.localeCompare(serializedElem2);\n};\n\n/**\n * Function that deep sorts an array. It handles cases where array elements are objects or arrays.\n * @returns the sorted array.\n */\nfunction getDeepSortedArray(array: unknown[]): unknown[] {\n\tconst sortedArray: unknown[] = [];\n\t// Sort arrays and objects, if any, in the array.\n\tfor (const element of array) {\n\t\tif (Array.isArray(element)) {\n\t\t\tsortedArray.push(getDeepSortedArray(element));\n\t\t} else if (element instanceof Object) {\n\t\t\tsortedArray.push(getDeepSortedObject(element));\n\t\t} else {\n\t\t\tsortedArray.push(element);\n\t\t}\n\t}\n\n\t// Now that all the arrays and objects in this array's elements have been sorted, sort it by comparing each\n\t// element's stringified version.\n\treturn sortedArray.sort(sortStringified);\n}\n\n/**\n * Function that deep sorts an object. It handles cases where object properties are arrays or objects.\n * @returns the sorted object.\n */\nfunction getDeepSortedObject<T extends object>(obj: T): T {\n\t// eslint-disable-next-line @typescript-eslint/consistent-type-assertions\n\tconst sortedObj: T = {} as T;\n\t// Sort the object keys first. Then sort arrays and objects, if any, in the object.\n\tconst keys = Object.keys(obj).sort();\n\tfor (const key of keys) {\n\t\tconst value: unknown = obj[key];\n\t\tif (Array.isArray(value)) {\n\t\t\tsortedObj[key] = getDeepSortedArray(value);\n\t\t} else if (value instanceof Object) {\n\t\t\tsortedObj[key] = getDeepSortedObject(value);\n\t\t} else {\n\t\t\tsortedObj[key] = value;\n\t\t}\n\t}\n\n\treturn sortedObj;\n}\n\n/**\n * Function that normalizes a blob's content. If the content is an object or an array, deep sorts them.\n * Special handling for certain runtime blobs, such as the \"gc\" blob.\n * @returns the normalized blob content.\n */\nfunction getNormalizedBlobContent(blobContent: string, blobName: string): string {\n\tlet content = blobContent;\n\tif (blobName.startsWith(gcBlobPrefix)) {\n\t\t// The following code parses JSON and makes some assumptions about the type of data within. There does not appear to\n\t\t// be a better type than `any` to use here, so the lint rules are disabled.\n\n\t\t/* eslint-disable @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access */\n\n\t\t// GC blobs may contain `unreferencedTimestampMs` for node that became unreferenced. This is the timestamp\n\t\t// of the last op processed or current timestamp and can differ between clients depending on when GC was run.\n\t\t// So, remove it for the purposes of comparing snapshots.\n\t\tconst gcState: any = JSON.parse(content);\n\t\t// eslint-disable-next-line @typescript-eslint/no-unsafe-argument\n\t\tfor (const [, data] of Object.entries(gcState.gcNodes)) {\n\t\t\tdelete (data as any).unreferencedTimestampMs;\n\t\t}\n\t\tcontent = JSON.stringify(gcState);\n\t}\n\n\t/**\n\t * The legacy catch-up ops blob in merge tree DDS contains sequenced messages. These ops used to have metadata property.\n\t * However, we stopped sending the metadata property to DDS because it was a Runtime layer concept. Remove the metadata\n\t * property from the ops because latest snapshots won't have the metadata property.\n\t */\n\tif (blobName === legacyCatchUpBlobName) {\n\t\ttry {\n\t\t\tconst catchupOps = JSON.parse(content) as ISequencedDocumentMessage[];\n\t\t\tif (catchupOps !== undefined && catchupOps.length > 0) {\n\t\t\t\tfor (const [index, op] of catchupOps.entries()) {\n\t\t\t\t\top.metadata = undefined;\n\t\t\t\t\tcatchupOps[index] = op;\n\t\t\t\t}\n\t\t\t}\n\t\t\tcontent = JSON.stringify(catchupOps);\n\t\t} catch {\n\t\t\t// Do nothing\n\t\t}\n\t}\n\n\t/**\n\t * The metadata blob has \"summaryNumber\" or \"summaryCount\" that tells which summary this is for a container. It can\n\t * be different in summaries of two clients even if they are generated at the same sequence#. For instance, at seq#\n\t * 1000, if one client has summarized 10 times and other has summarizer 15 times, summaryNumber will be different\n\t * for them. So, update \"summaryNumber\" to 0 for purposes of comparing snapshots.\n\t */\n\tif (blobName === metadataBlobName) {\n\t\tconst metadata = JSON.parse(content);\n\t\tif (metadata.summaryNumber !== undefined) {\n\t\t\tmetadata.summaryNumber = 0;\n\t\t}\n\t\tif (metadata.summaryCount !== undefined) {\n\t\t\tmetadata.summaryCount = 0;\n\t\t}\n\t\t// \"telemetryDocumentId\" is not a deterministic property (random guid), so we need to set it to something consistent\n\t\tif (metadata.telemetryDocumentId !== undefined) {\n\t\t\tmetadata.telemetryDocumentId = \"x\";\n\t\t}\n\t\t// default was not written before, now it's written in.\n\t\tif (metadata.documentSchema !== undefined) {\n\t\t\tmetadata.documentSchema = undefined;\n\t\t}\n\t\tcontent = JSON.stringify(metadata);\n\t}\n\n\t// Deep sort the content if it's parseable.\n\ttry {\n\t\tlet contentObj = JSON.parse(content);\n\t\tif (Array.isArray(contentObj)) {\n\t\t\tcontentObj = getDeepSortedArray(contentObj);\n\t\t} else if (contentObj instanceof Object) {\n\t\t\tcontentObj = getDeepSortedObject(contentObj);\n\t\t}\n\t\tcontent = JSON.stringify(contentObj);\n\t} catch {\n\t\t// Do nothing\n\t}\n\n\t/* eslint-enable @typescript-eslint/no-explicit-any, @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access */\n\n\treturn content;\n}\n\n/**\n * Helper function that normalizes the given snapshot tree. It sorts objects and arrays in the snapshot. It also\n * normalizes certain blob contents for which the order of content does not matter. For example, garbage collection\n * blobs contains objects / arrays whose element order do not matter.\n * @param snapshot - The snapshot tree to normalize.\n * @param config - Configs to use when normalizing snapshot. For example, it can contain paths of blobs whose contents\n * should be normalized as well.\n * @returns a copy of the normalized snapshot tree.\n * @internal\n */\nexport function getNormalizedSnapshot(\n\tsnapshot: ITree,\n\tconfig?: ISnapshotNormalizerConfig,\n): ITree {\n\t// Merge blobs to normalize in the config with runtime blobs to normalize. The contents of these blobs will be\n\t// parsed and deep sorted.\n\tconst normalizedEntries: ITreeEntry[] = [];\n\n\t// The metadata blob in the root of the summary tree needs to be normalized.\n\tconst blobsToNormalize = [metadataBlobName, ...(config?.blobsToNormalize ?? [])];\n\tfor (const entry of snapshot.entries) {\n\t\tnormalizedEntries.push(normalizeEntry(entry, { ...config, blobsToNormalize }));\n\t}\n\n\t// Sort the tree entries based on their path.\n\tnormalizedEntries.sort((a, b) => a.path.localeCompare(b.path));\n\n\treturn {\n\t\tentries: normalizedEntries,\n\t\tid: snapshot.id,\n\t};\n}\n\nfunction normalizeMatrix(value: ITree): ITree {\n\tconst rows = value.entries.find((e) => e.path === \"rows\");\n\n\tif (!rows || !(\"entries\" in rows.value)) {\n\t\treturn value;\n\t}\n\n\tconst segments = rows.value.entries.find((e) => e.path === \"segments\");\n\n\tif (!segments || !(\"entries\" in segments.value)) {\n\t\treturn value;\n\t}\n\n\tconst header = segments.value.entries.find((e) => e.path === \"header\");\n\n\tif (!header || !(\"contents\" in header.value)) {\n\t\treturn value;\n\t}\n\n\tif (!header?.value.contents.includes(\"removedClientId\")) {\n\t\treturn value;\n\t}\n\n\t/* eslint-disable @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access */\n\n\tconst contents = JSON.parse(header?.value.contents);\n\n\tfor (const segment of contents.segments) {\n\t\tif (\"removedClientId\" in segment) {\n\t\t\tsegment.removedClientId = undefined;\n\t\t}\n\n\t\tif (\"removedClientIds\" in segment) {\n\t\t\tsegment.removedClientIds = undefined;\n\t\t}\n\t}\n\n\theader.value.contents = JSON.stringify(contents);\n\n\t/* eslint-enable @typescript-eslint/no-unsafe-assignment, @typescript-eslint/no-unsafe-member-access */\n\n\treturn value;\n}\n\nfunction normalizeEntry(\n\tentry: ITreeEntry,\n\tconfig: ISnapshotNormalizerConfig | undefined,\n): ITreeEntry {\n\tswitch (entry.type) {\n\t\tcase TreeEntry.Blob: {\n\t\t\tlet contents = entry.value.contents;\n\t\t\t// If this blob has to be normalized, it's a GC or legacy catchup blob, parse and sort the blob contents first.\n\t\t\tif (\n\t\t\t\t(config?.blobsToNormalize?.includes(entry.path) ?? false) ||\n\t\t\t\tentry.path.startsWith(gcBlobPrefix) ||\n\t\t\t\tentry.path === legacyCatchUpBlobName\n\t\t\t) {\n\t\t\t\tcontents = getNormalizedBlobContent(contents, entry.path);\n\t\t\t}\n\t\t\treturn new BlobTreeEntry(entry.path, contents);\n\t\t}\n\t\tcase TreeEntry.Tree: {\n\t\t\tif (config?.excludedChannelContentTypes !== undefined) {\n\t\t\t\tfor (const maybeAttributes of entry.value.entries) {\n\t\t\t\t\tif (\n\t\t\t\t\t\tmaybeAttributes.type === TreeEntry.Blob &&\n\t\t\t\t\t\tmaybeAttributes.path === \".attributes\"\n\t\t\t\t\t) {\n\t\t\t\t\t\t// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment\n\t\t\t\t\t\tconst parsed: { type?: string } = JSON.parse(maybeAttributes.value.contents);\n\t\t\t\t\t\tif (parsed.type === \"https://graph.microsoft.com/types/sharedmatrix\") {\n\t\t\t\t\t\t\treturn new TreeTreeEntry(\n\t\t\t\t\t\t\t\tentry.path,\n\t\t\t\t\t\t\t\tnormalizeMatrix(getNormalizedSnapshot(entry.value, config)),\n\t\t\t\t\t\t\t);\n\t\t\t\t\t\t}\n\t\t\t\t\t\tif (\n\t\t\t\t\t\t\tparsed.type !== undefined &&\n\t\t\t\t\t\t\tconfig.excludedChannelContentTypes.includes(parsed.type)\n\t\t\t\t\t\t) {\n\t\t\t\t\t\t\t// remove everything to match the unknown channel\n\t\t\t\t\t\t\treturn new TreeTreeEntry(entry.path, { entries: [maybeAttributes] });\n\t\t\t\t\t\t}\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn new TreeTreeEntry(entry.path, getNormalizedSnapshot(entry.value, config));\n\t\t}\n\t\tcase TreeEntry.Attachment: {\n\t\t\treturn new AttachmentTreeEntry(entry.path, entry.value.id);\n\t\t}\n\n\t\tdefault: {\n\t\t\tthrow new Error(\"Unknown entry type\");\n\t\t}\n\t}\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"odspTokenManager.d.ts","sourceRoot":"","sources":["../src/odspTokenManager.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EACX,mBAAmB,EACnB,WAAW,EACX,MAAM,4CAA4C,CAAC;AAIpD,OAAO,KAAK,EAAE,WAAW,EAAc,MAAM,kBAAkB,CAAC;AAMhE;;GAEG;AACH,eAAO,MAAM,yBAAyB,QAAO,mBAQ3C,CAAC;AAEH;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAChC,IAAI,EAAE,KAAK,CAAC;IACZ,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,aAAa,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;CAC/D;AAED;;GAEG;AACH,MAAM,WAAW,yBAAyB;IACzC,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACtB;AAsBD;;GAEG;AACH,qBAAa,gBAAgB;IAK3B,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAC;IAJ7B,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAkC;IAC/D,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAkC;IAC5D,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAe;gBAExB,UAAU,CAAC,iEAAqD;IAGrE,iBAAiB,CAC7B,GAAG,EAAE,yBAAyB,EAC9B,KAAK,EAAE,WAAW,GAChB,OAAO,CAAC,IAAI,CAAC;YAMF,4BAA4B;IAU7B,aAAa,CACzB,WAAW,EAAE,gBAAgB,EAC7B,YAAY,UAAQ,EACpB,WAAW,UAAQ,GACjB,OAAO,CAAC,WAAW,CAAC;IAKV,aAAa,CACzB,WAAW,EAAE,gBAAgB,EAC7B,YAAY,UAAQ,EACpB,WAAW,UAAQ,GACjB,OAAO,CAAC,WAAW,CAAC;YAKT,iBAAiB;IAiB/B,OAAO,CAAC,MAAM,CAAC,WAAW;YAUZ,SAAS;YAgCT,aAAa;IA4C3B,OAAO,CAAC,qBAAqB;IAiB7B,OAAO,CAAC,gBAAgB;CA4BxB;AAaD;;GAEG;AACH,eAAO,MAAM,eAAe,EAAE,WAAW,CAAC,yBAAyB,EAAE,WAAW,CA8B/E,CAAC"}
1
+ {"version":3,"file":"odspTokenManager.d.ts","sourceRoot":"","sources":["../src/odspTokenManager.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,KAAK,EACX,mBAAmB,EACnB,WAAW,EACX,MAAM,4CAA4C,CAAC;AAIpD,OAAO,KAAK,EAAE,WAAW,EAAc,MAAM,kBAAkB,CAAC;AAMhE;;GAEG;AACH,eAAO,MAAM,yBAAyB,QAAO,mBAQ3C,CAAC;AAEH;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAChC,IAAI,EAAE,KAAK,CAAC;IACZ,QAAQ,EAAE,MAAM,CAAC;IACjB,UAAU,CAAC,aAAa,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;CAC/D;AAED;;GAEG;AACH,MAAM,WAAW,yBAAyB;IACzC,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC;IACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;CACtB;AAsBD;;GAEG;AACH,qBAAa,gBAAgB;IAK3B,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAC;IAJ7B,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAkC;IAC/D,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAkC;IAC5D,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAe;gBAExB,UAAU,CAAC,EAAE,WAAW,CAAC,yBAAyB,EAAE,WAAW,CAAC,YAAA;IAGrE,iBAAiB,CAC7B,GAAG,EAAE,yBAAyB,EAC9B,KAAK,EAAE,WAAW,GAChB,OAAO,CAAC,IAAI,CAAC;YAMF,4BAA4B;IAU7B,aAAa,CACzB,WAAW,EAAE,gBAAgB,EAC7B,YAAY,UAAQ,EACpB,WAAW,UAAQ,GACjB,OAAO,CAAC,WAAW,CAAC;IAKV,aAAa,CACzB,WAAW,EAAE,gBAAgB,EAC7B,YAAY,UAAQ,EACpB,WAAW,UAAQ,GACjB,OAAO,CAAC,WAAW,CAAC;YAKT,iBAAiB;IAiB/B,OAAO,CAAC,MAAM,CAAC,WAAW;YAUZ,SAAS;YAgCT,aAAa;IA4C3B,OAAO,CAAC,qBAAqB;IAiB7B,OAAO,CAAC,gBAAgB;CA4BxB;AAaD;;GAEG;AACH,eAAO,MAAM,eAAe,EAAE,WAAW,CAAC,yBAAyB,EAAE,WAAW,CA8B/E,CAAC"}
@@ -40,11 +40,12 @@ const cacheKeyToString = (key) => {
40
40
  * @internal
41
41
  */
42
42
  export class OdspTokenManager {
43
+ tokenCache;
44
+ storageCache = new Map();
45
+ pushCache = new Map();
46
+ cacheMutex = new Mutex();
43
47
  constructor(tokenCache) {
44
48
  this.tokenCache = tokenCache;
45
- this.storageCache = new Map();
46
- this.pushCache = new Map();
47
- this.cacheMutex = new Mutex();
48
49
  }
49
50
  async updateTokensCache(key, value) {
50
51
  await this.cacheMutex.runExclusive(async () => {
@@ -1 +1 @@
1
- {"version":3,"file":"odspTokenManager.js","sourceRoot":"","sources":["../src/odspTokenManager.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport type {\n\tIPublicClientConfig,\n\tIOdspTokens,\n} from \"@fluidframework/odsp-doclib-utils/internal\";\nimport { Mutex } from \"async-mutex\";\n\nimport { debug } from \"./debug.js\";\nimport type { IAsyncCache, IResources } from \"./fluidToolRc.js\";\nimport { loadRC, lockRC, saveRC } from \"./fluidToolRc.js\";\nimport { redactTokens } from \"./redactTokens.js\";\n\n// TODO: Add documentation\n// eslint-disable-next-line jsdoc/require-description\n/**\n * @internal\n */\nexport const getMicrosoftConfiguration = (): IPublicClientConfig => ({\n\tget clientId(): string {\n\t\t// eslint-disable-next-line @typescript-eslint/strict-boolean-expressions\n\t\tif (!process.env.login__microsoft__clientId) {\n\t\t\tthrow new Error(\"Client ID environment variable not set: login__microsoft__clientId.\");\n\t\t}\n\t\treturn process.env.login__microsoft__clientId;\n\t},\n});\n\n/**\n * @internal\n */\nexport interface LoginCredentials {\n\ttype: \"fic\";\n\tusername: string;\n\tfetchToken(scopeEndpoint: \"push\" | \"storage\"): Promise<string>;\n}\n\n/**\n * @internal\n */\nexport interface IOdspTokenManagerCacheKey {\n\treadonly isPush: boolean;\n\treadonly user: string;\n}\n\nconst isValidAndNotExpiredToken = (tokens: IOdspTokens): boolean => {\n\t// Return false for undefined or empty tokens.\n\tif (!tokens.accessToken || tokens.accessToken.length === 0) {\n\t\treturn false;\n\t}\n\n\tif (tokens.receivedAt === undefined || tokens.expiresIn === undefined) {\n\t\t// If we don't have receivedAt or expiresIn, we treat the token as expired.\n\t\treturn false;\n\t}\n\n\tconst expiresAt = tokens.receivedAt + tokens.expiresIn;\n\t// Give it a 60s buffer\n\treturn expiresAt - 60 >= Date.now() / 1000;\n};\n\nconst cacheKeyToString = (key: IOdspTokenManagerCacheKey): string => {\n\treturn `${key.user}${key.isPush ? \"[Push]\" : \"\"}`;\n};\n\n/**\n * @internal\n */\nexport class OdspTokenManager {\n\tprivate readonly storageCache = new Map<string, IOdspTokens>();\n\tprivate readonly pushCache = new Map<string, IOdspTokens>();\n\tprivate readonly cacheMutex = new Mutex();\n\tpublic constructor(\n\t\tprivate readonly tokenCache?: IAsyncCache<IOdspTokenManagerCacheKey, IOdspTokens>,\n\t) {}\n\n\tpublic async updateTokensCache(\n\t\tkey: IOdspTokenManagerCacheKey,\n\t\tvalue: IOdspTokens,\n\t): Promise<void> {\n\t\tawait this.cacheMutex.runExclusive(async () => {\n\t\t\tawait this.updateTokensCacheWithoutLock(key, value);\n\t\t});\n\t}\n\n\tprivate async updateTokensCacheWithoutLock(\n\t\tkey: IOdspTokenManagerCacheKey,\n\t\tvalue: IOdspTokens,\n\t): Promise<void> {\n\t\tdebug(`${cacheKeyToString(key)}: Saving tokens`);\n\t\tconst memoryCache = key.isPush ? this.pushCache : this.storageCache;\n\t\tmemoryCache.set(key.user, value);\n\t\tawait this.tokenCache?.save(key, value);\n\t}\n\n\tpublic async getOdspTokens(\n\t\tcredentials: LoginCredentials,\n\t\tforceRefresh = false,\n\t\tforceReauth = false,\n\t): Promise<IOdspTokens> {\n\t\tdebug(\"Getting odsp tokens\");\n\t\treturn this.getTokens(false, credentials, forceRefresh, forceReauth);\n\t}\n\n\tpublic async getPushTokens(\n\t\tcredentials: LoginCredentials,\n\t\tforceRefresh = false,\n\t\tforceReauth = false,\n\t): Promise<IOdspTokens> {\n\t\tdebug(\"Getting push tokens\");\n\t\treturn this.getTokens(true, credentials, forceRefresh, forceReauth);\n\t}\n\n\tprivate async getTokenFromCache(\n\t\tcacheKey: IOdspTokenManagerCacheKey,\n\t): Promise<IOdspTokens | undefined> {\n\t\tconst memoryCache = cacheKey.isPush ? this.pushCache : this.storageCache;\n\t\tconst memoryToken = memoryCache.get(cacheKey.user);\n\t\tif (memoryToken) {\n\t\t\tdebug(`${cacheKeyToString(cacheKey)}: Token found in memory `);\n\t\t\treturn memoryToken;\n\t\t}\n\t\tconst fileToken = await this.tokenCache?.get(cacheKey);\n\t\tif (fileToken) {\n\t\t\tdebug(`${cacheKeyToString(cacheKey)}: Token found in file`);\n\t\t\tmemoryCache.set(cacheKey.user, fileToken);\n\t\t\treturn fileToken;\n\t\t}\n\t}\n\n\tprivate static getCacheKey(\n\t\tisPush: boolean,\n\t\tcredentials: LoginCredentials,\n\t): IOdspTokenManagerCacheKey {\n\t\treturn {\n\t\t\tisPush,\n\t\t\tuser: credentials.username,\n\t\t};\n\t}\n\n\tprivate async getTokens(\n\t\tisPush: boolean,\n\t\tcredentials: LoginCredentials,\n\t\tforceRefresh: boolean,\n\t\tforceReauth: boolean,\n\t): Promise<IOdspTokens> {\n\t\tconst invokeGetTokensCore = async (): Promise<IOdspTokens> => {\n\t\t\t// Don't solely rely on tokenCache lock, ensure serialized execution of\n\t\t\t// cache update to avoid multiple fetch.\n\t\t\treturn this.cacheMutex.runExclusive(async () => {\n\t\t\t\treturn this.getTokensCore(isPush, credentials, forceRefresh, forceReauth);\n\t\t\t});\n\t\t};\n\t\tif (!forceReauth && !forceRefresh) {\n\t\t\t// check and return if it exists without lock\n\t\t\tconst cacheKey = OdspTokenManager.getCacheKey(isPush, credentials);\n\t\t\tconst tokensFromCache = await this.getTokenFromCache(cacheKey);\n\t\t\tif (tokensFromCache) {\n\t\t\t\tif (isValidAndNotExpiredToken(tokensFromCache)) {\n\t\t\t\t\tdebug(`${cacheKeyToString(cacheKey)}: Token reused from cache `);\n\t\t\t\t\treturn tokensFromCache;\n\t\t\t\t}\n\t\t\t\tdebug(`${cacheKeyToString(cacheKey)}: Token expired from cache `);\n\t\t\t}\n\t\t}\n\t\tif (this.tokenCache) {\n\t\t\t// check with lock, used to prevent concurrent auth attempts\n\t\t\treturn this.tokenCache.lock(invokeGetTokensCore);\n\t\t}\n\t\treturn invokeGetTokensCore();\n\t}\n\n\tprivate async getTokensCore(\n\t\tisPush: boolean,\n\t\tcredentials: LoginCredentials,\n\t\tforceRefresh: boolean,\n\t\tforceReauth: boolean,\n\t): Promise<IOdspTokens> {\n\t\tconst cacheKey = OdspTokenManager.getCacheKey(isPush, credentials);\n\t\tlet tokens: IOdspTokens | undefined;\n\t\tif (!forceReauth) {\n\t\t\t// check the cache again under the lock (if it is there)\n\t\t\tconst tokensFromCache = await this.getTokenFromCache(cacheKey);\n\t\t\tif (tokensFromCache) {\n\t\t\t\tif (forceRefresh || !isValidAndNotExpiredToken(tokensFromCache)) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst scopeEndpoint = isPush ? \"push\" : \"storage\";\n\t\t\t\t\t\tconst newTokenData = await credentials.fetchToken(scopeEndpoint);\n\t\t\t\t\t\ttokens = this.ficTokenToIOdspTokens(newTokenData, isPush);\n\t\t\t\t\t\tawait this.updateTokensCacheWithoutLock(cacheKey, tokens);\n\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\tdebug(`${cacheKeyToString(cacheKey)}: Error in refreshing token. ${error}`);\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\ttokens = tokensFromCache;\n\t\t\t\t\tdebug(`${cacheKeyToString(cacheKey)}: Token reused from locked cache `);\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (tokens) {\n\t\t\t\treturn tokens;\n\t\t\t}\n\t\t}\n\n\t\tconst tokenData = await credentials.fetchToken(isPush ? \"push\" : \"storage\");\n\t\ttokens = this.ficTokenToIOdspTokens(tokenData, isPush);\n\n\t\tif (!isValidAndNotExpiredToken(tokens)) {\n\t\t\tthrow new Error(\n\t\t\t\t`Acquired invalid tokens for ${cacheKeyToString(cacheKey)}. ${redactTokens(tokens)}`,\n\t\t\t);\n\t\t}\n\n\t\tawait this.updateTokensCacheWithoutLock(cacheKey, tokens);\n\t\treturn tokens;\n\t}\n\n\tprivate ficTokenToIOdspTokens(token: string, isPush: boolean): IOdspTokens {\n\t\t// eslint-disable-next-line unicorn/prefer-ternary -- using if statement for clarity\n\t\tif (isPush) {\n\t\t\t// Push tokens are not standard JWTs. With direct token exchange, the second leg includes information about expiry.\n\t\t\t// This is not available in the FIC flow, but in direct token exchange we request tokens with 1 hour expiry so default to that.\n\t\t\t// At worst this should result in some higher latency when a token is returned from the cache when it should really be\n\t\t\t// refreshed immediately (as attempting to use such a token will trigger a token refresh flow indirectly).\n\t\t\treturn {\n\t\t\t\taccessToken: token,\n\t\t\t\treceivedAt: Math.floor(Date.now() / 1000),\n\t\t\t\texpiresIn: 3600,\n\t\t\t};\n\t\t} else {\n\t\t\treturn this.jwtToIOdspTokens(token);\n\t\t}\n\t}\n\n\tprivate jwtToIOdspTokens(token: string): IOdspTokens {\n\t\tlet receivedAt: number;\n\t\tlet expiresIn: number;\n\t\tconst payloadSegment = token.split(\".\")[1];\n\t\tif (payloadSegment === undefined) {\n\t\t\tthrow new Error(\"Invalid JWT format\");\n\t\t}\n\t\tconst payload = JSON.parse(Buffer.from(payloadSegment, \"base64url\").toString(\"utf8\")) as {\n\t\t\tiat?: number;\n\t\t\texp?: number;\n\t\t};\n\t\tif (typeof payload.iat === \"number\") {\n\t\t\treceivedAt = payload.iat;\n\t\t} else {\n\t\t\tthrow new TypeError(\"JWT payload lacks valid iat claim.\");\n\t\t}\n\t\tif (typeof payload.exp === \"number\" && typeof payload.iat === \"number\") {\n\t\t\texpiresIn = payload.exp - payload.iat;\n\t\t} else {\n\t\t\tthrow new TypeError(\"JWT payload lacks valid exp claim.\");\n\t\t}\n\n\t\treturn {\n\t\t\taccessToken: token,\n\t\t\treceivedAt,\n\t\t\texpiresIn,\n\t\t};\n\t}\n}\n\nasync function loadAndPatchRC(): Promise<IResources> {\n\tconst rc = await loadRC();\n\tif (rc.tokens && rc.tokens.version === undefined) {\n\t\t// Clean up older versions\n\t\tdelete rc.tokens;\n\t\t// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-explicit-any\n\t\tdelete (rc as any).pushTokens;\n\t}\n\treturn rc;\n}\n\n/**\n * @internal\n */\nexport const odspTokensCache: IAsyncCache<IOdspTokenManagerCacheKey, IOdspTokens> = {\n\tasync get(key: IOdspTokenManagerCacheKey): Promise<IOdspTokens | undefined> {\n\t\tconst rc = await loadAndPatchRC();\n\t\treturn rc.tokens?.data[key.user]?.[key.isPush ? \"push\" : \"storage\"];\n\t},\n\tasync save(key: IOdspTokenManagerCacheKey, tokens: IOdspTokens): Promise<void> {\n\t\tconst rc = await loadAndPatchRC();\n\t\t// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing -- using ??= could change behavior if value is falsy\n\t\tif (!rc.tokens) {\n\t\t\trc.tokens = {\n\t\t\t\tversion: 1,\n\t\t\t\tdata: {},\n\t\t\t};\n\t\t}\n\t\tlet prevTokens = rc.tokens.data[key.user];\n\t\tif (!prevTokens) {\n\t\t\tprevTokens = {};\n\t\t\trc.tokens.data[key.user] = prevTokens;\n\t\t}\n\t\tprevTokens[key.isPush ? \"push\" : \"storage\"] = tokens;\n\t\treturn saveRC(rc);\n\t},\n\tasync lock<T>(callback: () => Promise<T>): Promise<T> {\n\t\tconst release = await lockRC();\n\t\ttry {\n\t\t\treturn await callback();\n\t\t} finally {\n\t\t\tawait release();\n\t\t}\n\t},\n};\n"]}
1
+ {"version":3,"file":"odspTokenManager.js","sourceRoot":"","sources":["../src/odspTokenManager.ts"],"names":[],"mappings":"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","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport type {\n\tIPublicClientConfig,\n\tIOdspTokens,\n} from \"@fluidframework/odsp-doclib-utils/internal\";\nimport { Mutex } from \"async-mutex\";\n\nimport { debug } from \"./debug.js\";\nimport type { IAsyncCache, IResources } from \"./fluidToolRc.js\";\nimport { loadRC, lockRC, saveRC } from \"./fluidToolRc.js\";\nimport { redactTokens } from \"./redactTokens.js\";\n\n// TODO: Add documentation\n// eslint-disable-next-line jsdoc/require-description\n/**\n * @internal\n */\nexport const getMicrosoftConfiguration = (): IPublicClientConfig => ({\n\tget clientId(): string {\n\t\t// eslint-disable-next-line @typescript-eslint/strict-boolean-expressions\n\t\tif (!process.env.login__microsoft__clientId) {\n\t\t\tthrow new Error(\"Client ID environment variable not set: login__microsoft__clientId.\");\n\t\t}\n\t\treturn process.env.login__microsoft__clientId;\n\t},\n});\n\n/**\n * @internal\n */\nexport interface LoginCredentials {\n\ttype: \"fic\";\n\tusername: string;\n\tfetchToken(scopeEndpoint: \"push\" | \"storage\"): Promise<string>;\n}\n\n/**\n * @internal\n */\nexport interface IOdspTokenManagerCacheKey {\n\treadonly isPush: boolean;\n\treadonly user: string;\n}\n\nconst isValidAndNotExpiredToken = (tokens: IOdspTokens): boolean => {\n\t// Return false for undefined or empty tokens.\n\tif (!tokens.accessToken || tokens.accessToken.length === 0) {\n\t\treturn false;\n\t}\n\n\tif (tokens.receivedAt === undefined || tokens.expiresIn === undefined) {\n\t\t// If we don't have receivedAt or expiresIn, we treat the token as expired.\n\t\treturn false;\n\t}\n\n\tconst expiresAt = tokens.receivedAt + tokens.expiresIn;\n\t// Give it a 60s buffer\n\treturn expiresAt - 60 >= Date.now() / 1000;\n};\n\nconst cacheKeyToString = (key: IOdspTokenManagerCacheKey): string => {\n\treturn `${key.user}${key.isPush ? \"[Push]\" : \"\"}`;\n};\n\n/**\n * @internal\n */\nexport class OdspTokenManager {\n\tprivate readonly storageCache = new Map<string, IOdspTokens>();\n\tprivate readonly pushCache = new Map<string, IOdspTokens>();\n\tprivate readonly cacheMutex = new Mutex();\n\tpublic constructor(\n\t\tprivate readonly tokenCache?: IAsyncCache<IOdspTokenManagerCacheKey, IOdspTokens>,\n\t) {}\n\n\tpublic async updateTokensCache(\n\t\tkey: IOdspTokenManagerCacheKey,\n\t\tvalue: IOdspTokens,\n\t): Promise<void> {\n\t\tawait this.cacheMutex.runExclusive(async () => {\n\t\t\tawait this.updateTokensCacheWithoutLock(key, value);\n\t\t});\n\t}\n\n\tprivate async updateTokensCacheWithoutLock(\n\t\tkey: IOdspTokenManagerCacheKey,\n\t\tvalue: IOdspTokens,\n\t): Promise<void> {\n\t\tdebug(`${cacheKeyToString(key)}: Saving tokens`);\n\t\tconst memoryCache = key.isPush ? this.pushCache : this.storageCache;\n\t\tmemoryCache.set(key.user, value);\n\t\tawait this.tokenCache?.save(key, value);\n\t}\n\n\tpublic async getOdspTokens(\n\t\tcredentials: LoginCredentials,\n\t\tforceRefresh = false,\n\t\tforceReauth = false,\n\t): Promise<IOdspTokens> {\n\t\tdebug(\"Getting odsp tokens\");\n\t\treturn this.getTokens(false, credentials, forceRefresh, forceReauth);\n\t}\n\n\tpublic async getPushTokens(\n\t\tcredentials: LoginCredentials,\n\t\tforceRefresh = false,\n\t\tforceReauth = false,\n\t): Promise<IOdspTokens> {\n\t\tdebug(\"Getting push tokens\");\n\t\treturn this.getTokens(true, credentials, forceRefresh, forceReauth);\n\t}\n\n\tprivate async getTokenFromCache(\n\t\tcacheKey: IOdspTokenManagerCacheKey,\n\t): Promise<IOdspTokens | undefined> {\n\t\tconst memoryCache = cacheKey.isPush ? this.pushCache : this.storageCache;\n\t\tconst memoryToken = memoryCache.get(cacheKey.user);\n\t\tif (memoryToken) {\n\t\t\tdebug(`${cacheKeyToString(cacheKey)}: Token found in memory `);\n\t\t\treturn memoryToken;\n\t\t}\n\t\tconst fileToken = await this.tokenCache?.get(cacheKey);\n\t\tif (fileToken) {\n\t\t\tdebug(`${cacheKeyToString(cacheKey)}: Token found in file`);\n\t\t\tmemoryCache.set(cacheKey.user, fileToken);\n\t\t\treturn fileToken;\n\t\t}\n\t}\n\n\tprivate static getCacheKey(\n\t\tisPush: boolean,\n\t\tcredentials: LoginCredentials,\n\t): IOdspTokenManagerCacheKey {\n\t\treturn {\n\t\t\tisPush,\n\t\t\tuser: credentials.username,\n\t\t};\n\t}\n\n\tprivate async getTokens(\n\t\tisPush: boolean,\n\t\tcredentials: LoginCredentials,\n\t\tforceRefresh: boolean,\n\t\tforceReauth: boolean,\n\t): Promise<IOdspTokens> {\n\t\tconst invokeGetTokensCore = async (): Promise<IOdspTokens> => {\n\t\t\t// Don't solely rely on tokenCache lock, ensure serialized execution of\n\t\t\t// cache update to avoid multiple fetch.\n\t\t\treturn this.cacheMutex.runExclusive(async () => {\n\t\t\t\treturn this.getTokensCore(isPush, credentials, forceRefresh, forceReauth);\n\t\t\t});\n\t\t};\n\t\tif (!forceReauth && !forceRefresh) {\n\t\t\t// check and return if it exists without lock\n\t\t\tconst cacheKey = OdspTokenManager.getCacheKey(isPush, credentials);\n\t\t\tconst tokensFromCache = await this.getTokenFromCache(cacheKey);\n\t\t\tif (tokensFromCache) {\n\t\t\t\tif (isValidAndNotExpiredToken(tokensFromCache)) {\n\t\t\t\t\tdebug(`${cacheKeyToString(cacheKey)}: Token reused from cache `);\n\t\t\t\t\treturn tokensFromCache;\n\t\t\t\t}\n\t\t\t\tdebug(`${cacheKeyToString(cacheKey)}: Token expired from cache `);\n\t\t\t}\n\t\t}\n\t\tif (this.tokenCache) {\n\t\t\t// check with lock, used to prevent concurrent auth attempts\n\t\t\treturn this.tokenCache.lock(invokeGetTokensCore);\n\t\t}\n\t\treturn invokeGetTokensCore();\n\t}\n\n\tprivate async getTokensCore(\n\t\tisPush: boolean,\n\t\tcredentials: LoginCredentials,\n\t\tforceRefresh: boolean,\n\t\tforceReauth: boolean,\n\t): Promise<IOdspTokens> {\n\t\tconst cacheKey = OdspTokenManager.getCacheKey(isPush, credentials);\n\t\tlet tokens: IOdspTokens | undefined;\n\t\tif (!forceReauth) {\n\t\t\t// check the cache again under the lock (if it is there)\n\t\t\tconst tokensFromCache = await this.getTokenFromCache(cacheKey);\n\t\t\tif (tokensFromCache) {\n\t\t\t\tif (forceRefresh || !isValidAndNotExpiredToken(tokensFromCache)) {\n\t\t\t\t\ttry {\n\t\t\t\t\t\tconst scopeEndpoint = isPush ? \"push\" : \"storage\";\n\t\t\t\t\t\tconst newTokenData = await credentials.fetchToken(scopeEndpoint);\n\t\t\t\t\t\ttokens = this.ficTokenToIOdspTokens(newTokenData, isPush);\n\t\t\t\t\t\tawait this.updateTokensCacheWithoutLock(cacheKey, tokens);\n\t\t\t\t\t} catch (error) {\n\t\t\t\t\t\tdebug(`${cacheKeyToString(cacheKey)}: Error in refreshing token. ${error}`);\n\t\t\t\t\t}\n\t\t\t\t} else {\n\t\t\t\t\ttokens = tokensFromCache;\n\t\t\t\t\tdebug(`${cacheKeyToString(cacheKey)}: Token reused from locked cache `);\n\t\t\t\t}\n\t\t\t}\n\t\t\tif (tokens) {\n\t\t\t\treturn tokens;\n\t\t\t}\n\t\t}\n\n\t\tconst tokenData = await credentials.fetchToken(isPush ? \"push\" : \"storage\");\n\t\ttokens = this.ficTokenToIOdspTokens(tokenData, isPush);\n\n\t\tif (!isValidAndNotExpiredToken(tokens)) {\n\t\t\tthrow new Error(\n\t\t\t\t`Acquired invalid tokens for ${cacheKeyToString(cacheKey)}. ${redactTokens(tokens)}`,\n\t\t\t);\n\t\t}\n\n\t\tawait this.updateTokensCacheWithoutLock(cacheKey, tokens);\n\t\treturn tokens;\n\t}\n\n\tprivate ficTokenToIOdspTokens(token: string, isPush: boolean): IOdspTokens {\n\t\t// eslint-disable-next-line unicorn/prefer-ternary -- using if statement for clarity\n\t\tif (isPush) {\n\t\t\t// Push tokens are not standard JWTs. With direct token exchange, the second leg includes information about expiry.\n\t\t\t// This is not available in the FIC flow, but in direct token exchange we request tokens with 1 hour expiry so default to that.\n\t\t\t// At worst this should result in some higher latency when a token is returned from the cache when it should really be\n\t\t\t// refreshed immediately (as attempting to use such a token will trigger a token refresh flow indirectly).\n\t\t\treturn {\n\t\t\t\taccessToken: token,\n\t\t\t\treceivedAt: Math.floor(Date.now() / 1000),\n\t\t\t\texpiresIn: 3600,\n\t\t\t};\n\t\t} else {\n\t\t\treturn this.jwtToIOdspTokens(token);\n\t\t}\n\t}\n\n\tprivate jwtToIOdspTokens(token: string): IOdspTokens {\n\t\tlet receivedAt: number;\n\t\tlet expiresIn: number;\n\t\tconst payloadSegment = token.split(\".\")[1];\n\t\tif (payloadSegment === undefined) {\n\t\t\tthrow new Error(\"Invalid JWT format\");\n\t\t}\n\t\tconst payload = JSON.parse(Buffer.from(payloadSegment, \"base64url\").toString(\"utf8\")) as {\n\t\t\tiat?: number;\n\t\t\texp?: number;\n\t\t};\n\t\tif (typeof payload.iat === \"number\") {\n\t\t\treceivedAt = payload.iat;\n\t\t} else {\n\t\t\tthrow new TypeError(\"JWT payload lacks valid iat claim.\");\n\t\t}\n\t\tif (typeof payload.exp === \"number\" && typeof payload.iat === \"number\") {\n\t\t\texpiresIn = payload.exp - payload.iat;\n\t\t} else {\n\t\t\tthrow new TypeError(\"JWT payload lacks valid exp claim.\");\n\t\t}\n\n\t\treturn {\n\t\t\taccessToken: token,\n\t\t\treceivedAt,\n\t\t\texpiresIn,\n\t\t};\n\t}\n}\n\nasync function loadAndPatchRC(): Promise<IResources> {\n\tconst rc = await loadRC();\n\tif (rc.tokens && rc.tokens.version === undefined) {\n\t\t// Clean up older versions\n\t\tdelete rc.tokens;\n\t\t// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, @typescript-eslint/no-explicit-any\n\t\tdelete (rc as any).pushTokens;\n\t}\n\treturn rc;\n}\n\n/**\n * @internal\n */\nexport const odspTokensCache: IAsyncCache<IOdspTokenManagerCacheKey, IOdspTokens> = {\n\tasync get(key: IOdspTokenManagerCacheKey): Promise<IOdspTokens | undefined> {\n\t\tconst rc = await loadAndPatchRC();\n\t\treturn rc.tokens?.data[key.user]?.[key.isPush ? \"push\" : \"storage\"];\n\t},\n\tasync save(key: IOdspTokenManagerCacheKey, tokens: IOdspTokens): Promise<void> {\n\t\tconst rc = await loadAndPatchRC();\n\t\t// eslint-disable-next-line @typescript-eslint/prefer-nullish-coalescing -- using ??= could change behavior if value is falsy\n\t\tif (!rc.tokens) {\n\t\t\trc.tokens = {\n\t\t\t\tversion: 1,\n\t\t\t\tdata: {},\n\t\t\t};\n\t\t}\n\t\tlet prevTokens = rc.tokens.data[key.user];\n\t\tif (!prevTokens) {\n\t\t\tprevTokens = {};\n\t\t\trc.tokens.data[key.user] = prevTokens;\n\t\t}\n\t\tprevTokens[key.isPush ? \"push\" : \"storage\"] = tokens;\n\t\treturn saveRC(rc);\n\t},\n\tasync lock<T>(callback: () => Promise<T>): Promise<T> {\n\t\tconst release = await lockRC();\n\t\ttry {\n\t\t\treturn await callback();\n\t\t} finally {\n\t\t\tawait release();\n\t\t}\n\t},\n};\n"]}
@@ -5,5 +5,5 @@
5
5
  * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY
6
6
  */
7
7
  export declare const pkgName = "@fluidframework/tool-utils";
8
- export declare const pkgVersion = "2.118.1";
8
+ export declare const pkgVersion = "3.0.1";
9
9
  //# sourceMappingURL=packageVersion.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"packageVersion.d.ts","sourceRoot":"","sources":["../src/packageVersion.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,eAAO,MAAM,OAAO,+BAA+B,CAAC;AACpD,eAAO,MAAM,UAAU,YAAY,CAAC"}
1
+ {"version":3,"file":"packageVersion.d.ts","sourceRoot":"","sources":["../src/packageVersion.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,eAAO,MAAM,OAAO,+BAA+B,CAAC;AACpD,eAAO,MAAM,UAAU,UAAU,CAAC"}
@@ -5,5 +5,5 @@
5
5
  * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY
6
6
  */
7
7
  export const pkgName = "@fluidframework/tool-utils";
8
- export const pkgVersion = "2.118.1";
8
+ export const pkgVersion = "3.0.1";
9
9
  //# sourceMappingURL=packageVersion.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"packageVersion.js","sourceRoot":"","sources":["../src/packageVersion.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,CAAC,MAAM,OAAO,GAAG,4BAA4B,CAAC;AACpD,MAAM,CAAC,MAAM,UAAU,GAAG,SAAS,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n *\n * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY\n */\n\nexport const pkgName = \"@fluidframework/tool-utils\";\nexport const pkgVersion = \"2.118.1\";\n"]}
1
+ {"version":3,"file":"packageVersion.js","sourceRoot":"","sources":["../src/packageVersion.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,MAAM,CAAC,MAAM,OAAO,GAAG,4BAA4B,CAAC;AACpD,MAAM,CAAC,MAAM,UAAU,GAAG,OAAO,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n *\n * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY\n */\n\nexport const pkgName = \"@fluidframework/tool-utils\";\nexport const pkgVersion = \"3.0.1\";\n"]}
package/lib/public.d.ts CHANGED
@@ -5,7 +5,7 @@
5
5
 
6
6
  /*
7
7
  * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
8
- * Generated by "flub generate entrypoints --outDir ./lib --node10TypeCompat" in @fluid-tools/build-cli.
8
+ * Generated by "flub generate entrypoints --outDir ./lib" in @fluid-tools/build-cli.
9
9
  */
10
10
 
11
11
  export {}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fluidframework/tool-utils",
3
- "version": "2.118.1",
3
+ "version": "3.0.1",
4
4
  "description": "Common utilities for Fluid tools",
5
5
  "homepage": "https://fluidframework.com",
6
6
  "repository": {
@@ -14,28 +14,17 @@
14
14
  "type": "module",
15
15
  "exports": {
16
16
  ".": {
17
- "import": {
18
- "types": "./lib/public.d.ts",
19
- "default": "./lib/index.js"
20
- },
21
- "require": {
22
- "types": "./dist/public.d.ts",
23
- "default": "./dist/index.js"
17
+ "types": "./lib/public.d.ts",
18
+ "default": "./lib/index.js",
19
+ "internal-entrypoint-generation": {
20
+ "types": "./dist/public.d.ts"
24
21
  }
25
22
  },
26
23
  "./internal": {
27
- "import": {
28
- "types": "./lib/index.d.ts",
29
- "default": "./lib/index.js"
30
- },
31
- "require": {
32
- "types": "./dist/index.d.ts",
33
- "default": "./dist/index.js"
34
- }
24
+ "types": "./lib/index.d.ts",
25
+ "default": "./lib/index.js"
35
26
  }
36
27
  },
37
- "main": "lib/index.js",
38
- "types": "lib/public.d.ts",
39
28
  "c8": {
40
29
  "all": true,
41
30
  "cache-dir": "nyc/.cache",
@@ -59,10 +48,10 @@
59
48
  "temp-directory": "nyc/.nyc_output"
60
49
  },
61
50
  "dependencies": {
62
- "@fluidframework/core-utils": "~2.118.1",
63
- "@fluidframework/driver-definitions": "~2.118.1",
64
- "@fluidframework/driver-utils": "~2.118.1",
65
- "@fluidframework/odsp-doclib-utils": "~2.118.1",
51
+ "@fluidframework/core-utils": "~3.0.1",
52
+ "@fluidframework/driver-definitions": "~3.0.1",
53
+ "@fluidframework/driver-utils": "~3.0.1",
54
+ "@fluidframework/odsp-doclib-utils": "~3.0.1",
66
55
  "async-mutex": "^0.3.1",
67
56
  "debug": "^4.3.4",
68
57
  "proper-lockfile": "^4.1.2"
@@ -70,7 +59,7 @@
70
59
  "devDependencies": {
71
60
  "@arethetypeswrong/cli": "^0.18.5",
72
61
  "@biomejs/biome": "~2.4.5",
73
- "@fluid-internal/mocha-test-setup": "~2.118.1",
62
+ "@fluid-internal/mocha-test-setup": "~3.0.1",
74
63
  "@fluid-tools/build-cli": "^0.67.0",
75
64
  "@fluidframework/build-common": "^2.0.3",
76
65
  "@fluidframework/build-tools": "^0.67.0",
@@ -90,7 +79,7 @@
90
79
  "mocha": "^11.7.5",
91
80
  "mocha-multi-reporters": "^1.5.1",
92
81
  "rimraf": "^6.1.3",
93
- "typescript": "~5.4.5"
82
+ "typescript": "~6.0.3"
94
83
  },
95
84
  "typeValidation": {
96
85
  "broken": {},
@@ -98,25 +87,28 @@
98
87
  },
99
88
  "scripts": {
100
89
  "build": "fluid-build . --task build",
90
+ "build:api-reports": "api-extractor run --local --config api-extractor/api-extractor-report.json",
91
+ "build:cjs": "fluid-tsc commonjs --project ./tsconfig.cjs.json && copyfiles -f ../../../common/build/build-common/src/cjs/package.json ./dist",
101
92
  "build:commonjs": "fluid-build . --task commonjs",
102
93
  "build:compile": "fluid-build . --task compile",
103
- "build:docs": "api-extractor run --local",
94
+ "build:docs": "api-extractor run --local --config api-extractor/api-extractor-model.json",
104
95
  "build:entrypoints": "fluid-build . --task build:entrypoints",
105
96
  "build:entrypoints:cjs": "flub generate entrypoints --resolutionConditions require --outDir ./dist",
106
- "build:entrypoints:esm": "flub generate entrypoints --outDir ./lib --node10TypeCompat",
107
- "build:esnext": "tsc --project ./tsconfig.json",
97
+ "build:entrypoints:esm": "flub generate entrypoints --outDir ./lib",
98
+ "build:esm": "tsc --project ./tsconfig.json",
108
99
  "build:genver": "gen-version",
109
100
  "build:test": "concurrently npm:build:test:esm npm:build:test:cjs",
110
101
  "build:test:cjs": "fluid-tsc commonjs --project ./src/test/tsconfig.cjs.json",
111
102
  "build:test:esm": "tsc --project ./src/test/tsconfig.json",
112
- "check:are-the-types-wrong": "attw --pack .",
103
+ "check:are-the-types-wrong": "attw --pack . --profile esm-only",
113
104
  "check:biome": "biome check .",
114
105
  "check:exports": "concurrently \"npm:check:exports:*\"",
115
106
  "check:exports:bundle-release-tags": "api-extractor run --config api-extractor/api-extractor-lint-bundle.json",
116
107
  "check:exports:cjs:public": "api-extractor run --config api-extractor/api-extractor-lint-public.cjs.json",
117
108
  "check:exports:esm:public": "api-extractor run --config api-extractor/api-extractor-lint-public.esm.json",
118
109
  "check:format": "npm run check:biome",
119
- "ci:build:docs": "api-extractor run",
110
+ "ci:build:api-reports": "api-extractor run --config api-extractor/api-extractor-report.json",
111
+ "ci:build:docs": "api-extractor run --config api-extractor/api-extractor-model.json",
120
112
  "clean": "rimraf --glob dist lib {alpha,beta,internal,legacy}.d.ts \"**/*.tsbuildinfo\" \"**/*.build.log\" _api-extractor-temp nyc",
121
113
  "eslint": "eslint --quiet --format stylish src",
122
114
  "eslint:fix": "eslint --quiet --format stylish src --fix --fix-type problem,suggestion,layout",
@@ -130,7 +122,6 @@
130
122
  "test:mocha:cjs": "cross-env FLUID_TEST_MODULE_SYSTEM=CJS mocha",
131
123
  "test:mocha:esm": "mocha",
132
124
  "test:mocha:verbose": "cross-env FLUID_TEST_VERBOSE=1 npm run test:mocha",
133
- "tsc": "fluid-tsc commonjs --project ./tsconfig.cjs.json && copyfiles -f ../../../common/build/build-common/src/cjs/package.json ./dist",
134
125
  "typetests:gen": "flub generate typetests --dir . -v"
135
126
  }
136
127
  }
@@ -6,4 +6,4 @@
6
6
  */
7
7
 
8
8
  export const pkgName = "@fluidframework/tool-utils";
9
- export const pkgVersion = "2.118.1";
9
+ export const pkgVersion = "3.0.1";
package/tsconfig.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "extends": "../../../common/build/build-common/tsconfig.node16.json",
2
+ "extends": "../../../common/build/build-common/tsconfig.node20.json",
3
3
  "include": ["src/**/*"],
4
4
  "exclude": ["src/test/**/*"],
5
5
  "compilerOptions": {
package/internal.d.ts DELETED
@@ -1,11 +0,0 @@
1
- /*!
2
- * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
3
- * Licensed under the MIT License.
4
- */
5
-
6
- /*
7
- * THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
8
- * Generated by "flub generate entrypoints --outDir ./lib --node10TypeCompat" in @fluid-tools/build-cli.
9
- */
10
-
11
- export * from "./lib/index.js";