function _check_private_redeclaration(obj, privateCollection) {
    if (privateCollection.has(obj)) {
        throw new TypeError("Cannot initialize the same private elements twice on an object");
    }
}
function _class_apply_descriptor_get(receiver, descriptor) {
    if (descriptor.get) {
        return descriptor.get.call(receiver);
    }
    return descriptor.value;
}
function _class_apply_descriptor_set(receiver, descriptor, value) {
    if (descriptor.set) {
        descriptor.set.call(receiver, value);
    } else {
        if (!descriptor.writable) {
            throw new TypeError("attempted to set read only private field");
        }
        descriptor.value = value;
    }
}
function _class_extract_field_descriptor(receiver, privateMap, action) {
    if (!privateMap.has(receiver)) {
        throw new TypeError("attempted to " + action + " private field on non-instance");
    }
    return privateMap.get(receiver);
}
function _class_private_field_get(receiver, privateMap) {
    var descriptor = _class_extract_field_descriptor(receiver, privateMap, "get");
    return _class_apply_descriptor_get(receiver, descriptor);
}
function _class_private_field_init(obj, privateMap, value) {
    _check_private_redeclaration(obj, privateMap);
    privateMap.set(obj, value);
}
function _class_private_field_set(receiver, privateMap, value) {
    var descriptor = _class_extract_field_descriptor(receiver, privateMap, "set");
    _class_apply_descriptor_set(receiver, descriptor, value);
    return value;
}
function _class_private_method_get(receiver, privateSet, fn) {
    if (!privateSet.has(receiver)) {
        throw new TypeError("attempted to get private field on non-instance");
    }
    return fn;
}
function _class_private_method_init(obj, privateSet) {
    _check_private_redeclaration(obj, privateSet);
    privateSet.add(obj);
}
import { isFunction } from '../../helpers/function.mjs';
import { error as logError } from '../../helpers/console.mjs';
import { throwWithCause } from '../../helpers/errors.mjs';
import * as I18nC from '../../i18n/constants.mjs';
import { BasePlugin } from '../base/index.mjs';
import { PLUGIN_KEY, PLUGIN_PRIORITY, DEFAULT_SETTINGS, SETTINGS_VALIDATORS, ABORT_REASON_MESSAGE, DATA_PROVIDER_BATCH_UPDATE_SOURCES, DATA_PROVIDER_ERROR_REMOVE_ROWS_MISSING_ID, DATA_PROVIDER_ERROR_UPDATE_ROWS_MISSING_ID, INITIAL_QUERY_PARAMETERS } from './constants.mjs';
import { buildManualUpdateRowPayloads, commitRowsUpdate as commitRowsUpdateCrud, enqueueMutation, filterChangesForBatchedServerUpdate, getRowIdByVisualRow, handleBeforeAlterForCrud, isMissingRowId, queueCrud, runAfterRowsMutation, runAfterRowsMutationError, runBeforeRowsMutation, runManualUpdateRowsMutation, runUpdateFromChanges, shouldIgnoreAfterChangeForServerUpdate } from './query/crud.mjs';
import { applyFiltersFromFiltersPluginToQueryParameters, cloneDataProviderFiltersPayload, filtersPayloadToConditionsStack, handleBeforeFilterForServer } from './query/filtering.mjs';
import { applyPaginationToQueryFromPlugin, getPagedRowHeaderIndex, handleAfterPageChangeExternalPagination, handleAfterPageSizeChangeExternalPagination } from './query/pagination.mjs';
import { applyColumnSortToQueryFromPlugin, handleBeforeColumnSortForServer, normalizeSortInFetchParams, sortingPayloadToSort } from './query/sorting.mjs';
import { clampDataProviderPageToTotalRows, getDataProviderRequestErrorDescription, isCompleteDataProviderConfig } from './utils.mjs';
import { registerConflict } from '../base/conflictRegistry.mjs';
registerConflict('dataProvider', [
    'manualRowMove',
    'manualColumnMove',
    'trimRows',
    'multiColumnSorting'
]);
/**
 * Sort descriptor in query parameters (`fetchRows` and DataProvider getters).
 *
 * @typedef {object} DataProviderSortDescriptor
 * @property {string} prop Column data key.
 * @property {'asc'|'desc'} order Sort direction.
 */ /**
 * Single filter condition entry (same shape as Filters `exportConditions` items).
 *
 * @typedef {object} DataProviderFilterCondition
 * @property {string} [name] Condition name (omitted for some stack entries).
 * @property {Array<*>} args Condition arguments.
 */ /**
 * Server filter column (`prop` replaces physical column index). Same shape as in `types/plugins/dataProvider/dataProvider.d.ts`.
 *
 * @typedef {object} DataProviderFilterColumn
 * @property {string} prop Column data key.
 * @property {'conjunction'|'disjunction'|'disjunctionWithExtraCondition'} operation Filters stack operation (same values as [[Filters#exportConditions]]).
 * @property {Array<DataProviderFilterCondition>} conditions Filter conditions (same shape as Filters `exportConditions`).
 */ /**
 * Query parameters passed to `fetchRows` and exposed by DataProvider.
 *
 * @typedef {object} DataProviderQueryParameters
 * @property {number} page 1-based page index.
 * @property {number} pageSize Rows per page.
 * @property {DataProviderSortDescriptor|null} sort Primary sort or null.
 * @property {Array<DataProviderFilterColumn>|null} filters Server-side filters or null.
 */ export { PLUGIN_KEY, PLUGIN_PRIORITY } from './constants.mjs';
var /**
   * Last request params passed to `fetchRows` (`page`, `pageSize`, `sort`, `filters`).
   * Same shape as `DataProviderQueryParameters` in `types/plugins/dataProvider/dataProvider.d.ts`.
   *
   * @type {DataProviderQueryParameters}
   */ _queryParameters = /*#__PURE__*/ new WeakMap(), /**
   * Aborts in-flight fetch when superseded or on disable/destroy.
   *
   * @type {AbortController|null}
   */ _abortController = /*#__PURE__*/ new WeakMap(), /**
   * Serializes create/update/remove mutations so they run one after another.
   *
   * @type {{ tail: Promise<void> }}
   */ _mutationQueue = /*#__PURE__*/ new WeakMap(), /**
   * Raw `dataProvider` setting (config object only).
   *
   * @returns {object|undefined}
   */ _getConfig = /*#__PURE__*/ new WeakSet(), /**
   * `rowId` from config (string path or function).
   *
   * @returns {string|Function|undefined|null}
   */ _getRowIdOption = /*#__PURE__*/ new WeakSet(), /**
   * @returns {Function|undefined}
   */ _getFetchFn = /*#__PURE__*/ new WeakSet(), /**
   * @returns {Function|undefined}
   */ _getOnRowsCreate = /*#__PURE__*/ new WeakSet(), /**
   * @returns {Function|undefined}
   */ _getOnRowsUpdate = /*#__PURE__*/ new WeakSet(), /**
   * @returns {Function|undefined}
   */ _getOnRowsRemove = /*#__PURE__*/ new WeakSet(), /**
   * @param {DataProviderQueryParameters} p Query parameters object.
   * @returns {DataProviderQueryParameters} Snapshot safe for comparisons and external use (`sort` and `filters` cloned when non-null).
   */ _snapshotQueryParameters = /*#__PURE__*/ new WeakSet(), /**
   * Fills `#queryParameters` from Pagination, ColumnSorting, and (when `fetchRows` exists) Filters so `fetchRows`
   * matches plugin UI state after enable or before a server-driven refetch.
   *
   * @returns {void}
   */ _applyQueryParametersFromPlugins = /*#__PURE__*/ new WeakSet(), /**
   * Aborts an in-flight `fetchRows` call so a new request can start.
   *
   * @returns {void}
   */ _abortInFlightFetch = /*#__PURE__*/ new WeakSet(), /**
   * Merges overrides into `#queryParameters` and normalizes sort / page for `fetchRows`.
   *
   * @param {object} overrides Partial query overrides (subset of [[DataProviderQueryParameters]] keys).
   * @returns {DataProviderQueryParameters} Query parameters object for `fetchRows`.
   */ _mergeAndNormalizeFetchParams = /*#__PURE__*/ new WeakSet(), /**
   * Replaces `#abortController` with a new controller for the next fetch.
   *
   * @returns {AbortController}
   */ _createFetchAbortController = /*#__PURE__*/ new WeakSet(), /**
   * @param {object} params Query parameters for the aborted `fetchRows` call.
   * @param {Error|undefined} reason `AbortError` (or subclass) when `fetchRows` rejected; omit the argument when the promise settled after superseding.
   * @returns {void}
   */ _runAfterDataProviderFetchAbort = /*#__PURE__*/ new WeakSet(), /**
   * Aborts any pending `fetchRows` and clears the controller.
   *
   * @returns {void}
   */ _resetAbortController = /*#__PURE__*/ new WeakSet(), /**
   * Appends a mutation onto the queue so concurrent CRUD runs sequentially.
   *
   * @param {function(): Promise<void>} fn Async work for one mutation.
   * @returns {Promise<void>}
   */ _enqueueMutation = /*#__PURE__*/ new WeakSet(), /**
   * Shows an error toast in the [[Options#notification]] plugin when it is enabled.
   * For `fetch` failures only, the toast includes a primary **Refetch** action (`duration: 0` until dismissed) that hides the toast and calls [[DataProvider#fetchData]] again.
   *
   * @param {'fetch'|'create'|'update'|'remove'} kind Which request failed.
   * @param {Error|*} err Rejection reason from the user callback or `fetchRows`.
   * @returns {void}
   */ _showDataProviderRequestErrorNotification = /*#__PURE__*/ new WeakSet(), /**
   * Calls `onRowsUpdate`, success/error hooks, then re-fetches or re-renders.
   *
   * @param {object[]} rowPayloads Per-row `{ id, changes, rowData }` payloads.
   * @param {object} [options] Optional flags.
   * @param {function(): void} [options.revertOptimistic] Restores previous cell values when the request fails.
   * @returns {Promise<void>}
   */ _commitRowsUpdate = /*#__PURE__*/ new WeakSet(), /**
   * Queues create/remove (or similar) server calls with before/after mutation hooks.
   *
   * @param {string} operation `'create'` or `'remove'`.
   * @param {object} payload Hook payload (`{ rowsCreate }` or `{ rowsRemove }`).
   * @param {function(): Promise<*>} userPromiseFn Server callback invocation.
   * @param {function(): Promise<void>|void} onSuccess Runs after success (e.g. `fetchData`).
   * @returns {Promise<void>}
   */ _queueCrud = /*#__PURE__*/ new WeakSet(), /**
   * Default handler for [[Hooks#hasExternalDataSource]]: `true` when this instance has a complete server-backed
   * `dataProvider` configuration. Registered in the constructor (early lifecycle) and in `enablePlugin()` after each
   * `disablePlugin()` clears `addHook` listeners.
   *
   * @returns {boolean}
   */ _onHasExternalDataSource = /*#__PURE__*/ new WeakMap(), /**
   * @returns {void}
   */ _onAfterInit = /*#__PURE__*/ new WeakMap(), /**
   * Loads the requested page when Pagination runs in external paged mode.
   * Skips when `#queryParameters` already matches the Pagination UI (e.g. right after a successful fetch).
   *
   * @param {number} oldPage Previous 1-based page.
   * @param {number} newPage New 1-based page.
   * @returns {void}
   */ _onAfterPageChangeExternalPagination = /*#__PURE__*/ new WeakMap(), /**
   * Loads page 1 with the new page size when Pagination runs in external paged mode.
   * Skips when `#queryParameters` already match (e.g. duplicate `afterPageSizeChange` from Pagination sync).
   *
   * @param {number | 'auto'} oldPageSize Previous page size.
   * @param {number | 'auto'} newPageSize New page size.
   * @returns {void}
   */ _onAfterPageSizeChangeExternalPagination = /*#__PURE__*/ new WeakMap(), /**
   * Intercepts filter action when `fetchRows` is set: applies server-side filters and refetches; returns false so Filters skip client-side trimming.
   * Without `fetchRows`, returns nothing so Filters run client-side trimming (same guard pattern as [[#onBeforeColumnSort]]).
   *
   * @param {Array} conditionsStack Exported filter conditions (column = physical index).
   * @returns {boolean|void} False when filtering is handled server-side.
   */ _onBeforeFilter = /*#__PURE__*/ new WeakMap(), /**
   * @param {Array} currentSortConfig Current sort config.
   * @param {Array} destinationSortConfigs Destination sort config.
   * @param {boolean} sortPossible Whether sort is allowed.
   * @returns {boolean|undefined}
   */ _onBeforeColumnSort = /*#__PURE__*/ new WeakMap(), /**
   * @param {number} visualRowIndex Visual row index.
   * @returns {number} Global row index for headers.
   */ _onModifyRowHeader = /*#__PURE__*/ new WeakMap(), /**
   * Skips the local undo stack for edits that batch to `onRowsUpdate` (same sources as `shouldIgnoreAfterChangeForServerUpdate`).
   *
   * @param {Array} doneActionsCopy Snapshot of the undo stack before the new action.
   * @param {string} [source] Change source for the action being pushed onto the stack.
   * @returns {boolean|void} Return `false` to block stacking (see [[Hooks#beforeUndoStackChange]]).
   */ _onBeforeUndoStackChange = /*#__PURE__*/ new WeakMap(), /**
   * After a valid edit applies locally, queues `onRowsUpdate`. On failure, cells revert to previous values.
   *
   * @param {Array} changes `[visualRow, prop, oldVal, newVal][]`.
   * @param {string} [source] Change source.
   * @returns {void}
   */ _onAfterChangeForServerUpdate = /*#__PURE__*/ new WeakMap(), /**
   * @param {string} action Alter action name.
   * @param {number|Array} index Row index or index groups.
   * @param {number} amount Row count.
   * @returns {boolean|undefined}
   */ _onBeforeAlter = /*#__PURE__*/ new WeakMap();
/**
 * @plugin DataProvider
 * @class DataProvider
 *
 * @description
 * A truthy [[Options#dataProvider]] value enables this plugin. Each key (`rowId`, `fetchRows`, `onRowsCreate`, `onRowsUpdate`, `onRowsRemove`) is validated like other plugin options.
 * When the object is a **complete** server-backed configuration (all of those keys present and valid), Handsontable loads rows via `fetchRows`, runs mutations through the callbacks, and the [[Hooks#hasExternalDataSource]] hook returns `true` so plugins such as Filters and Pagination can treat the grid as server-driven.
 * If required callbacks are missing or invalid, `fetchRows` and the affected mutation paths no-op until the configuration is valid.
 * Valid edits apply to the grid immediately; if `onRowsUpdate` fails, if validation fails later, or if `beforeRowsMutation` cancels, those cells revert to their previous values.
 * When the [[Options#notification]] plugin is enabled, failed `fetchRows`, `onRowsCreate`, `onRowsUpdate`, or `onRowsRemove` requests (including a refetch after a successful mutation) show an error notification toast with the same translated titles and description text as before.
 *
 * If `trimRows`, `manualRowMove`, `manualColumnMove`, or `multiColumnSorting` is enabled, the DataProvider plugin does not enable. Handsontable logs a console warning when you still set a complete `dataProvider` configuration.
 * Use [[Options#columnSorting]] for server-driven sort (single column). Query `sort` uses `prop` (column data key).
 */ export class DataProvider extends BasePlugin {
    static get PLUGIN_KEY() {
        return PLUGIN_KEY;
    }
    static get PLUGIN_PRIORITY() {
        return PLUGIN_PRIORITY;
    }
    static get SETTING_KEYS() {
        return [
            PLUGIN_KEY
        ];
    }
    static get DEFAULT_SETTINGS() {
        return DEFAULT_SETTINGS;
    }
    static get SETTINGS_VALIDATORS() {
        return SETTINGS_VALIDATORS;
    }
    /**
   * Check if the plugin is enabled in the handsontable settings.
   *
   * @returns {boolean}
   */ isEnabled() {
        return !!this.hot.getSettings()[PLUGIN_KEY];
    }
    /**
   * Enables the plugin, syncs query parameters from Pagination, ColumnSorting, and Filters, and registers hooks.
   */ enablePlugin() {
        if (this.enabled) {
            return;
        }
        _class_private_method_get(this, _applyQueryParametersFromPlugins, applyQueryParametersFromPlugins).call(this);
        this.addHook('hasExternalDataSource', _class_private_field_get(this, _onHasExternalDataSource));
        this.addHook('afterInit', ()=>_class_private_field_get(this, _onAfterInit).call(this));
        this.addHook('modifyRowHeader', (...args)=>_class_private_field_get(this, _onModifyRowHeader).call(this, ...args));
        this.addHook('beforeColumnSort', (...args)=>_class_private_field_get(this, _onBeforeColumnSort).call(this, ...args));
        this.addHook('beforeUndoStackChange', (...args)=>_class_private_field_get(this, _onBeforeUndoStackChange).call(this, ...args));
        this.addHook('afterChange', (...args)=>_class_private_field_get(this, _onAfterChangeForServerUpdate).call(this, ...args));
        this.addHook('beforeAlter', (...args)=>_class_private_field_get(this, _onBeforeAlter).call(this, ...args));
        this.addHook('afterPageChange', (...args)=>_class_private_field_get(this, _onAfterPageChangeExternalPagination).call(this, ...args));
        this.addHook('afterPageSizeChange', (...args)=>_class_private_field_get(this, _onAfterPageSizeChangeExternalPagination).call(this, ...args));
        this.addHook('beforeFilter', (...args)=>_class_private_field_get(this, _onBeforeFilter).call(this, ...args));
        super.enablePlugin();
    }
    /**
   * Re-applies settings and refetches when the instance is already initialized.
   */ updatePlugin() {
        this.disablePlugin();
        this.enablePlugin();
        if (this.hot.view) {
            this.fetchData();
        }
        super.updatePlugin();
    }
    /**
   * Disables the plugin, aborts fetch, resets query state.
   * Hook listeners registered with `addHook` are removed by `super.disablePlugin()` via `clearHooks()`.
   * The constructor registers [[Hooks#hasExternalDataSource]] for the period before the first `enablePlugin()`;
   * `enablePlugin()` registers it again so it survives each `updatePlugin()` cycle.
   */ disablePlugin() {
        _class_private_method_get(this, _resetAbortController, resetAbortController).call(this);
        _class_private_field_set(this, _queryParameters, {
            ...INITIAL_QUERY_PARAMETERS
        });
        super.disablePlugin();
    }
    /**
   * @returns {DataProviderQueryParameters} Copy of current query parameters (`sort` and `filters` are cloned when non-null).
   */ getQueryParameters() {
        return _class_private_method_get(this, _snapshotQueryParameters, snapshotQueryParameters).call(this, _class_private_field_get(this, _queryParameters));
    }
    /**
   * @param {number} visualRow Visual row index.
   * @returns {*} Row id from `rowId` option, or undefined.
   */ getRowId(visualRow) {
        return getRowIdByVisualRow(this.hot, _class_private_method_get(this, _getRowIdOption, getRowIdOption).call(this), visualRow);
    }
    /**
   * Fetches rows from `fetchRows` with current or overridden query parameters.
   *
   * @param {object} [overrides] Partial query overrides (e.g. `{ page: 2 }`, `{ pageSize: 20, page: 1 }`, `{ sort }`, `{ filters }`).
   * Pass `{ skipLoading: true }` to mark internal refetches (for example sort or CRUD); [[Hooks#beforeDataProviderFetch]] receives it, and it is not passed to `fetchRows`.
   * Numeric `page` is clamped to at least 1.
   * When the response `totalRows` implies fewer pages than the requested `page`, fetches again at the last valid page without applying the out-of-range result (avoids redundant `afterPageChange` loads and aborted duplicate requests after row removal on the last page).
   * @returns {Promise<{ rows: Array<*>, totalRows: number }|null>}
   *
   * @fires Hooks#afterDataProviderFetch when data loads.
   * @fires Hooks#afterDataProviderFetchError when `fetchRows` throws a non-abort error.
   * @fires Hooks#afterDataProviderFetchAbort when the request is superseded, aborted, or ends with `AbortError`.
   */ async fetchData(overrides = {}) {
        const fetchFn = _class_private_method_get(this, _getFetchFn, getFetchFn).call(this);
        if (!isFunction(fetchFn)) {
            this.hot.render();
            return null;
        }
        const params = _class_private_method_get(this, _mergeAndNormalizeFetchParams, mergeAndNormalizeFetchParams).call(this, overrides);
        const controller = _class_private_method_get(this, _createFetchAbortController, createFetchAbortController).call(this);
        const { signal } = controller;
        if (this.hot.runHooks('beforeDataProviderFetch', params) === false) {
            _class_private_field_set(this, _abortController, null);
            this.hot.render();
            return null;
        }
        const fetchRowsParams = _class_private_method_get(this, _snapshotQueryParameters, snapshotQueryParameters).call(this, params);
        try {
            const result = await fetchFn(fetchRowsParams, {
                signal
            });
            if (signal.aborted) {
                _class_private_method_get(this, _runAfterDataProviderFetchAbort, runAfterDataProviderFetchAbort).call(this, params, undefined);
                return null;
            }
            const rows = Array.isArray(result?.rows) ? result.rows : [];
            const totalRows = typeof result?.totalRows === 'number' && result.totalRows >= 0 ? result.totalRows : rows.length;
            const persistedParams = _class_private_method_get(this, _snapshotQueryParameters, snapshotQueryParameters).call(this, params);
            const clampedPage = clampDataProviderPageToTotalRows(persistedParams.page, persistedParams.pageSize, totalRows);
            if (clampedPage !== persistedParams.page) {
                return this.fetchData({
                    ...overrides,
                    page: clampedPage,
                    skipLoading: overrides.skipLoading
                });
            }
            _class_private_field_set(this, _queryParameters, persistedParams);
            this.hot.loadData(rows, PLUGIN_KEY);
            const columnSortConfig = sortingPayloadToSort(this.hot, persistedParams.sort ?? null);
            const filtersConditionsStack = filtersPayloadToConditionsStack(this.hot, persistedParams.filters ?? null);
            this.hot.runHooks('afterDataProviderFetch', {
                ...result,
                rows,
                totalRows,
                queryParameters: persistedParams,
                columnSortConfig,
                filtersConditionsStack
            });
            this.hot.render();
            return {
                rows,
                totalRows
            };
        } catch (err) {
            if (signal.aborted || err?.name === 'AbortError') {
                _class_private_method_get(this, _runAfterDataProviderFetchAbort, runAfterDataProviderFetchAbort).call(this, params, err);
                return null;
            }
            this.hot.runHooks('afterDataProviderFetchError', err, _class_private_method_get(this, _snapshotQueryParameters, snapshotQueryParameters).call(this, params));
            _class_private_method_get(this, _showDataProviderRequestErrorNotification, showDataProviderRequestErrorNotification).call(this, 'fetch', err);
            throw err;
        } finally{
            if (_class_private_field_get(this, _abortController) === controller) {
                _class_private_field_set(this, _abortController, null);
            }
        }
    }
    /**
   * Server create via `onRowsCreate`. Use `rowsAmount` to insert more than one row in one call.
   *
   * @param {object} [options] `position`, `referenceRowId`, `rowsAmount`.
   * @returns {Promise<void>}
   */ async createRows(options = {}) {
        const onRowsCreate = _class_private_method_get(this, _getOnRowsCreate, getOnRowsCreate).call(this);
        if (!isFunction(onRowsCreate)) {
            return Promise.resolve();
        }
        const rowsCreatePayload = {
            position: options.position ?? 'below',
            referenceRowId: options.referenceRowId,
            rowsAmount: options.rowsAmount ?? 1
        };
        const payload = {
            rowsCreate: rowsCreatePayload
        };
        return _class_private_method_get(this, _queueCrud, queueCrud1).call(this, 'create', payload, ()=>onRowsCreate(rowsCreatePayload), ()=>this.fetchData({
                skipLoading: true
            }));
    }
    /**
   * Server remove via `onRowsRemove`. Pass one row id or an array of ids.
   *
   * After a successful `onRowsRemove`, refetches from the server. When the remove clears every row currently
   * loaded (typical when emptying the last page) and the current page is greater than 1, loads the previous page
   * in one request. Otherwise refetches the current page, then loads the previous page when that response is empty
   * and the current page is still greater than 1.
   *
   * @param {Array<*>|*} rowIds Row id or ids.
   * @returns {Promise<void>}
   * @throws {Error} When any id is `null` or `undefined`.
   */ async removeRows(rowIds) {
        const onRowsRemove = _class_private_method_get(this, _getOnRowsRemove, getOnRowsRemove).call(this);
        if (!isFunction(onRowsRemove)) {
            return Promise.resolve();
        }
        const ids = Array.isArray(rowIds) ? rowIds : [
            rowIds
        ];
        ids.forEach((id)=>{
            if (isMissingRowId(id)) {
                throwWithCause(DATA_PROVIDER_ERROR_REMOVE_ROWS_MISSING_ID);
            }
        });
        const payload = {
            rowsRemove: ids
        };
        return _class_private_method_get(this, _queueCrud, queueCrud1).call(this, 'remove', payload, ()=>onRowsRemove(ids), async ()=>{
            const pageBeforeFetch = _class_private_field_get(this, _queryParameters).page;
            const rowsLoaded = this.hot.countRows();
            const removesEveryLoadedRow = ids.length >= rowsLoaded && rowsLoaded >= 1;
            if (removesEveryLoadedRow && pageBeforeFetch > 1) {
                await this.fetchData({
                    page: pageBeforeFetch - 1,
                    skipLoading: true
                });
                return;
            }
            const result = await this.fetchData({
                skipLoading: true
            });
            if (result?.rows.length === 0 && pageBeforeFetch > 1) {
                await this.fetchData({
                    page: pageBeforeFetch - 1,
                    skipLoading: true
                });
            }
        });
    }
    /**
   * Server update via `onRowsUpdate`. Pass an array of `{ id, changes, rowData? }` (same shape as `onRowsUpdate`).
   *
   * @param {object[]} rows Row update payloads (one or more).
   * @returns {Promise<void>}
   * @throws {Error} When any payload omits `id` or `id` is `null`.
   */ async updateRows(rows) {
        if (!isFunction(_class_private_method_get(this, _getOnRowsUpdate, getOnRowsUpdate).call(this)) || !Array.isArray(rows) || rows.length === 0) {
            return;
        }
        rows.forEach((p)=>{
            if (isMissingRowId(p.id)) {
                throwWithCause(DATA_PROVIDER_ERROR_UPDATE_ROWS_MISSING_ID);
            }
        });
        const rowPayloads = buildManualUpdateRowPayloads(this.hot, _class_private_method_get(this, _getRowIdOption, getRowIdOption).call(this), rows);
        return _class_private_method_get(this, _enqueueMutation, enqueueMutation1).call(this, ()=>runManualUpdateRowsMutation(this.hot, {
                getRowIdOption: ()=>_class_private_method_get(this, _getRowIdOption, getRowIdOption).call(this),
                commitRowsUpdate: (payloads)=>_class_private_method_get(this, _commitRowsUpdate, commitRowsUpdate).call(this, payloads)
            }, rowPayloads));
    }
    /**
   * Destroys the plugin.
   */ destroy() {
        _class_private_method_get(this, _resetAbortController, resetAbortController).call(this);
        super.destroy();
    }
    /**
   * @param {object} hotInstance Handsontable instance.
   */ constructor(hotInstance){
        super(hotInstance), _class_private_method_init(this, _getConfig), _class_private_method_init(this, _getRowIdOption), _class_private_method_init(this, _getFetchFn), _class_private_method_init(this, _getOnRowsCreate), _class_private_method_init(this, _getOnRowsUpdate), _class_private_method_init(this, _getOnRowsRemove), _class_private_method_init(this, _snapshotQueryParameters), _class_private_method_init(this, _applyQueryParametersFromPlugins), _class_private_method_init(this, _abortInFlightFetch), _class_private_method_init(this, _mergeAndNormalizeFetchParams), _class_private_method_init(this, _createFetchAbortController), _class_private_method_init(this, _runAfterDataProviderFetchAbort), _class_private_method_init(this, _resetAbortController), _class_private_method_init(this, _enqueueMutation), _class_private_method_init(this, _showDataProviderRequestErrorNotification), _class_private_method_init(this, _commitRowsUpdate), _class_private_method_init(this, _queueCrud), _class_private_field_init(this, _queryParameters, {
            writable: true,
            value: void 0
        }), _class_private_field_init(this, _abortController, {
            writable: true,
            value: void 0
        }), _class_private_field_init(this, _mutationQueue, {
            writable: true,
            value: void 0
        }), _class_private_field_init(this, _onHasExternalDataSource, {
            writable: true,
            value: void 0
        }), _class_private_field_init(this, _onAfterInit, {
            writable: true,
            value: void 0
        }), _class_private_field_init(this, _onAfterPageChangeExternalPagination, {
            writable: true,
            value: void 0
        }), _class_private_field_init(this, _onAfterPageSizeChangeExternalPagination, {
            writable: true,
            value: void 0
        }), _class_private_field_init(this, _onBeforeFilter, {
            writable: true,
            value: void 0
        }), _class_private_field_init(this, _onBeforeColumnSort, {
            writable: true,
            value: void 0
        }), _class_private_field_init(this, _onModifyRowHeader, {
            writable: true,
            value: void 0
        }), _class_private_field_init(this, _onBeforeUndoStackChange, {
            writable: true,
            value: void 0
        }), _class_private_field_init(this, _onAfterChangeForServerUpdate, {
            writable: true,
            value: void 0
        }), _class_private_field_init(this, _onBeforeAlter, {
            writable: true,
            value: void 0
        }), _class_private_field_set(this, _queryParameters, {
            ...INITIAL_QUERY_PARAMETERS
        }), _class_private_field_set(this, _abortController, null), _class_private_field_set(this, _mutationQueue, {
            tail: Promise.resolve()
        }), _class_private_field_set(this, _onHasExternalDataSource, ()=>isCompleteDataProviderConfig(this.hot.getSettings().dataProvider)), _class_private_field_set(this, _onAfterInit, ()=>{
            this.fetchData();
        }), _class_private_field_set(this, _onAfterPageChangeExternalPagination, (oldPage, newPage)=>{
            handleAfterPageChangeExternalPagination({
                hot: this.hot,
                getQueryPage: ()=>_class_private_field_get(this, _queryParameters).page,
                goToPage: (page)=>this.fetchData({
                        page
                    })
            }, oldPage, newPage);
        }), _class_private_field_set(this, _onAfterPageSizeChangeExternalPagination, (oldPageSize, newPageSize)=>{
            handleAfterPageSizeChangeExternalPagination({
                hot: this.hot,
                getQueryPage: ()=>_class_private_field_get(this, _queryParameters).page,
                getQueryPageSize: ()=>_class_private_field_get(this, _queryParameters).pageSize,
                setPageSize: (pageSize)=>this.fetchData({
                        pageSize,
                        page: 1
                    })
            }, oldPageSize, newPageSize);
        }), _class_private_field_set(this, _onBeforeFilter, (conditionsStack)=>handleBeforeFilterForServer({
                hot: this.hot,
                hasFetchFn: ()=>isFunction(_class_private_method_get(this, _getFetchFn, getFetchFn).call(this)),
                applyFiltersAndRefetch: (filtersForProvider)=>{
                    _class_private_field_get(this, _queryParameters).filters = filtersForProvider ?? null;
                    _class_private_field_get(this, _queryParameters).page = 1;
                    this.fetchData();
                }
            }, conditionsStack)), _class_private_field_set(this, _onBeforeColumnSort, (currentSortConfig, destinationSortConfigs, sortPossible)=>handleBeforeColumnSortForServer({
                hot: this.hot,
                hasFetchFn: ()=>isFunction(_class_private_method_get(this, _getFetchFn, getFetchFn).call(this)),
                applyQueryParametersFromPlugins: ()=>_class_private_method_get(this, _applyQueryParametersFromPlugins, applyQueryParametersFromPlugins).call(this),
                fetchData: (overrides)=>this.fetchData(overrides)
            }, currentSortConfig, destinationSortConfigs, sortPossible)), _class_private_field_set(this, _onModifyRowHeader, (visualRowIndex)=>getPagedRowHeaderIndex(_class_private_field_get(this, _queryParameters), visualRowIndex)), _class_private_field_set(this, _onBeforeUndoStackChange, (doneActionsCopy, source)=>{
            if (!isFunction(_class_private_method_get(this, _getOnRowsUpdate, getOnRowsUpdate).call(this))) {
                return;
            }
            if (!DATA_PROVIDER_BATCH_UPDATE_SOURCES.has(source)) {
                return;
            }
            return false;
        }), _class_private_field_set(this, _onAfterChangeForServerUpdate, (changes, source)=>{
            if (shouldIgnoreAfterChangeForServerUpdate(isFunction(_class_private_method_get(this, _getOnRowsUpdate, getOnRowsUpdate).call(this)), changes, source)) {
                return;
            }
            const valid = filterChangesForBatchedServerUpdate(this.hot, changes);
            if (valid.length === 0) {
                return;
            }
            _class_private_method_get(this, _enqueueMutation, enqueueMutation1).call(this, ()=>runUpdateFromChanges(this.hot, {
                    getRowIdOption: ()=>_class_private_method_get(this, _getRowIdOption, getRowIdOption).call(this),
                    commitRowsUpdate: (payloads, opts)=>_class_private_method_get(this, _commitRowsUpdate, commitRowsUpdate).call(this, payloads, opts)
                }, valid));
        }), _class_private_field_set(this, _onBeforeAlter, (action, index, amount)=>handleBeforeAlterForCrud({
                hot: this.hot,
                getOnRowsCreate: ()=>_class_private_method_get(this, _getOnRowsCreate, getOnRowsCreate).call(this),
                getOnRowsRemove: ()=>_class_private_method_get(this, _getOnRowsRemove, getOnRowsRemove).call(this),
                getRowIdOption: ()=>_class_private_method_get(this, _getRowIdOption, getRowIdOption).call(this),
                getRowId: (vr)=>this.getRowId(vr),
                createRows: (opts)=>this.createRows(opts),
                removeRows: (ids)=>this.removeRows(ids)
            }, action, index, amount));
        // Before `enablePlugin()` runs (`afterPluginsInitialized`), core may call `runHooks('hasExternalDataSource')`
        // (for example during `updateSettings`). `disablePlugin()` clears all `addHook` listeners, so `enablePlugin()`
        // registers this hook again.
        this.addHook('hasExternalDataSource', _class_private_field_get(this, _onHasExternalDataSource));
    }
}
function getConfig() {
    const c = this.hot.getSettings()[PLUGIN_KEY];
    return c && typeof c === 'object' ? c : undefined;
}
function getRowIdOption() {
    const c = _class_private_method_get(this, _getConfig, getConfig).call(this);
    return c ? c.rowId : undefined;
}
function getFetchFn() {
    const c = _class_private_method_get(this, _getConfig, getConfig).call(this);
    return c && isFunction(c.fetchRows) ? c.fetchRows : undefined;
}
function getOnRowsCreate() {
    const c = _class_private_method_get(this, _getConfig, getConfig).call(this);
    return c && isFunction(c.onRowsCreate) ? c.onRowsCreate : undefined;
}
function getOnRowsUpdate() {
    const c = _class_private_method_get(this, _getConfig, getConfig).call(this);
    return c && isFunction(c.onRowsUpdate) ? c.onRowsUpdate : undefined;
}
function getOnRowsRemove() {
    const c = _class_private_method_get(this, _getConfig, getConfig).call(this);
    return c && isFunction(c.onRowsRemove) ? c.onRowsRemove : undefined;
}
function snapshotQueryParameters(p) {
    return {
        page: p.page,
        pageSize: p.pageSize,
        sort: p.sort === null ? null : {
            ...p.sort
        },
        filters: cloneDataProviderFiltersPayload(p.filters)
    };
}
function applyQueryParametersFromPlugins() {
    applyPaginationToQueryFromPlugin(this.hot, _class_private_field_get(this, _queryParameters));
    applyColumnSortToQueryFromPlugin(this.hot, _class_private_field_get(this, _queryParameters));
    applyFiltersFromFiltersPluginToQueryParameters(this.hot, _class_private_field_get(this, _queryParameters), ()=>_class_private_method_get(this, _getFetchFn, getFetchFn).call(this));
}
function abortInFlightFetch() {
    if (!_class_private_field_get(this, _abortController)) {
        return;
    }
    const reason = new Error(ABORT_REASON_MESSAGE);
    reason.name = 'AbortError';
    _class_private_field_get(this, _abortController).abort(reason);
}
function mergeAndNormalizeFetchParams(overrides) {
    const params = {
        ..._class_private_field_get(this, _queryParameters),
        ...overrides
    };
    normalizeSortInFetchParams(params, this.hot);
    if (typeof params.page === 'number' && !Number.isNaN(params.page)) {
        params.page = Math.max(1, params.page);
    }
    return params;
}
function createFetchAbortController() {
    _class_private_method_get(this, _abortInFlightFetch, abortInFlightFetch).call(this);
    const controller = new AbortController();
    _class_private_field_set(this, _abortController, controller);
    return controller;
}
function runAfterDataProviderFetchAbort(params, reason) {
    const queryParameters = _class_private_method_get(this, _snapshotQueryParameters, snapshotQueryParameters).call(this, params);
    this.hot.runHooks('afterDataProviderFetchAbort', queryParameters, reason);
}
function resetAbortController() {
    _class_private_field_get(this, _abortController)?.abort();
    _class_private_field_set(this, _abortController, null);
}
function enqueueMutation1(fn) {
    return enqueueMutation(_class_private_field_get(this, _mutationQueue), fn);
}
function showDataProviderRequestErrorNotification(kind, err) {
    const notificationPlugin = this.hot.getPlugin('notification');
    if (!notificationPlugin?.enabled) {
        return;
    }
    const titleKeys = {
        fetch: I18nC.DATA_PROVIDER_ERRORS_FETCH,
        create: I18nC.DATA_PROVIDER_ERRORS_CREATE,
        update: I18nC.DATA_PROVIDER_ERRORS_UPDATE,
        remove: I18nC.DATA_PROVIDER_ERRORS_REMOVE
    };
    const title = this.hot.getTranslatedPhrase(titleKeys[kind] ?? I18nC.DATA_PROVIDER_ERRORS_REQUEST_FAILED);
    const message = getDataProviderRequestErrorDescription(err);
    let toastId = '';
    const options = {
        variant: 'error',
        title,
        message
    };
    if (kind === 'fetch') {
        options.duration = 0;
        options.actions = [
            {
                label: this.hot.getTranslatedPhrase(I18nC.DATA_PROVIDER_BUTTONS_REFETCH),
                type: 'primary',
                callback: ()=>{
                    if (toastId) {
                        notificationPlugin.hide(toastId);
                    }
                    this.fetchData();
                }
            }
        ];
    }
    toastId = notificationPlugin.showMessage(options);
}
function commitRowsUpdate(rowPayloads, options = {}) {
    return commitRowsUpdateCrud(this.hot, {
        getOnRowsUpdate: ()=>_class_private_method_get(this, _getOnRowsUpdate, getOnRowsUpdate).call(this),
        fetchData: ()=>this.fetchData({
                skipLoading: true
            }),
        logError,
        onRequestFailed: (kind, err)=>_class_private_method_get(this, _showDataProviderRequestErrorNotification, showDataProviderRequestErrorNotification).call(this, kind, err)
    }, rowPayloads, options);
}
function queueCrud1(operation, payload, userPromiseFn, onSuccess) {
    return queueCrud({
        enqueueMutation: (fn)=>_class_private_method_get(this, _enqueueMutation, enqueueMutation1).call(this, fn),
        runBeforeRowsMutation: (op, p)=>runBeforeRowsMutation(this.hot, op, p),
        runAfterRowsMutation: (op, p)=>runAfterRowsMutation(this.hot, op, p),
        runAfterRowsMutationError: (op, err, p)=>runAfterRowsMutationError(this.hot, op, err, p),
        logError,
        onRequestFailed: (kind, err)=>_class_private_method_get(this, _showDataProviderRequestErrorNotification, showDataProviderRequestErrorNotification).call(this, kind, err)
    }, operation, payload, userPromiseFn, onSuccess);
}
