@fluidframework/driver-utils 2.0.0-dev.6.4.0.192049 → 2.0.0-dev.7.2.0.203917
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 +70 -0
- package/api-extractor.json +12 -1
- package/api-report/driver-utils.api.md +393 -0
- package/dist/adapters/compression/compressionTypes.js +1 -1
- package/dist/adapters/compression/compressionTypes.js.map +1 -1
- package/dist/adapters/compression/documentServiceCompressionAdapter.d.ts.map +1 -1
- package/dist/adapters/compression/documentServiceCompressionAdapter.js.map +1 -1
- package/dist/adapters/compression/documentServiceFactoryCompressionAdapter.d.ts.map +1 -1
- package/dist/adapters/compression/documentServiceFactoryCompressionAdapter.js +1 -9
- package/dist/adapters/compression/documentServiceFactoryCompressionAdapter.js.map +1 -1
- package/dist/adapters/compression/summaryblob/documentStorageServiceSummaryBlobCompressionAdapter.js.map +1 -1
- package/dist/blob.d.ts.map +1 -1
- package/dist/blob.js.map +1 -1
- package/dist/documentStorageServiceProxy.js +3 -3
- package/dist/documentStorageServiceProxy.js.map +1 -1
- package/dist/driver-utils-alpha.d.ts +467 -0
- package/dist/driver-utils-beta.d.ts +467 -0
- package/dist/driver-utils-public.d.ts +467 -0
- package/dist/driver-utils-untrimmed.d.ts +481 -0
- package/dist/insecureUrlResolver.js +1 -1
- package/dist/insecureUrlResolver.js.map +1 -1
- package/dist/messageRecognition.js +1 -1
- package/dist/messageRecognition.js.map +1 -1
- package/dist/network.d.ts +1 -1
- package/dist/network.d.ts.map +1 -1
- package/dist/network.js +1 -1
- package/dist/network.js.map +1 -1
- package/dist/packageVersion.d.ts +1 -1
- package/dist/packageVersion.js +1 -1
- package/dist/packageVersion.js.map +1 -1
- package/dist/parallelRequests.d.ts.map +1 -1
- package/dist/parallelRequests.js +6 -6
- package/dist/parallelRequests.js.map +1 -1
- package/dist/prefetchDocumentStorageService.d.ts +0 -1
- package/dist/prefetchDocumentStorageService.d.ts.map +1 -1
- package/dist/runWithRetry.d.ts.map +1 -1
- package/dist/runWithRetry.js +0 -2
- package/dist/runWithRetry.js.map +1 -1
- package/dist/summaryForCreateNew.d.ts +1 -1
- package/dist/summaryForCreateNew.d.ts.map +1 -1
- package/dist/summaryForCreateNew.js +2 -2
- package/dist/summaryForCreateNew.js.map +1 -1
- package/dist/tsdoc-metadata.json +1 -1
- package/lib/adapters/compression/documentServiceCompressionAdapter.d.ts.map +1 -1
- package/lib/adapters/compression/documentServiceCompressionAdapter.js.map +1 -1
- package/lib/adapters/compression/documentServiceFactoryCompressionAdapter.d.ts.map +1 -1
- package/lib/adapters/compression/documentServiceFactoryCompressionAdapter.js +1 -9
- package/lib/adapters/compression/documentServiceFactoryCompressionAdapter.js.map +1 -1
- package/lib/adapters/compression/summaryblob/documentStorageServiceSummaryBlobCompressionAdapter.js.map +1 -1
- package/lib/blob.d.ts.map +1 -1
- package/lib/blob.js.map +1 -1
- package/lib/documentStorageServiceProxy.js +3 -3
- package/lib/documentStorageServiceProxy.js.map +1 -1
- package/lib/insecureUrlResolver.js +1 -1
- package/lib/insecureUrlResolver.js.map +1 -1
- package/lib/network.d.ts +1 -1
- package/lib/network.d.ts.map +1 -1
- package/lib/network.js.map +1 -1
- package/lib/packageVersion.d.ts +1 -1
- package/lib/packageVersion.js +1 -1
- package/lib/packageVersion.js.map +1 -1
- package/lib/parallelRequests.d.ts.map +1 -1
- package/lib/parallelRequests.js +6 -6
- package/lib/parallelRequests.js.map +1 -1
- package/lib/prefetchDocumentStorageService.d.ts +0 -1
- package/lib/prefetchDocumentStorageService.d.ts.map +1 -1
- package/lib/runWithRetry.d.ts.map +1 -1
- package/lib/runWithRetry.js +0 -2
- package/lib/runWithRetry.js.map +1 -1
- package/lib/summaryForCreateNew.d.ts +1 -1
- package/lib/summaryForCreateNew.d.ts.map +1 -1
- package/lib/summaryForCreateNew.js +2 -2
- package/lib/summaryForCreateNew.js.map +1 -1
- package/package.json +21 -22
- package/src/adapters/compression/documentServiceCompressionAdapter.ts +4 -1
- package/src/adapters/compression/documentServiceFactoryCompressionAdapter.ts +1 -9
- package/src/blob.ts +8 -2
- package/src/insecureUrlResolver.ts +1 -1
- package/src/network.ts +15 -3
- package/src/packageVersion.ts +1 -1
- package/src/parallelRequests.ts +1 -1
- package/src/runWithRetry.ts +2 -4
- package/src/summaryForCreateNew.ts +2 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"summaryForCreateNew.js","sourceRoot":"","sources":["../src/summaryForCreateNew.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAEN,WAAW,GAIX,MAAM,sCAAsC,CAAC;AAc9C;;;;GAIG;AACH,MAAM,UAAU,+BAA+B,CAC9C,OAAiC;
|
|
1
|
+
{"version":3,"file":"summaryForCreateNew.js","sourceRoot":"","sources":["../src/summaryForCreateNew.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAEN,WAAW,GAIX,MAAM,sCAAsC,CAAC;AAc9C;;;;GAIG;AACH,MAAM,UAAU,+BAA+B,CAC9C,OAAiC,EACjC,GAAG,iBAA2B;IAE9B,IACC,OAAO,EAAE,IAAI,KAAK,SAAS;QAC3B,OAAO,CAAC,IAAI,EAAE,CAAC,MAAM,CAAC,EAAE,IAAI,KAAK,WAAW,CAAC,IAAI;QACjD,OAAO,CAAC,IAAI,EAAE,CAAC,WAAW,CAAC,EAAE,IAAI,KAAK,WAAW,CAAC,IAAI,EACrD;QACD,OAAO,KAAK,CAAC;KACb;IACD,MAAM,QAAQ,GAAG,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,iBAAiB,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC;IACzF,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE;QAC1B,OAAO,KAAK,CAAC;KACb;IACD,OAAO,IAAI,CAAC;AACb,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,mCAAmC,CAClD,eAA6B;IAE7B,MAAM,cAAc,GAAG,eAAe,CAAC,IAAI,CAAC,UAA0B,CAAC;IACvE,OAAO,IAAI,CAAC,KAAK,CAAC,cAAc,CAAC,OAAiB,CAAwB,CAAC;AAC5E,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,kCAAkC,CACjD,eAA6B;IAE7B,MAAM,gBAAgB,GAAG,eAAe,CAAC,IAAI,CAAC,YAA4B,CAAC;IAC3E,MAAM,YAAY,GAAG,IAAI,CAAC,KAAK,CAAC,gBAAgB,CAAC,OAAiB,CAG/D,CAAC;IACJ,OAAO,YAAY,CAAC;AACrB,CAAC","sourcesContent":["/*!\n * Copyright (c) Microsoft Corporation and contributors. All rights reserved.\n * Licensed under the MIT License.\n */\n\nimport {\n\tISummaryTree,\n\tSummaryType,\n\tISummaryBlob,\n\tICommittedProposal,\n\tIDocumentAttributes,\n} from \"@fluidframework/protocol-definitions\";\n\n/**\n * Defines the current layout of an .app + .protocol summary tree\n * this is used internally for create new, and single commit summary\n * @internal\n */\nexport interface CombinedAppAndProtocolSummary extends ISummaryTree {\n\ttree: {\n\t\t[\".app\"]: ISummaryTree;\n\t\t[\".protocol\"]: ISummaryTree;\n\t};\n}\n\n/**\n * Validates the current layout of an .app + .protocol summary tree\n * this is used internally for create new, and single commit summary\n * @internal\n */\nexport function isCombinedAppAndProtocolSummary(\n\tsummary: ISummaryTree | undefined,\n\t...optionalRootTrees: string[]\n): summary is CombinedAppAndProtocolSummary {\n\tif (\n\t\tsummary?.tree === undefined ||\n\t\tsummary.tree?.[\".app\"]?.type !== SummaryType.Tree ||\n\t\tsummary.tree?.[\".protocol\"]?.type !== SummaryType.Tree\n\t) {\n\t\treturn false;\n\t}\n\tconst treeKeys = Object.keys(summary.tree).filter((t) => !optionalRootTrees.includes(t));\n\tif (treeKeys.length !== 2) {\n\t\treturn false;\n\t}\n\treturn true;\n}\n\n/**\n * Extract the attributes from the protocol summary.\n * @param protocolSummary - protocol summary from which the values are to be extracted.\n */\nexport function getDocAttributesFromProtocolSummary(\n\tprotocolSummary: ISummaryTree,\n): IDocumentAttributes {\n\tconst attributesBlob = protocolSummary.tree.attributes as ISummaryBlob;\n\treturn JSON.parse(attributesBlob.content as string) as IDocumentAttributes;\n}\n\n/**\n * Extract quorum values from the protocol summary.\n * @param protocolSummary - protocol summary from which the values are to be extracted.\n */\nexport function getQuorumValuesFromProtocolSummary(\n\tprotocolSummary: ISummaryTree,\n): [string, ICommittedProposal][] {\n\tconst quorumValuesBlob = protocolSummary.tree.quorumValues as ISummaryBlob;\n\tconst quorumValues = JSON.parse(quorumValuesBlob.content as string) as [\n\t\tstring,\n\t\tICommittedProposal,\n\t][];\n\treturn quorumValues;\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@fluidframework/driver-utils",
|
|
3
|
-
"version": "2.0.0-dev.
|
|
3
|
+
"version": "2.0.0-dev.7.2.0.203917",
|
|
4
4
|
"description": "Collection of utility functions for Fluid drivers",
|
|
5
5
|
"homepage": "https://fluidframework.com",
|
|
6
6
|
"repository": {
|
|
@@ -35,42 +35,41 @@
|
|
|
35
35
|
"temp-directory": "nyc/.nyc_output"
|
|
36
36
|
},
|
|
37
37
|
"dependencies": {
|
|
38
|
-
"@fluid-internal/client-utils": "2.0.0-dev.
|
|
39
|
-
"@fluidframework/core-interfaces": "2.0.0-dev.
|
|
40
|
-
"@fluidframework/core-utils": "2.0.0-dev.
|
|
41
|
-
"@fluidframework/driver-definitions": "2.0.0-dev.
|
|
42
|
-
"@fluidframework/gitresources": "^
|
|
43
|
-
"@fluidframework/protocol-base": "^
|
|
44
|
-
"@fluidframework/protocol-definitions": "^
|
|
45
|
-
"@fluidframework/telemetry-utils": "2.0.0-dev.
|
|
38
|
+
"@fluid-internal/client-utils": "2.0.0-dev.7.2.0.203917",
|
|
39
|
+
"@fluidframework/core-interfaces": "2.0.0-dev.7.2.0.203917",
|
|
40
|
+
"@fluidframework/core-utils": "2.0.0-dev.7.2.0.203917",
|
|
41
|
+
"@fluidframework/driver-definitions": "2.0.0-dev.7.2.0.203917",
|
|
42
|
+
"@fluidframework/gitresources": "^2.0.1",
|
|
43
|
+
"@fluidframework/protocol-base": "^2.0.1",
|
|
44
|
+
"@fluidframework/protocol-definitions": "^3.0.0",
|
|
45
|
+
"@fluidframework/telemetry-utils": "2.0.0-dev.7.2.0.203917",
|
|
46
46
|
"axios": "^0.26.0",
|
|
47
47
|
"lz4js": "^0.2.0",
|
|
48
48
|
"url": "^0.11.0",
|
|
49
49
|
"uuid": "^9.0.0"
|
|
50
50
|
},
|
|
51
51
|
"devDependencies": {
|
|
52
|
-
"@fluid-tools/build-cli": "
|
|
53
|
-
"@fluidframework/build-common": "^2.0.
|
|
54
|
-
"@fluidframework/build-tools": "
|
|
55
|
-
"@fluidframework/driver-utils-previous": "npm:@fluidframework/driver-utils@2.0.0-internal.
|
|
56
|
-
"@fluidframework/eslint-config-fluid": "^
|
|
57
|
-
"@fluidframework/mocha-test-setup": "2.0.0-dev.
|
|
58
|
-
"@microsoft/api-extractor": "^7.
|
|
52
|
+
"@fluid-tools/build-cli": "0.26.0-203096",
|
|
53
|
+
"@fluidframework/build-common": "^2.0.2",
|
|
54
|
+
"@fluidframework/build-tools": "0.26.0-203096",
|
|
55
|
+
"@fluidframework/driver-utils-previous": "npm:@fluidframework/driver-utils@2.0.0-internal.7.1.0",
|
|
56
|
+
"@fluidframework/eslint-config-fluid": "^3.0.0",
|
|
57
|
+
"@fluidframework/mocha-test-setup": "2.0.0-dev.7.2.0.203917",
|
|
58
|
+
"@microsoft/api-extractor": "^7.37.0",
|
|
59
59
|
"@types/mocha": "^9.1.1",
|
|
60
60
|
"@types/node": "^16.18.38",
|
|
61
61
|
"@types/sinon": "^7.0.13",
|
|
62
62
|
"c8": "^7.7.1",
|
|
63
|
-
"copyfiles": "^2.4.1",
|
|
64
63
|
"cross-env": "^7.0.3",
|
|
65
|
-
"eslint": "~8.
|
|
64
|
+
"eslint": "~8.50.0",
|
|
66
65
|
"mocha": "^10.2.0",
|
|
67
66
|
"mocha-json-output-reporter": "^2.0.1",
|
|
68
67
|
"mocha-multi-reporters": "^1.5.1",
|
|
69
68
|
"moment": "^2.21.0",
|
|
70
|
-
"prettier": "~
|
|
69
|
+
"prettier": "~3.0.3",
|
|
71
70
|
"rimraf": "^4.4.0",
|
|
72
71
|
"sinon": "^7.4.2",
|
|
73
|
-
"typescript": "~
|
|
72
|
+
"typescript": "~5.1.6"
|
|
74
73
|
},
|
|
75
74
|
"typeValidation": {
|
|
76
75
|
"broken": {}
|
|
@@ -79,11 +78,11 @@
|
|
|
79
78
|
"build": "fluid-build . --task build",
|
|
80
79
|
"build:commonjs": "fluid-build . --task commonjs",
|
|
81
80
|
"build:compile": "fluid-build . --task compile",
|
|
82
|
-
"build:docs": "api-extractor run --local
|
|
81
|
+
"build:docs": "api-extractor run --local",
|
|
83
82
|
"build:esnext": "tsc --project ./tsconfig.esnext.json",
|
|
84
83
|
"build:genver": "gen-version",
|
|
85
84
|
"build:test": "tsc --project ./src/test/tsconfig.json",
|
|
86
|
-
"ci:build:docs": "api-extractor run
|
|
85
|
+
"ci:build:docs": "api-extractor run",
|
|
87
86
|
"clean": "rimraf --glob 'dist' 'lib' '*.tsbuildinfo' '*.build.log' '_api-extractor-temp' 'nyc'",
|
|
88
87
|
"eslint": "eslint --format stylish src",
|
|
89
88
|
"eslint:fix": "eslint --format stylish src --fix --fix-type problem,suggestion,layout",
|
|
@@ -9,7 +9,10 @@ import { DocumentStorageServiceCompressionAdapter as DocumentStorageServiceSumma
|
|
|
9
9
|
import { ICompressionStorageConfig } from "./compressionTypes";
|
|
10
10
|
|
|
11
11
|
export class DocumentServiceCompressionAdapter extends DocumentServiceProxy {
|
|
12
|
-
constructor(
|
|
12
|
+
constructor(
|
|
13
|
+
service: IDocumentService,
|
|
14
|
+
private readonly _config: ICompressionStorageConfig,
|
|
15
|
+
) {
|
|
13
16
|
super(service);
|
|
14
17
|
}
|
|
15
18
|
|
|
@@ -30,15 +30,7 @@ export class DocumentServiceFactoryCompressionAdapter extends DocumentServiceFac
|
|
|
30
30
|
clientIsSummarizer?: boolean,
|
|
31
31
|
): Promise<IDocumentService> {
|
|
32
32
|
if (createNewSummary !== undefined) {
|
|
33
|
-
|
|
34
|
-
// We must prevent the initial summary from being compressed because
|
|
35
|
-
// of the hack at packages/drivers/routerlicious-driver/src/createNewUtils.ts
|
|
36
|
-
// where the binary blob is converted to a string using UTF-8 encoding
|
|
37
|
-
// which is producing incorrect results for compressed data.
|
|
38
|
-
const configForInitial = {
|
|
39
|
-
...this._config,
|
|
40
|
-
minSizeToCompress: Number.POSITIVE_INFINITY,
|
|
41
|
-
};
|
|
33
|
+
const configForInitial = this._config;
|
|
42
34
|
const newAppSumary =
|
|
43
35
|
DocumentStorageServiceSummaryBlobCompressionAdapter.compressSummary(
|
|
44
36
|
createNewSummary.tree[".app"] as ISummaryTree,
|
package/src/blob.ts
CHANGED
|
@@ -46,7 +46,10 @@ export class TreeTreeEntry {
|
|
|
46
46
|
* @param path - path of entry
|
|
47
47
|
* @param value - subtree
|
|
48
48
|
*/
|
|
49
|
-
constructor(
|
|
49
|
+
constructor(
|
|
50
|
+
public readonly path: string,
|
|
51
|
+
public readonly value: ITree,
|
|
52
|
+
) {}
|
|
50
53
|
}
|
|
51
54
|
|
|
52
55
|
/**
|
|
@@ -62,7 +65,10 @@ export class AttachmentTreeEntry {
|
|
|
62
65
|
* @param path - path of entry
|
|
63
66
|
* @param id - id of external blob attachment
|
|
64
67
|
*/
|
|
65
|
-
constructor(
|
|
68
|
+
constructor(
|
|
69
|
+
public readonly path: string,
|
|
70
|
+
public readonly id: string,
|
|
71
|
+
) {
|
|
66
72
|
this.value = { id };
|
|
67
73
|
}
|
|
68
74
|
}
|
|
@@ -48,7 +48,7 @@ export class InsecureUrlResolver implements IUrlResolver {
|
|
|
48
48
|
// service using our bearer token.
|
|
49
49
|
if (this.isForNodeTest) {
|
|
50
50
|
const [, documentId, tmpRelativePath] = parsedUrl.pathname.substr(1).split("/");
|
|
51
|
-
const relativePath = tmpRelativePath
|
|
51
|
+
const relativePath = tmpRelativePath ?? "";
|
|
52
52
|
return this.resolveHelper(documentId, relativePath, parsedUrl.search);
|
|
53
53
|
} else if (parsedUrl.host === window.location.host) {
|
|
54
54
|
const fullPath = parsedUrl.pathname.substr(1);
|
package/src/network.ts
CHANGED
|
@@ -48,7 +48,11 @@ export class GenericNetworkError extends LoggingError implements IDriverErrorBas
|
|
|
48
48
|
// eslint-disable-next-line import/no-deprecated
|
|
49
49
|
readonly errorType = DriverErrorType.genericNetworkError;
|
|
50
50
|
|
|
51
|
-
constructor(
|
|
51
|
+
constructor(
|
|
52
|
+
message: string,
|
|
53
|
+
readonly canRetry: boolean,
|
|
54
|
+
props: DriverErrorTelemetryProps,
|
|
55
|
+
) {
|
|
52
56
|
super(message, props);
|
|
53
57
|
}
|
|
54
58
|
}
|
|
@@ -134,13 +138,21 @@ export class NetworkErrorBasic<T extends string> extends LoggingError implements
|
|
|
134
138
|
}
|
|
135
139
|
|
|
136
140
|
export class NonRetryableError<T extends string> extends NetworkErrorBasic<T> {
|
|
137
|
-
constructor(
|
|
141
|
+
constructor(
|
|
142
|
+
message: string,
|
|
143
|
+
readonly errorType: T,
|
|
144
|
+
props: DriverErrorTelemetryProps,
|
|
145
|
+
) {
|
|
138
146
|
super(message, errorType, false, props);
|
|
139
147
|
}
|
|
140
148
|
}
|
|
141
149
|
|
|
142
150
|
export class RetryableError<T extends string> extends NetworkErrorBasic<T> {
|
|
143
|
-
constructor(
|
|
151
|
+
constructor(
|
|
152
|
+
message: string,
|
|
153
|
+
readonly errorType: T,
|
|
154
|
+
props: DriverErrorTelemetryProps,
|
|
155
|
+
) {
|
|
144
156
|
super(message, errorType, true, props);
|
|
145
157
|
}
|
|
146
158
|
}
|
package/src/packageVersion.ts
CHANGED
package/src/parallelRequests.ts
CHANGED
|
@@ -33,7 +33,7 @@ type WorkingState = "working" | "done" | "canceled";
|
|
|
33
33
|
export class ParallelRequests<T> {
|
|
34
34
|
private latestRequested: number;
|
|
35
35
|
private nextToDeliver: number;
|
|
36
|
-
private readonly results
|
|
36
|
+
private readonly results = new Map<number, T[]>();
|
|
37
37
|
private workingState: WorkingState = "working";
|
|
38
38
|
private requestsInFlight = 0;
|
|
39
39
|
private readonly endEvent = new Deferred<void>();
|
package/src/runWithRetry.ts
CHANGED
|
@@ -81,8 +81,7 @@ export async function runWithRetry<T>(
|
|
|
81
81
|
retry: numRetries,
|
|
82
82
|
duration: performance.now() - startTime,
|
|
83
83
|
fetchCallName,
|
|
84
|
-
|
|
85
|
-
reason: (progress.cancel as AbortSignal & { reason: any }).reason,
|
|
84
|
+
reason: progress.cancel.reason,
|
|
86
85
|
},
|
|
87
86
|
err,
|
|
88
87
|
);
|
|
@@ -92,8 +91,7 @@ export async function runWithRetry<T>(
|
|
|
92
91
|
{
|
|
93
92
|
driverVersion: pkgVersion,
|
|
94
93
|
fetchCallName,
|
|
95
|
-
|
|
96
|
-
reason: (progress.cancel as AbortSignal & { reason: any }).reason,
|
|
94
|
+
reason: progress.cancel.reason,
|
|
97
95
|
},
|
|
98
96
|
);
|
|
99
97
|
}
|
|
@@ -30,6 +30,7 @@ export interface CombinedAppAndProtocolSummary extends ISummaryTree {
|
|
|
30
30
|
*/
|
|
31
31
|
export function isCombinedAppAndProtocolSummary(
|
|
32
32
|
summary: ISummaryTree | undefined,
|
|
33
|
+
...optionalRootTrees: string[]
|
|
33
34
|
): summary is CombinedAppAndProtocolSummary {
|
|
34
35
|
if (
|
|
35
36
|
summary?.tree === undefined ||
|
|
@@ -38,7 +39,7 @@ export function isCombinedAppAndProtocolSummary(
|
|
|
38
39
|
) {
|
|
39
40
|
return false;
|
|
40
41
|
}
|
|
41
|
-
const treeKeys = Object.keys(summary.tree);
|
|
42
|
+
const treeKeys = Object.keys(summary.tree).filter((t) => !optionalRootTrees.includes(t));
|
|
42
43
|
if (treeKeys.length !== 2) {
|
|
43
44
|
return false;
|
|
44
45
|
}
|