@fluidframework/tool-utils 0.54.2 → 0.56.0-49831

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/.eslintrc.js CHANGED
@@ -5,12 +5,24 @@
5
5
 
6
6
  module.exports = {
7
7
  "extends": [
8
- "@fluidframework/eslint-config-fluid/eslint7"
8
+ "@fluidframework/eslint-config-fluid"
9
9
  ],
10
10
  "parserOptions": {
11
11
  "project": ["./tsconfig.json", "./src/test/tsconfig.json"]
12
12
  },
13
13
  "rules": {
14
- "@typescript-eslint/strict-boolean-expressions": "off"
14
+ "@typescript-eslint/strict-boolean-expressions": "off",
15
+ "unicorn/filename-case": [
16
+ "error",
17
+ {
18
+ "cases": {
19
+ "camelCase": true,
20
+ "pascalCase": true
21
+ },
22
+ "ignore": [
23
+ /.*fluidToolRC\.ts$/,
24
+ ]
25
+ }
26
+ ],
15
27
  }
16
28
  }
@@ -1 +1 @@
1
- {"version":3,"file":"fluidToolRC.d.ts","sourceRoot":"","sources":["../src/fluidToolRC.ts"],"names":[],"mappings":"AAAA;;;GAGG;AASH,OAAO,EAAE,WAAW,EAAE,MAAM,mCAAmC,CAAC;AAEhE,MAAM,WAAW,WAAW,CAAC,IAAI,EAAE,MAAM;IACrC,GAAG,CAAC,GAAG,EAAE,IAAI,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IAC5C,IAAI,CAAC,GAAG,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9C,IAAI,CAAC,CAAC,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;CACnD;AAED,MAAM,WAAW,UAAU;IACvB,MAAM,CAAC,EAAE;QACL,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,IAAI,EAAE;YACF,CAAC,GAAG,EAAE,MAAM,GAAG;gBACX,OAAO,CAAC,EAAE,WAAW,CAAC;gBACtB,IAAI,CAAC,EAAE,WAAW,CAAA;aACrB,CAAA;SACJ,CAAA;KACJ,CAAA;CACJ;AAID,wBAAsB,MAAM,IAAI,OAAO,CAAC,UAAU,CAAC,CAclD;AAED,wBAAsB,MAAM,CAAC,EAAE,EAAE,UAAU,iBAI1C;AAGD,wBAAsB,MAAM,iBAS3B"}
1
+ {"version":3,"file":"fluidToolRC.d.ts","sourceRoot":"","sources":["../src/fluidToolRC.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAOH,OAAO,EAAE,WAAW,EAAE,MAAM,mCAAmC,CAAC;AAEhE,MAAM,WAAW,WAAW,CAAC,IAAI,EAAE,MAAM;IACrC,GAAG,CAAC,GAAG,EAAE,IAAI,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IAC5C,IAAI,CAAC,GAAG,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9C,IAAI,CAAC,CAAC,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;CACnD;AAED,MAAM,WAAW,UAAU;IACvB,MAAM,CAAC,EAAE;QACL,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,IAAI,EAAE;YACF,CAAC,GAAG,EAAE,MAAM,GAAG;gBACX,OAAO,CAAC,EAAE,WAAW,CAAC;gBACtB,IAAI,CAAC,EAAE,WAAW,CAAA;aACrB,CAAA;SACJ,CAAA;KACJ,CAAA;CACJ;AAID,wBAAsB,MAAM,IAAI,OAAO,CAAC,UAAU,CAAC,CAclD;AAED,wBAAsB,MAAM,CAAC,EAAE,EAAE,UAAU,iBAI1C;AAED,wBAAsB,MAAM,iBAS3B"}
@@ -8,7 +8,6 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
8
8
  };
9
9
  Object.defineProperty(exports, "__esModule", { value: true });
10
10
  exports.lockRC = exports.saveRC = exports.loadRC = void 0;
11
- /* eslint-disable unicorn/filename-case */
12
11
  const fs_1 = __importDefault(require("fs"));
13
12
  const os_1 = __importDefault(require("os"));
14
13
  const path_1 = __importDefault(require("path"));
@@ -38,7 +37,6 @@ async function saveRC(rc) {
38
37
  return writeFile(getRCFileName(), Buffer.from(content, "utf8"));
39
38
  }
40
39
  exports.saveRC = saveRC;
41
- // eslint-disable-next-line prefer-arrow/prefer-arrow-functions
42
40
  async function lockRC() {
43
41
  // eslint-disable-next-line @typescript-eslint/no-unsafe-return
44
42
  return proper_lockfile_1.lock(getRCFileName(), {
@@ -1 +1 @@
1
- {"version":3,"file":"fluidToolRC.js","sourceRoot":"","sources":["../src/fluidToolRC.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;;;;AAEH,0CAA0C;AAE1C,4CAAoB;AACpB,4CAAoB;AACpB,gDAAwB;AACxB,gDAAwB;AACxB,qDAAuC;AAqBvC,MAAM,aAAa,GAAG,GAAG,EAAE,CAAC,cAAI,CAAC,IAAI,CAAC,YAAE,CAAC,OAAO,EAAE,EAAE,cAAc,CAAC,CAAC;AAE7D,KAAK,UAAU,MAAM;IACxB,MAAM,QAAQ,GAAG,cAAI,CAAC,SAAS,CAAC,YAAE,CAAC,QAAQ,CAAC,CAAC;IAC7C,MAAM,MAAM,GAAG,cAAI,CAAC,SAAS,CAAC,YAAE,CAAC,MAAM,CAAC,CAAC;IACzC,MAAM,QAAQ,GAAG,aAAa,EAAE,CAAC;IACjC,IAAI,MAAM,MAAM,CAAC,QAAQ,CAAC,EAAE;QACxB,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,QAAQ,CAAC,CAAC;QACrC,IAAI;YACA,+DAA+D;YAC/D,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC;SAC3C;QAAC,OAAO,CAAC,EAAE;YACR,UAAU;SACb;KACJ;IACD,OAAO,EAAE,CAAC;AACd,CAAC;AAdD,wBAcC;AAEM,KAAK,UAAU,MAAM,CAAC,EAAc;IACvC,MAAM,SAAS,GAAG,cAAI,CAAC,SAAS,CAAC,YAAE,CAAC,SAAS,CAAC,CAAC;IAC/C,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC,EAAE,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC;IACjD,OAAO,SAAS,CAAC,aAAa,EAAE,EAAE,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC;AACpE,CAAC;AAJD,wBAIC;AAED,+DAA+D;AACxD,KAAK,UAAU,MAAM;IACxB,+DAA+D;IAC/D,OAAO,sBAAI,CAAC,aAAa,EAAE,EAAE;QACzB,OAAO,EAAE;YACL,OAAO,EAAE,IAAI;SAChB;QACD,KAAK,EAAC,KAAK;QACX,QAAQ,EAAE,KAAK;KAClB,CAAC,CAAC;AACP,CAAC;AATD,wBASC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\n/* eslint-disable unicorn/filename-case */\n\nimport fs from \"fs\";\nimport os from \"os\";\nimport path from \"path\";\nimport util from \"util\";\nimport { lock } from \"proper-lockfile\";\nimport { IOdspTokens } from \"@fluidframework/odsp-doclib-utils\";\n\nexport interface IAsyncCache<TKey, TValue> {\n get(key: TKey): Promise<TValue | undefined>;\n save(key: TKey, value: TValue): Promise<void>;\n lock<T>(callback: () => Promise<T>): Promise<T>;\n}\n\nexport interface IResources {\n tokens?: {\n version?: number;\n data: {\n [key: string]: {\n storage?: IOdspTokens,\n push?: IOdspTokens\n }\n }\n }\n}\n\nconst getRCFileName = () => path.join(os.homedir(), \".fluidtoolrc\");\n\nexport async function loadRC(): Promise<IResources> {\n const readFile = util.promisify(fs.readFile);\n const exists = util.promisify(fs.exists);\n const fileName = getRCFileName();\n if (await exists(fileName)) {\n const buf = await readFile(fileName);\n try {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-return\n return JSON.parse(buf.toString(\"utf8\"));\n } catch (e) {\n // Nothing\n }\n }\n return {};\n}\n\nexport async function saveRC(rc: IResources) {\n const writeFile = util.promisify(fs.writeFile);\n const content = JSON.stringify(rc, undefined, 2);\n return writeFile(getRCFileName(), Buffer.from(content, \"utf8\"));\n}\n\n// eslint-disable-next-line prefer-arrow/prefer-arrow-functions\nexport async function lockRC() {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-return\n return lock(getRCFileName(), {\n retries: {\n forever: true,\n },\n stale:60000,\n realpath: false,\n });\n}\n"]}
1
+ {"version":3,"file":"fluidToolRC.js","sourceRoot":"","sources":["../src/fluidToolRC.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;;;;AAEH,4CAAoB;AACpB,4CAAoB;AACpB,gDAAwB;AACxB,gDAAwB;AACxB,qDAAuC;AAqBvC,MAAM,aAAa,GAAG,GAAG,EAAE,CAAC,cAAI,CAAC,IAAI,CAAC,YAAE,CAAC,OAAO,EAAE,EAAE,cAAc,CAAC,CAAC;AAE7D,KAAK,UAAU,MAAM;IACxB,MAAM,QAAQ,GAAG,cAAI,CAAC,SAAS,CAAC,YAAE,CAAC,QAAQ,CAAC,CAAC;IAC7C,MAAM,MAAM,GAAG,cAAI,CAAC,SAAS,CAAC,YAAE,CAAC,MAAM,CAAC,CAAC;IACzC,MAAM,QAAQ,GAAG,aAAa,EAAE,CAAC;IACjC,IAAI,MAAM,MAAM,CAAC,QAAQ,CAAC,EAAE;QACxB,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,QAAQ,CAAC,CAAC;QACrC,IAAI;YACA,+DAA+D;YAC/D,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC;SAC3C;QAAC,OAAO,CAAC,EAAE;YACR,UAAU;SACb;KACJ;IACD,OAAO,EAAE,CAAC;AACd,CAAC;AAdD,wBAcC;AAEM,KAAK,UAAU,MAAM,CAAC,EAAc;IACvC,MAAM,SAAS,GAAG,cAAI,CAAC,SAAS,CAAC,YAAE,CAAC,SAAS,CAAC,CAAC;IAC/C,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC,EAAE,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC;IACjD,OAAO,SAAS,CAAC,aAAa,EAAE,EAAE,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC;AACpE,CAAC;AAJD,wBAIC;AAEM,KAAK,UAAU,MAAM;IACxB,+DAA+D;IAC/D,OAAO,sBAAI,CAAC,aAAa,EAAE,EAAE;QACzB,OAAO,EAAE;YACL,OAAO,EAAE,IAAI;SAChB;QACD,KAAK,EAAC,KAAK;QACX,QAAQ,EAAE,KAAK;KAClB,CAAC,CAAC;AACP,CAAC;AATD,wBASC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport fs from \"fs\";\nimport os from \"os\";\nimport path from \"path\";\nimport util from \"util\";\nimport { lock } from \"proper-lockfile\";\nimport { IOdspTokens } from \"@fluidframework/odsp-doclib-utils\";\n\nexport interface IAsyncCache<TKey, TValue> {\n get(key: TKey): Promise<TValue | undefined>;\n save(key: TKey, value: TValue): Promise<void>;\n lock<T>(callback: () => Promise<T>): Promise<T>;\n}\n\nexport interface IResources {\n tokens?: {\n version?: number;\n data: {\n [key: string]: {\n storage?: IOdspTokens,\n push?: IOdspTokens\n }\n }\n }\n}\n\nconst getRCFileName = () => path.join(os.homedir(), \".fluidtoolrc\");\n\nexport async function loadRC(): Promise<IResources> {\n const readFile = util.promisify(fs.readFile);\n const exists = util.promisify(fs.exists);\n const fileName = getRCFileName();\n if (await exists(fileName)) {\n const buf = await readFile(fileName);\n try {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-return\n return JSON.parse(buf.toString(\"utf8\"));\n } catch (e) {\n // Nothing\n }\n }\n return {};\n}\n\nexport async function saveRC(rc: IResources) {\n const writeFile = util.promisify(fs.writeFile);\n const content = JSON.stringify(rc, undefined, 2);\n return writeFile(getRCFileName(), Buffer.from(content, \"utf8\"));\n}\n\nexport async function lockRC() {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-return\n return lock(getRCFileName(), {\n retries: {\n forever: true,\n },\n stale:60000,\n realpath: false,\n });\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"httpHelpers.d.ts","sourceRoot":"","sources":["../src/httpHelpers.ts"],"names":[],"mappings":"AAAA;;;GAGG;;AAEH,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,MAAM,EAAE,MAAM,KAAK,CAAC;AAE7B,MAAM,WAAW,kBAAkB;IAC/B,QAAQ,CAAC,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC;IAC7B,QAAQ,CAAC,OAAO,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAC9B,UAAU,IAAI,IAAI,CAAC;CACtB;AACD,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,eAAe,EAAE,IAAI,CAAC,eAAe,GAAG,kBAAkB,CAe3G;AACD,oBAAY,mBAAmB,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,eAAe,EAAE,GAAG,EAAE,IAAI,CAAC,cAAc,KAAK,OAAO,CAAC,CAAC,CAAC,CAAC;AACzG,oBAAY,kBAAkB,CAAC,CAAC,IAAI,OAAO,CAAC,MAAM,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;AAC9D,eAAO,MAAM,qBAAqB,YAAmB,MAAM,2DAiBrD,CAAC;AAEP,eAAO,MAAM,WAAW,aAAoB,KAAK,cAAc,KAAG,QAAQ,IAAI,CAM5E,CAAC"}
1
+ {"version":3,"file":"httpHelpers.d.ts","sourceRoot":"","sources":["../src/httpHelpers.ts"],"names":[],"mappings":"AAAA;;;GAGG;;AAEH,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,MAAM,EAAE,MAAM,KAAK,CAAC;AAE7B,MAAM,WAAW,kBAAkB;IAC/B,QAAQ,CAAC,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC;IAC7B,QAAQ,CAAC,OAAO,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAC9B,UAAU,IAAI,IAAI,CAAC;CACtB;AACD,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,eAAe,EAAE,IAAI,CAAC,eAAe,GAAG,kBAAkB,CAe3G;AACD,oBAAY,mBAAmB,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,eAAe,EAAE,GAAG,EAAE,IAAI,CAAC,cAAc,KAAK,OAAO,CAAC,CAAC,CAAC,CAAC;AACzG,oBAAY,kBAAkB,CAAC,CAAC,IAAI,OAAO,CAAC,MAAM,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;AAC9D,eAAO,MAAM,qBAAqB,YAAmB,MAAM,2DAmBrD,CAAC;AAEP,eAAO,MAAM,WAAW,aAAoB,KAAK,cAAc,KAAG,QAAQ,IAAI,CAM5E,CAAC"}
@@ -24,7 +24,10 @@ function createTrackedServer(port, requestListener) {
24
24
  };
25
25
  }
26
26
  exports.createTrackedServer = createTrackedServer;
27
- const serverListenAndHandle = async (port, handler) => new Promise((outerResolve, outerReject) => {
27
+ const serverListenAndHandle = async (port, handler) =>
28
+ // eslint-disable-next-line promise/param-names
29
+ new Promise((outerResolve, outerReject) => {
30
+ // eslint-disable-next-line promise/param-names
28
31
  const innerP = new Promise((innerResolve, innerReject) => {
29
32
  const httpServer = createTrackedServer(port, (req, res) => {
30
33
  // ignore favicon
@@ -1 +1 @@
1
- {"version":3,"file":"httpHelpers.js","sourceRoot":"","sources":["../src/httpHelpers.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;;;;AAEH,gDAAwB;AAQxB,SAAgB,mBAAmB,CAAC,IAAY,EAAE,eAAqC;IACnF,MAAM,MAAM,GAAG,cAAI,CAAC,YAAY,CAAC,eAAe,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IAC/D,MAAM,OAAO,GAAG,IAAI,GAAG,EAAU,CAAC;IAElC,MAAM,CAAC,EAAE,CAAC,YAAY,EAAE,CAAC,MAAM,EAAE,EAAE;QAC/B,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QACpB,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC;IACrD,CAAC,CAAC,CAAC;IAEH,OAAO;QACH,MAAM,EAAE,OAAO,EAAE,UAAU;YACvB,MAAM,CAAC,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,OAAO,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC;QAClD,CAAC;KACJ,CAAC;AACN,CAAC;AAfD,kDAeC;AAGM,MAAM,qBAAqB,GAAG,KAAK,EAAK,IAAY,EAAE,OAA+B,EAAyB,EAAE,CACnH,IAAI,OAAO,CAAC,CAAC,YAAY,EAAE,WAAW,EAAE,EAAE;IACtC,MAAM,MAAM,GAAG,IAAI,OAAO,CAAI,CAAC,YAAY,EAAE,WAAW,EAAE,EAAE;QACxD,MAAM,UAAU,GAAG,mBAAmB,CAAC,IAAI,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE;YACtD,iBAAiB;YACjB,IAAI,GAAG,CAAC,GAAG,KAAK,cAAc,EAAE;gBAC5B,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,cAAc,EAAE,CAAC,CAAC;gBACvD,GAAG,CAAC,GAAG,EAAE,CAAC;gBACV,OAAO;aACV;YACD,OAAO,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,UAAU,EAAE,CAAC,CAAC,IAAI,CACzD,CAAC,MAAM,EAAE,EAAE,CAAC,YAAY,CAAC,MAAM,CAAC,EAChC,CAAC,KAAK,EAAE,EAAE,CAAC,WAAW,CAAC,KAAK,CAAC,CAChC,CAAC;QACN,CAAC,CAAC,CAAC;QACH,YAAY,CAAC,KAAK,IAAI,EAAE,CAAC,MAAM,CAAC,CAAC;IACrC,CAAC,CAAC,CAAC;AACP,CAAC,CAAC,CAAC;AAjBM,QAAA,qBAAqB,yBAiB3B;AAEA,MAAM,WAAW,GAAG,KAAK,EAAE,QAA6B,EAAiB,EAAE,CAAC,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;IAC/G,IAAI;QACA,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;KACzB;IAAC,OAAO,KAAK,EAAE;QACZ,MAAM,CAAC,KAAK,CAAC,CAAC;KACjB;AACL,CAAC,CAAC,CAAC;AANU,QAAA,WAAW,eAMrB","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport http from \"http\";\nimport { Socket } from \"net\";\n\nexport interface ITrackedHttpServer {\n readonly server: http.Server;\n readonly sockets: Set<Socket>;\n fullyClose(): void;\n}\nexport function createTrackedServer(port: number, requestListener: http.RequestListener): ITrackedHttpServer {\n const server = http.createServer(requestListener).listen(port);\n const sockets = new Set<Socket>();\n\n server.on(\"connection\", (socket) => {\n sockets.add(socket);\n socket.on(\"close\", () => sockets.delete(socket));\n });\n\n return {\n server, sockets, fullyClose() {\n server.close();\n sockets.forEach((socket) => socket.destroy());\n },\n };\n}\nexport type OnceListenerHandler<T> = (req: http.IncomingMessage, res: http.ServerResponse) => Promise<T>;\nexport type OnceListenerResult<T> = Promise<() => Promise<T>>;\nexport const serverListenAndHandle = async <T>(port: number, handler: OnceListenerHandler<T>): OnceListenerResult<T> =>\n new Promise((outerResolve, outerReject) => {\n const innerP = new Promise<T>((innerResolve, innerReject) => {\n const httpServer = createTrackedServer(port, (req, res) => {\n // ignore favicon\n if (req.url === \"/favicon.ico\") {\n res.writeHead(200, { \"Content-Type\": \"image/x-icon\" });\n res.end();\n return;\n }\n handler(req, res).finally(() => httpServer.fullyClose()).then(\n (result) => innerResolve(result),\n (error) => innerReject(error),\n );\n });\n outerResolve(async () => innerP);\n });\n });\n\nexport const endResponse = async (response: http.ServerResponse): Promise<void> => new Promise((resolve, reject) => {\n try {\n response.end(resolve);\n } catch (error) {\n reject(error);\n }\n});\n"]}
1
+ {"version":3,"file":"httpHelpers.js","sourceRoot":"","sources":["../src/httpHelpers.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;;;;AAEH,gDAAwB;AAQxB,SAAgB,mBAAmB,CAAC,IAAY,EAAE,eAAqC;IACnF,MAAM,MAAM,GAAG,cAAI,CAAC,YAAY,CAAC,eAAe,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IAC/D,MAAM,OAAO,GAAG,IAAI,GAAG,EAAU,CAAC;IAElC,MAAM,CAAC,EAAE,CAAC,YAAY,EAAE,CAAC,MAAM,EAAE,EAAE;QAC/B,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QACpB,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC;IACrD,CAAC,CAAC,CAAC;IAEH,OAAO;QACH,MAAM,EAAE,OAAO,EAAE,UAAU;YACvB,MAAM,CAAC,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,OAAO,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC;QAClD,CAAC;KACJ,CAAC;AACN,CAAC;AAfD,kDAeC;AAGM,MAAM,qBAAqB,GAAG,KAAK,EAAK,IAAY,EAAE,OAA+B,EAAyB,EAAE;AACnH,+CAA+C;AAC/C,IAAI,OAAO,CAAC,CAAC,YAAY,EAAE,WAAW,EAAE,EAAE;IAC1C,+CAA+C;IAC3C,MAAM,MAAM,GAAG,IAAI,OAAO,CAAI,CAAC,YAAY,EAAE,WAAW,EAAE,EAAE;QACxD,MAAM,UAAU,GAAG,mBAAmB,CAAC,IAAI,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE;YACtD,iBAAiB;YACjB,IAAI,GAAG,CAAC,GAAG,KAAK,cAAc,EAAE;gBAC5B,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,cAAc,EAAE,CAAC,CAAC;gBACvD,GAAG,CAAC,GAAG,EAAE,CAAC;gBACV,OAAO;aACV;YACD,OAAO,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,UAAU,EAAE,CAAC,CAAC,IAAI,CACzD,CAAC,MAAM,EAAE,EAAE,CAAC,YAAY,CAAC,MAAM,CAAC,EAChC,CAAC,KAAK,EAAE,EAAE,CAAC,WAAW,CAAC,KAAK,CAAC,CAChC,CAAC;QACN,CAAC,CAAC,CAAC;QACH,YAAY,CAAC,KAAK,IAAI,EAAE,CAAC,MAAM,CAAC,CAAC;IACrC,CAAC,CAAC,CAAC;AACP,CAAC,CAAC,CAAC;AAnBM,QAAA,qBAAqB,yBAmB3B;AAEA,MAAM,WAAW,GAAG,KAAK,EAAE,QAA6B,EAAiB,EAAE,CAAC,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;IAC/G,IAAI;QACA,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;KACzB;IAAC,OAAO,KAAK,EAAE;QACZ,MAAM,CAAC,KAAK,CAAC,CAAC;KACjB;AACL,CAAC,CAAC,CAAC;AANU,QAAA,WAAW,eAMrB","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport http from \"http\";\nimport { Socket } from \"net\";\n\nexport interface ITrackedHttpServer {\n readonly server: http.Server;\n readonly sockets: Set<Socket>;\n fullyClose(): void;\n}\nexport function createTrackedServer(port: number, requestListener: http.RequestListener): ITrackedHttpServer {\n const server = http.createServer(requestListener).listen(port);\n const sockets = new Set<Socket>();\n\n server.on(\"connection\", (socket) => {\n sockets.add(socket);\n socket.on(\"close\", () => sockets.delete(socket));\n });\n\n return {\n server, sockets, fullyClose() {\n server.close();\n sockets.forEach((socket) => socket.destroy());\n },\n };\n}\nexport type OnceListenerHandler<T> = (req: http.IncomingMessage, res: http.ServerResponse) => Promise<T>;\nexport type OnceListenerResult<T> = Promise<() => Promise<T>>;\nexport const serverListenAndHandle = async <T>(port: number, handler: OnceListenerHandler<T>): OnceListenerResult<T> =>\n // eslint-disable-next-line promise/param-names\n new Promise((outerResolve, outerReject) => {\n // eslint-disable-next-line promise/param-names\n const innerP = new Promise<T>((innerResolve, innerReject) => {\n const httpServer = createTrackedServer(port, (req, res) => {\n // ignore favicon\n if (req.url === \"/favicon.ico\") {\n res.writeHead(200, { \"Content-Type\": \"image/x-icon\" });\n res.end();\n return;\n }\n handler(req, res).finally(() => httpServer.fullyClose()).then(\n (result) => innerResolve(result),\n (error) => innerReject(error),\n );\n });\n outerResolve(async () => innerP);\n });\n });\n\nexport const endResponse = async (response: http.ServerResponse): Promise<void> => new Promise((resolve, reject) => {\n try {\n response.end(resolve);\n } catch (error) {\n reject(error);\n }\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 = "0.54.2";
8
+ export declare const pkgVersion = "0.56.0-49831";
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,WAAW,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,iBAAiB,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 = "0.54.2";
11
+ exports.pkgVersion = "0.56.0-49831";
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,QAAQ,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 = \"0.54.2\";\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,cAAc,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 = \"0.56.0-49831\";\n"]}
@@ -3,7 +3,7 @@
3
3
  * Licensed under the MIT License.
4
4
  */
5
5
  import { ITree } from "@fluidframework/protocol-definitions";
6
- export declare const gcBlobKey = "gc";
6
+ export declare const gcBlobPrefix = "__gc";
7
7
  export interface ISnapshotNormalizerConfig {
8
8
  blobsToNormalize?: string[];
9
9
  }
@@ -1 +1 @@
1
- {"version":3,"file":"snapshotNormalizer.d.ts","sourceRoot":"","sources":["../src/snapshotNormalizer.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EACH,KAAK,EAGR,MAAM,sCAAsC,CAAC;AAE9C,eAAO,MAAM,SAAS,OAAO,CAAC;AAI9B,MAAM,WAAW,yBAAyB;IAEtC,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAC;CAC/B;AAiFD;;;;;;;;GAQG;AACH,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,KAAK,EAAE,MAAM,CAAC,EAAE,yBAAyB,GAAG,KAAK,CAsChG"}
1
+ {"version":3,"file":"snapshotNormalizer.d.ts","sourceRoot":"","sources":["../src/snapshotNormalizer.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EACH,KAAK,EAGR,MAAM,sCAAsC,CAAC;AAE9C,eAAO,MAAM,YAAY,SAAS,CAAC;AAEnC,MAAM,WAAW,yBAAyB;IAEtC,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAC;CAC/B;AAmFD;;;;;;;;GAQG;AACH,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,KAAK,EAAE,MAAM,CAAC,EAAE,yBAAyB,GAAG,KAAK,CAsChG"}
@@ -4,12 +4,10 @@
4
4
  * Licensed under the MIT License.
5
5
  */
6
6
  Object.defineProperty(exports, "__esModule", { value: true });
7
- exports.getNormalizedSnapshot = exports.gcBlobKey = void 0;
7
+ exports.getNormalizedSnapshot = exports.gcBlobPrefix = void 0;
8
8
  const protocol_base_1 = require("@fluidframework/protocol-base");
9
9
  const protocol_definitions_1 = require("@fluidframework/protocol-definitions");
10
- exports.gcBlobKey = "gc";
11
- // A list of runtime blob paths whose contents should be normalized.
12
- const runtimeBlobsToNormalize = [exports.gcBlobKey];
10
+ exports.gcBlobPrefix = "__gc";
13
11
  /**
14
12
  * Function that deep sorts an array. It handles cases where array elements are objects or arrays.
15
13
  * @returns the sorted array.
@@ -68,13 +66,15 @@ function getDeepSortedObject(obj) {
68
66
  */
69
67
  function getNormalizedBlobContent(blobContent, blobName) {
70
68
  let content = blobContent;
71
- if (blobName === exports.gcBlobKey) {
72
- // GC blobs may contain "unrefTimestamp" - The time the corresponding object became unreferenced. This is the
73
- // timestamp of the last op processed and can differ between clients depending on when GC was run. It will be
74
- // undefined if no ops were processed before running GC. So, remove it for the purposes of comparing snapshots.
75
- const gcDetails = JSON.parse(content);
76
- delete gcDetails.unrefTimestamp;
77
- content = JSON.stringify(gcDetails);
69
+ if (blobName.startsWith(exports.gcBlobPrefix)) {
70
+ // GC blobs may contain `unreferencedTimestampMs` for node that became unreferenced. This is the timestamp
71
+ // of the last op processed or current timestamp and can differ between clients depending on when GC was run.
72
+ // So, remove it for the purposes of comparing snapshots.
73
+ const gcState = JSON.parse(content);
74
+ for (const [, data] of Object.entries(gcState.gcNodes)) {
75
+ delete data.unreferencedTimestampMs;
76
+ }
77
+ content = JSON.stringify(gcState);
78
78
  }
79
79
  // Deep sort the content if it's parseable.
80
80
  try {
@@ -103,14 +103,14 @@ function getNormalizedSnapshot(snapshot, config) {
103
103
  var _a;
104
104
  // Merge blobs to normalize in the config with runtime blobs to normalize. The contents of these blobs will be
105
105
  // parsed and deep sorted.
106
- const blobsToNormalize = [...runtimeBlobsToNormalize, ...(_a = config === null || config === void 0 ? void 0 : config.blobsToNormalize) !== null && _a !== void 0 ? _a : []];
106
+ const blobsToNormalize = [...(_a = config === null || config === void 0 ? void 0 : config.blobsToNormalize) !== null && _a !== void 0 ? _a : []];
107
107
  const normalizedEntries = [];
108
108
  for (const entry of snapshot.entries) {
109
109
  switch (entry.type) {
110
110
  case protocol_definitions_1.TreeEntry.Blob: {
111
111
  let contents = entry.value.contents;
112
- // If this blob has to be normalized, parse and sort the blob contents first.
113
- if (blobsToNormalize.includes(entry.path)) {
112
+ // If this blob has to be normalized or it's a GC blob, parse and sort the blob contents first.
113
+ if (blobsToNormalize.includes(entry.path) || entry.path.startsWith(exports.gcBlobPrefix)) {
114
114
  contents = getNormalizedBlobContent(contents, entry.path);
115
115
  }
116
116
  normalizedEntries.push(new protocol_base_1.BlobTreeEntry(entry.path, contents));
@@ -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 { AttachmentTreeEntry, BlobTreeEntry, TreeTreeEntry } from \"@fluidframework/protocol-base\";\nimport {\n ITree,\n TreeEntry,\n ITreeEntry,\n} from \"@fluidframework/protocol-definitions\";\n\nexport const gcBlobKey = \"gc\";\n// A list of runtime blob paths whose contents should be normalized.\nconst runtimeBlobsToNormalize = [ gcBlobKey ];\n\nexport interface ISnapshotNormalizerConfig {\n // The paths of blobs whose contents should be normalized.\n blobsToNormalize?: string[];\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: any[]): any[] {\n const sortedArray: any[] = [];\n // Sort arrays and objects, if any, in the array.\n for (const element of array) {\n if (Array.isArray(element)) {\n sortedArray.push(getDeepSortedArray(element));\n } else if (element instanceof Object) {\n sortedArray.push(getDeepSortedObject(element));\n } else {\n sortedArray.push(element);\n }\n }\n\n // Now that all the arrays and objects in this array's elements have been sorted, sort it by comparing each\n // element's stringified version.\n const sortFn = (elem1: any, elem2: any) => {\n const serializedElem1 = JSON.stringify(elem1);\n const serializedElem2 = JSON.stringify(elem2);\n return serializedElem1.localeCompare(serializedElem2);\n };\n // eslint-disable-next-line @typescript-eslint/no-unsafe-return\n return sortedArray.sort(sortFn);\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(obj: any): any {\n const sortedObj: any = {};\n // Sort the object keys first. Then sort arrays and objects, if any, in the object.\n const keys = Object.keys(obj).sort();\n for (const key of keys) {\n const value = obj[key];\n if (Array.isArray(value)) {\n sortedObj[key] = getDeepSortedArray(value);\n } else if (value instanceof Object) {\n sortedObj[key] = getDeepSortedObject(value);\n } else {\n sortedObj[key] = value;\n }\n }\n // eslint-disable-next-line @typescript-eslint/no-unsafe-return\n return 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 let content = blobContent;\n if (blobName === gcBlobKey) {\n // GC blobs may contain \"unrefTimestamp\" - The time the corresponding object became unreferenced. This is the\n // timestamp of the last op processed and can differ between clients depending on when GC was run. It will be\n // undefined if no ops were processed before running GC. So, remove it for the purposes of comparing snapshots.\n const gcDetails = JSON.parse(content);\n delete gcDetails.unrefTimestamp;\n content = JSON.stringify(gcDetails);\n }\n\n // Deep sort the content if it's parseable.\n try {\n let contentObj = JSON.parse(content);\n if (Array.isArray(contentObj)) {\n contentObj = getDeepSortedArray(contentObj);\n } else if (contentObj instanceof Object) {\n contentObj = getDeepSortedObject(contentObj);\n }\n content = JSON.stringify(contentObj);\n } catch {}\n return 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 */\nexport function getNormalizedSnapshot(snapshot: ITree, config?: ISnapshotNormalizerConfig): ITree {\n // Merge blobs to normalize in the config with runtime blobs to normalize. The contents of these blobs will be\n // parsed and deep sorted.\n const blobsToNormalize = [ ...runtimeBlobsToNormalize, ...config?.blobsToNormalize ?? [] ];\n const normalizedEntries: ITreeEntry[] = [];\n\n for (const entry of snapshot.entries) {\n switch (entry.type) {\n case TreeEntry.Blob: {\n let contents = entry.value.contents;\n // If this blob has to be normalized, parse and sort the blob contents first.\n if (blobsToNormalize.includes(entry.path)) {\n contents = getNormalizedBlobContent(contents, entry.path);\n }\n normalizedEntries.push(new BlobTreeEntry(entry.path, contents));\n break;\n }\n case TreeEntry.Tree: {\n normalizedEntries.push(new TreeTreeEntry(entry.path, getNormalizedSnapshot(entry.value, config)));\n break;\n }\n case TreeEntry.Attachment: {\n normalizedEntries.push(new AttachmentTreeEntry(entry.path, (entry.value).id));\n break;\n }\n\n default:\n throw new Error(\"Unknown entry type\");\n }\n }\n\n // Sory the tree entries based on their path.\n normalizedEntries.sort((a, b) => a.path.localeCompare(b.path));\n\n return {\n entries: normalizedEntries,\n id: snapshot.id,\n };\n}\n"]}
1
+ {"version":3,"file":"snapshotNormalizer.js","sourceRoot":"","sources":["../src/snapshotNormalizer.ts"],"names":[],"mappings":";AAAA;;;GAGG;;;AAEH,iEAAkG;AAClG,+EAI8C;AAEjC,QAAA,YAAY,GAAG,MAAM,CAAC;AAOnC;;;GAGG;AACH,SAAS,kBAAkB,CAAC,KAAY;IACpC,MAAM,WAAW,GAAU,EAAE,CAAC;IAC9B,iDAAiD;IACjD,KAAK,MAAM,OAAO,IAAI,KAAK,EAAE;QACzB,IAAI,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE;YACxB,WAAW,CAAC,IAAI,CAAC,kBAAkB,CAAC,OAAO,CAAC,CAAC,CAAC;SACjD;aAAM,IAAI,OAAO,YAAY,MAAM,EAAE;YAClC,WAAW,CAAC,IAAI,CAAC,mBAAmB,CAAC,OAAO,CAAC,CAAC,CAAC;SAClD;aAAM;YACH,WAAW,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;SAC7B;KACJ;IAED,2GAA2G;IAC3G,iCAAiC;IACjC,MAAM,MAAM,GAAG,CAAC,KAAU,EAAE,KAAU,EAAE,EAAE;QACtC,MAAM,eAAe,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;QAC9C,MAAM,eAAe,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;QAC9C,OAAO,eAAe,CAAC,aAAa,CAAC,eAAe,CAAC,CAAC;IAC1D,CAAC,CAAC;IACF,+DAA+D;IAC/D,OAAO,WAAW,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;AACpC,CAAC;AAED;;;GAGG;AACH,SAAS,mBAAmB,CAAC,GAAQ;IACjC,MAAM,SAAS,GAAQ,EAAE,CAAC;IAC1B,mFAAmF;IACnF,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,CAAC;IACrC,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE;QACpB,MAAM,KAAK,GAAG,GAAG,CAAC,GAAG,CAAC,CAAC;QACvB,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,EAAE;YACtB,SAAS,CAAC,GAAG,CAAC,GAAG,kBAAkB,CAAC,KAAK,CAAC,CAAC;SAC9C;aAAM,IAAI,KAAK,YAAY,MAAM,EAAE;YAChC,SAAS,CAAC,GAAG,CAAC,GAAG,mBAAmB,CAAC,KAAK,CAAC,CAAC;SAC/C;aAAM;YACH,SAAS,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;SAC1B;KACJ;IACD,+DAA+D;IAC/D,OAAO,SAAS,CAAC;AACrB,CAAC;AAED;;;;GAIG;AACH,SAAS,wBAAwB,CAAC,WAAmB,EAAE,QAAgB;IACnE,IAAI,OAAO,GAAG,WAAW,CAAC;IAC1B,IAAI,QAAQ,CAAC,UAAU,CAAC,oBAAY,CAAC,EAAE;QACnC,0GAA0G;QAC1G,6GAA6G;QAC7G,yDAAyD;QACzD,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QACpC,KAAK,MAAM,CAAC,EAAE,IAAI,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE;YACpD,OAAQ,IAAY,CAAC,uBAAuB,CAAC;SAChD;QACD,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;KACrC;IAED,2CAA2C;IAC3C,IAAI;QACA,IAAI,UAAU,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;QACrC,IAAI,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE;YAC3B,UAAU,GAAG,kBAAkB,CAAC,UAAU,CAAC,CAAC;SAC/C;aAAM,IAAI,UAAU,YAAY,MAAM,EAAE;YACrC,UAAU,GAAG,mBAAmB,CAAC,UAAU,CAAC,CAAC;SAChD;QACD,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,CAAC;KACxC;IAAC,WAAM,GAAE;IACV,OAAO,OAAO,CAAC;AACnB,CAAC;AAED;;;;;;;;GAQG;AACH,SAAgB,qBAAqB,CAAC,QAAe,EAAE,MAAkC;;IACrF,8GAA8G;IAC9G,0BAA0B;IAC1B,MAAM,gBAAgB,GAAG,CAAE,SAAG,MAAM,aAAN,MAAM,uBAAN,MAAM,CAAE,gBAAgB,mCAAI,EAAE,CAAE,CAAC;IAC/D,MAAM,iBAAiB,GAAiB,EAAE,CAAC;IAE3C,KAAK,MAAM,KAAK,IAAI,QAAQ,CAAC,OAAO,EAAE;QAClC,QAAQ,KAAK,CAAC,IAAI,EAAE;YAChB,KAAK,gCAAS,CAAC,IAAI,CAAC,CAAC;gBACjB,IAAI,QAAQ,GAAG,KAAK,CAAC,KAAK,CAAC,QAAQ,CAAC;gBACpC,+FAA+F;gBAC/F,IAAI,gBAAgB,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,KAAK,CAAC,IAAI,CAAC,UAAU,CAAC,oBAAY,CAAC,EAAE;oBAC9E,QAAQ,GAAG,wBAAwB,CAAC,QAAQ,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;iBAC7D;gBACD,iBAAiB,CAAC,IAAI,CAAC,IAAI,6BAAa,CAAC,KAAK,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC,CAAC;gBAChE,MAAM;aACT;YACD,KAAK,gCAAS,CAAC,IAAI,CAAC,CAAC;gBACjB,iBAAiB,CAAC,IAAI,CAAC,IAAI,6BAAa,CAAC,KAAK,CAAC,IAAI,EAAE,qBAAqB,CAAC,KAAK,CAAC,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,CAAC;gBAClG,MAAM;aACT;YACD,KAAK,gCAAS,CAAC,UAAU,CAAC,CAAC;gBACvB,iBAAiB,CAAC,IAAI,CAAC,IAAI,mCAAmB,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;gBAC9E,MAAM;aACT;YAED;gBACI,MAAM,IAAI,KAAK,CAAC,oBAAoB,CAAC,CAAC;SAC7C;KACJ;IAED,6CAA6C;IAC7C,iBAAiB,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;IAE/D,OAAO;QACH,OAAO,EAAE,iBAAiB;QAC1B,EAAE,EAAE,QAAQ,CAAC,EAAE;KAClB,CAAC;AACN,CAAC;AAtCD,sDAsCC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport { AttachmentTreeEntry, BlobTreeEntry, TreeTreeEntry } from \"@fluidframework/protocol-base\";\nimport {\n ITree,\n TreeEntry,\n ITreeEntry,\n} from \"@fluidframework/protocol-definitions\";\n\nexport const gcBlobPrefix = \"__gc\";\n\nexport interface ISnapshotNormalizerConfig {\n // The paths of blobs whose contents should be normalized.\n blobsToNormalize?: string[];\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: any[]): any[] {\n const sortedArray: any[] = [];\n // Sort arrays and objects, if any, in the array.\n for (const element of array) {\n if (Array.isArray(element)) {\n sortedArray.push(getDeepSortedArray(element));\n } else if (element instanceof Object) {\n sortedArray.push(getDeepSortedObject(element));\n } else {\n sortedArray.push(element);\n }\n }\n\n // Now that all the arrays and objects in this array's elements have been sorted, sort it by comparing each\n // element's stringified version.\n const sortFn = (elem1: any, elem2: any) => {\n const serializedElem1 = JSON.stringify(elem1);\n const serializedElem2 = JSON.stringify(elem2);\n return serializedElem1.localeCompare(serializedElem2);\n };\n // eslint-disable-next-line @typescript-eslint/no-unsafe-return\n return sortedArray.sort(sortFn);\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(obj: any): any {\n const sortedObj: any = {};\n // Sort the object keys first. Then sort arrays and objects, if any, in the object.\n const keys = Object.keys(obj).sort();\n for (const key of keys) {\n const value = obj[key];\n if (Array.isArray(value)) {\n sortedObj[key] = getDeepSortedArray(value);\n } else if (value instanceof Object) {\n sortedObj[key] = getDeepSortedObject(value);\n } else {\n sortedObj[key] = value;\n }\n }\n // eslint-disable-next-line @typescript-eslint/no-unsafe-return\n return 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 let content = blobContent;\n if (blobName.startsWith(gcBlobPrefix)) {\n // GC blobs may contain `unreferencedTimestampMs` for node that became unreferenced. This is the timestamp\n // of the last op processed or current timestamp and can differ between clients depending on when GC was run.\n // So, remove it for the purposes of comparing snapshots.\n const gcState = JSON.parse(content);\n for (const [, data] of Object.entries(gcState.gcNodes)) {\n delete (data as any).unreferencedTimestampMs;\n }\n content = JSON.stringify(gcState);\n }\n\n // Deep sort the content if it's parseable.\n try {\n let contentObj = JSON.parse(content);\n if (Array.isArray(contentObj)) {\n contentObj = getDeepSortedArray(contentObj);\n } else if (contentObj instanceof Object) {\n contentObj = getDeepSortedObject(contentObj);\n }\n content = JSON.stringify(contentObj);\n } catch {}\n return 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 */\nexport function getNormalizedSnapshot(snapshot: ITree, config?: ISnapshotNormalizerConfig): ITree {\n // Merge blobs to normalize in the config with runtime blobs to normalize. The contents of these blobs will be\n // parsed and deep sorted.\n const blobsToNormalize = [ ...config?.blobsToNormalize ?? [] ];\n const normalizedEntries: ITreeEntry[] = [];\n\n for (const entry of snapshot.entries) {\n switch (entry.type) {\n case TreeEntry.Blob: {\n let contents = entry.value.contents;\n // If this blob has to be normalized or it's a GC blob, parse and sort the blob contents first.\n if (blobsToNormalize.includes(entry.path) || entry.path.startsWith(gcBlobPrefix)) {\n contents = getNormalizedBlobContent(contents, entry.path);\n }\n normalizedEntries.push(new BlobTreeEntry(entry.path, contents));\n break;\n }\n case TreeEntry.Tree: {\n normalizedEntries.push(new TreeTreeEntry(entry.path, getNormalizedSnapshot(entry.value, config)));\n break;\n }\n case TreeEntry.Attachment: {\n normalizedEntries.push(new AttachmentTreeEntry(entry.path, (entry.value).id));\n break;\n }\n\n default:\n throw new Error(\"Unknown entry type\");\n }\n }\n\n // Sory the tree entries based on their path.\n normalizedEntries.sort((a, b) => a.path.localeCompare(b.path));\n\n return {\n entries: normalizedEntries,\n id: snapshot.id,\n };\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"fluidToolRC.d.ts","sourceRoot":"","sources":["../src/fluidToolRC.ts"],"names":[],"mappings":"AAAA;;;GAGG;AASH,OAAO,EAAE,WAAW,EAAE,MAAM,mCAAmC,CAAC;AAEhE,MAAM,WAAW,WAAW,CAAC,IAAI,EAAE,MAAM;IACrC,GAAG,CAAC,GAAG,EAAE,IAAI,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IAC5C,IAAI,CAAC,GAAG,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9C,IAAI,CAAC,CAAC,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;CACnD;AAED,MAAM,WAAW,UAAU;IACvB,MAAM,CAAC,EAAE;QACL,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,IAAI,EAAE;YACF,CAAC,GAAG,EAAE,MAAM,GAAG;gBACX,OAAO,CAAC,EAAE,WAAW,CAAC;gBACtB,IAAI,CAAC,EAAE,WAAW,CAAA;aACrB,CAAA;SACJ,CAAA;KACJ,CAAA;CACJ;AAID,wBAAsB,MAAM,IAAI,OAAO,CAAC,UAAU,CAAC,CAclD;AAED,wBAAsB,MAAM,CAAC,EAAE,EAAE,UAAU,iBAI1C;AAGD,wBAAsB,MAAM,iBAS3B"}
1
+ {"version":3,"file":"fluidToolRC.d.ts","sourceRoot":"","sources":["../src/fluidToolRC.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAOH,OAAO,EAAE,WAAW,EAAE,MAAM,mCAAmC,CAAC;AAEhE,MAAM,WAAW,WAAW,CAAC,IAAI,EAAE,MAAM;IACrC,GAAG,CAAC,GAAG,EAAE,IAAI,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAAC;IAC5C,IAAI,CAAC,GAAG,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC9C,IAAI,CAAC,CAAC,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;CACnD;AAED,MAAM,WAAW,UAAU;IACvB,MAAM,CAAC,EAAE;QACL,OAAO,CAAC,EAAE,MAAM,CAAC;QACjB,IAAI,EAAE;YACF,CAAC,GAAG,EAAE,MAAM,GAAG;gBACX,OAAO,CAAC,EAAE,WAAW,CAAC;gBACtB,IAAI,CAAC,EAAE,WAAW,CAAA;aACrB,CAAA;SACJ,CAAA;KACJ,CAAA;CACJ;AAID,wBAAsB,MAAM,IAAI,OAAO,CAAC,UAAU,CAAC,CAclD;AAED,wBAAsB,MAAM,CAAC,EAAE,EAAE,UAAU,iBAI1C;AAED,wBAAsB,MAAM,iBAS3B"}
@@ -2,7 +2,6 @@
2
2
  * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
3
3
  * Licensed under the MIT License.
4
4
  */
5
- /* eslint-disable unicorn/filename-case */
6
5
  import fs from "fs";
7
6
  import os from "os";
8
7
  import path from "path";
@@ -30,7 +29,6 @@ export async function saveRC(rc) {
30
29
  const content = JSON.stringify(rc, undefined, 2);
31
30
  return writeFile(getRCFileName(), Buffer.from(content, "utf8"));
32
31
  }
33
- // eslint-disable-next-line prefer-arrow/prefer-arrow-functions
34
32
  export async function lockRC() {
35
33
  // eslint-disable-next-line @typescript-eslint/no-unsafe-return
36
34
  return lock(getRCFileName(), {
@@ -1 +1 @@
1
- {"version":3,"file":"fluidToolRC.js","sourceRoot":"","sources":["../src/fluidToolRC.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,0CAA0C;AAE1C,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAC;AAqBvC,MAAM,aAAa,GAAG,GAAG,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,cAAc,CAAC,CAAC;AAEpE,MAAM,CAAC,KAAK,UAAU,MAAM;IACxB,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC;IAC7C,MAAM,MAAM,GAAG,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC;IACzC,MAAM,QAAQ,GAAG,aAAa,EAAE,CAAC;IACjC,IAAI,MAAM,MAAM,CAAC,QAAQ,CAAC,EAAE;QACxB,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,QAAQ,CAAC,CAAC;QACrC,IAAI;YACA,+DAA+D;YAC/D,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC;SAC3C;QAAC,OAAO,CAAC,EAAE;YACR,UAAU;SACb;KACJ;IACD,OAAO,EAAE,CAAC;AACd,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,MAAM,CAAC,EAAc;IACvC,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC;IAC/C,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC,EAAE,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC;IACjD,OAAO,SAAS,CAAC,aAAa,EAAE,EAAE,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC;AACpE,CAAC;AAED,+DAA+D;AAC/D,MAAM,CAAC,KAAK,UAAU,MAAM;IACxB,+DAA+D;IAC/D,OAAO,IAAI,CAAC,aAAa,EAAE,EAAE;QACzB,OAAO,EAAE;YACL,OAAO,EAAE,IAAI;SAChB;QACD,KAAK,EAAC,KAAK;QACX,QAAQ,EAAE,KAAK;KAClB,CAAC,CAAC;AACP,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\n/* eslint-disable unicorn/filename-case */\n\nimport fs from \"fs\";\nimport os from \"os\";\nimport path from \"path\";\nimport util from \"util\";\nimport { lock } from \"proper-lockfile\";\nimport { IOdspTokens } from \"@fluidframework/odsp-doclib-utils\";\n\nexport interface IAsyncCache<TKey, TValue> {\n get(key: TKey): Promise<TValue | undefined>;\n save(key: TKey, value: TValue): Promise<void>;\n lock<T>(callback: () => Promise<T>): Promise<T>;\n}\n\nexport interface IResources {\n tokens?: {\n version?: number;\n data: {\n [key: string]: {\n storage?: IOdspTokens,\n push?: IOdspTokens\n }\n }\n }\n}\n\nconst getRCFileName = () => path.join(os.homedir(), \".fluidtoolrc\");\n\nexport async function loadRC(): Promise<IResources> {\n const readFile = util.promisify(fs.readFile);\n const exists = util.promisify(fs.exists);\n const fileName = getRCFileName();\n if (await exists(fileName)) {\n const buf = await readFile(fileName);\n try {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-return\n return JSON.parse(buf.toString(\"utf8\"));\n } catch (e) {\n // Nothing\n }\n }\n return {};\n}\n\nexport async function saveRC(rc: IResources) {\n const writeFile = util.promisify(fs.writeFile);\n const content = JSON.stringify(rc, undefined, 2);\n return writeFile(getRCFileName(), Buffer.from(content, \"utf8\"));\n}\n\n// eslint-disable-next-line prefer-arrow/prefer-arrow-functions\nexport async function lockRC() {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-return\n return lock(getRCFileName(), {\n retries: {\n forever: true,\n },\n stale:60000,\n realpath: false,\n });\n}\n"]}
1
+ {"version":3,"file":"fluidToolRC.js","sourceRoot":"","sources":["../src/fluidToolRC.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,EAAE,MAAM,IAAI,CAAC;AACpB,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,IAAI,EAAE,MAAM,iBAAiB,CAAC;AAqBvC,MAAM,aAAa,GAAG,GAAG,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,cAAc,CAAC,CAAC;AAEpE,MAAM,CAAC,KAAK,UAAU,MAAM;IACxB,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC,QAAQ,CAAC,CAAC;IAC7C,MAAM,MAAM,GAAG,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC;IACzC,MAAM,QAAQ,GAAG,aAAa,EAAE,CAAC;IACjC,IAAI,MAAM,MAAM,CAAC,QAAQ,CAAC,EAAE;QACxB,MAAM,GAAG,GAAG,MAAM,QAAQ,CAAC,QAAQ,CAAC,CAAC;QACrC,IAAI;YACA,+DAA+D;YAC/D,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAC;SAC3C;QAAC,OAAO,CAAC,EAAE;YACR,UAAU;SACb;KACJ;IACD,OAAO,EAAE,CAAC;AACd,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,MAAM,CAAC,EAAc;IACvC,MAAM,SAAS,GAAG,IAAI,CAAC,SAAS,CAAC,EAAE,CAAC,SAAS,CAAC,CAAC;IAC/C,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,CAAC,EAAE,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC;IACjD,OAAO,SAAS,CAAC,aAAa,EAAE,EAAE,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC,CAAC;AACpE,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,MAAM;IACxB,+DAA+D;IAC/D,OAAO,IAAI,CAAC,aAAa,EAAE,EAAE;QACzB,OAAO,EAAE;YACL,OAAO,EAAE,IAAI;SAChB;QACD,KAAK,EAAC,KAAK;QACX,QAAQ,EAAE,KAAK;KAClB,CAAC,CAAC;AACP,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport fs from \"fs\";\nimport os from \"os\";\nimport path from \"path\";\nimport util from \"util\";\nimport { lock } from \"proper-lockfile\";\nimport { IOdspTokens } from \"@fluidframework/odsp-doclib-utils\";\n\nexport interface IAsyncCache<TKey, TValue> {\n get(key: TKey): Promise<TValue | undefined>;\n save(key: TKey, value: TValue): Promise<void>;\n lock<T>(callback: () => Promise<T>): Promise<T>;\n}\n\nexport interface IResources {\n tokens?: {\n version?: number;\n data: {\n [key: string]: {\n storage?: IOdspTokens,\n push?: IOdspTokens\n }\n }\n }\n}\n\nconst getRCFileName = () => path.join(os.homedir(), \".fluidtoolrc\");\n\nexport async function loadRC(): Promise<IResources> {\n const readFile = util.promisify(fs.readFile);\n const exists = util.promisify(fs.exists);\n const fileName = getRCFileName();\n if (await exists(fileName)) {\n const buf = await readFile(fileName);\n try {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-return\n return JSON.parse(buf.toString(\"utf8\"));\n } catch (e) {\n // Nothing\n }\n }\n return {};\n}\n\nexport async function saveRC(rc: IResources) {\n const writeFile = util.promisify(fs.writeFile);\n const content = JSON.stringify(rc, undefined, 2);\n return writeFile(getRCFileName(), Buffer.from(content, \"utf8\"));\n}\n\nexport async function lockRC() {\n // eslint-disable-next-line @typescript-eslint/no-unsafe-return\n return lock(getRCFileName(), {\n retries: {\n forever: true,\n },\n stale:60000,\n realpath: false,\n });\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"httpHelpers.d.ts","sourceRoot":"","sources":["../src/httpHelpers.ts"],"names":[],"mappings":"AAAA;;;GAGG;;AAEH,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,MAAM,EAAE,MAAM,KAAK,CAAC;AAE7B,MAAM,WAAW,kBAAkB;IAC/B,QAAQ,CAAC,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC;IAC7B,QAAQ,CAAC,OAAO,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAC9B,UAAU,IAAI,IAAI,CAAC;CACtB;AACD,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,eAAe,EAAE,IAAI,CAAC,eAAe,GAAG,kBAAkB,CAe3G;AACD,oBAAY,mBAAmB,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,eAAe,EAAE,GAAG,EAAE,IAAI,CAAC,cAAc,KAAK,OAAO,CAAC,CAAC,CAAC,CAAC;AACzG,oBAAY,kBAAkB,CAAC,CAAC,IAAI,OAAO,CAAC,MAAM,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;AAC9D,eAAO,MAAM,qBAAqB,YAAmB,MAAM,2DAiBrD,CAAC;AAEP,eAAO,MAAM,WAAW,aAAoB,KAAK,cAAc,KAAG,QAAQ,IAAI,CAM5E,CAAC"}
1
+ {"version":3,"file":"httpHelpers.d.ts","sourceRoot":"","sources":["../src/httpHelpers.ts"],"names":[],"mappings":"AAAA;;;GAGG;;AAEH,OAAO,IAAI,MAAM,MAAM,CAAC;AACxB,OAAO,EAAE,MAAM,EAAE,MAAM,KAAK,CAAC;AAE7B,MAAM,WAAW,kBAAkB;IAC/B,QAAQ,CAAC,MAAM,EAAE,IAAI,CAAC,MAAM,CAAC;IAC7B,QAAQ,CAAC,OAAO,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IAC9B,UAAU,IAAI,IAAI,CAAC;CACtB;AACD,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,eAAe,EAAE,IAAI,CAAC,eAAe,GAAG,kBAAkB,CAe3G;AACD,oBAAY,mBAAmB,CAAC,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,eAAe,EAAE,GAAG,EAAE,IAAI,CAAC,cAAc,KAAK,OAAO,CAAC,CAAC,CAAC,CAAC;AACzG,oBAAY,kBAAkB,CAAC,CAAC,IAAI,OAAO,CAAC,MAAM,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC;AAC9D,eAAO,MAAM,qBAAqB,YAAmB,MAAM,2DAmBrD,CAAC;AAEP,eAAO,MAAM,WAAW,aAAoB,KAAK,cAAc,KAAG,QAAQ,IAAI,CAM5E,CAAC"}
@@ -17,7 +17,10 @@ export function createTrackedServer(port, requestListener) {
17
17
  },
18
18
  };
19
19
  }
20
- export const serverListenAndHandle = async (port, handler) => new Promise((outerResolve, outerReject) => {
20
+ export const serverListenAndHandle = async (port, handler) =>
21
+ // eslint-disable-next-line promise/param-names
22
+ new Promise((outerResolve, outerReject) => {
23
+ // eslint-disable-next-line promise/param-names
21
24
  const innerP = new Promise((innerResolve, innerReject) => {
22
25
  const httpServer = createTrackedServer(port, (req, res) => {
23
26
  // ignore favicon
@@ -1 +1 @@
1
- {"version":3,"file":"httpHelpers.js","sourceRoot":"","sources":["../src/httpHelpers.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,IAAI,MAAM,MAAM,CAAC;AAQxB,MAAM,UAAU,mBAAmB,CAAC,IAAY,EAAE,eAAqC;IACnF,MAAM,MAAM,GAAG,IAAI,CAAC,YAAY,CAAC,eAAe,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IAC/D,MAAM,OAAO,GAAG,IAAI,GAAG,EAAU,CAAC;IAElC,MAAM,CAAC,EAAE,CAAC,YAAY,EAAE,CAAC,MAAM,EAAE,EAAE;QAC/B,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QACpB,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC;IACrD,CAAC,CAAC,CAAC;IAEH,OAAO;QACH,MAAM,EAAE,OAAO,EAAE,UAAU;YACvB,MAAM,CAAC,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,OAAO,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC;QAClD,CAAC;KACJ,CAAC;AACN,CAAC;AAGD,MAAM,CAAC,MAAM,qBAAqB,GAAG,KAAK,EAAK,IAAY,EAAE,OAA+B,EAAyB,EAAE,CACnH,IAAI,OAAO,CAAC,CAAC,YAAY,EAAE,WAAW,EAAE,EAAE;IACtC,MAAM,MAAM,GAAG,IAAI,OAAO,CAAI,CAAC,YAAY,EAAE,WAAW,EAAE,EAAE;QACxD,MAAM,UAAU,GAAG,mBAAmB,CAAC,IAAI,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE;YACtD,iBAAiB;YACjB,IAAI,GAAG,CAAC,GAAG,KAAK,cAAc,EAAE;gBAC5B,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,cAAc,EAAE,CAAC,CAAC;gBACvD,GAAG,CAAC,GAAG,EAAE,CAAC;gBACV,OAAO;aACV;YACD,OAAO,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,UAAU,EAAE,CAAC,CAAC,IAAI,CACzD,CAAC,MAAM,EAAE,EAAE,CAAC,YAAY,CAAC,MAAM,CAAC,EAChC,CAAC,KAAK,EAAE,EAAE,CAAC,WAAW,CAAC,KAAK,CAAC,CAChC,CAAC;QACN,CAAC,CAAC,CAAC;QACH,YAAY,CAAC,KAAK,IAAI,EAAE,CAAC,MAAM,CAAC,CAAC;IACrC,CAAC,CAAC,CAAC;AACP,CAAC,CAAC,CAAC;AAEP,MAAM,CAAC,MAAM,WAAW,GAAG,KAAK,EAAE,QAA6B,EAAiB,EAAE,CAAC,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;IAC/G,IAAI;QACA,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;KACzB;IAAC,OAAO,KAAK,EAAE;QACZ,MAAM,CAAC,KAAK,CAAC,CAAC;KACjB;AACL,CAAC,CAAC,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport http from \"http\";\nimport { Socket } from \"net\";\n\nexport interface ITrackedHttpServer {\n readonly server: http.Server;\n readonly sockets: Set<Socket>;\n fullyClose(): void;\n}\nexport function createTrackedServer(port: number, requestListener: http.RequestListener): ITrackedHttpServer {\n const server = http.createServer(requestListener).listen(port);\n const sockets = new Set<Socket>();\n\n server.on(\"connection\", (socket) => {\n sockets.add(socket);\n socket.on(\"close\", () => sockets.delete(socket));\n });\n\n return {\n server, sockets, fullyClose() {\n server.close();\n sockets.forEach((socket) => socket.destroy());\n },\n };\n}\nexport type OnceListenerHandler<T> = (req: http.IncomingMessage, res: http.ServerResponse) => Promise<T>;\nexport type OnceListenerResult<T> = Promise<() => Promise<T>>;\nexport const serverListenAndHandle = async <T>(port: number, handler: OnceListenerHandler<T>): OnceListenerResult<T> =>\n new Promise((outerResolve, outerReject) => {\n const innerP = new Promise<T>((innerResolve, innerReject) => {\n const httpServer = createTrackedServer(port, (req, res) => {\n // ignore favicon\n if (req.url === \"/favicon.ico\") {\n res.writeHead(200, { \"Content-Type\": \"image/x-icon\" });\n res.end();\n return;\n }\n handler(req, res).finally(() => httpServer.fullyClose()).then(\n (result) => innerResolve(result),\n (error) => innerReject(error),\n );\n });\n outerResolve(async () => innerP);\n });\n });\n\nexport const endResponse = async (response: http.ServerResponse): Promise<void> => new Promise((resolve, reject) => {\n try {\n response.end(resolve);\n } catch (error) {\n reject(error);\n }\n});\n"]}
1
+ {"version":3,"file":"httpHelpers.js","sourceRoot":"","sources":["../src/httpHelpers.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,IAAI,MAAM,MAAM,CAAC;AAQxB,MAAM,UAAU,mBAAmB,CAAC,IAAY,EAAE,eAAqC;IACnF,MAAM,MAAM,GAAG,IAAI,CAAC,YAAY,CAAC,eAAe,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IAC/D,MAAM,OAAO,GAAG,IAAI,GAAG,EAAU,CAAC;IAElC,MAAM,CAAC,EAAE,CAAC,YAAY,EAAE,CAAC,MAAM,EAAE,EAAE;QAC/B,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QACpB,MAAM,CAAC,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC;IACrD,CAAC,CAAC,CAAC;IAEH,OAAO;QACH,MAAM,EAAE,OAAO,EAAE,UAAU;YACvB,MAAM,CAAC,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,OAAO,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC;QAClD,CAAC;KACJ,CAAC;AACN,CAAC;AAGD,MAAM,CAAC,MAAM,qBAAqB,GAAG,KAAK,EAAK,IAAY,EAAE,OAA+B,EAAyB,EAAE;AACnH,+CAA+C;AAC/C,IAAI,OAAO,CAAC,CAAC,YAAY,EAAE,WAAW,EAAE,EAAE;IAC1C,+CAA+C;IAC3C,MAAM,MAAM,GAAG,IAAI,OAAO,CAAI,CAAC,YAAY,EAAE,WAAW,EAAE,EAAE;QACxD,MAAM,UAAU,GAAG,mBAAmB,CAAC,IAAI,EAAE,CAAC,GAAG,EAAE,GAAG,EAAE,EAAE;YACtD,iBAAiB;YACjB,IAAI,GAAG,CAAC,GAAG,KAAK,cAAc,EAAE;gBAC5B,GAAG,CAAC,SAAS,CAAC,GAAG,EAAE,EAAE,cAAc,EAAE,cAAc,EAAE,CAAC,CAAC;gBACvD,GAAG,CAAC,GAAG,EAAE,CAAC;gBACV,OAAO;aACV;YACD,OAAO,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,OAAO,CAAC,GAAG,EAAE,CAAC,UAAU,CAAC,UAAU,EAAE,CAAC,CAAC,IAAI,CACzD,CAAC,MAAM,EAAE,EAAE,CAAC,YAAY,CAAC,MAAM,CAAC,EAChC,CAAC,KAAK,EAAE,EAAE,CAAC,WAAW,CAAC,KAAK,CAAC,CAChC,CAAC;QACN,CAAC,CAAC,CAAC;QACH,YAAY,CAAC,KAAK,IAAI,EAAE,CAAC,MAAM,CAAC,CAAC;IACrC,CAAC,CAAC,CAAC;AACP,CAAC,CAAC,CAAC;AAEP,MAAM,CAAC,MAAM,WAAW,GAAG,KAAK,EAAE,QAA6B,EAAiB,EAAE,CAAC,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;IAC/G,IAAI;QACA,QAAQ,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;KACzB;IAAC,OAAO,KAAK,EAAE;QACZ,MAAM,CAAC,KAAK,CAAC,CAAC;KACjB;AACL,CAAC,CAAC,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport http from \"http\";\nimport { Socket } from \"net\";\n\nexport interface ITrackedHttpServer {\n readonly server: http.Server;\n readonly sockets: Set<Socket>;\n fullyClose(): void;\n}\nexport function createTrackedServer(port: number, requestListener: http.RequestListener): ITrackedHttpServer {\n const server = http.createServer(requestListener).listen(port);\n const sockets = new Set<Socket>();\n\n server.on(\"connection\", (socket) => {\n sockets.add(socket);\n socket.on(\"close\", () => sockets.delete(socket));\n });\n\n return {\n server, sockets, fullyClose() {\n server.close();\n sockets.forEach((socket) => socket.destroy());\n },\n };\n}\nexport type OnceListenerHandler<T> = (req: http.IncomingMessage, res: http.ServerResponse) => Promise<T>;\nexport type OnceListenerResult<T> = Promise<() => Promise<T>>;\nexport const serverListenAndHandle = async <T>(port: number, handler: OnceListenerHandler<T>): OnceListenerResult<T> =>\n // eslint-disable-next-line promise/param-names\n new Promise((outerResolve, outerReject) => {\n // eslint-disable-next-line promise/param-names\n const innerP = new Promise<T>((innerResolve, innerReject) => {\n const httpServer = createTrackedServer(port, (req, res) => {\n // ignore favicon\n if (req.url === \"/favicon.ico\") {\n res.writeHead(200, { \"Content-Type\": \"image/x-icon\" });\n res.end();\n return;\n }\n handler(req, res).finally(() => httpServer.fullyClose()).then(\n (result) => innerResolve(result),\n (error) => innerReject(error),\n );\n });\n outerResolve(async () => innerP);\n });\n });\n\nexport const endResponse = async (response: http.ServerResponse): Promise<void> => new Promise((resolve, reject) => {\n try {\n response.end(resolve);\n } catch (error) {\n reject(error);\n }\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 = "0.54.2";
8
+ export declare const pkgVersion = "0.56.0-49831";
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,WAAW,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,iBAAiB,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 = "0.54.2";
8
+ export const pkgVersion = "0.56.0-49831";
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,QAAQ,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 = \"0.54.2\";\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,cAAc,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 = \"0.56.0-49831\";\n"]}
@@ -3,7 +3,7 @@
3
3
  * Licensed under the MIT License.
4
4
  */
5
5
  import { ITree } from "@fluidframework/protocol-definitions";
6
- export declare const gcBlobKey = "gc";
6
+ export declare const gcBlobPrefix = "__gc";
7
7
  export interface ISnapshotNormalizerConfig {
8
8
  blobsToNormalize?: string[];
9
9
  }
@@ -1 +1 @@
1
- {"version":3,"file":"snapshotNormalizer.d.ts","sourceRoot":"","sources":["../src/snapshotNormalizer.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EACH,KAAK,EAGR,MAAM,sCAAsC,CAAC;AAE9C,eAAO,MAAM,SAAS,OAAO,CAAC;AAI9B,MAAM,WAAW,yBAAyB;IAEtC,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAC;CAC/B;AAiFD;;;;;;;;GAQG;AACH,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,KAAK,EAAE,MAAM,CAAC,EAAE,yBAAyB,GAAG,KAAK,CAsChG"}
1
+ {"version":3,"file":"snapshotNormalizer.d.ts","sourceRoot":"","sources":["../src/snapshotNormalizer.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAGH,OAAO,EACH,KAAK,EAGR,MAAM,sCAAsC,CAAC;AAE9C,eAAO,MAAM,YAAY,SAAS,CAAC;AAEnC,MAAM,WAAW,yBAAyB;IAEtC,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAC;CAC/B;AAmFD;;;;;;;;GAQG;AACH,wBAAgB,qBAAqB,CAAC,QAAQ,EAAE,KAAK,EAAE,MAAM,CAAC,EAAE,yBAAyB,GAAG,KAAK,CAsChG"}
@@ -4,9 +4,7 @@
4
4
  */
5
5
  import { AttachmentTreeEntry, BlobTreeEntry, TreeTreeEntry } from "@fluidframework/protocol-base";
6
6
  import { TreeEntry, } from "@fluidframework/protocol-definitions";
7
- export const gcBlobKey = "gc";
8
- // A list of runtime blob paths whose contents should be normalized.
9
- const runtimeBlobsToNormalize = [gcBlobKey];
7
+ export const gcBlobPrefix = "__gc";
10
8
  /**
11
9
  * Function that deep sorts an array. It handles cases where array elements are objects or arrays.
12
10
  * @returns the sorted array.
@@ -65,13 +63,15 @@ function getDeepSortedObject(obj) {
65
63
  */
66
64
  function getNormalizedBlobContent(blobContent, blobName) {
67
65
  let content = blobContent;
68
- if (blobName === gcBlobKey) {
69
- // GC blobs may contain "unrefTimestamp" - The time the corresponding object became unreferenced. This is the
70
- // timestamp of the last op processed and can differ between clients depending on when GC was run. It will be
71
- // undefined if no ops were processed before running GC. So, remove it for the purposes of comparing snapshots.
72
- const gcDetails = JSON.parse(content);
73
- delete gcDetails.unrefTimestamp;
74
- content = JSON.stringify(gcDetails);
66
+ if (blobName.startsWith(gcBlobPrefix)) {
67
+ // GC blobs may contain `unreferencedTimestampMs` for node that became unreferenced. This is the timestamp
68
+ // of the last op processed or current timestamp and can differ between clients depending on when GC was run.
69
+ // So, remove it for the purposes of comparing snapshots.
70
+ const gcState = JSON.parse(content);
71
+ for (const [, data] of Object.entries(gcState.gcNodes)) {
72
+ delete data.unreferencedTimestampMs;
73
+ }
74
+ content = JSON.stringify(gcState);
75
75
  }
76
76
  // Deep sort the content if it's parseable.
77
77
  try {
@@ -100,14 +100,14 @@ export function getNormalizedSnapshot(snapshot, config) {
100
100
  var _a;
101
101
  // Merge blobs to normalize in the config with runtime blobs to normalize. The contents of these blobs will be
102
102
  // parsed and deep sorted.
103
- const blobsToNormalize = [...runtimeBlobsToNormalize, ...(_a = config === null || config === void 0 ? void 0 : config.blobsToNormalize) !== null && _a !== void 0 ? _a : []];
103
+ const blobsToNormalize = [...(_a = config === null || config === void 0 ? void 0 : config.blobsToNormalize) !== null && _a !== void 0 ? _a : []];
104
104
  const normalizedEntries = [];
105
105
  for (const entry of snapshot.entries) {
106
106
  switch (entry.type) {
107
107
  case TreeEntry.Blob: {
108
108
  let contents = entry.value.contents;
109
- // If this blob has to be normalized, parse and sort the blob contents first.
110
- if (blobsToNormalize.includes(entry.path)) {
109
+ // If this blob has to be normalized or it's a GC blob, parse and sort the blob contents first.
110
+ if (blobsToNormalize.includes(entry.path) || entry.path.startsWith(gcBlobPrefix)) {
111
111
  contents = getNormalizedBlobContent(contents, entry.path);
112
112
  }
113
113
  normalizedEntries.push(new BlobTreeEntry(entry.path, contents));
@@ -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 { AttachmentTreeEntry, BlobTreeEntry, TreeTreeEntry } from \"@fluidframework/protocol-base\";\nimport {\n ITree,\n TreeEntry,\n ITreeEntry,\n} from \"@fluidframework/protocol-definitions\";\n\nexport const gcBlobKey = \"gc\";\n// A list of runtime blob paths whose contents should be normalized.\nconst runtimeBlobsToNormalize = [ gcBlobKey ];\n\nexport interface ISnapshotNormalizerConfig {\n // The paths of blobs whose contents should be normalized.\n blobsToNormalize?: string[];\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: any[]): any[] {\n const sortedArray: any[] = [];\n // Sort arrays and objects, if any, in the array.\n for (const element of array) {\n if (Array.isArray(element)) {\n sortedArray.push(getDeepSortedArray(element));\n } else if (element instanceof Object) {\n sortedArray.push(getDeepSortedObject(element));\n } else {\n sortedArray.push(element);\n }\n }\n\n // Now that all the arrays and objects in this array's elements have been sorted, sort it by comparing each\n // element's stringified version.\n const sortFn = (elem1: any, elem2: any) => {\n const serializedElem1 = JSON.stringify(elem1);\n const serializedElem2 = JSON.stringify(elem2);\n return serializedElem1.localeCompare(serializedElem2);\n };\n // eslint-disable-next-line @typescript-eslint/no-unsafe-return\n return sortedArray.sort(sortFn);\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(obj: any): any {\n const sortedObj: any = {};\n // Sort the object keys first. Then sort arrays and objects, if any, in the object.\n const keys = Object.keys(obj).sort();\n for (const key of keys) {\n const value = obj[key];\n if (Array.isArray(value)) {\n sortedObj[key] = getDeepSortedArray(value);\n } else if (value instanceof Object) {\n sortedObj[key] = getDeepSortedObject(value);\n } else {\n sortedObj[key] = value;\n }\n }\n // eslint-disable-next-line @typescript-eslint/no-unsafe-return\n return 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 let content = blobContent;\n if (blobName === gcBlobKey) {\n // GC blobs may contain \"unrefTimestamp\" - The time the corresponding object became unreferenced. This is the\n // timestamp of the last op processed and can differ between clients depending on when GC was run. It will be\n // undefined if no ops were processed before running GC. So, remove it for the purposes of comparing snapshots.\n const gcDetails = JSON.parse(content);\n delete gcDetails.unrefTimestamp;\n content = JSON.stringify(gcDetails);\n }\n\n // Deep sort the content if it's parseable.\n try {\n let contentObj = JSON.parse(content);\n if (Array.isArray(contentObj)) {\n contentObj = getDeepSortedArray(contentObj);\n } else if (contentObj instanceof Object) {\n contentObj = getDeepSortedObject(contentObj);\n }\n content = JSON.stringify(contentObj);\n } catch {}\n return 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 */\nexport function getNormalizedSnapshot(snapshot: ITree, config?: ISnapshotNormalizerConfig): ITree {\n // Merge blobs to normalize in the config with runtime blobs to normalize. The contents of these blobs will be\n // parsed and deep sorted.\n const blobsToNormalize = [ ...runtimeBlobsToNormalize, ...config?.blobsToNormalize ?? [] ];\n const normalizedEntries: ITreeEntry[] = [];\n\n for (const entry of snapshot.entries) {\n switch (entry.type) {\n case TreeEntry.Blob: {\n let contents = entry.value.contents;\n // If this blob has to be normalized, parse and sort the blob contents first.\n if (blobsToNormalize.includes(entry.path)) {\n contents = getNormalizedBlobContent(contents, entry.path);\n }\n normalizedEntries.push(new BlobTreeEntry(entry.path, contents));\n break;\n }\n case TreeEntry.Tree: {\n normalizedEntries.push(new TreeTreeEntry(entry.path, getNormalizedSnapshot(entry.value, config)));\n break;\n }\n case TreeEntry.Attachment: {\n normalizedEntries.push(new AttachmentTreeEntry(entry.path, (entry.value).id));\n break;\n }\n\n default:\n throw new Error(\"Unknown entry type\");\n }\n }\n\n // Sory the tree entries based on their path.\n normalizedEntries.sort((a, b) => a.path.localeCompare(b.path));\n\n return {\n entries: normalizedEntries,\n id: snapshot.id,\n };\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 { AttachmentTreeEntry, BlobTreeEntry, TreeTreeEntry } from \"@fluidframework/protocol-base\";\nimport {\n ITree,\n TreeEntry,\n ITreeEntry,\n} from \"@fluidframework/protocol-definitions\";\n\nexport const gcBlobPrefix = \"__gc\";\n\nexport interface ISnapshotNormalizerConfig {\n // The paths of blobs whose contents should be normalized.\n blobsToNormalize?: string[];\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: any[]): any[] {\n const sortedArray: any[] = [];\n // Sort arrays and objects, if any, in the array.\n for (const element of array) {\n if (Array.isArray(element)) {\n sortedArray.push(getDeepSortedArray(element));\n } else if (element instanceof Object) {\n sortedArray.push(getDeepSortedObject(element));\n } else {\n sortedArray.push(element);\n }\n }\n\n // Now that all the arrays and objects in this array's elements have been sorted, sort it by comparing each\n // element's stringified version.\n const sortFn = (elem1: any, elem2: any) => {\n const serializedElem1 = JSON.stringify(elem1);\n const serializedElem2 = JSON.stringify(elem2);\n return serializedElem1.localeCompare(serializedElem2);\n };\n // eslint-disable-next-line @typescript-eslint/no-unsafe-return\n return sortedArray.sort(sortFn);\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(obj: any): any {\n const sortedObj: any = {};\n // Sort the object keys first. Then sort arrays and objects, if any, in the object.\n const keys = Object.keys(obj).sort();\n for (const key of keys) {\n const value = obj[key];\n if (Array.isArray(value)) {\n sortedObj[key] = getDeepSortedArray(value);\n } else if (value instanceof Object) {\n sortedObj[key] = getDeepSortedObject(value);\n } else {\n sortedObj[key] = value;\n }\n }\n // eslint-disable-next-line @typescript-eslint/no-unsafe-return\n return 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 let content = blobContent;\n if (blobName.startsWith(gcBlobPrefix)) {\n // GC blobs may contain `unreferencedTimestampMs` for node that became unreferenced. This is the timestamp\n // of the last op processed or current timestamp and can differ between clients depending on when GC was run.\n // So, remove it for the purposes of comparing snapshots.\n const gcState = JSON.parse(content);\n for (const [, data] of Object.entries(gcState.gcNodes)) {\n delete (data as any).unreferencedTimestampMs;\n }\n content = JSON.stringify(gcState);\n }\n\n // Deep sort the content if it's parseable.\n try {\n let contentObj = JSON.parse(content);\n if (Array.isArray(contentObj)) {\n contentObj = getDeepSortedArray(contentObj);\n } else if (contentObj instanceof Object) {\n contentObj = getDeepSortedObject(contentObj);\n }\n content = JSON.stringify(contentObj);\n } catch {}\n return 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 */\nexport function getNormalizedSnapshot(snapshot: ITree, config?: ISnapshotNormalizerConfig): ITree {\n // Merge blobs to normalize in the config with runtime blobs to normalize. The contents of these blobs will be\n // parsed and deep sorted.\n const blobsToNormalize = [ ...config?.blobsToNormalize ?? [] ];\n const normalizedEntries: ITreeEntry[] = [];\n\n for (const entry of snapshot.entries) {\n switch (entry.type) {\n case TreeEntry.Blob: {\n let contents = entry.value.contents;\n // If this blob has to be normalized or it's a GC blob, parse and sort the blob contents first.\n if (blobsToNormalize.includes(entry.path) || entry.path.startsWith(gcBlobPrefix)) {\n contents = getNormalizedBlobContent(contents, entry.path);\n }\n normalizedEntries.push(new BlobTreeEntry(entry.path, contents));\n break;\n }\n case TreeEntry.Tree: {\n normalizedEntries.push(new TreeTreeEntry(entry.path, getNormalizedSnapshot(entry.value, config)));\n break;\n }\n case TreeEntry.Attachment: {\n normalizedEntries.push(new AttachmentTreeEntry(entry.path, (entry.value).id));\n break;\n }\n\n default:\n throw new Error(\"Unknown entry type\");\n }\n }\n\n // Sory the tree entries based on their path.\n normalizedEntries.sort((a, b) => a.path.localeCompare(b.path));\n\n return {\n entries: normalizedEntries,\n id: snapshot.id,\n };\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fluidframework/tool-utils",
3
- "version": "0.54.2",
3
+ "version": "0.56.0-49831",
4
4
  "description": "Common utilities for Fluid tools",
5
5
  "homepage": "https://fluidframework.com",
6
6
  "repository": "https://github.com/microsoft/FluidFramework",
@@ -23,7 +23,7 @@
23
23
  "ci:build:docs": "api-extractor run --typescript-compiler-folder ../../../node_modules/typescript && copyfiles -u 1 ./_api-extractor-temp/* ../../../_api-extractor-temp/",
24
24
  "clean": "rimraf dist *.tsbuildinfo *.build.log",
25
25
  "eslint": "eslint --format stylish src",
26
- "eslint:fix": "eslint --format stylish src --fix",
26
+ "eslint:fix": "eslint --format stylish src --fix --fix-type problem,suggestion,layout",
27
27
  "lint": "npm run eslint",
28
28
  "lint:fix": "npm run eslint:fix",
29
29
  "test": "npm run test:mocha",
@@ -57,7 +57,7 @@
57
57
  },
58
58
  "dependencies": {
59
59
  "@fluidframework/common-utils": "^0.32.1",
60
- "@fluidframework/odsp-doclib-utils": "^0.54.2",
60
+ "@fluidframework/odsp-doclib-utils": "0.56.0-49831",
61
61
  "@fluidframework/protocol-base": "^0.1034.0",
62
62
  "@fluidframework/protocol-definitions": "^0.1026.0",
63
63
  "async-mutex": "^0.3.1",
@@ -67,25 +67,26 @@
67
67
  },
68
68
  "devDependencies": {
69
69
  "@fluidframework/build-common": "^0.23.0",
70
- "@fluidframework/eslint-config-fluid": "^0.24.0",
71
- "@fluidframework/mocha-test-setup": "^0.54.2",
70
+ "@fluidframework/eslint-config-fluid": "^0.25.0",
71
+ "@fluidframework/mocha-test-setup": "0.56.0-49831",
72
72
  "@microsoft/api-extractor": "^7.16.1",
73
+ "@rushstack/eslint-config": "^2.5.1",
73
74
  "@types/debug": "^4.1.5",
74
75
  "@types/jwt-decode": "^2.2.1",
75
76
  "@types/mocha": "^8.2.2",
76
77
  "@types/node": "^14.18.0",
77
- "@typescript-eslint/eslint-plugin": "~4.14.0",
78
- "@typescript-eslint/parser": "~4.14.0",
78
+ "@typescript-eslint/eslint-plugin": "~5.9.0",
79
+ "@typescript-eslint/parser": "~5.9.0",
79
80
  "concurrently": "^6.2.0",
80
81
  "copyfiles": "^2.1.0",
81
82
  "cross-env": "^7.0.2",
82
- "eslint": "~7.18.0",
83
+ "eslint": "~8.6.0",
84
+ "eslint-plugin-editorconfig": "~3.2.0",
83
85
  "eslint-plugin-eslint-comments": "~3.2.0",
84
- "eslint-plugin-import": "~2.22.1",
86
+ "eslint-plugin-import": "~2.25.4",
85
87
  "eslint-plugin-no-null": "~1.0.2",
86
- "eslint-plugin-prefer-arrow": "~1.2.2",
87
- "eslint-plugin-react": "~7.22.0",
88
- "eslint-plugin-unicorn": "~26.0.1",
88
+ "eslint-plugin-react": "~7.28.0",
89
+ "eslint-plugin-unicorn": "~40.0.0",
89
90
  "mocha": "^8.4.0",
90
91
  "nyc": "^15.0.0",
91
92
  "rimraf": "^2.6.2",
@@ -3,8 +3,6 @@
3
3
  * Licensed under the MIT License.
4
4
  */
5
5
 
6
- /* eslint-disable unicorn/filename-case */
7
-
8
6
  import fs from "fs";
9
7
  import os from "os";
10
8
  import path from "path";
@@ -54,7 +52,6 @@ export async function saveRC(rc: IResources) {
54
52
  return writeFile(getRCFileName(), Buffer.from(content, "utf8"));
55
53
  }
56
54
 
57
- // eslint-disable-next-line prefer-arrow/prefer-arrow-functions
58
55
  export async function lockRC() {
59
56
  // eslint-disable-next-line @typescript-eslint/no-unsafe-return
60
57
  return lock(getRCFileName(), {
@@ -30,7 +30,9 @@ export function createTrackedServer(port: number, requestListener: http.RequestL
30
30
  export type OnceListenerHandler<T> = (req: http.IncomingMessage, res: http.ServerResponse) => Promise<T>;
31
31
  export type OnceListenerResult<T> = Promise<() => Promise<T>>;
32
32
  export const serverListenAndHandle = async <T>(port: number, handler: OnceListenerHandler<T>): OnceListenerResult<T> =>
33
+ // eslint-disable-next-line promise/param-names
33
34
  new Promise((outerResolve, outerReject) => {
35
+ // eslint-disable-next-line promise/param-names
34
36
  const innerP = new Promise<T>((innerResolve, innerReject) => {
35
37
  const httpServer = createTrackedServer(port, (req, res) => {
36
38
  // ignore favicon
@@ -6,4 +6,4 @@
6
6
  */
7
7
 
8
8
  export const pkgName = "@fluidframework/tool-utils";
9
- export const pkgVersion = "0.54.2";
9
+ export const pkgVersion = "0.56.0-49831";
@@ -10,9 +10,7 @@ import {
10
10
  ITreeEntry,
11
11
  } from "@fluidframework/protocol-definitions";
12
12
 
13
- export const gcBlobKey = "gc";
14
- // A list of runtime blob paths whose contents should be normalized.
15
- const runtimeBlobsToNormalize = [ gcBlobKey ];
13
+ export const gcBlobPrefix = "__gc";
16
14
 
17
15
  export interface ISnapshotNormalizerConfig {
18
16
  // The paths of blobs whose contents should be normalized.
@@ -76,13 +74,15 @@ function getDeepSortedObject(obj: any): any {
76
74
  */
77
75
  function getNormalizedBlobContent(blobContent: string, blobName: string): string {
78
76
  let content = blobContent;
79
- if (blobName === gcBlobKey) {
80
- // GC blobs may contain "unrefTimestamp" - The time the corresponding object became unreferenced. This is the
81
- // timestamp of the last op processed and can differ between clients depending on when GC was run. It will be
82
- // undefined if no ops were processed before running GC. So, remove it for the purposes of comparing snapshots.
83
- const gcDetails = JSON.parse(content);
84
- delete gcDetails.unrefTimestamp;
85
- content = JSON.stringify(gcDetails);
77
+ if (blobName.startsWith(gcBlobPrefix)) {
78
+ // GC blobs may contain `unreferencedTimestampMs` for node that became unreferenced. This is the timestamp
79
+ // of the last op processed or current timestamp and can differ between clients depending on when GC was run.
80
+ // So, remove it for the purposes of comparing snapshots.
81
+ const gcState = JSON.parse(content);
82
+ for (const [, data] of Object.entries(gcState.gcNodes)) {
83
+ delete (data as any).unreferencedTimestampMs;
84
+ }
85
+ content = JSON.stringify(gcState);
86
86
  }
87
87
 
88
88
  // Deep sort the content if it's parseable.
@@ -110,15 +110,15 @@ function getNormalizedBlobContent(blobContent: string, blobName: string): string
110
110
  export function getNormalizedSnapshot(snapshot: ITree, config?: ISnapshotNormalizerConfig): ITree {
111
111
  // Merge blobs to normalize in the config with runtime blobs to normalize. The contents of these blobs will be
112
112
  // parsed and deep sorted.
113
- const blobsToNormalize = [ ...runtimeBlobsToNormalize, ...config?.blobsToNormalize ?? [] ];
113
+ const blobsToNormalize = [ ...config?.blobsToNormalize ?? [] ];
114
114
  const normalizedEntries: ITreeEntry[] = [];
115
115
 
116
116
  for (const entry of snapshot.entries) {
117
117
  switch (entry.type) {
118
118
  case TreeEntry.Blob: {
119
119
  let contents = entry.value.contents;
120
- // If this blob has to be normalized, parse and sort the blob contents first.
121
- if (blobsToNormalize.includes(entry.path)) {
120
+ // If this blob has to be normalized or it's a GC blob, parse and sort the blob contents first.
121
+ if (blobsToNormalize.includes(entry.path) || entry.path.startsWith(gcBlobPrefix)) {
122
122
  contents = getNormalizedBlobContent(contents, entry.path);
123
123
  }
124
124
  normalizedEntries.push(new BlobTreeEntry(entry.path, contents));