"use strict";
/*---------------------------------------------------------------------------------------------
* Copyright (c) Bentley Systems, Incorporated. All rights reserved.
* See LICENSE.md in the project root for license terms and full copyright notice.
*--------------------------------------------------------------------------------------------*/
/** @packageDocumentation
 * @module IModelHost
 */
Object.defineProperty(exports, "__esModule", { value: true });
exports.FileNameResolver = exports.KnownLocations = exports.Platform = exports.IModelHost = exports.IModelHostConfiguration = void 0;
// To avoid circular load errors, the "Element" classes must be loaded before IModelHost.
require("./IModelDb"); // DO NOT REMOVE OR MOVE THIS LINE!
const NativePlatform_1 = require("./internal/NativePlatform");
const os = require("node:os");
const imodeljs_native_1 = require("@bentley/imodeljs-native");
const core_bentley_1 = require("@itwin/core-bentley");
const core_common_1 = require("@itwin/core-common");
const object_storage_azure_1 = require("@itwin/object-storage-azure");
const storage_blob_1 = require("@azure/storage-blob");
const BackendLoggerCategory_1 = require("./BackendLoggerCategory");
const BisCoreSchema_1 = require("./BisCoreSchema");
const BriefcaseManager_1 = require("./BriefcaseManager");
const CloudSqlite_1 = require("./CloudSqlite");
const FunctionalSchema_1 = require("./domains/FunctionalSchema");
const GenericSchema_1 = require("./domains/GenericSchema");
const EditTxn_1 = require("./EditTxn");
const GeoCoordConfig_1 = require("./GeoCoordConfig");
const IModelJsFs_1 = require("./IModelJsFs");
const DevToolsRpcImpl_1 = require("./rpc-impl/DevToolsRpcImpl");
const IModelReadRpcImpl_1 = require("./rpc-impl/IModelReadRpcImpl");
const IModelTileRpcImpl_1 = require("./rpc-impl/IModelTileRpcImpl");
const SnapshotIModelRpcImpl_1 = require("./rpc-impl/SnapshotIModelRpcImpl");
const RpcBackend_1 = require("./RpcBackend");
const TileStorage_1 = require("./TileStorage");
const Settings_1 = require("./workspace/Settings");
const SettingsDb_1 = require("./workspace/SettingsDb");
const SettingsEditor_1 = require("./workspace/SettingsEditor");
const path_1 = require("path");
const WorkspaceImpl_1 = require("./internal/workspace/WorkspaceImpl");
const SettingsImpl_1 = require("./internal/workspace/SettingsImpl");
const SettingsSchemasImpl_1 = require("./internal/workspace/SettingsSchemasImpl");
const Symbols_1 = require("./internal/Symbols");
const loggerCategory = BackendLoggerCategory_1.BackendLoggerCategory.IModelHost;
/** Configuration of core-backend.
 * @public
 */
class IModelHostConfiguration {
    static defaultTileRequestTimeout = 20 * 1000;
    static defaultLogTileLoadTimeThreshold = 40;
    static defaultLogTileSizeThreshold = 20 * 1000000;
    /** @internal */
    static defaultMaxTileCacheDbSize = 1024 * 1024 * 1024;
    appAssetsDir;
    cacheDir;
    /** @beta */
    workspace;
    hubAccess;
    /** The AuthorizationClient used to obtain [AccessToken]($bentley)s. */
    authorizationClient;
    /** @beta */
    restrictTileUrlsByClientIp;
    compressCachedTiles;
    /** @beta */
    tileCacheAzureCredentials;
    /** @internal */
    tileTreeRequestTimeout = IModelHostConfiguration.defaultTileRequestTimeout;
    /** @internal */
    tileContentRequestTimeout = IModelHostConfiguration.defaultTileRequestTimeout;
    /** @internal */
    logTileLoadTimeThreshold = IModelHostConfiguration.defaultLogTileLoadTimeThreshold;
    /** @internal */
    logTileSizeThreshold = IModelHostConfiguration.defaultLogTileSizeThreshold;
    /** @internal */
    crashReportingConfig;
    /**
     * Configuration controlling whether to use the thinned down native instance functions for element, model, and aspect CRUD operations
     * or use the previous behavior of using the native side for all CRUD operations. Set to true to revert to the previous behavior.
     * @beta
    */
    disableThinnedNativeInstanceWorkflow;
    /**
     * Configuration controlling whether to disable the creation of restore points during pull/merge operations.
     * @beta
     */
    disableRestorePointOnPullMerge;
    /**
     * Configuration controlling whether incremental schema loading is disabled.
     * Default is "disabled" at the moment to preserve existing behavior.
     * @beta
     */
    incrementalSchemaLoading = "disabled";
    /**
     * Configuration controlling whether to use semantic rebase or not. By default it is undefined meaning semantic rebase is not used.
     * @beta
     */
    useSemanticRebase;
    /**
      * Controls how writes through the implicit transaction are enforced.
      * See [[IModelHostOptions.implicitWriteEnforcement]] for the meaning of each allowed value.
     * @beta
     */
    implicitWriteEnforcement = "allow";
}
exports.IModelHostConfiguration = IModelHostConfiguration;
/**
 * Settings for `IModelHost.appWorkspace`.
 * @note this includes the default dictionary from the SettingsSpecRegistry
 */
class ApplicationSettings extends SettingsImpl_1.SettingsImpl {
    _remove;
    verifyPriority(priority) {
        if (priority > Settings_1.SettingsPriority.application) // only application or lower may appear in ApplicationSettings
            throw new Error("Use IModelSettings");
    }
    updateDefaults() {
        const defaults = {};
        for (const [schemaName, val] of IModelHost.settingsSchemas.settingDefs) {
            if (val.default)
                defaults[schemaName] = val.default;
        }
        this.addDictionary({ name: "_default_", priority: 0 }, defaults);
    }
    constructor() {
        super();
        this._remove = IModelHost.settingsSchemas.onSchemaChanged.addListener(() => this.updateDefaults());
        this.updateDefaults();
    }
    close() {
        if (this._remove) {
            this._remove();
            this._remove = undefined;
        }
    }
}
/**
 * Settings for an iTwin. May only include settings priority for iTwin and organization.
 */
class ITwinWorkspaceSettings extends SettingsImpl_1.SettingsImpl {
    verifyPriority(priority) {
        if (priority <= Settings_1.SettingsPriority.application)
            core_common_1.ITwinSettingsError.throwError("invalid-priority", { message: `Settings with priority ${priority} cannot be added to an iTwin workspace.` });
        if (priority > Settings_1.SettingsPriority.iTwin)
            core_common_1.ITwinSettingsError.throwError("invalid-priority", { message: `Settings with priority ${priority} cannot be added to an iTwin workspace.` });
    }
    *getSettingEntries(name) {
        yield* super.getSettingEntries(name);
        yield* IModelHost.appWorkspace.settings.getSettingEntries(name);
    }
}
const definedInStartup = (obj) => {
    if (obj === undefined)
        throw new Error("IModelHost.startup must be called first");
    return obj;
};
/** IModelHost initializes ($backend) and captures its configuration. A backend must call [[IModelHost.startup]] before using any backend classes.
 * See [the learning article]($docs/learning/backend/IModelHost.md)
 * @public
 */
class IModelHost {
    constructor() { }
    /** The AuthorizationClient used to obtain [AccessToken]($bentley)s. */
    static authorizationClient;
    static backendVersion = "";
    static _profileName;
    static _cacheDir = "";
    static _settingsSchemas;
    static _appWorkspace;
    // Omit the hubAccess field from configuration so it stays internal.
    static configuration;
    /**
     * The name of the *Profile* directory (a subdirectory of "[[cacheDir]]/profiles/") for this process.
     *
     * The *Profile* directory is used to cache data that is specific to a type-of-usage of the iTwin.js library.
     * It is important that information in the profile cache be consistent but isolated across sessions (i.e.
     * data for a profile is maintained between runs, but each profile is completely independent and
     * unaffected by the presence or use of others.)
     * @note **Only one process at a time may be using a given profile**, and an exception will be thrown by [[startup]]
     * if a second process attempts to use the same profile.
     * @beta
     */
    static get profileName() {
        return this._profileName;
    }
    /** The full path of the Profile directory.
     * @see [[profileName]]
     * @beta
     */
    static get profileDir() {
        return (0, path_1.join)(this._cacheDir, "profiles", this._profileName);
    }
    /** Event raised during startup to allow loading settings data */
    static onWorkspaceStartup = new core_bentley_1.BeEvent();
    /** Event raised just after the backend IModelHost was started */
    static onAfterStartup = new core_bentley_1.BeEvent();
    /** Event raised just before the backend IModelHost is to be shut down */
    static onBeforeShutdown = new core_bentley_1.BeEvent();
    /** @internal */
    static session = { applicationId: "2686", applicationVersion: "1.0.0", sessionId: "" };
    /** A uniqueId for this session */
    static get sessionId() { return this.session.sessionId; }
    static set sessionId(id) { this.session.sessionId = id; }
    /** The Id of this application - needs to be set only if it is an agent application. The applicationId will otherwise originate at the frontend. */
    static get applicationId() { return this.session.applicationId; }
    static set applicationId(id) { this.session.applicationId = id; }
    /** The version of this application - needs to be set if is an agent application. The applicationVersion will otherwise originate at the frontend. */
    static get applicationVersion() { return this.session.applicationVersion; }
    static set applicationVersion(version) { this.session.applicationVersion = version; }
    /** A string that can identify the current user to other users when collaborating. */
    static userMoniker = "unknown";
    /** Root directory holding files that iTwin.js caches */
    static get cacheDir() { return this._cacheDir; }
    /** The application [[Workspace]] for this `IModelHost`
     * @note this `Workspace` only holds [[WorkspaceContainer]]s and [[Settings]] scoped to the currently loaded application(s).
     * All organization, iTwin, and iModel based containers or settings must be accessed through [[IModelDb.workspace]] and
     * attempting to add them to this Workspace will fail.
     * @beta
     */
    static get appWorkspace() { return definedInStartup(this._appWorkspace); }
    /** @internal */
    static async getITwinWorkspace(args) {
        const isITwinId = typeof args === "string";
        const workspace = (0, WorkspaceImpl_1.constructWorkspace)(new ITwinWorkspaceSettings());
        try {
            const settingsSources = isITwinId ? await SettingsEditor_1.SettingsContainers.getITwinSettingsSources(args) : args;
            if (undefined === settingsSources)
                return workspace;
            workspace.settingsSources = settingsSources;
            const problems = [];
            await workspace.loadSettingsDictionary(settingsSources, problems);
            if (problems.length > 0) {
                const label = isITwinId ? `iTwin '${args}'` : "the supplied settings workspace db properties";
                (0, WorkspaceImpl_1.throwWorkspaceDbLoadErrors)(`attempting to load workspace settings for ${label}`, problems);
            }
            return workspace;
        }
        catch (error) {
            workspace.close();
            throw error;
        }
    }
    /** Save a named [[SettingsDictionary]] to the iTwin's settings container.
     * If no iTwin settings container exists for `iTwinId`, one is created.
     * The dictionary is stored as a named resource in the container's default [[WorkspaceDb]], where `name` is used as the resource name.
     * @param iTwinId The iTwin whose settings container should be updated.
     * @param name The name of the dictionary, used as the resource name in the [[WorkspaceDb]].
     * @param settings The settings key-value pairs to store.
     * @note uses [[IModelHost.userMoniker]] as the user name for acquiring the write lock on the settings container.
     * @beta
     */
    static async saveSettingDictionary(iTwinId, name, settings) {
        const { editor, container } = await SettingsEditor_1.SettingsEditor.constructForITwin(iTwinId);
        try {
            await container.withEditableDb(this.userMoniker, (db) => {
                db.updateSettingsResource(settings, name);
            }, { dbName: SettingsDb_1.settingsWorkspaceDbName });
        }
        finally {
            editor.close();
        }
    }
    /** Delete a named [[SettingsDictionary]] from the iTwin's settings container.
     * If no iTwin settings container exists, this method does nothing.
     * @param iTwinId The iTwin whose settings container should be updated.
     * @param name The name of the dictionary (resource name) to delete.
     * @note uses [[IModelHost.userMoniker]] as the user name for acquiring the write lock on the settings container.
     * @beta
     */
    static async deleteSettingDictionary(iTwinId, name) {
        const settingsEditor = await SettingsEditor_1.SettingsEditor.getForITwin(iTwinId);
        if (undefined === settingsEditor)
            return;
        const { editor, container } = settingsEditor;
        try {
            await container.withEditableDb(this.userMoniker, (db) => {
                db.removeString(name);
            }, { dbName: SettingsDb_1.settingsWorkspaceDbName });
        }
        finally {
            editor.close();
        }
    }
    /** The registry of schemas describing the [[Setting]]s for the application session.
     * Applications should register their schemas via methods like [[SettingsSchemas.addGroup]].
     * @beta
     */
    static get settingsSchemas() { return definedInStartup(this._settingsSchemas); }
    /** The optional [[FileNameResolver]] that resolves keys and partial file names for snapshot iModels.
     * @deprecated in 4.10 - will not be removed until after 2026-06-13. When opening a snapshot by file name, ensure to pass already resolved path. Using a key to open a snapshot is now deprecated.
     */
    static snapshotFileNameResolver; // eslint-disable-line @typescript-eslint/no-deprecated
    /** Get the current access token for this IModelHost, or a blank string if none is available.
     * @note for web backends, this will *always* return a blank string because the backend itself has no token (but never needs one either.)
     * For all IpcHosts, where this backend is servicing a single frontend, this will be the user's token. For ElectronHost, the backend
     * obtains the token and forwards it to the frontend.
     * @note accessTokens expire periodically and are automatically refreshed, if possible. Therefore tokens should not be saved, and the value
     * returned by this method may change over time throughout the course of a session.
     */
    static async getAccessToken() {
        try {
            return (await IModelHost.authorizationClient?.getAccessToken()) ?? "";
        }
        catch {
            return "";
        }
    }
    static loadNative(options) {
        (0, NativePlatform_1.loadNativePlatform)();
        if (options.crashReportingConfig && options.crashReportingConfig.crashDir && !core_bentley_1.ProcessDetector.isElectronAppBackend && !core_bentley_1.ProcessDetector.isMobileAppBackend) {
            NativePlatform_1.IModelNative.platform.setCrashReporting(options.crashReportingConfig);
            core_bentley_1.Logger.logTrace(loggerCategory, "Configured crash reporting", {
                enableCrashDumps: options.crashReportingConfig?.enableCrashDumps,
                wantFullMemoryDumps: options.crashReportingConfig?.wantFullMemoryDumps,
                enableNodeReport: options.crashReportingConfig?.enableNodeReport,
                uploadToBentley: options.crashReportingConfig?.uploadToBentley,
            });
            if (options.crashReportingConfig.enableNodeReport) {
                if (process.report !== undefined) {
                    process.report.reportOnFatalError = true;
                    process.report.reportOnUncaughtException = true;
                    process.report.directory = options.crashReportingConfig.crashDir;
                    core_bentley_1.Logger.logTrace(loggerCategory, "Configured Node.js crash reporting");
                }
                else {
                    core_bentley_1.Logger.logWarning(loggerCategory, "Unable to configure Node.js crash reporting");
                }
            }
        }
    }
    /** @internal */
    static tileStorage;
    static _hubAccess;
    /** @internal */
    static [Symbols_1._setHubAccess](hubAccess) { this._hubAccess = hubAccess; }
    /** get the current hubAccess, if present.
     * @internal
     */
    static [Symbols_1._getHubAccess]() { return this._hubAccess; }
    /** Provides access to the IModelHub for this IModelHost
     * @internal
     * @note If [[IModelHostOptions.hubAccess]] was undefined when initializing this class, accessing this property will throw an error.
     * To determine whether one is present, use [[_getHubAccess]].
     */
    static get [Symbols_1._hubAccess]() {
        if (IModelHost._hubAccess === undefined)
            throw new core_common_1.IModelError(core_bentley_1.IModelStatus.BadRequest, "No BackendHubAccess supplied in IModelHostOptions");
        return IModelHost._hubAccess;
    }
    static initializeWorkspace(configuration) {
        const settingAssets = (0, path_1.join)(KnownLocations.packageAssetsDir, "Settings");
        this._settingsSchemas = (0, SettingsSchemasImpl_1.constructSettingsSchemas)();
        this._settingsSchemas.addDirectory((0, path_1.join)(settingAssets, "Schemas"));
        this._appWorkspace = (0, WorkspaceImpl_1.constructWorkspace)(new ApplicationSettings(), configuration.workspace);
        // Create the CloudCache for Workspaces. This will fail if another process is already using the same profile.
        try {
            this.appWorkspace.getCloudCache();
        }
        catch (e) {
            throw (e.errorNumber === core_bentley_1.DbResult.BE_SQLITE_BUSY) ? new core_common_1.IModelError(core_bentley_1.DbResult.BE_SQLITE_BUSY, `Profile [${this.profileDir}] is already in use by another process`) : e;
        }
        this.appWorkspace.settings.addDirectory(settingAssets, Settings_1.SettingsPriority.defaults);
        GeoCoordConfig_1.GeoCoordConfig.onStartup();
        // allow applications to load their default settings
        this.onWorkspaceStartup.raiseEvent();
    }
    static _isValid = false;
    /** true between a successful call to [[startup]] and before [[shutdown]] */
    static get isValid() {
        return IModelHost._isValid;
    }
    /** This method must be called before any iTwin.js services are used.
     * @param options Host configuration data.
     * Raises [[onAfterStartup]].
     * @see [[shutdown]].
     */
    static async startup(options) {
        if (this._isValid)
            return; // we're already initialized
        this._isValid = true;
        options = options ?? {};
        if (this.sessionId === "")
            this.sessionId = core_bentley_1.Guid.createValue();
        this.authorizationClient = options.authorizationClient;
        this.backendVersion = require("../../package.json").version; // eslint-disable-line @typescript-eslint/no-require-imports
        (0, RpcBackend_1.initializeRpcBackend)(options.enableOpenTelemetry);
        this.loadNative(options);
        this.setupCacheDir(options);
        this.initializeWorkspace(options);
        EditTxn_1.EditTxn.implicitWriteEnforcement = options.implicitWriteEnforcement ?? "allow";
        BriefcaseManager_1.BriefcaseManager.initialize((0, path_1.join)(this._cacheDir, "imodels"));
        [
            IModelReadRpcImpl_1.IModelReadRpcImpl,
            IModelTileRpcImpl_1.IModelTileRpcImpl,
            SnapshotIModelRpcImpl_1.SnapshotIModelRpcImpl, // eslint-disable-line @typescript-eslint/no-deprecated
            DevToolsRpcImpl_1.DevToolsRpcImpl,
        ].forEach((rpc) => rpc.register()); // register all of the RPC implementations
        [
            BisCoreSchema_1.BisCoreSchema,
            GenericSchema_1.GenericSchema,
            FunctionalSchema_1.FunctionalSchema,
        ].forEach((schema) => schema.registerSchema()); // register all of the schemas
        const { hubAccess, ...otherOptions } = options;
        if (undefined !== hubAccess)
            this._hubAccess = hubAccess;
        this.configuration = otherOptions;
        this.setupTileCache();
        process.once("beforeExit", IModelHost.shutdown);
        this.onAfterStartup.raiseEvent();
    }
    static setupCacheDir(configuration) {
        this._cacheDir = (0, path_1.normalize)(configuration.cacheDir ?? imodeljs_native_1.NativeLibrary.defaultCacheDir);
        IModelJsFs_1.IModelJsFs.recursiveMkDirSync(this._cacheDir);
        this._profileName = configuration.profileName ?? "default";
        core_bentley_1.Logger.logInfo(loggerCategory, `cacheDir: [${this.cacheDir}], profileDir: [${this.profileDir}]`);
    }
    /** This method must be called when an iTwin.js host is shut down. Raises [[onBeforeShutdown]] */
    static async shutdown() {
        // Note: This method is set as a node listener where `this` is unbound. Call private method to
        // ensure `this` is correct. Don't combine these methods.
        return IModelHost.doShutdown();
    }
    /**
     * Create a new iModel.
     * @returns the Guid of the newly created iModel.
     * @throws [IModelError]($common) in case of errors.
     * @note If [[IModelHostOptions.hubAccess]] was undefined in the call to [[startup]], this function will throw an error.
     */
    static async createNewIModel(arg) {
        return this[Symbols_1._hubAccess].createNewIModel(arg);
    }
    static async doShutdown() {
        if (!this._isValid)
            return;
        this._isValid = false;
        this.onBeforeShutdown.raiseEvent();
        this.configuration = undefined;
        EditTxn_1.EditTxn.implicitWriteEnforcement = "allow";
        this.tileStorage = undefined;
        this._appWorkspace?.close();
        this._appWorkspace = undefined;
        this._settingsSchemas = undefined;
        CloudSqlite_1.CloudSqlite.CloudCaches.destroy();
        process.removeListener("beforeExit", IModelHost.shutdown);
    }
    /**
     * Add or update a property that should be included in a crash report.
     * @internal
     */
    static setCrashReportProperty(name, value) {
        NativePlatform_1.IModelNative.platform.setCrashReportProperty(name, value);
    }
    /**
     * Remove a previously defined property so that will not be included in a crash report.
     * @internal
     */
    static removeCrashReportProperty(name) {
        NativePlatform_1.IModelNative.platform.setCrashReportProperty(name, undefined);
    }
    /**
     * Get all properties that will be included in a crash report.
     * @internal
     */
    static getCrashReportProperties() {
        return NativePlatform_1.IModelNative.platform.getCrashReportProperties();
    }
    /** The directory where application assets may be found */
    static get appAssetsDir() {
        return undefined !== IModelHost.configuration ? IModelHost.configuration.appAssetsDir : undefined;
    }
    /** The time, in milliseconds, for which IModelTileRpcInterface.requestTileTreeProps should wait before returning a "pending" status.
     * @internal
     */
    static get tileTreeRequestTimeout() {
        return IModelHost.configuration?.tileTreeRequestTimeout ?? IModelHostConfiguration.defaultTileRequestTimeout;
    }
    /** The time, in milliseconds, for which IModelTileRpcInterface.requestTileContent should wait before returning a "pending" status.
     * @internal
     */
    static get tileContentRequestTimeout() {
        return IModelHost.configuration?.tileContentRequestTimeout ?? IModelHostConfiguration.defaultTileRequestTimeout;
    }
    /** The backend will log when a tile took longer to load than this threshold in seconds. */
    static get logTileLoadTimeThreshold() {
        return IModelHost.configuration?.logTileLoadTimeThreshold ?? IModelHostConfiguration.defaultLogTileLoadTimeThreshold;
    }
    /** The backend will log when a tile is loaded with a size in bytes above this threshold. */
    static get logTileSizeThreshold() {
        return IModelHost.configuration?.logTileSizeThreshold ?? IModelHostConfiguration.defaultLogTileSizeThreshold;
    }
    /** Whether external tile caching is active.
     * @internal
     */
    static get usingExternalTileCache() {
        return undefined !== IModelHost.tileStorage;
    }
    /** Whether to restrict tile cache URLs by client IP address.
     * @internal
     */
    static get restrictTileUrlsByClientIp() {
        return undefined !== IModelHost.configuration && (IModelHost.configuration.restrictTileUrlsByClientIp ? true : false);
    }
    /** Whether to compress cached tiles.
     * @internal
     */
    static get compressCachedTiles() {
        return false !== IModelHost.configuration?.compressCachedTiles;
    }
    /**
     * Whether to use semantic rebase or not.
     * @internal
     */
    static get useSemanticRebase() {
        return undefined !== IModelHost.configuration && (IModelHost.configuration.useSemanticRebase ? true : false);
    }
    static setupTileCache() {
        (0, core_bentley_1.assert)(undefined !== IModelHost.configuration);
        const config = IModelHost.configuration;
        const storage = config.tileCacheStorage;
        const credentials = config.tileCacheAzureCredentials;
        if (!storage && !credentials) {
            NativePlatform_1.IModelNative.platform.setMaxTileCacheSize(config.maxTileCacheDbSize ?? IModelHostConfiguration.defaultMaxTileCacheDbSize);
            return;
        }
        NativePlatform_1.IModelNative.platform.setMaxTileCacheSize(0);
        if (credentials) {
            if (storage)
                throw new core_common_1.IModelError(core_bentley_1.BentleyStatus.ERROR, "Cannot use both Azure and custom cloud storage providers for tile cache.");
            this.setupAzureTileCache(credentials);
        }
        if (storage)
            IModelHost.tileStorage = new TileStorage_1.TileStorage(storage);
    }
    static setupAzureTileCache(credentials) {
        const storageConfig = {
            accountName: credentials.account,
            accountKey: credentials.accessKey,
            baseUrl: credentials.baseUrl ?? `https://${credentials.account}.blob.core.windows.net`,
        };
        const blobServiceClient = new storage_blob_1.BlobServiceClient(storageConfig.baseUrl, new storage_blob_1.StorageSharedKeyCredential(storageConfig.accountName, storageConfig.accountKey));
        const azureStorage = new object_storage_azure_1.AzureServerStorage(storageConfig, new object_storage_azure_1.BlobServiceClientWrapper(blobServiceClient));
        IModelHost.tileStorage = new TileStorage_1.TileStorage(azureStorage);
    }
    /** @internal */
    static computeSchemaChecksum(arg) {
        return NativePlatform_1.IModelNative.platform.computeSchemaChecksum(arg);
    }
}
exports.IModelHost = IModelHost;
/** Information about the platform on which the app is running.
 * @public
 */
class Platform {
    /** Get the name of the platform. */
    static get platformName() {
        return process.platform;
    }
}
exports.Platform = Platform;
/** Well known directories that may be used by the application.
 * @public
 */
class KnownLocations {
    /** The directory where the imodeljs-native assets are stored. */
    static get nativeAssetsDir() {
        return NativePlatform_1.IModelNative.platform.DgnDb.getAssetsDir();
    }
    /** The directory where the core-backend assets are stored. */
    static get packageAssetsDir() {
        return (0, path_1.join)(__dirname, "assets");
    }
    /** The temporary directory. */
    static get tmpdir() {
        return os.tmpdir();
    }
}
exports.KnownLocations = KnownLocations;
/** Extend this class to provide custom file name resolution behavior.
 * @note Only `tryResolveKey` and/or `tryResolveFileName` need to be overridden as the implementations of `resolveKey` and `resolveFileName` work for most purposes.
 * @see [[IModelHost.snapshotFileNameResolver]]
 * @public
 * @deprecated in 4.10 - will not be removed until after 2026-06-13. When opening a snapshot by file name, ensure to pass already resolved path. Using a key to open a snapshot is now deprecated.
 */
class FileNameResolver {
    /** Resolve a file name from the specified key.
     * @param _fileKey The key that identifies the file name in a `Map` or other similar data structure.
     * @returns The resolved file name or `undefined` if not found.
     */
    tryResolveKey(_fileKey) { return undefined; }
    /** Resolve a file name from the specified key.
     * @param fileKey The key that identifies the file name in a `Map` or other similar data structure.
     * @returns The resolved file name.
     * @throws [[IModelError]] if not found.
     */
    resolveKey(fileKey) {
        const resolvedFileName = this.tryResolveKey(fileKey);
        if (undefined === resolvedFileName) {
            throw new core_common_1.IModelError(core_bentley_1.IModelStatus.NotFound, `${fileKey} not resolved`);
        }
        return resolvedFileName;
    }
    /** Resolve the input file name, which may be a partial name, into a full path file name.
     * @param inFileName The partial file name.
     * @returns The resolved full path file name or `undefined` if not found.
     */
    tryResolveFileName(inFileName) { return inFileName; }
    /** Resolve the input file name, which may be a partial name, into a full path file name.
     * @param inFileName The partial file name.
     * @returns The resolved full path file name.
     * @throws [[IModelError]] if not found.
     */
    resolveFileName(inFileName) {
        const resolvedFileName = this.tryResolveFileName(inFileName);
        if (undefined === resolvedFileName) {
            throw new core_common_1.IModelError(core_bentley_1.IModelStatus.NotFound, `${inFileName} not resolved`);
        }
        return resolvedFileName;
    }
}
exports.FileNameResolver = FileNameResolver;
//# sourceMappingURL=IModelHost.js.map