@fluidframework/azure-end-to-end-tests 2.70.0-361092 → 2.70.0-361788

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.
@@ -136,7 +136,7 @@ export function createAzureClientLegacy(userID, userName, logger) {
136
136
  * currently these are mainly fetched from ephemeralSummaryTrees.ts
137
137
  * @param userID - ID for the user creating the container
138
138
  * @param userName - Name for the user creating the container
139
- * @returns - An AxiosResponse containing the container ID(response.data.id)
139
+ * @returns An AxiosResponse containing the container ID(response.data.id)
140
140
  */
141
141
  export async function createContainerFromPayload(requestPayload, userID, userName) {
142
142
  const useAzure = process.env.FLUID_CLIENT === "azure";
@@ -195,7 +195,7 @@ export async function createContainerFromPayload(requestPayload, userID, userNam
195
195
  * (Tinylicious has the ID stored at a different path than other services)
196
196
  *
197
197
  * @param response - A container creation response returned by createContainerFromPayload
198
- * @returns - The ID of the container that was created by createContainerFromPayload
198
+ * @returns The ID of the container that was created by createContainerFromPayload
199
199
  */
200
200
  export function getContainerIdFromPayloadResponse(response) {
201
201
  const useAzure = process.env.FLUID_CLIENT === "azure";
@@ -1 +1 @@
1
- {"version":3,"file":"AzureClientFactory.js","sourceRoot":"","sources":["../../src/test/AzureClientFactory.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 {\n\tAzureClient,\n\ttype AzureLocalConnectionConfig,\n\ttype AzureRemoteConnectionConfig,\n\ttype ITelemetryBaseLogger,\n} from \"@fluidframework/azure-client\";\n// eslint-disable-next-line import/no-internal-modules -- TODO consider a test exposure to avoid /internal\nimport type { AzureClientPropsInternal } from \"@fluidframework/azure-client/internal\";\nimport {\n\tAzureClient as AzureClientLegacy,\n\ttype AzureLocalConnectionConfig as AzureLocalConnectionConfigLegacy,\n\ttype AzureRemoteConnectionConfig as AzureRemoteConnectionConfigLegacy,\n\ttype ITelemetryBaseLogger as ITelemetryBaseLoggerLegacy,\n} from \"@fluidframework/azure-client-legacy\";\nimport type { IRuntimeFactory } from \"@fluidframework/container-definitions/legacy\";\nimport type { IConfigProviderBase } from \"@fluidframework/core-interfaces\";\nimport { ScopeType } from \"@fluidframework/driver-definitions/legacy\";\nimport type { CompatibilityMode, ContainerSchema } from \"@fluidframework/fluid-static\";\nimport {\n\ttype MockLogger,\n\tcreateChildLogger,\n\tcreateMultiSinkLogger,\n} from \"@fluidframework/telemetry-utils/internal\";\nimport { InsecureTokenProvider } from \"@fluidframework/test-runtime-utils/internal\";\nimport { default as Axios, type AxiosResponse, type AxiosRequestConfig } from \"axios\";\nimport { v4 as uuid } from \"uuid\";\n\nimport { createAzureTokenProvider } from \"./AzureTokenFactory.js\";\n\n// eslint-disable-next-line unicorn/prefer-export-from\nexport { ScopeType };\n\n/**\n * This function will determine if local or remote mode is required (based on FLUID_CLIENT), and return a new\n * {@link AzureClient} instance based on the mode by setting the Connection config accordingly.\n */\nexport function createAzureClient(\n\tid?: string,\n\tname?: string,\n\tlogger?: MockLogger,\n\tconfigProvider?: IConfigProviderBase,\n\tscopes?: ScopeType[],\n\tcreateContainerRuntimeFactory?: ({\n\t\tschema,\n\t\tcompatibilityMode,\n\t}: {\n\t\tschema: ContainerSchema;\n\t\tcompatibilityMode: CompatibilityMode;\n\t}) => IRuntimeFactory,\n): AzureClient {\n\tconst args = process.argv.slice(2);\n\n\tconst driverIndex = args.indexOf(\"--driver\");\n\tconst r11sEndpointNameIndex = args.indexOf(\"--r11sEndpointName\");\n\n\t// Get values associated with the flags\n\tconst driver = driverIndex === -1 ? undefined : args[driverIndex + 1];\n\tconst r11sEndpointName =\n\t\tr11sEndpointNameIndex === -1 ? undefined : args[r11sEndpointNameIndex + 1];\n\n\tconst useAzure = process.env.FLUID_CLIENT === \"azure\";\n\tconst tenantId = useAzure\n\t\t? (process.env.azure__fluid__relay__service__tenantId as string)\n\t\t: \"frs-client-tenant\";\n\tconst user = {\n\t\tid: id ?? uuid(),\n\t\tname: name ?? uuid(),\n\t};\n\tconst endPoint = process.env.azure__fluid__relay__service__endpoint as string;\n\tif (useAzure && endPoint === undefined) {\n\t\tthrow new Error(\"Azure Fluid Relay service endpoint is missing\");\n\t}\n\n\t// use AzureClient remote mode will run against live Azure Fluid Relay.\n\t// Default to running Tinylicious for PR validation\n\t// and local testing so it's not hindered by service availability\n\tconst connectionProps: AzureRemoteConnectionConfig | AzureLocalConnectionConfig = useAzure\n\t\t? {\n\t\t\t\ttenantId,\n\t\t\t\ttokenProvider: createAzureTokenProvider(id ?? \"foo\", name ?? \"bar\", scopes),\n\t\t\t\tendpoint: endPoint,\n\t\t\t\ttype: \"remote\",\n\t\t\t}\n\t\t: {\n\t\t\t\ttokenProvider: new InsecureTokenProvider(\"fooBar\", user, scopes),\n\t\t\t\tendpoint: \"http://localhost:7071\",\n\t\t\t\ttype: \"local\",\n\t\t\t};\n\tconst getLogger = (): ITelemetryBaseLogger | undefined => {\n\t\tconst testLogger = getTestLogger?.();\n\t\tif (!logger && !testLogger) {\n\t\t\treturn undefined;\n\t\t}\n\t\tif (logger && testLogger) {\n\t\t\treturn createMultiSinkLogger({ loggers: [logger, testLogger] });\n\t\t}\n\t\treturn logger ?? testLogger;\n\t};\n\n\tconst createLogger = createChildLogger({\n\t\tlogger: getLogger(),\n\t\tproperties: {\n\t\t\tall: {\n\t\t\t\tdriverType: useAzure ? r11sEndpointName : driver,\n\t\t\t\tdriverEndpointName: driver,\n\t\t\t},\n\t\t},\n\t});\n\n\tconst props: AzureClientPropsInternal = {\n\t\tconnection: connectionProps,\n\t\tlogger: createLogger,\n\t\tconfigProvider,\n\t\tcreateContainerRuntimeFactory,\n\t};\n\treturn new AzureClient(props);\n}\n\n/**\n * Copy of {@link createAzureClient} with legacy (LTS) AzureClient APIs.\n */\nexport function createAzureClientLegacy(\n\tuserID?: string,\n\tuserName?: string,\n\tlogger?: MockLogger,\n): AzureClientLegacy {\n\tconst useAzure = process.env.FLUID_CLIENT === \"azure\";\n\tconst tenantId = useAzure\n\t\t? (process.env.azure__fluid__relay__service__tenantId as string)\n\t\t: \"frs-client-tenant\";\n\tconst user = {\n\t\tid: userID ?? uuid(),\n\t\tname: userName ?? uuid(),\n\t};\n\tconst endPoint = process.env.azure__fluid__relay__service__endpoint as string;\n\tif (useAzure && endPoint === undefined) {\n\t\tthrow new Error(\"Azure Azure Fluid Relay service endpoint is missing\");\n\t}\n\n\t// use AzureClient remote mode will run against live Azure Fluid Relay.\n\t// Default to running Tinylicious for PR validation\n\t// and local testing so it's not hindered by service availability\n\tconst connectionProps: AzureRemoteConnectionConfigLegacy | AzureLocalConnectionConfigLegacy =\n\t\tuseAzure\n\t\t\t? {\n\t\t\t\t\ttenantId,\n\t\t\t\t\ttokenProvider: createAzureTokenProvider(userID ?? \"foo\", userName ?? \"bar\"),\n\t\t\t\t\tendpoint: endPoint,\n\t\t\t\t\ttype: \"remote\",\n\t\t\t\t}\n\t\t\t: {\n\t\t\t\t\ttokenProvider: new InsecureTokenProvider(\"fooBar\", user),\n\t\t\t\t\tendpoint: \"http://localhost:7071\",\n\t\t\t\t\ttype: \"local\",\n\t\t\t\t};\n\tconst getLogger = (): ITelemetryBaseLoggerLegacy | undefined => {\n\t\tconst testLogger = getTestLogger?.();\n\t\tif (!logger && !testLogger) {\n\t\t\treturn undefined;\n\t\t}\n\t\tif (logger && testLogger) {\n\t\t\treturn createMultiSinkLogger({ loggers: [logger, testLogger] });\n\t\t}\n\t\treturn logger ?? testLogger;\n\t};\n\treturn new AzureClientLegacy({\n\t\tconnection: connectionProps,\n\t\tlogger: getLogger(),\n\t});\n}\n\n/**\n * This function is used to create a container using any summary payload.\n * It is primary intended as a workaround to using the AzureClient, and\n * is only being used at the moment for ephemeral container E2E tests\n * since AzureClient does not currently support ephemeral containers.\n *\n * Usage of this function for anything other than ephemeral E2E tests is\n * not recommended.\n *\n * @param requestPayload - The summary payload used to create the container,\n * currently these are mainly fetched from ephemeralSummaryTrees.ts\n * @param userID - ID for the user creating the container\n * @param userName - Name for the user creating the container\n * @returns - An AxiosResponse containing the container ID(response.data.id)\n */\nexport async function createContainerFromPayload(\n\trequestPayload: object,\n\tuserID?: string,\n\tuserName?: string,\n): Promise<AxiosResponse> {\n\tconst useAzure = process.env.FLUID_CLIENT === \"azure\";\n\tconst tenantId = useAzure\n\t\t? (process.env.azure__fluid__relay__service__tenantId as string)\n\t\t: \"local\";\n\tconst user = {\n\t\tid: userID ?? uuid(),\n\t\tname: userName ?? uuid(),\n\t};\n\tconst endPoint = useAzure\n\t\t? (process.env.azure__fluid__relay__service__endpoint as string)\n\t\t: \"http://localhost:7071\";\n\tif (useAzure && endPoint === undefined) {\n\t\tthrow new Error(\"Azure Fluid Relay service endpoint is missing\");\n\t}\n\n\tconst tokenProvider = useAzure\n\t\t? createAzureTokenProvider(userID ?? \"foo\", userName ?? \"bar\")\n\t\t: new InsecureTokenProvider(\"fooBar\", user);\n\tconst ordererToken = await tokenProvider.fetchOrdererToken(tenantId, undefined, false);\n\n\tconst headers = {\n\t\t\"Authorization\": `Basic ${ordererToken.jwt}`,\n\t\t\"Content-Type\": \"application/json\",\n\t};\n\n\tconst url = `/documents/${tenantId}`;\n\n\tconst options: AxiosRequestConfig = {\n\t\tbaseURL: endPoint,\n\t\tdata: requestPayload,\n\t\theaders,\n\t\tmaxBodyLength: 1048576000,\n\t\tmaxContentLength: 1048576000,\n\t\tmethod: \"POST\",\n\t\turl,\n\t};\n\n\ttry {\n\t\tconst response: AxiosResponse = await Axios(options);\n\n\t\tif (response.status === 201) {\n\t\t\tconsole.log(\"Container created successfully\");\n\t\t} else {\n\t\t\tthrow new Error(`Error creating container. Status code: ${response.status}`);\n\t\t}\n\n\t\t// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n\t\tif (response?.data === undefined || (useAzure && response?.data?.id === undefined)) {\n\t\t\tthrow new Error(`ID of the created container is undefined`);\n\t\t}\n\n\t\treturn response;\n\t} catch (error) {\n\t\tthrow new Error(`An error occurred: ${error}`);\n\t}\n}\n\n/**\n * This function takes an AxiosResponse returned by the createContainerFromPayload and returns the containerId.\n * A separate function is used for this, since the data path to the containerID is not always the same.\n * (Tinylicious has the ID stored at a different path than other services)\n *\n * @param response - A container creation response returned by createContainerFromPayload\n * @returns - The ID of the container that was created by createContainerFromPayload\n */\nexport function getContainerIdFromPayloadResponse(response: AxiosResponse): string {\n\tconst useAzure = process.env.FLUID_CLIENT === \"azure\";\n\t// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n\treturn (useAzure ? response.data.id : response.data) as string;\n}\n"]}
1
+ {"version":3,"file":"AzureClientFactory.js","sourceRoot":"","sources":["../../src/test/AzureClientFactory.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 {\n\tAzureClient,\n\ttype AzureLocalConnectionConfig,\n\ttype AzureRemoteConnectionConfig,\n\ttype ITelemetryBaseLogger,\n} from \"@fluidframework/azure-client\";\n// eslint-disable-next-line import/no-internal-modules -- TODO consider a test exposure to avoid /internal\nimport type { AzureClientPropsInternal } from \"@fluidframework/azure-client/internal\";\nimport {\n\tAzureClient as AzureClientLegacy,\n\ttype AzureLocalConnectionConfig as AzureLocalConnectionConfigLegacy,\n\ttype AzureRemoteConnectionConfig as AzureRemoteConnectionConfigLegacy,\n\ttype ITelemetryBaseLogger as ITelemetryBaseLoggerLegacy,\n} from \"@fluidframework/azure-client-legacy\";\nimport type { IRuntimeFactory } from \"@fluidframework/container-definitions/legacy\";\nimport type { IConfigProviderBase } from \"@fluidframework/core-interfaces\";\nimport { ScopeType } from \"@fluidframework/driver-definitions/legacy\";\nimport type { CompatibilityMode, ContainerSchema } from \"@fluidframework/fluid-static\";\nimport {\n\ttype MockLogger,\n\tcreateChildLogger,\n\tcreateMultiSinkLogger,\n} from \"@fluidframework/telemetry-utils/internal\";\nimport { InsecureTokenProvider } from \"@fluidframework/test-runtime-utils/internal\";\nimport { default as Axios, type AxiosResponse, type AxiosRequestConfig } from \"axios\";\nimport { v4 as uuid } from \"uuid\";\n\nimport { createAzureTokenProvider } from \"./AzureTokenFactory.js\";\n\n// eslint-disable-next-line unicorn/prefer-export-from\nexport { ScopeType };\n\n/**\n * This function will determine if local or remote mode is required (based on FLUID_CLIENT), and return a new\n * {@link AzureClient} instance based on the mode by setting the Connection config accordingly.\n */\nexport function createAzureClient(\n\tid?: string,\n\tname?: string,\n\tlogger?: MockLogger,\n\tconfigProvider?: IConfigProviderBase,\n\tscopes?: ScopeType[],\n\tcreateContainerRuntimeFactory?: ({\n\t\tschema,\n\t\tcompatibilityMode,\n\t}: {\n\t\tschema: ContainerSchema;\n\t\tcompatibilityMode: CompatibilityMode;\n\t}) => IRuntimeFactory,\n): AzureClient {\n\tconst args = process.argv.slice(2);\n\n\tconst driverIndex = args.indexOf(\"--driver\");\n\tconst r11sEndpointNameIndex = args.indexOf(\"--r11sEndpointName\");\n\n\t// Get values associated with the flags\n\tconst driver = driverIndex === -1 ? undefined : args[driverIndex + 1];\n\tconst r11sEndpointName =\n\t\tr11sEndpointNameIndex === -1 ? undefined : args[r11sEndpointNameIndex + 1];\n\n\tconst useAzure = process.env.FLUID_CLIENT === \"azure\";\n\tconst tenantId = useAzure\n\t\t? (process.env.azure__fluid__relay__service__tenantId as string)\n\t\t: \"frs-client-tenant\";\n\tconst user = {\n\t\tid: id ?? uuid(),\n\t\tname: name ?? uuid(),\n\t};\n\tconst endPoint = process.env.azure__fluid__relay__service__endpoint as string;\n\tif (useAzure && endPoint === undefined) {\n\t\tthrow new Error(\"Azure Fluid Relay service endpoint is missing\");\n\t}\n\n\t// use AzureClient remote mode will run against live Azure Fluid Relay.\n\t// Default to running Tinylicious for PR validation\n\t// and local testing so it's not hindered by service availability\n\tconst connectionProps: AzureRemoteConnectionConfig | AzureLocalConnectionConfig = useAzure\n\t\t? {\n\t\t\t\ttenantId,\n\t\t\t\ttokenProvider: createAzureTokenProvider(id ?? \"foo\", name ?? \"bar\", scopes),\n\t\t\t\tendpoint: endPoint,\n\t\t\t\ttype: \"remote\",\n\t\t\t}\n\t\t: {\n\t\t\t\ttokenProvider: new InsecureTokenProvider(\"fooBar\", user, scopes),\n\t\t\t\tendpoint: \"http://localhost:7071\",\n\t\t\t\ttype: \"local\",\n\t\t\t};\n\tconst getLogger = (): ITelemetryBaseLogger | undefined => {\n\t\tconst testLogger = getTestLogger?.();\n\t\tif (!logger && !testLogger) {\n\t\t\treturn undefined;\n\t\t}\n\t\tif (logger && testLogger) {\n\t\t\treturn createMultiSinkLogger({ loggers: [logger, testLogger] });\n\t\t}\n\t\treturn logger ?? testLogger;\n\t};\n\n\tconst createLogger = createChildLogger({\n\t\tlogger: getLogger(),\n\t\tproperties: {\n\t\t\tall: {\n\t\t\t\tdriverType: useAzure ? r11sEndpointName : driver,\n\t\t\t\tdriverEndpointName: driver,\n\t\t\t},\n\t\t},\n\t});\n\n\tconst props: AzureClientPropsInternal = {\n\t\tconnection: connectionProps,\n\t\tlogger: createLogger,\n\t\tconfigProvider,\n\t\tcreateContainerRuntimeFactory,\n\t};\n\treturn new AzureClient(props);\n}\n\n/**\n * Copy of {@link createAzureClient} with legacy (LTS) AzureClient APIs.\n */\nexport function createAzureClientLegacy(\n\tuserID?: string,\n\tuserName?: string,\n\tlogger?: MockLogger,\n): AzureClientLegacy {\n\tconst useAzure = process.env.FLUID_CLIENT === \"azure\";\n\tconst tenantId = useAzure\n\t\t? (process.env.azure__fluid__relay__service__tenantId as string)\n\t\t: \"frs-client-tenant\";\n\tconst user = {\n\t\tid: userID ?? uuid(),\n\t\tname: userName ?? uuid(),\n\t};\n\tconst endPoint = process.env.azure__fluid__relay__service__endpoint as string;\n\tif (useAzure && endPoint === undefined) {\n\t\tthrow new Error(\"Azure Azure Fluid Relay service endpoint is missing\");\n\t}\n\n\t// use AzureClient remote mode will run against live Azure Fluid Relay.\n\t// Default to running Tinylicious for PR validation\n\t// and local testing so it's not hindered by service availability\n\tconst connectionProps: AzureRemoteConnectionConfigLegacy | AzureLocalConnectionConfigLegacy =\n\t\tuseAzure\n\t\t\t? {\n\t\t\t\t\ttenantId,\n\t\t\t\t\ttokenProvider: createAzureTokenProvider(userID ?? \"foo\", userName ?? \"bar\"),\n\t\t\t\t\tendpoint: endPoint,\n\t\t\t\t\ttype: \"remote\",\n\t\t\t\t}\n\t\t\t: {\n\t\t\t\t\ttokenProvider: new InsecureTokenProvider(\"fooBar\", user),\n\t\t\t\t\tendpoint: \"http://localhost:7071\",\n\t\t\t\t\ttype: \"local\",\n\t\t\t\t};\n\tconst getLogger = (): ITelemetryBaseLoggerLegacy | undefined => {\n\t\tconst testLogger = getTestLogger?.();\n\t\tif (!logger && !testLogger) {\n\t\t\treturn undefined;\n\t\t}\n\t\tif (logger && testLogger) {\n\t\t\treturn createMultiSinkLogger({ loggers: [logger, testLogger] });\n\t\t}\n\t\treturn logger ?? testLogger;\n\t};\n\treturn new AzureClientLegacy({\n\t\tconnection: connectionProps,\n\t\tlogger: getLogger(),\n\t});\n}\n\n/**\n * This function is used to create a container using any summary payload.\n * It is primary intended as a workaround to using the AzureClient, and\n * is only being used at the moment for ephemeral container E2E tests\n * since AzureClient does not currently support ephemeral containers.\n *\n * Usage of this function for anything other than ephemeral E2E tests is\n * not recommended.\n *\n * @param requestPayload - The summary payload used to create the container,\n * currently these are mainly fetched from ephemeralSummaryTrees.ts\n * @param userID - ID for the user creating the container\n * @param userName - Name for the user creating the container\n * @returns An AxiosResponse containing the container ID(response.data.id)\n */\nexport async function createContainerFromPayload(\n\trequestPayload: object,\n\tuserID?: string,\n\tuserName?: string,\n): Promise<AxiosResponse> {\n\tconst useAzure = process.env.FLUID_CLIENT === \"azure\";\n\tconst tenantId = useAzure\n\t\t? (process.env.azure__fluid__relay__service__tenantId as string)\n\t\t: \"local\";\n\tconst user = {\n\t\tid: userID ?? uuid(),\n\t\tname: userName ?? uuid(),\n\t};\n\tconst endPoint = useAzure\n\t\t? (process.env.azure__fluid__relay__service__endpoint as string)\n\t\t: \"http://localhost:7071\";\n\tif (useAzure && endPoint === undefined) {\n\t\tthrow new Error(\"Azure Fluid Relay service endpoint is missing\");\n\t}\n\n\tconst tokenProvider = useAzure\n\t\t? createAzureTokenProvider(userID ?? \"foo\", userName ?? \"bar\")\n\t\t: new InsecureTokenProvider(\"fooBar\", user);\n\tconst ordererToken = await tokenProvider.fetchOrdererToken(tenantId, undefined, false);\n\n\tconst headers = {\n\t\t\"Authorization\": `Basic ${ordererToken.jwt}`,\n\t\t\"Content-Type\": \"application/json\",\n\t};\n\n\tconst url = `/documents/${tenantId}`;\n\n\tconst options: AxiosRequestConfig = {\n\t\tbaseURL: endPoint,\n\t\tdata: requestPayload,\n\t\theaders,\n\t\tmaxBodyLength: 1048576000,\n\t\tmaxContentLength: 1048576000,\n\t\tmethod: \"POST\",\n\t\turl,\n\t};\n\n\ttry {\n\t\tconst response: AxiosResponse = await Axios(options);\n\n\t\tif (response.status === 201) {\n\t\t\tconsole.log(\"Container created successfully\");\n\t\t} else {\n\t\t\tthrow new Error(`Error creating container. Status code: ${response.status}`);\n\t\t}\n\n\t\t// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n\t\tif (response?.data === undefined || (useAzure && response?.data?.id === undefined)) {\n\t\t\tthrow new Error(`ID of the created container is undefined`);\n\t\t}\n\n\t\treturn response;\n\t} catch (error) {\n\t\tthrow new Error(`An error occurred: ${error}`);\n\t}\n}\n\n/**\n * This function takes an AxiosResponse returned by the createContainerFromPayload and returns the containerId.\n * A separate function is used for this, since the data path to the containerID is not always the same.\n * (Tinylicious has the ID stored at a different path than other services)\n *\n * @param response - A container creation response returned by createContainerFromPayload\n * @returns The ID of the container that was created by createContainerFromPayload\n */\nexport function getContainerIdFromPayloadResponse(response: AxiosResponse): string {\n\tconst useAzure = process.env.FLUID_CLIENT === \"azure\";\n\t// eslint-disable-next-line @typescript-eslint/no-unsafe-member-access\n\treturn (useAzure ? response.data.id : response.data) as string;\n}\n"]}
@@ -24,28 +24,42 @@ const endPoint = process.env.azure__fluid__relay__service__endpoint;
24
24
  if (useAzure && endPoint === undefined) {
25
25
  throw new Error("Azure Fluid Relay service endpoint is missing");
26
26
  }
27
+ const containerSchema = {
28
+ initialObjects: {
29
+ // A DataObject is added as otherwise fluid-static complains "Container cannot be initialized without any DataTypes"
30
+ _unused: TestDataObject,
31
+ },
32
+ };
33
+ function telemetryEventInterestLevel(eventName) {
34
+ if (eventName.includes(":Signal") || eventName.includes(":Join")) {
35
+ return "details";
36
+ }
37
+ else if (eventName.includes(":Container:") || eventName.includes(":Presence:")) {
38
+ return "basic";
39
+ }
40
+ return "none";
41
+ }
27
42
  function selectiveVerboseLog(event, logLevel) {
28
- if (event.eventName.includes(":Signal") || event.eventName.includes(":Join")) {
29
- console.log(`[${process_id}] [${logLevel ?? LogLevel.default}]`, {
30
- eventName: event.eventName,
31
- details: event.details,
32
- containerConnectionState: event.containerConnectionState,
33
- });
43
+ const interest = telemetryEventInterestLevel(event.eventName);
44
+ if (interest === "none") {
45
+ return;
34
46
  }
35
- else if (event.eventName.includes(":Container:") ||
36
- event.eventName.includes(":Presence:")) {
37
- console.log(`[${process_id}] [${logLevel ?? LogLevel.default}]`, {
38
- eventName: event.eventName,
39
- containerConnectionState: event.containerConnectionState,
40
- });
47
+ const content = {
48
+ eventName: event.eventName,
49
+ containerConnectionState: event.containerConnectionState,
50
+ };
51
+ if (interest === "details") {
52
+ content.details = event.details;
41
53
  }
54
+ console.log(`[${process_id}] [${logLevel ?? LogLevel.default}]`, content);
42
55
  }
43
56
  /**
44
- * Get or create a Fluid container with Presence in initialObjects.
57
+ * Get or create a Fluid container.
45
58
  */
46
- const getOrCreatePresenceContainer = async (id, user, scopes, createScopes) => {
59
+ const getOrCreateContainer = async (params) => {
47
60
  let container;
48
- let containerId;
61
+ let { containerId } = params;
62
+ const { logger, onDisconnected, user, scopes, createScopes } = params;
49
63
  const connectionProps = useAzure
50
64
  ? {
51
65
  tenantId,
@@ -60,40 +74,30 @@ const getOrCreatePresenceContainer = async (id, user, scopes, createScopes) => {
60
74
  };
61
75
  const client = new AzureClient({
62
76
  connection: connectionProps,
63
- logger: {
64
- send: verbosity.includes("telem") ? selectiveVerboseLog : () => { },
65
- },
77
+ logger,
66
78
  });
67
- const schema = {
68
- initialObjects: {
69
- // A DataObject is added as otherwise fluid-static complains "Container cannot be initialized without any DataTypes"
70
- _unused: TestDataObject,
71
- },
72
- };
73
79
  let services;
74
- if (id === undefined) {
75
- ({ container, services } = await client.createContainer(schema, "2"));
80
+ if (containerId === undefined) {
81
+ ({ container, services } = await client.createContainer(containerSchema, "2"));
76
82
  containerId = await container.attach();
77
83
  }
78
84
  else {
79
- containerId = id;
80
- ({ container, services } = await client.getContainer(containerId, schema, "2"));
85
+ ({ container, services } = await client.getContainer(containerId, containerSchema, "2"));
81
86
  }
82
- // wait for 'ConnectionState.Connected' so we return with client connected to container
83
- if (container.connectionState !== ConnectionState.Connected) {
84
- await timeoutPromise((resolve) => container.once("connected", () => resolve()), {
87
+ container.on("disconnected", onDisconnected);
88
+ const connected = container.connectionState === ConnectionState.Connected
89
+ ? Promise.resolve()
90
+ : timeoutPromise((resolve) => container.once("connected", () => resolve()), {
85
91
  durationMs: connectTimeoutMs,
86
92
  errorMsg: "container connect() timeout",
87
93
  });
88
- }
89
94
  assert.strictEqual(container.attachState, AttachState.Attached, "Container is not attached after attach is called");
90
- const presence = getPresence(container);
91
95
  return {
92
96
  client,
93
97
  container,
94
- presence,
95
98
  services,
96
99
  containerId,
100
+ connected,
97
101
  };
98
102
  };
99
103
  function createSendFunction() {
@@ -110,21 +114,6 @@ function createSendFunction() {
110
114
  throw new Error("process.send is not defined");
111
115
  }
112
116
  const send = createSendFunction();
113
- function sendAttendeeConnected(attendee) {
114
- send({
115
- event: "attendeeConnected",
116
- attendeeId: attendee.attendeeId,
117
- });
118
- }
119
- function sendAttendeeDisconnected(attendee) {
120
- send({
121
- event: "attendeeDisconnected",
122
- attendeeId: attendee.attendeeId,
123
- });
124
- }
125
- function isConnected(container) {
126
- return container !== undefined && container.connectionState === ConnectionState.Connected;
127
- }
128
117
  function isStringOrNumberRecord(value) {
129
118
  if (value === null || typeof value !== "object" || Array.isArray(value)) {
130
119
  return false;
@@ -145,11 +134,58 @@ function isStringOrNumberRecord(value) {
145
134
  const WorkspaceSchema = {};
146
135
  class MessageHandler {
147
136
  constructor() {
137
+ this.log = [];
148
138
  this.workspaces = new Map();
139
+ this.sendAttendeeConnected = (attendee) => {
140
+ this.send({
141
+ event: "attendeeConnected",
142
+ attendeeId: attendee.attendeeId,
143
+ });
144
+ };
145
+ this.sendAttendeeDisconnected = (attendee) => {
146
+ this.send({
147
+ event: "attendeeDisconnected",
148
+ attendeeId: attendee.attendeeId,
149
+ });
150
+ };
151
+ this.logger = {
152
+ send: (event, logLevel) => {
153
+ const interest = telemetryEventInterestLevel(event.eventName);
154
+ if (interest === "none") {
155
+ return;
156
+ }
157
+ this.log.push({
158
+ timestamp: Date.now(),
159
+ agentId: process_id,
160
+ eventCategory: "telemetry",
161
+ eventName: event.eventName,
162
+ details: typeof event.details === "string" ? event.details : JSON.stringify(event.details),
163
+ });
164
+ if (verbosity.includes("telem")) {
165
+ selectiveVerboseLog(event, logLevel);
166
+ }
167
+ },
168
+ };
169
+ this.onDisconnected = () => {
170
+ // Test state is a bit fragile and does not account for reconnections.
171
+ this.send({ event: "error", error: `${process_id}: Container disconnected` });
172
+ };
173
+ }
174
+ send(msg) {
175
+ this.log.push({
176
+ timestamp: Date.now(),
177
+ agentId: process_id,
178
+ eventCategory: "messageSent",
179
+ eventName: msg.event,
180
+ details: msg.event === "debugReportComplete" && msg.log
181
+ ? JSON.stringify({ logLength: msg.log.length })
182
+ : JSON.stringify(msg),
183
+ });
184
+ send(msg);
149
185
  }
150
186
  registerWorkspace(workspaceId, options) {
151
187
  if (!this.presence) {
152
- send({ event: "error", error: `${process_id} is not connected to presence` });
188
+ this.send({ event: "error", error: `${process_id} is not connected to presence` });
153
189
  return;
154
190
  }
155
191
  const { latest, latestMap } = options;
@@ -160,7 +196,7 @@ class MessageHandler {
160
196
  // TODO: AB#47518
161
197
  const latestState = workspace.states.latest;
162
198
  latestState.events.on("remoteUpdated", (update) => {
163
- send({
199
+ this.send({
164
200
  event: "latestValueUpdated",
165
201
  workspaceId,
166
202
  attendeeId: update.attendee.attendeeId,
@@ -168,7 +204,7 @@ class MessageHandler {
168
204
  });
169
205
  });
170
206
  for (const remote of latestState.getRemotes()) {
171
- send({
207
+ this.send({
172
208
  event: "latestValueUpdated",
173
209
  workspaceId,
174
210
  attendeeId: remote.attendee.attendeeId,
@@ -185,7 +221,7 @@ class MessageHandler {
185
221
  const latestMapState = workspace.states.latestMap;
186
222
  latestMapState.events.on("remoteUpdated", (update) => {
187
223
  for (const [key, valueWithMetadata] of update.items) {
188
- send({
224
+ this.send({
189
225
  event: "latestMapValueUpdated",
190
226
  workspaceId,
191
227
  attendeeId: update.attendee.attendeeId,
@@ -196,7 +232,7 @@ class MessageHandler {
196
232
  });
197
233
  for (const remote of latestMapState.getRemotes()) {
198
234
  for (const [key, valueWithMetadata] of remote.items) {
199
- send({
235
+ this.send({
200
236
  event: "latestMapValueUpdated",
201
237
  workspaceId,
202
238
  attendeeId: remote.attendee.attendeeId,
@@ -207,7 +243,7 @@ class MessageHandler {
207
243
  }
208
244
  }
209
245
  this.workspaces.set(workspaceId, workspace);
210
- send({
246
+ this.send({
211
247
  event: "workspaceRegistered",
212
248
  workspaceId,
213
249
  latest: latest ?? false,
@@ -216,15 +252,33 @@ class MessageHandler {
216
252
  }
217
253
  async onMessage(msg) {
218
254
  if (verbosity.includes("msgs")) {
255
+ this.log.push({
256
+ timestamp: Date.now(),
257
+ agentId: process_id,
258
+ eventCategory: "messageReceived",
259
+ eventName: msg.command,
260
+ });
219
261
  console.log(`[${process_id}] Received`, msg);
220
262
  }
263
+ if (msg.command === "ping") {
264
+ this.handlePing();
265
+ return;
266
+ }
267
+ if (msg.command === "connect") {
268
+ await this.handleConnect(msg);
269
+ return;
270
+ }
271
+ // All other message must wait if connect is in progress
272
+ if (this.msgQueue !== undefined) {
273
+ this.msgQueue.push(msg);
274
+ return;
275
+ }
276
+ this.processMessage(msg);
277
+ }
278
+ processMessage(msg) {
221
279
  switch (msg.command) {
222
- case "ping": {
223
- this.handlePing();
224
- break;
225
- }
226
- case "connect": {
227
- await this.handleConnect(msg);
280
+ case "debugReport": {
281
+ this.handleDebugReport(msg);
228
282
  break;
229
283
  }
230
284
  case "disconnectSelf": {
@@ -255,74 +309,125 @@ class MessageHandler {
255
309
  break;
256
310
  }
257
311
  default: {
258
- console.error(`${process_id}: Unknown command`);
259
- send({ event: "error", error: `${process_id} Unknown command` });
312
+ console.error(`${process_id}: Unknown command:`, msg);
313
+ this.send({
314
+ event: "error",
315
+ error: `${process_id} Unknown command: ${JSON.stringify(msg)}`,
316
+ });
260
317
  }
261
318
  }
262
319
  }
263
320
  handlePing() {
264
- send({ event: "ack" });
321
+ this.send({ event: "ack" });
265
322
  }
266
323
  async handleConnect(msg) {
267
324
  if (!msg.user) {
268
- send({ event: "error", error: `${process_id}: No azure user information given` });
325
+ this.send({ event: "error", error: `${process_id}: No azure user information given` });
269
326
  return;
270
327
  }
271
- if (isConnected(this.container)) {
272
- send({ event: "error", error: `${process_id}: Already connected to container` });
328
+ if (this.container) {
329
+ this.send({ event: "error", error: `${process_id}: Container already loaded` });
273
330
  return;
274
331
  }
275
- const { container, presence, containerId } = await getOrCreatePresenceContainer(msg.containerId, msg.user, msg.scopes, msg.createScopes);
276
- this.container = container;
277
- this.presence = presence;
278
- this.containerId = containerId;
279
- // Acknowledge connection before sending current attendee information
280
- send({
281
- event: "connected",
282
- containerId,
283
- attendeeId: presence.attendees.getMyself().attendeeId,
284
- });
285
- // Send existing attendees excluding self to parent/orchestrator
286
- const self = presence.attendees.getMyself();
287
- for (const attendee of presence.attendees.getAttendees()) {
288
- if (attendee !== self) {
289
- sendAttendeeConnected(attendee);
332
+ // Prevent reentrance. Queue messages until after connect is fully processed.
333
+ this.msgQueue = [];
334
+ try {
335
+ const { container, containerId, connected } = await getOrCreateContainer({
336
+ ...msg,
337
+ logger: this.logger,
338
+ onDisconnected: this.onDisconnected,
339
+ });
340
+ this.container = container;
341
+ const presence = getPresence(container);
342
+ this.presence = presence;
343
+ // wait for 'ConnectionState.Connected'
344
+ await connected;
345
+ // Acknowledge connection before sending current attendee information
346
+ this.send({
347
+ event: "connected",
348
+ containerId,
349
+ attendeeId: presence.attendees.getMyself().attendeeId,
350
+ });
351
+ // Send existing attendees excluding self to parent/orchestrator
352
+ const self = presence.attendees.getMyself();
353
+ for (const attendee of presence.attendees.getAttendees()) {
354
+ if (attendee !== self && attendee.getConnectionStatus() === "Connected") {
355
+ this.sendAttendeeConnected(attendee);
356
+ }
357
+ }
358
+ // Listen for presence events to notify parent/orchestrator when a new attendee joins or leaves the session.
359
+ presence.attendees.events.on("attendeeConnected", this.sendAttendeeConnected);
360
+ presence.attendees.events.on("attendeeDisconnected", this.sendAttendeeDisconnected);
361
+ }
362
+ finally {
363
+ // Process any queued messages received while connecting
364
+ for (const queuedMsg of this.msgQueue) {
365
+ this.processMessage(queuedMsg);
366
+ }
367
+ this.msgQueue = undefined;
368
+ }
369
+ }
370
+ handleDebugReport(msg) {
371
+ if (msg.reportAttendees) {
372
+ if (this.presence) {
373
+ const attendees = this.presence.attendees.getAttendees();
374
+ let connectedCount = 0;
375
+ for (const attendee of attendees) {
376
+ if (attendee.getConnectionStatus() === "Connected") {
377
+ connectedCount++;
378
+ }
379
+ }
380
+ console.log(`[${process_id}] Report: ${attendees.size} attendees, ${connectedCount} connected`);
381
+ }
382
+ else {
383
+ this.send({ event: "error", error: `${process_id} is not connected to presence` });
290
384
  }
291
385
  }
292
- // Listen for presence events to notify parent/orchestrator when a new attendee joins or leaves the session.
293
- presence.attendees.events.on("attendeeConnected", sendAttendeeConnected);
294
- presence.attendees.events.on("attendeeDisconnected", sendAttendeeDisconnected);
386
+ const debugReport = {
387
+ event: "debugReportComplete",
388
+ };
389
+ if (msg.sendEventLog) {
390
+ debugReport.log = this.log;
391
+ }
392
+ this.send(debugReport);
295
393
  }
296
394
  handleDisconnectSelf() {
297
395
  if (!this.container) {
298
- send({ event: "error", error: `${process_id} is not connected to container` });
396
+ this.send({ event: "error", error: `${process_id} is not connected to container` });
299
397
  return;
300
398
  }
399
+ // There are no current scenarios where disconnect without presence is expected.
301
400
  if (!this.presence) {
302
- send({ event: "error", error: `${process_id} is not connected to presence` });
401
+ this.send({ event: "error", error: `${process_id} is not connected to presence` });
303
402
  return;
304
403
  }
404
+ // Disconnect event is treated as an error in normal handling.
405
+ // Remove listener as this disconnect is intentional.
406
+ this.container.off("disconnected", this.onDisconnected);
305
407
  this.container.disconnect();
306
- send({
408
+ this.send({
307
409
  event: "disconnectedSelf",
308
410
  attendeeId: this.presence.attendees.getMyself().attendeeId,
309
411
  });
310
412
  }
311
413
  handleSetLatestValue(msg) {
312
414
  if (!this.presence) {
313
- send({ event: "error", error: `${process_id} is not connected to presence` });
415
+ this.send({ event: "error", error: `${process_id} is not connected to presence` });
314
416
  return;
315
417
  }
316
418
  const workspace = this.workspaces.get(msg.workspaceId);
317
419
  if (!workspace) {
318
- send({ event: "error", error: `${process_id} workspace ${msg.workspaceId} not found` });
420
+ this.send({
421
+ event: "error",
422
+ error: `${process_id} workspace ${msg.workspaceId} not found`,
423
+ });
319
424
  return;
320
425
  }
321
426
  // Cast required due to optional keys in WorkspaceSchema
322
427
  // TODO: AB#47518
323
428
  const latestState = workspace.states.latest;
324
429
  if (!latestState) {
325
- send({
430
+ this.send({
326
431
  event: "error",
327
432
  error: `${process_id} latest state not registered for workspace ${msg.workspaceId}`,
328
433
  });
@@ -335,23 +440,26 @@ class MessageHandler {
335
440
  }
336
441
  handleSetLatestMapValue(msg) {
337
442
  if (!this.presence) {
338
- send({ event: "error", error: `${process_id} is not connected to presence` });
443
+ this.send({ event: "error", error: `${process_id} is not connected to presence` });
339
444
  return;
340
445
  }
341
446
  if (typeof msg.key !== "string") {
342
- send({ event: "error", error: `${process_id} invalid key type` });
447
+ this.send({ event: "error", error: `${process_id} invalid key type` });
343
448
  return;
344
449
  }
345
450
  const workspace = this.workspaces.get(msg.workspaceId);
346
451
  if (!workspace) {
347
- send({ event: "error", error: `${process_id} workspace ${msg.workspaceId} not found` });
452
+ this.send({
453
+ event: "error",
454
+ error: `${process_id} workspace ${msg.workspaceId} not found`,
455
+ });
348
456
  return;
349
457
  }
350
458
  // Cast required due to optional keys in WorkspaceSchema
351
459
  // TODO: AB#47518
352
460
  const latestMapState = workspace.states.latestMap;
353
461
  if (!latestMapState) {
354
- send({
462
+ this.send({
355
463
  event: "error",
356
464
  error: `${process_id} latestMap state not registered for workspace ${msg.workspaceId}`,
357
465
  });
@@ -364,19 +472,22 @@ class MessageHandler {
364
472
  }
365
473
  handleGetLatestValue(msg) {
366
474
  if (!this.presence) {
367
- send({ event: "error", error: `${process_id} is not connected to presence` });
475
+ this.send({ event: "error", error: `${process_id} is not connected to presence` });
368
476
  return;
369
477
  }
370
478
  const workspace = this.workspaces.get(msg.workspaceId);
371
479
  if (!workspace) {
372
- send({ event: "error", error: `${process_id} workspace ${msg.workspaceId} not found` });
480
+ this.send({
481
+ event: "error",
482
+ error: `${process_id} workspace ${msg.workspaceId} not found`,
483
+ });
373
484
  return;
374
485
  }
375
486
  // Cast required due to optional keys in WorkspaceSchema
376
487
  // TODO: AB#47518
377
488
  const latestState = workspace.states.latest;
378
489
  if (!latestState) {
379
- send({
490
+ this.send({
380
491
  event: "error",
381
492
  error: `${process_id} latest state not registered for workspace ${msg.workspaceId}`,
382
493
  });
@@ -391,7 +502,7 @@ class MessageHandler {
391
502
  else {
392
503
  value = latestState.local;
393
504
  }
394
- send({
505
+ this.send({
395
506
  event: "latestValueGetResponse",
396
507
  workspaceId: msg.workspaceId,
397
508
  attendeeId: msg.attendeeId,
@@ -400,23 +511,26 @@ class MessageHandler {
400
511
  }
401
512
  handleGetLatestMapValue(msg) {
402
513
  if (!this.presence) {
403
- send({ event: "error", error: `${process_id} is not connected to presence` });
514
+ this.send({ event: "error", error: `${process_id} is not connected to presence` });
404
515
  return;
405
516
  }
406
517
  if (typeof msg.key !== "string") {
407
- send({ event: "error", error: `${process_id} invalid key type` });
518
+ this.send({ event: "error", error: `${process_id} invalid key type` });
408
519
  return;
409
520
  }
410
521
  const workspace = this.workspaces.get(msg.workspaceId);
411
522
  if (!workspace) {
412
- send({ event: "error", error: `${process_id} workspace ${msg.workspaceId} not found` });
523
+ this.send({
524
+ event: "error",
525
+ error: `${process_id} workspace ${msg.workspaceId} not found`,
526
+ });
413
527
  return;
414
528
  }
415
529
  // Cast required due to optional keys in WorkspaceSchema
416
530
  // TODO: AB#47518
417
531
  const latestMapState = workspace.states.latestMap;
418
532
  if (!latestMapState) {
419
- send({
533
+ this.send({
420
534
  event: "error",
421
535
  error: `${process_id} latestMap state not registered for workspace ${msg.workspaceId}`,
422
536
  });
@@ -432,7 +546,7 @@ class MessageHandler {
432
546
  else {
433
547
  value = latestMapState.local.get(msg.key);
434
548
  }
435
- send({
549
+ this.send({
436
550
  event: "latestMapValueGetResponse",
437
551
  workspaceId: msg.workspaceId,
438
552
  attendeeId: msg.attendeeId,