"use strict";
/*!
 * Copyright (c) Microsoft Corporation and contributors. All rights reserved.
 * Licensed under the MIT License.
 */
Object.defineProperty(exports, "__esModule", { value: true });
exports.isValidCompatVersion = exports.getConfigsForCompatMode = exports.getCompatibilityVersionDefaults = exports.defaultCompatibilityVersion = void 0;
const internal_1 = require("@fluidframework/runtime-definitions/internal");
const semver_ts_1 = require("semver-ts");
const compressionDefinitions_js_1 = require("./compressionDefinitions.js");
const packageVersion_js_1 = require("./packageVersion.js");
/**
 * Our policy is to support N/N-1 compatibility by default, where N is the most
 * recent public major release of the runtime.
 * Therefore, if the customer does not provide a compatibility mode, we will
 * default to use N-1.
 *
 * However, this is not consistent with today's behavior. Some options (i.e.
 * batching, compression) are enabled by default despite not being compatible
 * with 1.x clients. Since the policy was introduced during 2.x's lifespan,
 * N/N-1 compatibility by **default** will be in effect starting with 3.0.
 * Importantly though, N/N-2 compatibility is still guaranteed with the proper
 * configurations set.
 *
 * Further to distinguish unspecified `compatibilityVersion` from a specified
 * version and allow `enableExplicitSchemaControl` to default to `true` for
 * any 2.0.0+ version, we will use a special value of `2.0.0-defaults`, which
 * is semantically less than 2.0.0.
 */
exports.defaultCompatibilityVersion = "2.0.0-defaults";
/**
 * Mapping of RuntimeOptionsAffectingDocSchema to their compatibility related configs.
 *
 * Each key in this map corresponds to a property in RuntimeOptionsAffectingDocSchema. The value is an object that maps SemanticVersions
 * to the appropriate default value for that property to supporting that SemanticVersion. If clients running SemanticVersion X are able to understand
 * the format changes introduced by the property, then the default value for that SemanticVersion will enable the feature associated with the property.
 * Otherwise, the feature will be disabled.
 *
 * For example if the compatibilityVersion is a 1.x version (i.e. "1.5.0"), then the default value for `enableGroupedBatching` will be false since 1.x
 * clients do not understand the document format when batching is enabled. If the compatibilityVersion is a 2.x client (i.e. "2.0.0" or later), then the
 * default value for `enableGroupedBatching` will be true because clients running 2.0 or later will be able to understand the format changes associated
 * with the batching feature.
 */
const runtimeOptionsAffectingDocSchemaConfigMap = {
    enableGroupedBatching: {
        "1.0.0": false,
        "2.0.0-defaults": true,
    },
    compressionOptions: {
        "1.0.0": compressionDefinitions_js_1.disabledCompressionConfig,
        "2.0.0-defaults": compressionDefinitions_js_1.enabledCompressionConfig,
    },
    enableRuntimeIdCompressor: {
        // For IdCompressorMode, `undefined` represents a logical state (off).
        // However, to satisfy the Required<> constraint while
        // `exactOptionalPropertyTypes` is `false` (TODO: AB#8215), we need
        // to have it defined, so we trick the type checker here.
        "1.0.0": undefined,
        // We do not yet want to enable idCompressor by default since it will
        // increase bundle sizes, and not all customers will benefit from it.
        // Therefore, we will require customers to explicitly enable it. We
        // are keeping it as a DocSchema affecting option for now as this may
        // change in the future.
    },
    explicitSchemaControl: {
        "1.0.0": false,
        // This option's intention is to prevent 1.x clients from joining sessions
        // when enabled. This is set to true when the compatibility version is set
        // to >=2.0.0 (explicitly). This is different than other 2.0 defaults
        // because it was not enabled by default prior to the implementation of
        // `compatibilityVersion`.
        // `defaultCompatibilityVersion` is set to "2.0.0-defaults" which "2.0.0"
        // does not satisfy to avoiding enabling this option by default as of
        // `compatibilityVersion` introduction, which could be unexpected.
        // Only enable as a default when `compatibilityVersion` is specified at
        // 2.0.0+.
        "2.0.0": true,
    },
    flushMode: {
        // Note: 1.x clients are compatible with TurnBased flushing, but here we elect to remain on Immediate flush mode
        // as a work-around for inability to send batches larger than 1Mb. Immediate flushing keeps batches smaller as
        // fewer messages will be included per flush.
        "1.0.0": internal_1.FlushMode.Immediate,
        "2.0.0-defaults": internal_1.FlushMode.TurnBased,
    },
    gcOptions: {
        "1.0.0": {},
        // Although sweep is supported in 2.x, it is disabled by default until compatibilityVersion>=3.0.0 to be extra safe.
        "3.0.0": { enableGCSweep: true },
    },
    createBlobPayloadPending: {
        // This feature is new and disabled by default. In the future we will enable it by default, but we have not
        // closed on the version where that will happen yet.  Probably a .10 release since blob functionality is not
        // exposed on the `@public` API surface.
        "1.0.0": undefined,
    },
};
/**
 * Returns the default RuntimeOptionsAffectingDocSchema configuration for a given compatibility version.
 */
function getCompatibilityVersionDefaults(compatibilityVersion) {
    return getConfigsForCompatMode(compatibilityVersion, runtimeOptionsAffectingDocSchemaConfigMap);
}
exports.getCompatibilityVersionDefaults = getCompatibilityVersionDefaults;
/**
 * Returns a default configuration given compatibility version and configuration version map.
 */
function getConfigsForCompatMode(compatibilityVersion, configMap) {
    const defaultConfigs = {};
    // Iterate over configMap to get default values for each option.
    for (const key of Object.keys(configMap)) {
        const config = configMap[key];
        // Sort the versions in ascending order so we can short circuit the loop.
        const versions = Object.keys(config).sort(semver_ts_1.compare);
        // For each config, we iterate over the keys and check if compatibilityVersion is greater than or equal to the version.
        // If so, we set it as the default value for the option. At the end of the loop we should have the most recent default
        // value that is compatible with the version specified as the compatibilityVersion.
        for (const version of versions) {
            if ((0, semver_ts_1.gte)(compatibilityVersion, version)) {
                defaultConfigs[key] = config[version];
            }
            else {
                // If the compatibility mode is less than the version, we break out of the loop since we don't need to check
                // any later versions.
                break;
            }
        }
    }
    return defaultConfigs;
}
exports.getConfigsForCompatMode = getConfigsForCompatMode;
/**
 * Checks if the compatibility version is valid.
 * A valid compatibility version is a string that is a valid semver version and is less than or equal to the current package version.
 */
function isValidCompatVersion(compatibilityVersion) {
    return (compatibilityVersion !== undefined &&
        (0, semver_ts_1.valid)(compatibilityVersion) !== null &&
        (0, semver_ts_1.lte)(compatibilityVersion, packageVersion_js_1.pkgVersion));
}
exports.isValidCompatVersion = isValidCompatVersion;
//# sourceMappingURL=compatUtils.js.map