@ryuzaki13/react-foundation-api 1.0.0 → 1.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/adt/index.js +1 -1
- package/dist/chunks/{fetch-BW2OtCu7.js → fetch-teHV5e4t.js} +3 -3
- package/dist/chunks/{fetch-BW2OtCu7.js.map → fetch-teHV5e4t.js.map} +1 -1
- package/dist/chunks/{odata-ZgZGme_K.js → odata-BvLTiawF.js} +4 -4
- package/dist/chunks/{odata-ZgZGme_K.js.map → odata-BvLTiawF.js.map} +1 -1
- package/dist/chunks/{odataFetchFn-BXVJxOou.js → odataFetchFn-CJIPv-CJ.js} +3 -3
- package/dist/chunks/{odataFetchFn-BXVJxOou.js.map → odataFetchFn-CJIPv-CJ.js.map} +1 -1
- package/dist/odata/index.js +3 -3
- package/dist/persisted/index.js +1 -1
- package/dist/s3/index.js +2 -2
- package/dist/transport/index.js +1 -1
- package/package.json +2 -2
package/dist/adt/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { t as e } from "../chunks/fetch-
|
|
1
|
+
import { t as e } from "../chunks/fetch-teHV5e4t.js";
|
|
2
2
|
import { isRecord as t } from "@ryuzaki13/react-foundation-lib/validators";
|
|
3
3
|
import { normalizeText as n } from "@ryuzaki13/react-foundation-lib/formatters";
|
|
4
4
|
import { arrayUniqueBy as r } from "@ryuzaki13/react-foundation-lib/array";
|
|
@@ -110,7 +110,7 @@ function S(e) {
|
|
|
110
110
|
return e ? typeof e.inputs.SAMLRequest == "string" || typeof e.inputs.SAMLResponse == "string" : !1;
|
|
111
111
|
}
|
|
112
112
|
function C() {
|
|
113
|
-
let e = `@ryuzaki13/react-foundation-api@1.0.
|
|
113
|
+
let e = `@ryuzaki13/react-foundation-api@1.0.1-sso-iframe-${++le}`, t = document.createElement("iframe");
|
|
114
114
|
return t.name = e, t.style.display = "none", t;
|
|
115
115
|
}
|
|
116
116
|
function w(e, t) {
|
|
@@ -218,7 +218,7 @@ async function R(e, t) {
|
|
|
218
218
|
}
|
|
219
219
|
function z(e, t, n) {
|
|
220
220
|
if (t === "config") return {
|
|
221
|
-
cacheKey: `@ryuzaki13/react-foundation-api@1.0.
|
|
221
|
+
cacheKey: `@ryuzaki13/react-foundation-api@1.0.1:${n ?? ""}`,
|
|
222
222
|
fetchUrl: "/Statistics"
|
|
223
223
|
};
|
|
224
224
|
let [r] = v(_(e)).split("/").filter(Boolean);
|
|
@@ -505,4 +505,4 @@ function Se(e, t) {
|
|
|
505
505
|
//#endregion
|
|
506
506
|
export { u as C, l as S, g as _, be as a, s as b, me as c, D as d, ue as f, f as g, m as h, xe as i, O as l, p as m, Se as n, Q as o, h as p, $ as r, ye as s, Z as t, S as u, _ as v, d as w, c as x, v as y };
|
|
507
507
|
|
|
508
|
-
//# sourceMappingURL=fetch-
|
|
508
|
+
//# sourceMappingURL=fetch-teHV5e4t.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fetch-BW2OtCu7.js","names":[],"sources":["../../src/odata/odataProjectAdapter.ts","../../src/odata/transport/url.ts","../../src/odata/transport/errorReport.ts","../../src/odata/transport/SsoRequiredError.ts","../../src/odata/transport/fetch.ts"],"sourcesContent":["import type { BaseURLType } from \"./transport/types\";\n\nexport type ODataProjectTechnicalEndpoint = {\n\tservice: string;\n\ttarget: string;\n\tbaseUrl?: BaseURLType;\n};\n\nexport type ODataProjectAdapter = {\n\t/**\n\t * OData-сервис, который в dev/preview нужно проксировать через DP0.\n\t * В проектах без SAP/OData оставляется пустым.\n\t */\n\tdevDp0Service?: string;\n\tresolveSapClient?: () => string | null | undefined;\n\tmetadataVersion?: ODataProjectTechnicalEndpoint;\n\tcollectionUpdates?: ODataProjectTechnicalEndpoint;\n};\n\nlet odataProjectAdapter: ODataProjectAdapter = {};\n\nexport function configureODataProjectAdapter(adapter: ODataProjectAdapter) {\n\todataProjectAdapter = adapter;\n}\n\nexport function getODataProjectAdapter() {\n\treturn odataProjectAdapter;\n}\n\nexport function normalizeODataServiceName(service: string) {\n\treturn service.split(\";\")[0] ?? service;\n}\n\nexport function resolveODataBaseUrl(service: string, baseUrl?: BaseURLType): BaseURLType {\n\tconst devDp0Service = odataProjectAdapter.devDp0Service;\n\tif ((__DEV__ || __PREVIEW__) && devDp0Service && normalizeODataServiceName(service) === normalizeODataServiceName(devDp0Service)) {\n\t\treturn \"odataDp0\";\n\t}\n\n\treturn baseUrl ?? \"odata\";\n}\n\nexport function resolveODataSapClient() {\n\treturn odataProjectAdapter.resolveSapClient?.() ?? null;\n}\n","import { BaseURLType } from \"./types\";\n\nexport const BaseODataURL = \"/sap/opu/odata/sap\";\n/**\n * DP0-прокси используется только для сервиса, который проект явно указывает\n * через `odataProjectAdapter.devDp0Service`.\n */\nexport const BaseODataDp0URL = __DEV__ || __PREVIEW__ ? \"/sap-dp0/opu/odata/sap\" : \"/sap/opu/odata/sap\";\nexport const BaseODataUI2URL = __DEV__ || __PREVIEW__ ? \"/sap-dp0/opu/odata/UI2\" : \"/sap/opu/odata/UI2\";\nexport const BaseAppConfigURL = __BASE_APP_CONFIG_URL__;\n\nexport const BaseUrlMap = Object.freeze<Record<BaseURLType, string>>({\n\t[\"\"]: \"\",\n\todata: BaseODataURL,\n\todataDp0: BaseODataDp0URL,\n\todataUi2: BaseODataUI2URL,\n\tconfig: BaseAppConfigURL\n});\n\nexport function getInputUrl(input: RequestInfo) {\n\tif (typeof input === \"string\") return input;\n\tif (typeof Request !== \"undefined\" && input instanceof Request) {\n\t\treturn input.url;\n\t}\n\treturn input.toString();\n}\n\nexport function normalizeRelativePath(url: string) {\n\tconst path = url.split(\"?\")[0]?.split(\"#\")[0] ?? \"\";\n\tif (!path) return \"/\";\n\treturn path.startsWith(\"/\") ? path : `/${path}`;\n}\n","import { reportTransportError } from \"@ryuzaki13/react-foundation-lib/error-report\";\nimport { truncateText } from \"@ryuzaki13/react-foundation-lib/formatters\";\n\nimport { FetchErrorReportContext } from \"./types\";\nimport { BaseUrlMap, getInputUrl, normalizeRelativePath } from \"./url\";\n\nconst MAX_HTML_INPUT_NAMES = 40;\nconst MAX_HTML_PREVIEW_LENGTH = 1000;\n\nfunction normalizeUrlForReport(url: string) {\n\ttry {\n\t\tconst baseOrigin = typeof window !== \"undefined\" ? window.location.origin : \"http://localhost\";\n\t\tconst parsedUrl = new URL(url, baseOrigin);\n\t\tconst sameOrigin = parsedUrl.origin === baseOrigin;\n\t\treturn `${sameOrigin ? \"\" : parsedUrl.origin}${parsedUrl.pathname}`;\n\t} catch {\n\t\treturn normalizeRelativePath(url);\n\t}\n}\n\nfunction readHtmlDocument(html: string) {\n\tif (typeof DOMParser === \"undefined\") return undefined;\n\n\ttry {\n\t\treturn new DOMParser().parseFromString(html, \"text/html\");\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n\nfunction extractHtmlTitle(html: string, doc: Document | undefined) {\n\tconst title = doc?.querySelector(\"title\")?.textContent;\n\tif (title) return title;\n\n\treturn /<title[^>]*>([\\s\\S]*?)<\\/title>/i.exec(html)?.[1];\n}\n\nfunction countHtmlForms(html: string, doc: Document | undefined) {\n\tconst formsCount = doc?.querySelectorAll(\"form\").length;\n\tif (formsCount !== undefined) return formsCount;\n\n\treturn Array.from(html.matchAll(/<form\\b/gi)).length;\n}\n\nfunction collectHtmlInputNames(html: string, doc: Document | undefined) {\n\tconst names = doc\n\t\t? Array.from(\n\t\t\t\tdoc.querySelectorAll<HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement>(\"input[name],textarea[name],select[name]\")\n\t\t\t)\n\t\t\t\t.map((element) => element.name)\n\t\t\t\t.filter(Boolean)\n\t\t: Array.from(html.matchAll(/\\bname\\s*=\\s*[\"']([^\"']+)[\"']/gi))\n\t\t\t\t.map((match) => match[1])\n\t\t\t\t.filter((name): name is string => !!name);\n\n\treturn Array.from(new Set(names)).slice(0, MAX_HTML_INPUT_NAMES);\n}\n\nfunction extractHtmlTextPreview(html: string, doc: Document | undefined) {\n\tconst text =\n\t\tdoc?.body?.textContent ??\n\t\thtml\n\t\t\t.replace(/<script\\b[\\s\\S]*?<\\/script>/gi, \" \")\n\t\t\t.replace(/<style\\b[\\s\\S]*?<\\/style>/gi, \" \")\n\t\t\t.replace(/<[^>]+>/g, \" \");\n\treturn truncateText(text, MAX_HTML_PREVIEW_LENGTH);\n}\n\nfunction createHtmlResponseSummary(html: string) {\n\tconst doc = readHtmlDocument(html);\n\n\treturn {\n\t\tlength: html.length,\n\t\ttitle: truncateText(extractHtmlTitle(html, doc), 200),\n\t\tformCount: countHtmlForms(html, doc),\n\t\tinputNames: collectHtmlInputNames(html, doc),\n\t\ttextPreview: extractHtmlTextPreview(html, doc)\n\t};\n}\n\nexport function reportUnexpectedHtmlResponse(\n\terror: Error,\n\tsource: \"fetch.parseResponse\" | \"fetch.buildHttpError\",\n\tres: Response,\n\ttext: string,\n\tcontext: FetchErrorReportContext | undefined\n) {\n\tconst inputUrl = context ? getInputUrl(context.input) : undefined;\n\tconst requestUrl = inputUrl?.startsWith(\"http\")\n\t\t? inputUrl\n\t\t: inputUrl\n\t\t\t? `${BaseUrlMap[context?.baseUrlType ?? \"\"]}${inputUrl}`\n\t\t\t: undefined;\n\n\treportTransportError(error, {\n\t\tsource,\n\t\trequestUrl: requestUrl ? normalizeUrlForReport(requestUrl) : undefined,\n\t\tresponseUrl: res.url ? normalizeUrlForReport(res.url) : undefined,\n\t\tmethod: context?.init.method?.toUpperCase() ?? \"GET\",\n\t\tbaseUrlType: context?.baseUrlType,\n\t\tsapClient: context?.sapClient,\n\t\tstatus: res.status,\n\t\tstatusText: res.statusText,\n\t\tcontentType: res.headers.get(\"Content-Type\") || undefined,\n\t\tredirected: res.redirected,\n\t\tresponseType: res.type,\n\t\thtml: createHtmlResponseSummary(text)\n\t});\n}\n","export type SsoForm = {\n\taction: string;\n\tmethod: string;\n\tinputs: Record<string, string>;\n};\n\nexport type SsoRecoveryArgs = {\n\tform?: SsoForm;\n\trecoveryUrl?: string;\n};\n\nexport type SsoRequiredErrorOptions = {\n\trecoverable?: boolean;\n};\n\nlet ssoRecoveryPromise: Promise<boolean> | null = null;\nlet ssoIframeCounter = 0;\n\nfunction normalizeSsoAction(action: string) {\n\tif (typeof window === \"undefined\") return action;\n\n\ttry {\n\t\tconst originRegExp = new RegExp(__ORIGIN_REG_EXP__, \"i\");\n\t\tconst url = new URL(action, window.location.origin);\n\t\tconst isSapHost = originRegExp.test(url.origin);\n\t\tconst isSsoHost = url.origin === __SSO_ORIGIN__;\n\n\t\tif (isSapHost || isSsoHost || url.origin === window.location.origin) {\n\t\t\treturn `${url.pathname}${url.search}${url.hash}`;\n\t\t}\n\n\t\treturn url.toString();\n\t} catch {\n\t\treturn action;\n\t}\n}\n\nexport function isSsoForm(form?: SsoForm): form is SsoForm {\n\tif (!form) return false;\n\n\treturn typeof form.inputs.SAMLRequest === \"string\" || typeof form.inputs.SAMLResponse === \"string\";\n}\n\nfunction createHiddenIframe() {\n\tconst iframeName = `${__APP_ID__}-sso-iframe-${++ssoIframeCounter}`;\n\tconst iframe = document.createElement(\"iframe\");\n\tiframe.name = iframeName;\n\tiframe.style.display = \"none\";\n\treturn iframe;\n}\n\nfunction waitForIframe(iframe: HTMLIFrameElement, cleanup: () => void) {\n\treturn new Promise<boolean>((resolve) => {\n\t\tlet settleTimer: number | null = null;\n\t\tconst complete = () => {\n\t\t\tif (settleTimer !== null) {\n\t\t\t\twindow.clearTimeout(settleTimer);\n\t\t\t}\n\n\t\t\tsettleTimer = window.setTimeout(() => {\n\t\t\t\tcleanup();\n\t\t\t\tresolve(true);\n\t\t\t}, 400);\n\t\t};\n\n\t\tiframe.addEventListener(\"load\", complete);\n\t\tiframe.addEventListener(\"error\", complete);\n\t});\n}\n\nfunction createSsoFormElement(form: SsoForm, target: string) {\n\tconst formElement = document.createElement(\"form\");\n\tformElement.method = form.method === \"GET\" ? \"GET\" : \"POST\";\n\tformElement.action = normalizeSsoAction(form.action);\n\tformElement.target = target;\n\tformElement.style.display = \"none\";\n\n\tfor (const [name, value] of Object.entries(form.inputs)) {\n\t\tconst input = document.createElement(\"input\");\n\t\tinput.type = \"hidden\";\n\t\tinput.name = name;\n\t\tinput.value = value;\n\t\tformElement.appendChild(input);\n\t}\n\n\treturn formElement;\n}\n\nfunction getMountPoint() {\n\tif (typeof document === \"undefined\") return null;\n\treturn document.body ?? document.documentElement;\n}\n\nexport function submitSsoForm(form?: SsoForm) {\n\tif (!isSsoForm(form)) return false;\n\tif (typeof document === \"undefined\") return false;\n\n\tconst mountPoint = getMountPoint();\n\tif (!mountPoint) return false;\n\n\tconst iframe = createHiddenIframe();\n\tconst formElement = createSsoFormElement(form, iframe.name);\n\n\tmountPoint.appendChild(iframe);\n\tmountPoint.appendChild(formElement);\n\tformElement.submit();\n\treturn true;\n}\n\nfunction recoverBySsoForm(form: SsoForm) {\n\tconst mountPoint = getMountPoint();\n\tif (!mountPoint) return Promise.resolve(false);\n\n\tconst iframe = createHiddenIframe();\n\tconst formElement = createSsoFormElement(form, iframe.name);\n\tconst recovery = waitForIframe(iframe, () => {\n\t\tiframe.remove();\n\t\tformElement.remove();\n\t});\n\n\tmountPoint.appendChild(iframe);\n\tmountPoint.appendChild(formElement);\n\tformElement.submit();\n\n\treturn recovery;\n}\n\nfunction recoverByDocumentNavigation(recoveryUrl: string) {\n\tconst mountPoint = getMountPoint();\n\tif (!mountPoint) return Promise.resolve(false);\n\n\tconst iframe = createHiddenIframe();\n\tconst recovery = waitForIframe(iframe, () => {\n\t\tiframe.remove();\n\t});\n\n\tmountPoint.appendChild(iframe);\n\tiframe.src = normalizeSsoAction(recoveryUrl);\n\n\treturn recovery;\n}\n\nexport function recoverSsoSession({ form, recoveryUrl }: SsoRecoveryArgs = {}) {\n\tif (ssoRecoveryPromise) return ssoRecoveryPromise;\n\tif (typeof window === \"undefined\") return false;\n\n\tssoRecoveryPromise = (async () => {\n\t\tif (isSsoForm(form)) return recoverBySsoForm(form);\n\t\tif (recoveryUrl) return recoverByDocumentNavigation(recoveryUrl);\n\t\treturn false;\n\t})().finally(() => {\n\t\tssoRecoveryPromise = null;\n\t});\n\n\treturn ssoRecoveryPromise;\n}\n\nexport class SsoRequiredError extends Error {\n\tpublic readonly form?: SsoForm;\n\tpublic readonly recoveryUrl?: string;\n\tpublic readonly recoverable: boolean;\n\tconstructor(message: string, form?: SsoForm, recoveryUrl?: string, options: SsoRequiredErrorOptions = {}) {\n\t\tsuper(message);\n\t\tthis.form = form;\n\t\tthis.recoveryUrl = recoveryUrl;\n\t\tthis.recoverable = options.recoverable ?? true;\n\t\tObject.setPrototypeOf(this, SsoRequiredError.prototype);\n\t}\n}\n","import { logError } from \"@ryuzaki13/react-foundation-lib/utils\";\nimport { asRecord, isRecord, isSafe } from \"@ryuzaki13/react-foundation-lib/validators\";\n\nimport { normalizeODataServiceName, resolveODataBaseUrl, resolveODataSapClient } from \"../odataProjectAdapter\";\n\nimport { reportUnexpectedHtmlResponse } from \"./errorReport\";\nimport { isSsoForm, recoverSsoSession, SsoForm, SsoRequiredError } from \"./SsoRequiredError\";\nimport { BaseURLType, FetchErrorReportContext, RequestInitType } from \"./types\";\nimport { BaseUrlMap, getInputUrl, normalizeRelativePath } from \"./url\";\n\nconst csrfTokenCache = new Map<string, string>();\nconst csrfFetchInProgressCache = new Map<string, Promise<string>>();\nlet ssoRecoveryGate: Promise<void> | null = null;\nlet ssoBlockedError: SsoRequiredError | null = null;\n\nexport { normalizeODataServiceName, resolveODataBaseUrl };\n\nfunction isSapRequest(input: RequestInfo, baseUrlType: BaseURLType) {\n\tif (baseUrlType !== \"\") return true;\n\n\tconst path = normalizeRelativePath(getInputUrl(input));\n\treturn path.startsWith(\"/sap/\") || path.startsWith(\"/sap-dp0/\");\n}\n\nfunction getSapClient(input: RequestInfo, baseUrlType: BaseURLType): string | null {\n\tif (__DEV__ || __PREVIEW__) {\n\t\tif (!isSapRequest(input, baseUrlType)) return null;\n\t\tif (baseUrlType === \"odataDp0\") return \"300\";\n\t\tif (baseUrlType === \"\" && normalizeRelativePath(getInputUrl(input)).startsWith(\"/sap-dp0/\")) {\n\t\t\treturn \"300\";\n\t\t}\n\t\treturn `${__SAP_CLIENT__}`;\n\t}\n\n\treturn resolveODataSapClient();\n}\n\nfunction createUnrecoverableSsoError(source: SsoRequiredError) {\n\treturn new SsoRequiredError(\n\t\t\"Не удалось автоматически восстановить SSO-сессию. Перезагрузите страницу и выполните вход заново.\",\n\t\tsource.form,\n\t\tsource.recoveryUrl,\n\t\t{ recoverable: false }\n\t);\n}\n\nfunction markSsoBlocked(source: SsoRequiredError) {\n\tconst error = createUnrecoverableSsoError(source);\n\tif (typeof window !== \"undefined\") {\n\t\tssoBlockedError = error;\n\t}\n\treturn error;\n}\n\nasync function waitForSsoRecoveryGate() {\n\tconst gate = ssoRecoveryGate;\n\tif (gate) {\n\t\tawait gate.catch(() => {});\n\t}\n\n\tif (ssoBlockedError) {\n\t\tthrow ssoBlockedError;\n\t}\n}\n\nasync function recoverSsoSessionAndRetry<T>(error: SsoRequiredError, retry: () => Promise<T>) {\n\tif (ssoBlockedError) {\n\t\tthrow ssoBlockedError;\n\t}\n\n\tlet retryResult: { value: T } | undefined;\n\n\tif (!ssoRecoveryGate) {\n\t\tssoRecoveryGate = (async () => {\n\t\t\tconst recovered = await Promise.resolve(recoverSsoSession({ form: error.form, recoveryUrl: error.recoveryUrl })).catch(\n\t\t\t\t() => false\n\t\t\t);\n\n\t\t\tif (!recovered) {\n\t\t\t\tthrow markSsoBlocked(error);\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tretryResult = { value: await retry() };\n\t\t\t\tssoBlockedError = null;\n\t\t\t} catch (retryError: unknown) {\n\t\t\t\tif (retryError instanceof SsoRequiredError) {\n\t\t\t\t\tthrow markSsoBlocked(retryError);\n\t\t\t\t}\n\n\t\t\t\tthrow retryError;\n\t\t\t}\n\t\t})().finally(() => {\n\t\t\tssoRecoveryGate = null;\n\t\t});\n\n\t\tawait ssoRecoveryGate;\n\n\t\tif (!retryResult) {\n\t\t\tthrow ssoBlockedError ?? createUnrecoverableSsoError(error);\n\t\t}\n\n\t\treturn retryResult.value;\n\t}\n\n\tawait waitForSsoRecoveryGate();\n\ttry {\n\t\treturn await retry();\n\t} catch (retryError: unknown) {\n\t\tif (retryError instanceof SsoRequiredError) {\n\t\t\tthrow markSsoBlocked(retryError);\n\t\t}\n\n\t\tthrow retryError;\n\t}\n}\n\nfunction resolveCsrfScope(input: RequestInfo, baseUrlType: BaseURLType, sapClient: string | null) {\n\tif (baseUrlType === \"config\") {\n\t\treturn {\n\t\t\tcacheKey: `${__APP_ID__}:${sapClient ?? \"\"}`,\n\t\t\tfetchUrl: \"/Statistics\"\n\t\t};\n\t}\n\n\tconst requestPath = normalizeRelativePath(getInputUrl(input));\n\tconst [serviceName] = requestPath.split(\"/\").filter(Boolean);\n\tif (!serviceName) {\n\t\tthrow new Error(\"Не удалось определить сервис для получения CSRF-токена\");\n\t}\n\n\treturn {\n\t\tcacheKey: `${baseUrlType}:${sapClient ?? \"\"}:${serviceName}`,\n\t\tfetchUrl: `/${serviceName}/`\n\t};\n}\n\nasync function getCsrfToken(input: RequestInfo, baseUrlType: BaseURLType, sapClient: string | null): Promise<string> {\n\tconst scope = resolveCsrfScope(input, baseUrlType, sapClient);\n\tconst cachedToken = csrfTokenCache.get(scope.cacheKey);\n\tif (cachedToken) return cachedToken;\n\n\tconst inflightToken = csrfFetchInProgressCache.get(scope.cacheKey);\n\tif (inflightToken) return inflightToken;\n\n\tconst headers = new Headers({ \"x-csrf-token\": \"Fetch\" });\n\theaders.set(\"sap-language\", \"ru\");\n\theaders.set(\"sap-contextid-accept\", \"header\");\n\theaders.set(\"Accept-Language\", \"ru\");\n\tif (sapClient) {\n\t\theaders.set(\"sap-client\", sapClient);\n\t}\n\n\tconst baseUrl = (baseUrlType && BaseUrlMap[baseUrlType]) ?? \"\";\n\tconst tokenPromise = fetch(baseUrl + scope.fetchUrl, {\n\t\tmethod: \"GET\",\n\t\theaders,\n\t\tcredentials: \"include\",\n\t\tredirect: \"manual\"\n\t})\n\t\t.then(async (res) => {\n\t\t\tif (isSsoRedirectResponse(res)) {\n\t\t\t\tthrow new SsoRequiredError(\"Требуется повторная аутентификация\", undefined, baseUrl + scope.fetchUrl);\n\t\t\t}\n\n\t\t\tif (!res.ok) throw new Error(\"Не удалось получить CSRF-токен\");\n\n\t\t\tconst token = res.headers.get(\"x-csrf-token\");\n\t\t\tif (!token) {\n\t\t\t\tconst contentType = (res.headers.get(\"Content-Type\") || \"\").toLowerCase();\n\t\t\t\tconst text = await res.text();\n\t\t\t\tif (looksLikeHtmlResponse(contentType, text)) {\n\t\t\t\t\tconst form = extractFormFromHtml(text);\n\t\t\t\t\tif (isSsoForm(form)) {\n\t\t\t\t\t\tthrow new SsoRequiredError(\"Требуется повторная аутентификация\", form, baseUrl + scope.fetchUrl);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tthrow new Error(\"CSRF-токен отсутствует в ответе\");\n\t\t\t}\n\n\t\t\tcsrfTokenCache.set(scope.cacheKey, token);\n\t\t\tcsrfFetchInProgressCache.delete(scope.cacheKey);\n\t\t\treturn token;\n\t\t})\n\t\t.catch((err) => {\n\t\t\tcsrfFetchInProgressCache.delete(scope.cacheKey);\n\t\t\tthrow err;\n\t\t});\n\n\tcsrfFetchInProgressCache.set(scope.cacheKey, tokenPromise);\n\treturn tokenPromise;\n}\n\nfunction extractHtmlAttribute(source: string, attributeName: string) {\n\tconst escapedAttributeName = attributeName.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n\tconst match = new RegExp(`${escapedAttributeName}\\\\s*=\\\\s*[\"']([^\"']*)[\"']`, \"i\").exec(source);\n\treturn match?.[1];\n}\n\n/**\n * Попытка извлечь форму (действие + скрытые входные данные) из HTML, возвращаемого ADFS/SSO.\n * Возвращает undefined, если форма не найдена.\n */\nfunction extractFormFromHtml(html: string): SsoForm | undefined {\n\ttry {\n\t\tif (typeof DOMParser !== \"undefined\") {\n\t\t\tconst parser = new DOMParser();\n\t\t\tconst doc = parser.parseFromString(html, \"text/html\");\n\t\t\tconst form = doc.querySelector(\"form\");\n\t\t\tif (form) {\n\t\t\t\tconst action = form.getAttribute(\"action\") || (typeof window !== \"undefined\" ? window.location.href : \"\");\n\t\t\t\tconst method = (form.getAttribute(\"method\") || \"GET\").toUpperCase();\n\t\t\t\tconst inputs: Record<string, string> = {};\n\t\t\t\tform.querySelectorAll<HTMLInputElement>(\"input[name]\").forEach((i) => {\n\t\t\t\t\tinputs[i.name] = i.value ?? \"\";\n\t\t\t\t});\n\t\t\t\treturn { action, method, inputs };\n\t\t\t}\n\t\t}\n\t} catch {\n\t\t// Игнорируем и переходим к текстовому fallback-разбору.\n\t}\n\n\tconst formMatch = /<form\\b([^>]*)>([\\s\\S]*?)<\\/form>/i.exec(html);\n\tif (!formMatch) return undefined;\n\n\tconst [, formAttributes = \"\", formBody = \"\"] = formMatch;\n\tconst action = extractHtmlAttribute(formAttributes, \"action\") || (typeof window !== \"undefined\" ? window.location.href : \"\");\n\tconst method = (extractHtmlAttribute(formAttributes, \"method\") || \"GET\").toUpperCase();\n\tconst inputs: Record<string, string> = {};\n\tconst inputTagPattern = /<input\\b([^>]*)>/gi;\n\n\tfor (const match of formBody.matchAll(inputTagPattern)) {\n\t\tconst inputAttributes = match[1] ?? \"\";\n\t\tconst inputName = extractHtmlAttribute(inputAttributes, \"name\");\n\t\tif (!inputName) continue;\n\n\t\tinputs[inputName] = extractHtmlAttribute(inputAttributes, \"value\") ?? \"\";\n\t}\n\n\treturn { action, method, inputs };\n}\n\nfunction looksLikeHtmlResponse(contentType: string, text: string) {\n\treturn contentType.includes(\"text/html\") || /<html/i.test(text) || /<form/i.test(text);\n}\n\nfunction stripODataMetadata(value: unknown) {\n\tif (!isRecord(value)) return value;\n\n\tconst record = { ...value };\n\tdelete record.__metadata;\n\treturn record;\n}\n\nfunction extractJson<T>(json: unknown) {\n\tif (isRecord(json) && isRecord(json.d) && Array.isArray(json.d.results)) {\n\t\tlet totalCount: number | undefined = undefined;\n\t\tif (json.d.__count) {\n\t\t\ttotalCount = Number(json.d.__count);\n\t\t}\n\n\t\tconst data = json.d.results.map(stripODataMetadata) as T;\n\n\t\treturn { data, totalCount };\n\t}\n\tif (isRecord(json) && json.d !== undefined) {\n\t\tconst data = stripODataMetadata(json.d);\n\n\t\treturn { data: data as T };\n\t}\n\treturn {\n\t\tdata: json as T\n\t};\n}\n\nconst NO_CONTENT_RESPONSE = Object.freeze({ __noContent: true } as const);\n\nexport function isNoContentResponse(value: unknown): value is typeof NO_CONTENT_RESPONSE {\n\treturn !!value && typeof value === \"object\" && \"__noContent\" in value;\n}\n\nasync function parseResponse<T>(res: Response, reportContext?: FetchErrorReportContext): Promise<{ data: T; totalCount?: number }> {\n\tif (res.status === 204 || res.status === 205 /*|| res.headers.get(\"Content-Length\") === \"0\"*/) {\n\t\treturn { data: NO_CONTENT_RESPONSE as T };\n\t}\n\n\tconst contentType = (res.headers.get(\"Content-Type\") || \"\").toLowerCase();\n\n\t// Если явный JSON — безопасно парсим\n\tif (contentType.includes(\"application/json\") || contentType.includes(\"application/odata+json\")) {\n\t\tconst json = await res.json();\n\t\treturn extractJson<T>(json);\n\t}\n\n\t// Попытка парсинга как текст (на случай, если server неправильно прописал content-type)\n\tconst text = await res.text();\n\n\t// если в теле HTML — проверяем, есть ли форма (SSO)\n\tif (looksLikeHtmlResponse(contentType, text)) {\n\t\tconst form = extractFormFromHtml(text);\n\t\tif (isSsoForm(form)) {\n\t\t\tthrow new SsoRequiredError(\"Требуется повторная аутентификация\", form);\n\t\t}\n\t\tconst error = new Error(\"Unexpected HTML response from OData endpoint\");\n\t\treportUnexpectedHtmlResponse(error, \"fetch.parseResponse\", res, text, reportContext);\n\t\tthrow error;\n\t}\n\n\t// Попытка безопасно распарсить JSON, если сервер не установил content-type\n\ttry {\n\t\tconst maybeJson = JSON.parse(text);\n\t\treturn extractJson<T>(maybeJson);\n\t} catch (e) {\n\t\tlogError(e);\n\t\t// ни текст, ни JSON — возвращаем ошибку\n\t\tthrow new Error(\"Unsupported response content type and body is not JSON\");\n\t}\n}\n\n/**\n * Безопасно извлекает текстовое сообщение из неизвестного значения.\n */\nfunction asNonEmptyString(value: unknown): string | null {\n\tif (typeof value !== \"string\") return null;\n\tconst normalized = value.trim();\n\treturn normalized.length ? normalized : null;\n}\n\nfunction pushUniqueMessage(parts: string[], value: unknown) {\n\tconst normalized = asNonEmptyString(value);\n\tif (!normalized || parts.includes(normalized)) return;\n\tparts.push(normalized);\n}\n\nfunction extractJsonErrorParts(payload: Record<string, unknown>) {\n\tconst parts: string[] = [];\n\tconst errorValue = payload.error;\n\n\tif (typeof errorValue === \"string\") {\n\t\tpushUniqueMessage(parts, errorValue);\n\t}\n\n\tconst errorRecord = asRecord(errorValue);\n\tif (errorRecord) {\n\t\tpushUniqueMessage(parts, errorRecord.code);\n\n\t\tconst errorMessage = asRecord(errorRecord.message);\n\t\tpushUniqueMessage(parts, errorMessage?.value ?? errorRecord.message);\n\n\t\t// const innerError = asRecord(errorRecord.innererror);\n\t\t// const errorDetails = innerError?.errordetails;\n\t\t// if (Array.isArray(errorDetails)) {\n\t\t// \tfor (const detail of errorDetails) {\n\t\t// \t\tpushUniqueMessage(parts, asRecord(detail)?.message);\n\t\t// \t}\n\t\t// }\n\t}\n\n\tpushUniqueMessage(parts, payload.details);\n\tpushUniqueMessage(parts, payload.message);\n\n\treturn parts;\n}\n\n/**\n * Строит детализированную ошибку HTTP на основе статуса и тела ответа.\n * Для JSON-ответов приоритетно используются поля `error`, `details`, `message`.\n */\nasync function buildHttpError(res: Response, reportContext?: FetchErrorReportContext): Promise<Error> {\n\tconst contentType = (res.headers.get(\"Content-Type\") || \"\").toLowerCase();\n\n\ttry {\n\t\tif (contentType.includes(\"application/json\") || contentType.includes(\"application/odata+json\")) {\n\t\t\tconst payload = (await res.json()) as Record<string, unknown>;\n\t\t\tconst parts = extractJsonErrorParts(payload);\n\n\t\t\tif (parts.length) {\n\t\t\t\treturn new Error(parts.join(\" | \"));\n\t\t\t}\n\t\t} else {\n\t\t\tconst text = await res.text();\n\t\t\tconst normalizedText = asNonEmptyString(text);\n\t\t\tif (normalizedText) {\n\t\t\t\tif (looksLikeHtmlResponse(contentType, normalizedText)) {\n\t\t\t\t\tconst form = extractFormFromHtml(normalizedText);\n\t\t\t\t\tif (isSsoForm(form)) {\n\t\t\t\t\t\treturn new SsoRequiredError(\"Требуется повторная аутентификация\", form);\n\t\t\t\t\t}\n\n\t\t\t\t\tconst error = new Error(\"Unexpected HTML response from OData endpoint\");\n\t\t\t\t\treportUnexpectedHtmlResponse(error, \"fetch.buildHttpError\", res, normalizedText, reportContext);\n\t\t\t\t\treturn error;\n\t\t\t\t}\n\n\t\t\t\treturn new Error(normalizedText);\n\t\t\t}\n\t\t}\n\t} catch {\n\t\t// Ничего не делаем: в этом случае вернем стандартный текст ошибки по статусу.\n\t}\n\n\treturn new Error(`HTTP error: ${res.status} ${res.statusText}`);\n}\n\nfunction isSsoRedirectResponse(res: Response) {\n\treturn res.type === \"opaqueredirect\";\n}\n\nasync function sendFetchBaseRequest(input: RequestInfo, init: RequestInitType = {}, baseUrlType: BaseURLType = \"odata\"): Promise<Response> {\n\tconst method = init.method?.toUpperCase() || \"GET\";\n\tconst headers = new Headers(init.headers);\n\tconst isWrite = ![\"GET\", \"HEAD\"].includes(method);\n\tconst hasBody = isSafe(init.body);\n\tconst sapRequest = isSapRequest(input, baseUrlType);\n\tconst sapClient = getSapClient(input, baseUrlType);\n\n\theaders.set(\"sap-language\", \"ru\");\n\tif (sapRequest) {\n\t\theaders.set(\"sap-language\", \"ru\");\n\t\theaders.set(\"sap-contextid-accept\", \"header\");\n\t}\n\tif (sapClient) {\n\t\theaders.set(\"sap-client\", sapClient);\n\t}\n\tif (isWrite && sapRequest) {\n\t\tconst token = await getCsrfToken(input, baseUrlType, sapClient);\n\t\theaders.set(\"x-csrf-token\", token);\n\t}\n\n\tif (!headers.has(\"Accept\")) {\n\t\theaders.set(\"Accept\", \"application/json\");\n\t}\n\n\tif (hasBody && isWrite && !headers.has(\"Content-Type\")) {\n\t\theaders.set(\"Content-Type\", \"application/json\");\n\t}\n\n\tconst baseUrl = (baseUrlType && BaseUrlMap[baseUrlType]) ?? \"\";\n\tconst url = typeof input === \"string\" ? input : input.toString();\n\tlet res = await fetch(baseUrl + url, {\n\t\t...init,\n\t\theaders,\n\t\tcredentials: \"include\",\n\t\tredirect: sapRequest ? \"manual\" : init.redirect\n\t});\n\n\tif (sapRequest && isSsoRedirectResponse(res)) {\n\t\tthrow new SsoRequiredError(\"Требуется повторная аутентификация\", undefined, baseUrl + url);\n\t}\n\n\t// Если 401 — возможно, токен истёк, пробуем получить заново и повторить\n\tif ((res.status === 401 || res.status === 403) && isWrite && sapRequest && !init.retried) {\n\t\tconst scope = resolveCsrfScope(input, baseUrlType, sapClient);\n\t\tcsrfTokenCache.delete(scope.cacheKey);\n\t\tcsrfFetchInProgressCache.delete(scope.cacheKey);\n\t\tconst token = await getCsrfToken(input, baseUrlType, sapClient);\n\n\t\tconst retryHeaders = new Headers(headers);\n\t\tretryHeaders.set(\"x-csrf-token\", token);\n\n\t\tres = await fetch(baseUrl + url, {\n\t\t\t...init,\n\t\t\theaders: retryHeaders,\n\t\t\tcredentials: \"include\",\n\t\t\tredirect: \"manual\",\n\t\t\tretried: true // кастомная метка, чтобы избежать бесконечного цикла\n\t\t} as RequestInitType);\n\n\t\tif (isSsoRedirectResponse(res)) {\n\t\t\tthrow new SsoRequiredError(\"Требуется повторная аутентификация\", undefined, baseUrl + url);\n\t\t}\n\t}\n\n\treturn res;\n}\n\nasync function finalizeFetchBaseResponse(\n\tres: Response,\n\tinput: RequestInfo,\n\tinit: RequestInitType,\n\tbaseUrlType: BaseURLType,\n\tsapClient: string | null\n) {\n\tif (!res.ok) {\n\t\tif (res.status === 0) {\n\t\t\tthrow new Error(\"Ошибка сети или CORS. Проверьте подключение и настройки сервера.\");\n\t\t}\n\n\t\tthrow await buildHttpError(res, { input, init, baseUrlType, sapClient });\n\t}\n\n\treturn res;\n}\n\nasync function fetchBaseWithoutSsoRecovery(input: RequestInfo, init: RequestInitType = {}, baseUrlType: BaseURLType = \"odata\") {\n\tconst sapClient = getSapClient(input, baseUrlType);\n\tconst res = await sendFetchBaseRequest(input, init, baseUrlType);\n\treturn finalizeFetchBaseResponse(res, input, init, baseUrlType, sapClient);\n}\n\nexport async function fetchBase(input: RequestInfo, init: RequestInitType = {}, baseUrlType: BaseURLType = \"odata\"): Promise<Response> {\n\tconst sapRequest = isSapRequest(input, baseUrlType);\n\tconst sapClient = getSapClient(input, baseUrlType);\n\tconst retry = () => fetchBaseWithoutSsoRecovery(input, { ...init, ssoRetried: true }, baseUrlType);\n\n\tif (sapRequest) {\n\t\tawait waitForSsoRecoveryGate();\n\t}\n\n\tlet res: Response;\n\ttry {\n\t\tres = await sendFetchBaseRequest(input, init, baseUrlType);\n\t} catch (error: unknown) {\n\t\tif (sapRequest && error instanceof SsoRequiredError && error.recoverable && !init.ssoRetried) {\n\t\t\tres = await recoverSsoSessionAndRetry(error, retry);\n\t\t} else {\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\ttry {\n\t\treturn await finalizeFetchBaseResponse(res, input, init, baseUrlType, sapClient);\n\t} catch (error: unknown) {\n\t\tif (sapRequest && error instanceof SsoRequiredError && error.recoverable && !init.ssoRetried) {\n\t\t\tconst recoveredResponse = await recoverSsoSessionAndRetry(error, retry);\n\t\t\treturn finalizeFetchBaseResponse(recoveredResponse, input, init, baseUrlType, sapClient);\n\t\t}\n\n\t\tthrow error;\n\t}\n}\n\nexport async function fetchODataJson<T = unknown>(input: RequestInfo, init: RequestInitType = {}, baseUrlType: BaseURLType = \"odata\") {\n\tconst headers = new Headers(init.headers);\n\n\theaders.set(\"DataServiceVersion\", \"2.0\");\n\theaders.set(\"MaxDataServiceVersion\", \"2.0\");\n\n\tconst requestInit = { ...init, headers };\n\tconst parseContext = { input, init, baseUrlType, sapClient: getSapClient(input, baseUrlType) };\n\n\ttry {\n\t\tconst res = await fetchBase(input, requestInit, baseUrlType);\n\t\treturn await parseResponse<T>(res, parseContext);\n\t} catch (error: unknown) {\n\t\tif (isSapRequest(input, baseUrlType) && error instanceof SsoRequiredError && error.recoverable && !init.ssoRetried) {\n\t\t\treturn recoverSsoSessionAndRetry(error, async () => {\n\t\t\t\tconst retryInit = { ...requestInit, ssoRetried: true };\n\t\t\t\tconst res = await fetchBaseWithoutSsoRecovery(input, retryInit, baseUrlType);\n\t\t\t\treturn parseResponse<T>(res, { input, init: retryInit, baseUrlType, sapClient: getSapClient(input, baseUrlType) });\n\t\t\t});\n\t\t}\n\n\t\tthrow error;\n\t}\n}\n\nexport async function fetchJson<T = unknown>(input: RequestInfo, init: RequestInitType = {}, baseUrlType: BaseURLType = \"odata\") {\n\tconst response = await fetchODataJson<T>(input, init, baseUrlType);\n\treturn response.data;\n}\n\ninterface FetchQueryFnBaseOptions {\n\tinit?: RequestInit;\n\tbaseUrl?: BaseURLType;\n\t/** Политика кеширования в Service Worker (`\"off\"` | `\"ttl=24h\"` | `\"ttl=24h;max=100;name=ref\"` | `\"bust=24h\"` и т.д.) */\n\tswCache?: string;\n}\n\ninterface FetchQueryFnOptions<R> extends FetchQueryFnBaseOptions {\n\ttransform: (data: Response) => Promise<R>;\n}\n\nexport function fetchQueryFn<R = unknown>(url: string, options: FetchQueryFnOptions<R>) {\n\tconst initValue = options.init || {};\n\tconst baseUrlValue = options.baseUrl;\n\tconst transform = options.transform;\n\n\tif (options.swCache) {\n\t\tconst headers = new Headers(initValue.headers);\n\t\theaders.set(\"x-sw-cache\", options.swCache);\n\t\tinitValue.headers = headers;\n\t}\n\n\treturn async (params?: { signal?: AbortSignal }): Promise<R> => {\n\t\tif (!initValue.signal && params?.signal) {\n\t\t\tinitValue.signal = params.signal;\n\t\t}\n\n\t\tconst data = await fetchBase(url, initValue, baseUrlValue);\n\n\t\tif (typeof transform !== \"function\") {\n\t\t\tthrow new Error(\"fetchQueryFn requires a transformation function!\");\n\t\t}\n\n\t\treturn await transform(data);\n\t};\n}\n\ninterface FetchJsonQueryFnOptions<T, R> extends FetchQueryFnBaseOptions {\n\ttransform?: (data: T) => R;\n}\n\n/**\n * @deprecated скоро будет замена\n */\nexport function fetchJsonQueryFn<T, R = T>(url: string, options?: FetchJsonQueryFnOptions<T, R>) {\n\tconst baseUrlValue = options?.baseUrl || \"odata\";\n\tconst transform = options?.transform;\n\n\treturn async (params?: { signal: AbortSignal }) => {\n\t\tconst initValue = options?.init || {};\n\t\tif (!initValue.signal && params?.signal) {\n\t\t\tinitValue.signal = params.signal;\n\t\t}\n\n\t\tif (options?.swCache) {\n\t\t\tconst headers = new Headers(initValue.headers);\n\t\t\theaders.set(\"x-sw-cache\", options.swCache);\n\t\t\tinitValue.headers = headers;\n\t\t}\n\n\t\tconst data = await fetchJson<T>(url, initValue, baseUrlValue);\n\n\t\tif (!transform) {\n\t\t\treturn data as unknown as R;\n\t\t}\n\n\t\treturn transform ? transform(data) : (data as unknown as R);\n\t};\n}\n\n/**\n * @deprecated скоро будет замена\n */\nexport function fetchJsonMutationFn<T = unknown, TBody = unknown>(url: string, method: \"POST\" | \"PUT\" = \"POST\", baseUrl?: BaseURLType) {\n\treturn async (body: TBody, signal?: AbortSignal) => {\n\t\treturn fetchJson<T>(\n\t\t\turl,\n\t\t\t{\n\t\t\t\tmethod,\n\t\t\t\theaders: { \"Content-Type\": \"application/json\" },\n\t\t\t\tbody: JSON.stringify(body),\n\t\t\t\tsignal\n\t\t\t},\n\t\t\tbaseUrl\n\t\t);\n\t};\n}\n\n/**\n * @deprecated скоро будет замена\n */\nexport function fetchDeleteFn<T = unknown>(url: string, baseUrl?: BaseURLType) {\n\treturn async (signal?: AbortSignal) => {\n\t\treturn fetchJson<T>(url, { method: \"DELETE\", signal }, baseUrl);\n\t};\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"fetch-teHV5e4t.js","names":[],"sources":["../../src/odata/odataProjectAdapter.ts","../../src/odata/transport/url.ts","../../src/odata/transport/errorReport.ts","../../src/odata/transport/SsoRequiredError.ts","../../src/odata/transport/fetch.ts"],"sourcesContent":["import type { BaseURLType } from \"./transport/types\";\n\nexport type ODataProjectTechnicalEndpoint = {\n\tservice: string;\n\ttarget: string;\n\tbaseUrl?: BaseURLType;\n};\n\nexport type ODataProjectAdapter = {\n\t/**\n\t * OData-сервис, который в dev/preview нужно проксировать через DP0.\n\t * В проектах без SAP/OData оставляется пустым.\n\t */\n\tdevDp0Service?: string;\n\tresolveSapClient?: () => string | null | undefined;\n\tmetadataVersion?: ODataProjectTechnicalEndpoint;\n\tcollectionUpdates?: ODataProjectTechnicalEndpoint;\n};\n\nlet odataProjectAdapter: ODataProjectAdapter = {};\n\nexport function configureODataProjectAdapter(adapter: ODataProjectAdapter) {\n\todataProjectAdapter = adapter;\n}\n\nexport function getODataProjectAdapter() {\n\treturn odataProjectAdapter;\n}\n\nexport function normalizeODataServiceName(service: string) {\n\treturn service.split(\";\")[0] ?? service;\n}\n\nexport function resolveODataBaseUrl(service: string, baseUrl?: BaseURLType): BaseURLType {\n\tconst devDp0Service = odataProjectAdapter.devDp0Service;\n\tif ((__DEV__ || __PREVIEW__) && devDp0Service && normalizeODataServiceName(service) === normalizeODataServiceName(devDp0Service)) {\n\t\treturn \"odataDp0\";\n\t}\n\n\treturn baseUrl ?? \"odata\";\n}\n\nexport function resolveODataSapClient() {\n\treturn odataProjectAdapter.resolveSapClient?.() ?? null;\n}\n","import { BaseURLType } from \"./types\";\n\nexport const BaseODataURL = \"/sap/opu/odata/sap\";\n/**\n * DP0-прокси используется только для сервиса, который проект явно указывает\n * через `odataProjectAdapter.devDp0Service`.\n */\nexport const BaseODataDp0URL = __DEV__ || __PREVIEW__ ? \"/sap-dp0/opu/odata/sap\" : \"/sap/opu/odata/sap\";\nexport const BaseODataUI2URL = __DEV__ || __PREVIEW__ ? \"/sap-dp0/opu/odata/UI2\" : \"/sap/opu/odata/UI2\";\nexport const BaseAppConfigURL = __BASE_APP_CONFIG_URL__;\n\nexport const BaseUrlMap = Object.freeze<Record<BaseURLType, string>>({\n\t[\"\"]: \"\",\n\todata: BaseODataURL,\n\todataDp0: BaseODataDp0URL,\n\todataUi2: BaseODataUI2URL,\n\tconfig: BaseAppConfigURL\n});\n\nexport function getInputUrl(input: RequestInfo) {\n\tif (typeof input === \"string\") return input;\n\tif (typeof Request !== \"undefined\" && input instanceof Request) {\n\t\treturn input.url;\n\t}\n\treturn input.toString();\n}\n\nexport function normalizeRelativePath(url: string) {\n\tconst path = url.split(\"?\")[0]?.split(\"#\")[0] ?? \"\";\n\tif (!path) return \"/\";\n\treturn path.startsWith(\"/\") ? path : `/${path}`;\n}\n","import { reportTransportError } from \"@ryuzaki13/react-foundation-lib/error-report\";\nimport { truncateText } from \"@ryuzaki13/react-foundation-lib/formatters\";\n\nimport { FetchErrorReportContext } from \"./types\";\nimport { BaseUrlMap, getInputUrl, normalizeRelativePath } from \"./url\";\n\nconst MAX_HTML_INPUT_NAMES = 40;\nconst MAX_HTML_PREVIEW_LENGTH = 1000;\n\nfunction normalizeUrlForReport(url: string) {\n\ttry {\n\t\tconst baseOrigin = typeof window !== \"undefined\" ? window.location.origin : \"http://localhost\";\n\t\tconst parsedUrl = new URL(url, baseOrigin);\n\t\tconst sameOrigin = parsedUrl.origin === baseOrigin;\n\t\treturn `${sameOrigin ? \"\" : parsedUrl.origin}${parsedUrl.pathname}`;\n\t} catch {\n\t\treturn normalizeRelativePath(url);\n\t}\n}\n\nfunction readHtmlDocument(html: string) {\n\tif (typeof DOMParser === \"undefined\") return undefined;\n\n\ttry {\n\t\treturn new DOMParser().parseFromString(html, \"text/html\");\n\t} catch {\n\t\treturn undefined;\n\t}\n}\n\nfunction extractHtmlTitle(html: string, doc: Document | undefined) {\n\tconst title = doc?.querySelector(\"title\")?.textContent;\n\tif (title) return title;\n\n\treturn /<title[^>]*>([\\s\\S]*?)<\\/title>/i.exec(html)?.[1];\n}\n\nfunction countHtmlForms(html: string, doc: Document | undefined) {\n\tconst formsCount = doc?.querySelectorAll(\"form\").length;\n\tif (formsCount !== undefined) return formsCount;\n\n\treturn Array.from(html.matchAll(/<form\\b/gi)).length;\n}\n\nfunction collectHtmlInputNames(html: string, doc: Document | undefined) {\n\tconst names = doc\n\t\t? Array.from(\n\t\t\t\tdoc.querySelectorAll<HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement>(\"input[name],textarea[name],select[name]\")\n\t\t\t)\n\t\t\t\t.map((element) => element.name)\n\t\t\t\t.filter(Boolean)\n\t\t: Array.from(html.matchAll(/\\bname\\s*=\\s*[\"']([^\"']+)[\"']/gi))\n\t\t\t\t.map((match) => match[1])\n\t\t\t\t.filter((name): name is string => !!name);\n\n\treturn Array.from(new Set(names)).slice(0, MAX_HTML_INPUT_NAMES);\n}\n\nfunction extractHtmlTextPreview(html: string, doc: Document | undefined) {\n\tconst text =\n\t\tdoc?.body?.textContent ??\n\t\thtml\n\t\t\t.replace(/<script\\b[\\s\\S]*?<\\/script>/gi, \" \")\n\t\t\t.replace(/<style\\b[\\s\\S]*?<\\/style>/gi, \" \")\n\t\t\t.replace(/<[^>]+>/g, \" \");\n\treturn truncateText(text, MAX_HTML_PREVIEW_LENGTH);\n}\n\nfunction createHtmlResponseSummary(html: string) {\n\tconst doc = readHtmlDocument(html);\n\n\treturn {\n\t\tlength: html.length,\n\t\ttitle: truncateText(extractHtmlTitle(html, doc), 200),\n\t\tformCount: countHtmlForms(html, doc),\n\t\tinputNames: collectHtmlInputNames(html, doc),\n\t\ttextPreview: extractHtmlTextPreview(html, doc)\n\t};\n}\n\nexport function reportUnexpectedHtmlResponse(\n\terror: Error,\n\tsource: \"fetch.parseResponse\" | \"fetch.buildHttpError\",\n\tres: Response,\n\ttext: string,\n\tcontext: FetchErrorReportContext | undefined\n) {\n\tconst inputUrl = context ? getInputUrl(context.input) : undefined;\n\tconst requestUrl = inputUrl?.startsWith(\"http\")\n\t\t? inputUrl\n\t\t: inputUrl\n\t\t\t? `${BaseUrlMap[context?.baseUrlType ?? \"\"]}${inputUrl}`\n\t\t\t: undefined;\n\n\treportTransportError(error, {\n\t\tsource,\n\t\trequestUrl: requestUrl ? normalizeUrlForReport(requestUrl) : undefined,\n\t\tresponseUrl: res.url ? normalizeUrlForReport(res.url) : undefined,\n\t\tmethod: context?.init.method?.toUpperCase() ?? \"GET\",\n\t\tbaseUrlType: context?.baseUrlType,\n\t\tsapClient: context?.sapClient,\n\t\tstatus: res.status,\n\t\tstatusText: res.statusText,\n\t\tcontentType: res.headers.get(\"Content-Type\") || undefined,\n\t\tredirected: res.redirected,\n\t\tresponseType: res.type,\n\t\thtml: createHtmlResponseSummary(text)\n\t});\n}\n","export type SsoForm = {\n\taction: string;\n\tmethod: string;\n\tinputs: Record<string, string>;\n};\n\nexport type SsoRecoveryArgs = {\n\tform?: SsoForm;\n\trecoveryUrl?: string;\n};\n\nexport type SsoRequiredErrorOptions = {\n\trecoverable?: boolean;\n};\n\nlet ssoRecoveryPromise: Promise<boolean> | null = null;\nlet ssoIframeCounter = 0;\n\nfunction normalizeSsoAction(action: string) {\n\tif (typeof window === \"undefined\") return action;\n\n\ttry {\n\t\tconst originRegExp = new RegExp(__ORIGIN_REG_EXP__, \"i\");\n\t\tconst url = new URL(action, window.location.origin);\n\t\tconst isSapHost = originRegExp.test(url.origin);\n\t\tconst isSsoHost = url.origin === __SSO_ORIGIN__;\n\n\t\tif (isSapHost || isSsoHost || url.origin === window.location.origin) {\n\t\t\treturn `${url.pathname}${url.search}${url.hash}`;\n\t\t}\n\n\t\treturn url.toString();\n\t} catch {\n\t\treturn action;\n\t}\n}\n\nexport function isSsoForm(form?: SsoForm): form is SsoForm {\n\tif (!form) return false;\n\n\treturn typeof form.inputs.SAMLRequest === \"string\" || typeof form.inputs.SAMLResponse === \"string\";\n}\n\nfunction createHiddenIframe() {\n\tconst iframeName = `${__APP_ID__}-sso-iframe-${++ssoIframeCounter}`;\n\tconst iframe = document.createElement(\"iframe\");\n\tiframe.name = iframeName;\n\tiframe.style.display = \"none\";\n\treturn iframe;\n}\n\nfunction waitForIframe(iframe: HTMLIFrameElement, cleanup: () => void) {\n\treturn new Promise<boolean>((resolve) => {\n\t\tlet settleTimer: number | null = null;\n\t\tconst complete = () => {\n\t\t\tif (settleTimer !== null) {\n\t\t\t\twindow.clearTimeout(settleTimer);\n\t\t\t}\n\n\t\t\tsettleTimer = window.setTimeout(() => {\n\t\t\t\tcleanup();\n\t\t\t\tresolve(true);\n\t\t\t}, 400);\n\t\t};\n\n\t\tiframe.addEventListener(\"load\", complete);\n\t\tiframe.addEventListener(\"error\", complete);\n\t});\n}\n\nfunction createSsoFormElement(form: SsoForm, target: string) {\n\tconst formElement = document.createElement(\"form\");\n\tformElement.method = form.method === \"GET\" ? \"GET\" : \"POST\";\n\tformElement.action = normalizeSsoAction(form.action);\n\tformElement.target = target;\n\tformElement.style.display = \"none\";\n\n\tfor (const [name, value] of Object.entries(form.inputs)) {\n\t\tconst input = document.createElement(\"input\");\n\t\tinput.type = \"hidden\";\n\t\tinput.name = name;\n\t\tinput.value = value;\n\t\tformElement.appendChild(input);\n\t}\n\n\treturn formElement;\n}\n\nfunction getMountPoint() {\n\tif (typeof document === \"undefined\") return null;\n\treturn document.body ?? document.documentElement;\n}\n\nexport function submitSsoForm(form?: SsoForm) {\n\tif (!isSsoForm(form)) return false;\n\tif (typeof document === \"undefined\") return false;\n\n\tconst mountPoint = getMountPoint();\n\tif (!mountPoint) return false;\n\n\tconst iframe = createHiddenIframe();\n\tconst formElement = createSsoFormElement(form, iframe.name);\n\n\tmountPoint.appendChild(iframe);\n\tmountPoint.appendChild(formElement);\n\tformElement.submit();\n\treturn true;\n}\n\nfunction recoverBySsoForm(form: SsoForm) {\n\tconst mountPoint = getMountPoint();\n\tif (!mountPoint) return Promise.resolve(false);\n\n\tconst iframe = createHiddenIframe();\n\tconst formElement = createSsoFormElement(form, iframe.name);\n\tconst recovery = waitForIframe(iframe, () => {\n\t\tiframe.remove();\n\t\tformElement.remove();\n\t});\n\n\tmountPoint.appendChild(iframe);\n\tmountPoint.appendChild(formElement);\n\tformElement.submit();\n\n\treturn recovery;\n}\n\nfunction recoverByDocumentNavigation(recoveryUrl: string) {\n\tconst mountPoint = getMountPoint();\n\tif (!mountPoint) return Promise.resolve(false);\n\n\tconst iframe = createHiddenIframe();\n\tconst recovery = waitForIframe(iframe, () => {\n\t\tiframe.remove();\n\t});\n\n\tmountPoint.appendChild(iframe);\n\tiframe.src = normalizeSsoAction(recoveryUrl);\n\n\treturn recovery;\n}\n\nexport function recoverSsoSession({ form, recoveryUrl }: SsoRecoveryArgs = {}) {\n\tif (ssoRecoveryPromise) return ssoRecoveryPromise;\n\tif (typeof window === \"undefined\") return false;\n\n\tssoRecoveryPromise = (async () => {\n\t\tif (isSsoForm(form)) return recoverBySsoForm(form);\n\t\tif (recoveryUrl) return recoverByDocumentNavigation(recoveryUrl);\n\t\treturn false;\n\t})().finally(() => {\n\t\tssoRecoveryPromise = null;\n\t});\n\n\treturn ssoRecoveryPromise;\n}\n\nexport class SsoRequiredError extends Error {\n\tpublic readonly form?: SsoForm;\n\tpublic readonly recoveryUrl?: string;\n\tpublic readonly recoverable: boolean;\n\tconstructor(message: string, form?: SsoForm, recoveryUrl?: string, options: SsoRequiredErrorOptions = {}) {\n\t\tsuper(message);\n\t\tthis.form = form;\n\t\tthis.recoveryUrl = recoveryUrl;\n\t\tthis.recoverable = options.recoverable ?? true;\n\t\tObject.setPrototypeOf(this, SsoRequiredError.prototype);\n\t}\n}\n","import { logError } from \"@ryuzaki13/react-foundation-lib/utils\";\nimport { asRecord, isRecord, isSafe } from \"@ryuzaki13/react-foundation-lib/validators\";\n\nimport { normalizeODataServiceName, resolveODataBaseUrl, resolveODataSapClient } from \"../odataProjectAdapter\";\n\nimport { reportUnexpectedHtmlResponse } from \"./errorReport\";\nimport { isSsoForm, recoverSsoSession, SsoForm, SsoRequiredError } from \"./SsoRequiredError\";\nimport { BaseURLType, FetchErrorReportContext, RequestInitType } from \"./types\";\nimport { BaseUrlMap, getInputUrl, normalizeRelativePath } from \"./url\";\n\nconst csrfTokenCache = new Map<string, string>();\nconst csrfFetchInProgressCache = new Map<string, Promise<string>>();\nlet ssoRecoveryGate: Promise<void> | null = null;\nlet ssoBlockedError: SsoRequiredError | null = null;\n\nexport { normalizeODataServiceName, resolveODataBaseUrl };\n\nfunction isSapRequest(input: RequestInfo, baseUrlType: BaseURLType) {\n\tif (baseUrlType !== \"\") return true;\n\n\tconst path = normalizeRelativePath(getInputUrl(input));\n\treturn path.startsWith(\"/sap/\") || path.startsWith(\"/sap-dp0/\");\n}\n\nfunction getSapClient(input: RequestInfo, baseUrlType: BaseURLType): string | null {\n\tif (__DEV__ || __PREVIEW__) {\n\t\tif (!isSapRequest(input, baseUrlType)) return null;\n\t\tif (baseUrlType === \"odataDp0\") return \"300\";\n\t\tif (baseUrlType === \"\" && normalizeRelativePath(getInputUrl(input)).startsWith(\"/sap-dp0/\")) {\n\t\t\treturn \"300\";\n\t\t}\n\t\treturn `${__SAP_CLIENT__}`;\n\t}\n\n\treturn resolveODataSapClient();\n}\n\nfunction createUnrecoverableSsoError(source: SsoRequiredError) {\n\treturn new SsoRequiredError(\n\t\t\"Не удалось автоматически восстановить SSO-сессию. Перезагрузите страницу и выполните вход заново.\",\n\t\tsource.form,\n\t\tsource.recoveryUrl,\n\t\t{ recoverable: false }\n\t);\n}\n\nfunction markSsoBlocked(source: SsoRequiredError) {\n\tconst error = createUnrecoverableSsoError(source);\n\tif (typeof window !== \"undefined\") {\n\t\tssoBlockedError = error;\n\t}\n\treturn error;\n}\n\nasync function waitForSsoRecoveryGate() {\n\tconst gate = ssoRecoveryGate;\n\tif (gate) {\n\t\tawait gate.catch(() => {});\n\t}\n\n\tif (ssoBlockedError) {\n\t\tthrow ssoBlockedError;\n\t}\n}\n\nasync function recoverSsoSessionAndRetry<T>(error: SsoRequiredError, retry: () => Promise<T>) {\n\tif (ssoBlockedError) {\n\t\tthrow ssoBlockedError;\n\t}\n\n\tlet retryResult: { value: T } | undefined;\n\n\tif (!ssoRecoveryGate) {\n\t\tssoRecoveryGate = (async () => {\n\t\t\tconst recovered = await Promise.resolve(recoverSsoSession({ form: error.form, recoveryUrl: error.recoveryUrl })).catch(\n\t\t\t\t() => false\n\t\t\t);\n\n\t\t\tif (!recovered) {\n\t\t\t\tthrow markSsoBlocked(error);\n\t\t\t}\n\n\t\t\ttry {\n\t\t\t\tretryResult = { value: await retry() };\n\t\t\t\tssoBlockedError = null;\n\t\t\t} catch (retryError: unknown) {\n\t\t\t\tif (retryError instanceof SsoRequiredError) {\n\t\t\t\t\tthrow markSsoBlocked(retryError);\n\t\t\t\t}\n\n\t\t\t\tthrow retryError;\n\t\t\t}\n\t\t})().finally(() => {\n\t\t\tssoRecoveryGate = null;\n\t\t});\n\n\t\tawait ssoRecoveryGate;\n\n\t\tif (!retryResult) {\n\t\t\tthrow ssoBlockedError ?? createUnrecoverableSsoError(error);\n\t\t}\n\n\t\treturn retryResult.value;\n\t}\n\n\tawait waitForSsoRecoveryGate();\n\ttry {\n\t\treturn await retry();\n\t} catch (retryError: unknown) {\n\t\tif (retryError instanceof SsoRequiredError) {\n\t\t\tthrow markSsoBlocked(retryError);\n\t\t}\n\n\t\tthrow retryError;\n\t}\n}\n\nfunction resolveCsrfScope(input: RequestInfo, baseUrlType: BaseURLType, sapClient: string | null) {\n\tif (baseUrlType === \"config\") {\n\t\treturn {\n\t\t\tcacheKey: `${__APP_ID__}:${sapClient ?? \"\"}`,\n\t\t\tfetchUrl: \"/Statistics\"\n\t\t};\n\t}\n\n\tconst requestPath = normalizeRelativePath(getInputUrl(input));\n\tconst [serviceName] = requestPath.split(\"/\").filter(Boolean);\n\tif (!serviceName) {\n\t\tthrow new Error(\"Не удалось определить сервис для получения CSRF-токена\");\n\t}\n\n\treturn {\n\t\tcacheKey: `${baseUrlType}:${sapClient ?? \"\"}:${serviceName}`,\n\t\tfetchUrl: `/${serviceName}/`\n\t};\n}\n\nasync function getCsrfToken(input: RequestInfo, baseUrlType: BaseURLType, sapClient: string | null): Promise<string> {\n\tconst scope = resolveCsrfScope(input, baseUrlType, sapClient);\n\tconst cachedToken = csrfTokenCache.get(scope.cacheKey);\n\tif (cachedToken) return cachedToken;\n\n\tconst inflightToken = csrfFetchInProgressCache.get(scope.cacheKey);\n\tif (inflightToken) return inflightToken;\n\n\tconst headers = new Headers({ \"x-csrf-token\": \"Fetch\" });\n\theaders.set(\"sap-language\", \"ru\");\n\theaders.set(\"sap-contextid-accept\", \"header\");\n\theaders.set(\"Accept-Language\", \"ru\");\n\tif (sapClient) {\n\t\theaders.set(\"sap-client\", sapClient);\n\t}\n\n\tconst baseUrl = (baseUrlType && BaseUrlMap[baseUrlType]) ?? \"\";\n\tconst tokenPromise = fetch(baseUrl + scope.fetchUrl, {\n\t\tmethod: \"GET\",\n\t\theaders,\n\t\tcredentials: \"include\",\n\t\tredirect: \"manual\"\n\t})\n\t\t.then(async (res) => {\n\t\t\tif (isSsoRedirectResponse(res)) {\n\t\t\t\tthrow new SsoRequiredError(\"Требуется повторная аутентификация\", undefined, baseUrl + scope.fetchUrl);\n\t\t\t}\n\n\t\t\tif (!res.ok) throw new Error(\"Не удалось получить CSRF-токен\");\n\n\t\t\tconst token = res.headers.get(\"x-csrf-token\");\n\t\t\tif (!token) {\n\t\t\t\tconst contentType = (res.headers.get(\"Content-Type\") || \"\").toLowerCase();\n\t\t\t\tconst text = await res.text();\n\t\t\t\tif (looksLikeHtmlResponse(contentType, text)) {\n\t\t\t\t\tconst form = extractFormFromHtml(text);\n\t\t\t\t\tif (isSsoForm(form)) {\n\t\t\t\t\t\tthrow new SsoRequiredError(\"Требуется повторная аутентификация\", form, baseUrl + scope.fetchUrl);\n\t\t\t\t\t}\n\t\t\t\t}\n\n\t\t\t\tthrow new Error(\"CSRF-токен отсутствует в ответе\");\n\t\t\t}\n\n\t\t\tcsrfTokenCache.set(scope.cacheKey, token);\n\t\t\tcsrfFetchInProgressCache.delete(scope.cacheKey);\n\t\t\treturn token;\n\t\t})\n\t\t.catch((err) => {\n\t\t\tcsrfFetchInProgressCache.delete(scope.cacheKey);\n\t\t\tthrow err;\n\t\t});\n\n\tcsrfFetchInProgressCache.set(scope.cacheKey, tokenPromise);\n\treturn tokenPromise;\n}\n\nfunction extractHtmlAttribute(source: string, attributeName: string) {\n\tconst escapedAttributeName = attributeName.replace(/[.*+?^${}()|[\\]\\\\]/g, \"\\\\$&\");\n\tconst match = new RegExp(`${escapedAttributeName}\\\\s*=\\\\s*[\"']([^\"']*)[\"']`, \"i\").exec(source);\n\treturn match?.[1];\n}\n\n/**\n * Попытка извлечь форму (действие + скрытые входные данные) из HTML, возвращаемого ADFS/SSO.\n * Возвращает undefined, если форма не найдена.\n */\nfunction extractFormFromHtml(html: string): SsoForm | undefined {\n\ttry {\n\t\tif (typeof DOMParser !== \"undefined\") {\n\t\t\tconst parser = new DOMParser();\n\t\t\tconst doc = parser.parseFromString(html, \"text/html\");\n\t\t\tconst form = doc.querySelector(\"form\");\n\t\t\tif (form) {\n\t\t\t\tconst action = form.getAttribute(\"action\") || (typeof window !== \"undefined\" ? window.location.href : \"\");\n\t\t\t\tconst method = (form.getAttribute(\"method\") || \"GET\").toUpperCase();\n\t\t\t\tconst inputs: Record<string, string> = {};\n\t\t\t\tform.querySelectorAll<HTMLInputElement>(\"input[name]\").forEach((i) => {\n\t\t\t\t\tinputs[i.name] = i.value ?? \"\";\n\t\t\t\t});\n\t\t\t\treturn { action, method, inputs };\n\t\t\t}\n\t\t}\n\t} catch {\n\t\t// Игнорируем и переходим к текстовому fallback-разбору.\n\t}\n\n\tconst formMatch = /<form\\b([^>]*)>([\\s\\S]*?)<\\/form>/i.exec(html);\n\tif (!formMatch) return undefined;\n\n\tconst [, formAttributes = \"\", formBody = \"\"] = formMatch;\n\tconst action = extractHtmlAttribute(formAttributes, \"action\") || (typeof window !== \"undefined\" ? window.location.href : \"\");\n\tconst method = (extractHtmlAttribute(formAttributes, \"method\") || \"GET\").toUpperCase();\n\tconst inputs: Record<string, string> = {};\n\tconst inputTagPattern = /<input\\b([^>]*)>/gi;\n\n\tfor (const match of formBody.matchAll(inputTagPattern)) {\n\t\tconst inputAttributes = match[1] ?? \"\";\n\t\tconst inputName = extractHtmlAttribute(inputAttributes, \"name\");\n\t\tif (!inputName) continue;\n\n\t\tinputs[inputName] = extractHtmlAttribute(inputAttributes, \"value\") ?? \"\";\n\t}\n\n\treturn { action, method, inputs };\n}\n\nfunction looksLikeHtmlResponse(contentType: string, text: string) {\n\treturn contentType.includes(\"text/html\") || /<html/i.test(text) || /<form/i.test(text);\n}\n\nfunction stripODataMetadata(value: unknown) {\n\tif (!isRecord(value)) return value;\n\n\tconst record = { ...value };\n\tdelete record.__metadata;\n\treturn record;\n}\n\nfunction extractJson<T>(json: unknown) {\n\tif (isRecord(json) && isRecord(json.d) && Array.isArray(json.d.results)) {\n\t\tlet totalCount: number | undefined = undefined;\n\t\tif (json.d.__count) {\n\t\t\ttotalCount = Number(json.d.__count);\n\t\t}\n\n\t\tconst data = json.d.results.map(stripODataMetadata) as T;\n\n\t\treturn { data, totalCount };\n\t}\n\tif (isRecord(json) && json.d !== undefined) {\n\t\tconst data = stripODataMetadata(json.d);\n\n\t\treturn { data: data as T };\n\t}\n\treturn {\n\t\tdata: json as T\n\t};\n}\n\nconst NO_CONTENT_RESPONSE = Object.freeze({ __noContent: true } as const);\n\nexport function isNoContentResponse(value: unknown): value is typeof NO_CONTENT_RESPONSE {\n\treturn !!value && typeof value === \"object\" && \"__noContent\" in value;\n}\n\nasync function parseResponse<T>(res: Response, reportContext?: FetchErrorReportContext): Promise<{ data: T; totalCount?: number }> {\n\tif (res.status === 204 || res.status === 205 /*|| res.headers.get(\"Content-Length\") === \"0\"*/) {\n\t\treturn { data: NO_CONTENT_RESPONSE as T };\n\t}\n\n\tconst contentType = (res.headers.get(\"Content-Type\") || \"\").toLowerCase();\n\n\t// Если явный JSON — безопасно парсим\n\tif (contentType.includes(\"application/json\") || contentType.includes(\"application/odata+json\")) {\n\t\tconst json = await res.json();\n\t\treturn extractJson<T>(json);\n\t}\n\n\t// Попытка парсинга как текст (на случай, если server неправильно прописал content-type)\n\tconst text = await res.text();\n\n\t// если в теле HTML — проверяем, есть ли форма (SSO)\n\tif (looksLikeHtmlResponse(contentType, text)) {\n\t\tconst form = extractFormFromHtml(text);\n\t\tif (isSsoForm(form)) {\n\t\t\tthrow new SsoRequiredError(\"Требуется повторная аутентификация\", form);\n\t\t}\n\t\tconst error = new Error(\"Unexpected HTML response from OData endpoint\");\n\t\treportUnexpectedHtmlResponse(error, \"fetch.parseResponse\", res, text, reportContext);\n\t\tthrow error;\n\t}\n\n\t// Попытка безопасно распарсить JSON, если сервер не установил content-type\n\ttry {\n\t\tconst maybeJson = JSON.parse(text);\n\t\treturn extractJson<T>(maybeJson);\n\t} catch (e) {\n\t\tlogError(e);\n\t\t// ни текст, ни JSON — возвращаем ошибку\n\t\tthrow new Error(\"Unsupported response content type and body is not JSON\");\n\t}\n}\n\n/**\n * Безопасно извлекает текстовое сообщение из неизвестного значения.\n */\nfunction asNonEmptyString(value: unknown): string | null {\n\tif (typeof value !== \"string\") return null;\n\tconst normalized = value.trim();\n\treturn normalized.length ? normalized : null;\n}\n\nfunction pushUniqueMessage(parts: string[], value: unknown) {\n\tconst normalized = asNonEmptyString(value);\n\tif (!normalized || parts.includes(normalized)) return;\n\tparts.push(normalized);\n}\n\nfunction extractJsonErrorParts(payload: Record<string, unknown>) {\n\tconst parts: string[] = [];\n\tconst errorValue = payload.error;\n\n\tif (typeof errorValue === \"string\") {\n\t\tpushUniqueMessage(parts, errorValue);\n\t}\n\n\tconst errorRecord = asRecord(errorValue);\n\tif (errorRecord) {\n\t\tpushUniqueMessage(parts, errorRecord.code);\n\n\t\tconst errorMessage = asRecord(errorRecord.message);\n\t\tpushUniqueMessage(parts, errorMessage?.value ?? errorRecord.message);\n\n\t\t// const innerError = asRecord(errorRecord.innererror);\n\t\t// const errorDetails = innerError?.errordetails;\n\t\t// if (Array.isArray(errorDetails)) {\n\t\t// \tfor (const detail of errorDetails) {\n\t\t// \t\tpushUniqueMessage(parts, asRecord(detail)?.message);\n\t\t// \t}\n\t\t// }\n\t}\n\n\tpushUniqueMessage(parts, payload.details);\n\tpushUniqueMessage(parts, payload.message);\n\n\treturn parts;\n}\n\n/**\n * Строит детализированную ошибку HTTP на основе статуса и тела ответа.\n * Для JSON-ответов приоритетно используются поля `error`, `details`, `message`.\n */\nasync function buildHttpError(res: Response, reportContext?: FetchErrorReportContext): Promise<Error> {\n\tconst contentType = (res.headers.get(\"Content-Type\") || \"\").toLowerCase();\n\n\ttry {\n\t\tif (contentType.includes(\"application/json\") || contentType.includes(\"application/odata+json\")) {\n\t\t\tconst payload = (await res.json()) as Record<string, unknown>;\n\t\t\tconst parts = extractJsonErrorParts(payload);\n\n\t\t\tif (parts.length) {\n\t\t\t\treturn new Error(parts.join(\" | \"));\n\t\t\t}\n\t\t} else {\n\t\t\tconst text = await res.text();\n\t\t\tconst normalizedText = asNonEmptyString(text);\n\t\t\tif (normalizedText) {\n\t\t\t\tif (looksLikeHtmlResponse(contentType, normalizedText)) {\n\t\t\t\t\tconst form = extractFormFromHtml(normalizedText);\n\t\t\t\t\tif (isSsoForm(form)) {\n\t\t\t\t\t\treturn new SsoRequiredError(\"Требуется повторная аутентификация\", form);\n\t\t\t\t\t}\n\n\t\t\t\t\tconst error = new Error(\"Unexpected HTML response from OData endpoint\");\n\t\t\t\t\treportUnexpectedHtmlResponse(error, \"fetch.buildHttpError\", res, normalizedText, reportContext);\n\t\t\t\t\treturn error;\n\t\t\t\t}\n\n\t\t\t\treturn new Error(normalizedText);\n\t\t\t}\n\t\t}\n\t} catch {\n\t\t// Ничего не делаем: в этом случае вернем стандартный текст ошибки по статусу.\n\t}\n\n\treturn new Error(`HTTP error: ${res.status} ${res.statusText}`);\n}\n\nfunction isSsoRedirectResponse(res: Response) {\n\treturn res.type === \"opaqueredirect\";\n}\n\nasync function sendFetchBaseRequest(input: RequestInfo, init: RequestInitType = {}, baseUrlType: BaseURLType = \"odata\"): Promise<Response> {\n\tconst method = init.method?.toUpperCase() || \"GET\";\n\tconst headers = new Headers(init.headers);\n\tconst isWrite = ![\"GET\", \"HEAD\"].includes(method);\n\tconst hasBody = isSafe(init.body);\n\tconst sapRequest = isSapRequest(input, baseUrlType);\n\tconst sapClient = getSapClient(input, baseUrlType);\n\n\theaders.set(\"sap-language\", \"ru\");\n\tif (sapRequest) {\n\t\theaders.set(\"sap-language\", \"ru\");\n\t\theaders.set(\"sap-contextid-accept\", \"header\");\n\t}\n\tif (sapClient) {\n\t\theaders.set(\"sap-client\", sapClient);\n\t}\n\tif (isWrite && sapRequest) {\n\t\tconst token = await getCsrfToken(input, baseUrlType, sapClient);\n\t\theaders.set(\"x-csrf-token\", token);\n\t}\n\n\tif (!headers.has(\"Accept\")) {\n\t\theaders.set(\"Accept\", \"application/json\");\n\t}\n\n\tif (hasBody && isWrite && !headers.has(\"Content-Type\")) {\n\t\theaders.set(\"Content-Type\", \"application/json\");\n\t}\n\n\tconst baseUrl = (baseUrlType && BaseUrlMap[baseUrlType]) ?? \"\";\n\tconst url = typeof input === \"string\" ? input : input.toString();\n\tlet res = await fetch(baseUrl + url, {\n\t\t...init,\n\t\theaders,\n\t\tcredentials: \"include\",\n\t\tredirect: sapRequest ? \"manual\" : init.redirect\n\t});\n\n\tif (sapRequest && isSsoRedirectResponse(res)) {\n\t\tthrow new SsoRequiredError(\"Требуется повторная аутентификация\", undefined, baseUrl + url);\n\t}\n\n\t// Если 401 — возможно, токен истёк, пробуем получить заново и повторить\n\tif ((res.status === 401 || res.status === 403) && isWrite && sapRequest && !init.retried) {\n\t\tconst scope = resolveCsrfScope(input, baseUrlType, sapClient);\n\t\tcsrfTokenCache.delete(scope.cacheKey);\n\t\tcsrfFetchInProgressCache.delete(scope.cacheKey);\n\t\tconst token = await getCsrfToken(input, baseUrlType, sapClient);\n\n\t\tconst retryHeaders = new Headers(headers);\n\t\tretryHeaders.set(\"x-csrf-token\", token);\n\n\t\tres = await fetch(baseUrl + url, {\n\t\t\t...init,\n\t\t\theaders: retryHeaders,\n\t\t\tcredentials: \"include\",\n\t\t\tredirect: \"manual\",\n\t\t\tretried: true // кастомная метка, чтобы избежать бесконечного цикла\n\t\t} as RequestInitType);\n\n\t\tif (isSsoRedirectResponse(res)) {\n\t\t\tthrow new SsoRequiredError(\"Требуется повторная аутентификация\", undefined, baseUrl + url);\n\t\t}\n\t}\n\n\treturn res;\n}\n\nasync function finalizeFetchBaseResponse(\n\tres: Response,\n\tinput: RequestInfo,\n\tinit: RequestInitType,\n\tbaseUrlType: BaseURLType,\n\tsapClient: string | null\n) {\n\tif (!res.ok) {\n\t\tif (res.status === 0) {\n\t\t\tthrow new Error(\"Ошибка сети или CORS. Проверьте подключение и настройки сервера.\");\n\t\t}\n\n\t\tthrow await buildHttpError(res, { input, init, baseUrlType, sapClient });\n\t}\n\n\treturn res;\n}\n\nasync function fetchBaseWithoutSsoRecovery(input: RequestInfo, init: RequestInitType = {}, baseUrlType: BaseURLType = \"odata\") {\n\tconst sapClient = getSapClient(input, baseUrlType);\n\tconst res = await sendFetchBaseRequest(input, init, baseUrlType);\n\treturn finalizeFetchBaseResponse(res, input, init, baseUrlType, sapClient);\n}\n\nexport async function fetchBase(input: RequestInfo, init: RequestInitType = {}, baseUrlType: BaseURLType = \"odata\"): Promise<Response> {\n\tconst sapRequest = isSapRequest(input, baseUrlType);\n\tconst sapClient = getSapClient(input, baseUrlType);\n\tconst retry = () => fetchBaseWithoutSsoRecovery(input, { ...init, ssoRetried: true }, baseUrlType);\n\n\tif (sapRequest) {\n\t\tawait waitForSsoRecoveryGate();\n\t}\n\n\tlet res: Response;\n\ttry {\n\t\tres = await sendFetchBaseRequest(input, init, baseUrlType);\n\t} catch (error: unknown) {\n\t\tif (sapRequest && error instanceof SsoRequiredError && error.recoverable && !init.ssoRetried) {\n\t\t\tres = await recoverSsoSessionAndRetry(error, retry);\n\t\t} else {\n\t\t\tthrow error;\n\t\t}\n\t}\n\n\ttry {\n\t\treturn await finalizeFetchBaseResponse(res, input, init, baseUrlType, sapClient);\n\t} catch (error: unknown) {\n\t\tif (sapRequest && error instanceof SsoRequiredError && error.recoverable && !init.ssoRetried) {\n\t\t\tconst recoveredResponse = await recoverSsoSessionAndRetry(error, retry);\n\t\t\treturn finalizeFetchBaseResponse(recoveredResponse, input, init, baseUrlType, sapClient);\n\t\t}\n\n\t\tthrow error;\n\t}\n}\n\nexport async function fetchODataJson<T = unknown>(input: RequestInfo, init: RequestInitType = {}, baseUrlType: BaseURLType = \"odata\") {\n\tconst headers = new Headers(init.headers);\n\n\theaders.set(\"DataServiceVersion\", \"2.0\");\n\theaders.set(\"MaxDataServiceVersion\", \"2.0\");\n\n\tconst requestInit = { ...init, headers };\n\tconst parseContext = { input, init, baseUrlType, sapClient: getSapClient(input, baseUrlType) };\n\n\ttry {\n\t\tconst res = await fetchBase(input, requestInit, baseUrlType);\n\t\treturn await parseResponse<T>(res, parseContext);\n\t} catch (error: unknown) {\n\t\tif (isSapRequest(input, baseUrlType) && error instanceof SsoRequiredError && error.recoverable && !init.ssoRetried) {\n\t\t\treturn recoverSsoSessionAndRetry(error, async () => {\n\t\t\t\tconst retryInit = { ...requestInit, ssoRetried: true };\n\t\t\t\tconst res = await fetchBaseWithoutSsoRecovery(input, retryInit, baseUrlType);\n\t\t\t\treturn parseResponse<T>(res, { input, init: retryInit, baseUrlType, sapClient: getSapClient(input, baseUrlType) });\n\t\t\t});\n\t\t}\n\n\t\tthrow error;\n\t}\n}\n\nexport async function fetchJson<T = unknown>(input: RequestInfo, init: RequestInitType = {}, baseUrlType: BaseURLType = \"odata\") {\n\tconst response = await fetchODataJson<T>(input, init, baseUrlType);\n\treturn response.data;\n}\n\ninterface FetchQueryFnBaseOptions {\n\tinit?: RequestInit;\n\tbaseUrl?: BaseURLType;\n\t/** Политика кеширования в Service Worker (`\"off\"` | `\"ttl=24h\"` | `\"ttl=24h;max=100;name=ref\"` | `\"bust=24h\"` и т.д.) */\n\tswCache?: string;\n}\n\ninterface FetchQueryFnOptions<R> extends FetchQueryFnBaseOptions {\n\ttransform: (data: Response) => Promise<R>;\n}\n\nexport function fetchQueryFn<R = unknown>(url: string, options: FetchQueryFnOptions<R>) {\n\tconst initValue = options.init || {};\n\tconst baseUrlValue = options.baseUrl;\n\tconst transform = options.transform;\n\n\tif (options.swCache) {\n\t\tconst headers = new Headers(initValue.headers);\n\t\theaders.set(\"x-sw-cache\", options.swCache);\n\t\tinitValue.headers = headers;\n\t}\n\n\treturn async (params?: { signal?: AbortSignal }): Promise<R> => {\n\t\tif (!initValue.signal && params?.signal) {\n\t\t\tinitValue.signal = params.signal;\n\t\t}\n\n\t\tconst data = await fetchBase(url, initValue, baseUrlValue);\n\n\t\tif (typeof transform !== \"function\") {\n\t\t\tthrow new Error(\"fetchQueryFn requires a transformation function!\");\n\t\t}\n\n\t\treturn await transform(data);\n\t};\n}\n\ninterface FetchJsonQueryFnOptions<T, R> extends FetchQueryFnBaseOptions {\n\ttransform?: (data: T) => R;\n}\n\n/**\n * @deprecated скоро будет замена\n */\nexport function fetchJsonQueryFn<T, R = T>(url: string, options?: FetchJsonQueryFnOptions<T, R>) {\n\tconst baseUrlValue = options?.baseUrl || \"odata\";\n\tconst transform = options?.transform;\n\n\treturn async (params?: { signal: AbortSignal }) => {\n\t\tconst initValue = options?.init || {};\n\t\tif (!initValue.signal && params?.signal) {\n\t\t\tinitValue.signal = params.signal;\n\t\t}\n\n\t\tif (options?.swCache) {\n\t\t\tconst headers = new Headers(initValue.headers);\n\t\t\theaders.set(\"x-sw-cache\", options.swCache);\n\t\t\tinitValue.headers = headers;\n\t\t}\n\n\t\tconst data = await fetchJson<T>(url, initValue, baseUrlValue);\n\n\t\tif (!transform) {\n\t\t\treturn data as unknown as R;\n\t\t}\n\n\t\treturn transform ? transform(data) : (data as unknown as R);\n\t};\n}\n\n/**\n * @deprecated скоро будет замена\n */\nexport function fetchJsonMutationFn<T = unknown, TBody = unknown>(url: string, method: \"POST\" | \"PUT\" = \"POST\", baseUrl?: BaseURLType) {\n\treturn async (body: TBody, signal?: AbortSignal) => {\n\t\treturn fetchJson<T>(\n\t\t\turl,\n\t\t\t{\n\t\t\t\tmethod,\n\t\t\t\theaders: { \"Content-Type\": \"application/json\" },\n\t\t\t\tbody: JSON.stringify(body),\n\t\t\t\tsignal\n\t\t\t},\n\t\t\tbaseUrl\n\t\t);\n\t};\n}\n\n/**\n * @deprecated скоро будет замена\n */\nexport function fetchDeleteFn<T = unknown>(url: string, baseUrl?: BaseURLType) {\n\treturn async (signal?: AbortSignal) => {\n\t\treturn fetchJson<T>(url, { method: \"DELETE\", signal }, baseUrl);\n\t};\n}\n"],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { C as e, c as t, x as n } from "./fetch-
|
|
2
|
-
import { f as r, h as i, m as a, r as o } from "./odataFetchFn-
|
|
1
|
+
import { C as e, c as t, x as n } from "./fetch-teHV5e4t.js";
|
|
2
|
+
import { f as r, h as i, m as a, r as o } from "./odataFetchFn-CJIPv-CJ.js";
|
|
3
3
|
import { logError as s } from "@ryuzaki13/react-foundation-lib/utils";
|
|
4
4
|
import { parseDate as c } from "@ryuzaki13/react-foundation-lib/formatters";
|
|
5
5
|
import { compareStrings as l } from "@ryuzaki13/react-foundation-lib/string-comparison";
|
|
@@ -110,7 +110,7 @@ async function M(e) {
|
|
|
110
110
|
}
|
|
111
111
|
//#endregion
|
|
112
112
|
//#region src/odata/useODataCollectionUpdatesQuery.ts
|
|
113
|
-
var N = "@ryuzaki13/react-foundation-api@1.0.
|
|
113
|
+
var N = "@ryuzaki13/react-foundation-api@1.0.1", P = 1e3 * 60 * 60 * 4, F = 1e3 * 60 * 60 * 24 * 7, I = "ttl=forever;name=ref", L = "bust=forever;name=ref", R = "ttl=4h;name=ref-updates", z = () => [
|
|
114
114
|
...i,
|
|
115
115
|
"collection-updates",
|
|
116
116
|
{ buildId: N }
|
|
@@ -470,4 +470,4 @@ function le(e) {
|
|
|
470
470
|
//#endregion
|
|
471
471
|
export { U as C, O as D, k as E, E as O, H as S, j as T, L as _, se as a, R as b, ne as c, Q as d, J as f, G as g, q as h, ce as i, D as k, ee as l, Z as m, oe as n, ae as o, X as p, le as r, re as s, ie as t, $ as u, I as v, W as w, z as x, F as y };
|
|
472
472
|
|
|
473
|
-
//# sourceMappingURL=odata-
|
|
473
|
+
//# sourceMappingURL=odata-BvLTiawF.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"odata-ZgZGme_K.js","names":[],"sources":["../../src/odata/createODataCollectionQueryKey.ts","../../src/odata/flattenODataDependentServices.ts","../../src/odata/sortODataDependentSegmentItemsByChains.ts","../../src/odata/sortODataDependentServicesByChains.ts","../../src/odata/fetchCollectionData.ts","../../src/odata/useODataCollectionUpdatesQuery.ts","../../src/odata/useODataMetadata.ts","../../src/odata/useODataEntity.ts","../../src/odata/useODataCollectionQuery.ts","../../src/odata/useODataCollection.ts","../../src/odata/useODataCollectionChains.ts","../../src/odata/useODataCollectionModel.ts","../../src/odata/useODataTableColumns.ts","../../src/odata/useTextServiceQuery.ts","../../src/odata/odataFetchFnDev.ts"],"sourcesContent":["import { odataBaseQueryKey } from \"./odataBaseQueryKey\";\nimport { ODataServiceCollectionConfig } from \"./types\";\n\nexport const createODataCollectionBaseQueryKey = () => [...odataBaseQueryKey, \"collection\"] as const;\n\nexport const createODataCollectionQueryKey = ({ service, target, limitedKeys, serverFilter }: ODataServiceCollectionConfig) =>\n\t[...createODataCollectionBaseQueryKey(), { service, target, limitedKeys, serverFilter }] as const;\n","import type { ODataDependentBaseProps, ODataDependentSegmentItem } from \"./types\";\n\n/**\n * Разворачивает зависимые OData-сервисы в плоский список segment-level элементов.\n */\nexport function flattenODataDependentServices(services: readonly ODataDependentBaseProps[]): ODataDependentSegmentItem[] {\n\tconst out: ODataDependentSegmentItem[] = [];\n\n\tfor (const [serviceIndex, service] of services.entries()) {\n\t\tconst serviceKey = `${service.odata.service}.${service.odata.target}`;\n\n\t\tfor (const [segmentIndex, [id, segment]] of Object.entries(service.segments).entries()) {\n\t\t\tout.push({\n\t\t\t\tid,\n\t\t\t\tserviceKey,\n\t\t\t\tserviceIndex,\n\t\t\t\tsegmentIndex,\n\t\t\t\todata: service.odata,\n\t\t\t\tsegment,\n\t\t\t\tmodel: {\n\t\t\t\t\t...service.model,\n\t\t\t\t\tcodeKey: id\n\t\t\t\t},\n\t\t\t\tpanelVisibility: segment.panelVisibility ?? \"user\"\n\t\t\t});\n\t\t}\n\t}\n\n\treturn out;\n}\n","import { ODataDependentSegmentItem } from \"./types\";\n\nimport type { ODataChainsMap } from \"@ryuzaki13/react-foundation-lib/odata-service\";\n\n/**\n * Сортирует плоские segment-level элементы по chain-порядку\n * и опционально накладывает пользовательский override.\n */\nexport function sortODataDependentSegmentItemsByChains(\n\titems: readonly ODataDependentSegmentItem[],\n\tchains: ODataChainsMap,\n\torderOverrideIds?: readonly string[]\n): ODataDependentSegmentItem[] {\n\tconst chainOrderByService = new Map<string, Map<string, number>>();\n\n\tfor (const [serviceKey, chain] of Object.entries(chains)) {\n\t\tchainOrderByService.set(serviceKey, new Map(chain.map((item, index) => [item.codeKey, index])));\n\t}\n\n\tconst baseOrdered = [...items]\n\t\t.map((item, index) => ({\n\t\t\titem,\n\t\t\tindex\n\t\t}))\n\t\t.sort((left, right) => {\n\t\t\tif (left.item.serviceIndex !== right.item.serviceIndex) {\n\t\t\t\treturn left.item.serviceIndex - right.item.serviceIndex;\n\t\t\t}\n\n\t\t\tconst chainOrder = chainOrderByService.get(left.item.serviceKey);\n\t\t\tconst leftChainOrder = chainOrder?.get(left.item.id);\n\t\t\tconst rightChainOrder = chainOrder?.get(right.item.id);\n\n\t\t\tif (leftChainOrder !== undefined && rightChainOrder !== undefined) {\n\t\t\t\treturn leftChainOrder - rightChainOrder;\n\t\t\t}\n\t\t\tif (leftChainOrder !== undefined) return -1;\n\t\t\tif (rightChainOrder !== undefined) return 1;\n\n\t\t\tif (left.item.segmentIndex !== right.item.segmentIndex) {\n\t\t\t\treturn left.item.segmentIndex - right.item.segmentIndex;\n\t\t\t}\n\n\t\t\treturn left.index - right.index;\n\t\t});\n\n\tif (!orderOverrideIds?.length) {\n\t\treturn baseOrdered.map(({ item }) => item);\n\t}\n\n\tconst availableIds = new Set(baseOrdered.map(({ item }) => item.id));\n\tconst normalizedOverride = [...new Set(orderOverrideIds)].filter((id) => availableIds.has(id));\n\tif (normalizedOverride.length === 0) {\n\t\treturn baseOrdered.map(({ item }) => item);\n\t}\n\n\tconst overrideRank = new Map(normalizedOverride.map((id, index) => [id, index]));\n\n\treturn [...baseOrdered]\n\t\t.sort((left, right) => {\n\t\t\tconst leftOverrideRank = overrideRank.get(left.item.id);\n\t\t\tconst rightOverrideRank = overrideRank.get(right.item.id);\n\n\t\t\tif (leftOverrideRank !== undefined && rightOverrideRank !== undefined) {\n\t\t\t\treturn leftOverrideRank - rightOverrideRank;\n\t\t\t}\n\t\t\tif (leftOverrideRank !== undefined) return -1;\n\t\t\tif (rightOverrideRank !== undefined) return 1;\n\n\t\t\treturn left.index - right.index;\n\t\t})\n\t\t.map(({ item }) => item);\n}\n","import { compareStrings } from \"@ryuzaki13/react-foundation-lib/string-comparison\";\n\nimport { ODataDependentBaseProps } from \"./types\";\n\nimport type { ODataChainsMap } from \"@ryuzaki13/react-foundation-lib/odata-service\";\n\n/**\n * Применяет пользовательский override порядка сегментов поверх уже рассчитанного базового порядка.\n *\n * Алгоритм:\n * 1. берёт только валидные id из `orderOverrideIds` (без дублей);\n * 2. поднимает эти id в начало в указанной последовательности;\n * 3. все остальные сегменты оставляет в исходном относительном порядке.\n */\nfunction applySegmentsOrderOverride(\n\tservices: readonly ODataDependentBaseProps[],\n\torderOverrideIds?: readonly string[]\n): ODataDependentBaseProps[] {\n\tif (!orderOverrideIds?.length) return [...services];\n\n\tconst visibleIds = new Set<string>();\n\tfor (const service of services) {\n\t\tfor (const segmentId of Object.keys(service.segments)) {\n\t\t\tvisibleIds.add(segmentId);\n\t\t}\n\t}\n\n\tconst normalizedOverride = [...new Set(orderOverrideIds)].filter((id) => visibleIds.has(id));\n\tif (normalizedOverride.length === 0) return [...services];\n\n\tconst overrideRank = new Map(normalizedOverride.map((id, index) => [id, index]));\n\tconst fallbackRankStart = normalizedOverride.length;\n\tconst segmentRank = new Map<string, number>();\n\tlet fallbackRank = fallbackRankStart;\n\n\tfor (const service of services) {\n\t\tfor (const segmentId of Object.keys(service.segments)) {\n\t\t\tif (segmentRank.has(segmentId)) continue;\n\t\t\tsegmentRank.set(segmentId, overrideRank.get(segmentId) ?? fallbackRank++);\n\t\t}\n\t}\n\n\tconst withOrderedSegments = services.map((service) => {\n\t\tconst orderedEntries = Object.entries(service.segments).sort(\n\t\t\t([leftId], [rightId]) =>\n\t\t\t\t(segmentRank.get(leftId) ?? Number.MAX_SAFE_INTEGER) - (segmentRank.get(rightId) ?? Number.MAX_SAFE_INTEGER)\n\t\t);\n\n\t\treturn {\n\t\t\t...service,\n\t\t\tsegments: Object.fromEntries(orderedEntries)\n\t\t};\n\t});\n\n\treturn [...withOrderedSegments].sort((leftService, rightService) => {\n\t\tconst leftFirstSegmentId = Object.keys(leftService.segments)[0];\n\t\tconst rightFirstSegmentId = Object.keys(rightService.segments)[0];\n\t\tconst leftRank = leftFirstSegmentId ? (segmentRank.get(leftFirstSegmentId) ?? Number.MAX_SAFE_INTEGER) : Number.MAX_SAFE_INTEGER;\n\t\tconst rightRank = rightFirstSegmentId ? (segmentRank.get(rightFirstSegmentId) ?? Number.MAX_SAFE_INTEGER) : Number.MAX_SAFE_INTEGER;\n\n\t\treturn leftRank - rightRank;\n\t});\n}\n\n/**\n * Сортирует сегменты сервисов по chain-порядку (от меньшего к большему)\n * и опционально накладывает пользовательский override.\n *\n * Если chain недоступен, сохраняет исходный порядок сегментов.\n *\n * @deprecated функционал должен быть вырезан и оставлен только с `sortODataDependentSegmentItemsByChains`\n */\nexport function sortODataDependentServicesByChains(\n\tservices: readonly ODataDependentBaseProps[],\n\tchains: ODataChainsMap,\n\torderOverrideIds?: readonly string[]\n): ODataDependentBaseProps[] {\n\tconst sortedByChains = services.map((service) => {\n\t\tconst serviceKey = `${service.odata.service}.${service.odata.target}`;\n\t\tconst chain = chains[serviceKey];\n\t\tif (!chain?.length) return service;\n\n\t\tconst chainOrder = new Map(chain.map((item, index) => [item.codeKey, index]));\n\t\tconst orderedEntries = Object.entries(service.segments).sort(([leftId], [rightId]) => {\n\t\t\tconst leftOrder = chainOrder.get(leftId);\n\t\t\tconst rightOrder = chainOrder.get(rightId);\n\n\t\t\tif (leftOrder !== undefined && rightOrder !== undefined) return leftOrder - rightOrder;\n\t\t\tif (leftOrder !== undefined) return -1;\n\t\t\tif (rightOrder !== undefined) return 1;\n\t\t\treturn compareStrings(leftId, rightId);\n\t\t});\n\n\t\treturn {\n\t\t\t...service,\n\t\t\tsegments: Object.fromEntries(orderedEntries)\n\t\t};\n\t});\n\n\treturn applySegmentsOrderOverride(sortedByChains, orderOverrideIds);\n}\n","import { type CollectionItem } from \"@ryuzaki13/react-foundation-lib/odata\";\nimport { logError } from \"@ryuzaki13/react-foundation-lib/utils\";\n\nimport { odataFetch, type ODataFetchOptions } from \"./odataFetch\";\nimport { isNoContentResponse } from \"./transport\";\n\n// Тип для результата запроса справочника\ninterface ODataServiceResult<T extends CollectionItem> {\n\titems: T[];\n}\n\n/**\n * Загрузка данных справочника из OData сервиса\n */\nexport async function fetchCollectionData<T extends CollectionItem>(params: {\n\turl: string;\n\tquery?: ODataFetchOptions<T>;\n\tsignal: AbortSignal;\n}): Promise<ODataServiceResult<T>> {\n\tconst { url, query, signal } = params;\n\n\ttry {\n\t\t// Загружаем данные из OData сервиса\n\t\tconst response = await odataFetch<T, T[]>(url, query, { signal });\n\n\t\t// Считаем отсутствие данных ошибкой, ведь query запрос обязан вернуть корректное тело json\n\t\tif (isNoContentResponse(response)) {\n\t\t\tthrow new Error(\"отсутствует тело ответа\");\n\t\t}\n\n\t\tconst data = response.data;\n\n\t\t// Удаление ненужных полей.\n\n\t\treturn {\n\t\t\t// eslint-disable-next-line @typescript-eslint/naming-convention, @typescript-eslint/no-unused-vars\n\t\t\titems: data.map(({ ID, CNT, __metadata, __Parameters, ...item }) => item as T) /*, pairs, pairsMap */\n\t\t};\n\t} catch (error) {\n\t\tlogError(\"Ошибка загрузки справочника:\", error);\n\t\t// throw error;\n\n\t\treturn { items: [] };\n\t}\n}\n","import { parseDate } from \"@ryuzaki13/react-foundation-lib/formatters\";\nimport { persistedQueryMeta } from \"@ryuzaki13/react-foundation-lib/query-client\";\nimport { queryOptions, useQuery } from \"@tanstack/react-query\";\n\nimport { odataBaseQueryKey } from \"./odataBaseQueryKey\";\nimport { odataFetch } from \"./odataFetch\";\nimport { getODataProjectAdapter, resolveODataBaseUrl } from \"./odataProjectAdapter\";\n\nconst COLLECTION_UPDATES_BUILD_ID = __APP_BUILD_ID__;\nconst COLLECTION_UPDATES_STALE_TIME = 1000 * 60 * 60 * 4;\nexport const ODATA_COLLECTION_UPDATES_LOOKBACK_MS = 1000 * 60 * 60 * 24 * 7;\nexport const ODATA_COLLECTION_DEFAULT_SW_CACHE = \"ttl=forever;name=ref\";\nexport const ODATA_COLLECTION_BUST_SW_CACHE = \"bust=forever;name=ref\";\nexport const ODATA_COLLECTION_UPDATES_SW_CACHE = \"ttl=4h;name=ref-updates\";\n\ninterface ODataCollectionUpdateRecord {\n\tentityName: string;\n\tlastChanged: string;\n}\n\nexport interface ODataCollectionUpdateItem extends ODataCollectionUpdateRecord {\n\tlastChangedAt: Date | null;\n}\n\nexport interface ODataCollectionUpdatesResult {\n\titems: ODataCollectionUpdateItem[];\n\tbyEntityName: Record<string, ODataCollectionUpdateItem>;\n\tfetchedAt: number;\n\tcoverageStartedAt: number;\n}\n\nexport interface ODataCollectionUpdatesOptions {\n\tstaleTime?: number;\n}\n\nexport const createODataCollectionUpdatesQueryKey = () =>\n\t[...odataBaseQueryKey, \"collection-updates\", { buildId: COLLECTION_UPDATES_BUILD_ID }] as const;\n\nfunction normalizeCollectionUpdateRecord(record: ODataCollectionUpdateRecord): ODataCollectionUpdateItem {\n\treturn {\n\t\t...record,\n\t\tlastChangedAt: parseDate(record.lastChanged)\n\t};\n}\n\nfunction normalizeCollectionUpdates(records: ODataCollectionUpdateRecord[], fetchedAt: number): ODataCollectionUpdatesResult {\n\tconst items = records.map(normalizeCollectionUpdateRecord);\n\tconst byEntityName = items.reduce<Record<string, ODataCollectionUpdateItem>>((acc, item) => {\n\t\tif (item.entityName) {\n\t\t\tacc[item.entityName] = item;\n\t\t}\n\n\t\treturn acc;\n\t}, {});\n\n\treturn { items, byEntityName, fetchedAt, coverageStartedAt: fetchedAt - ODATA_COLLECTION_UPDATES_LOOKBACK_MS };\n}\n\n/**\n * Загружает компактный список справочников, изменённых за последние 7 дней.\n * Сам список живёт отдельно от данных справочников и управляет их точечной инвалидацией.\n */\nexport function fetchODataCollectionUpdates() {\n\treturn async ({ signal }: { signal: AbortSignal }): Promise<ODataCollectionUpdatesResult> => {\n\t\tconst requestStartedAt = Date.now();\n\t\tconst endpoint = getODataProjectAdapter().collectionUpdates;\n\t\tif (!endpoint) return normalizeCollectionUpdates([], requestStartedAt);\n\n\t\tconst response = await odataFetch<ODataCollectionUpdateRecord, ODataCollectionUpdateRecord[]>(\n\t\t\t`/${endpoint.service}/${endpoint.target}`,\n\t\t\t{\n\t\t\t\tbaseUrl: resolveODataBaseUrl(endpoint.service, endpoint.baseUrl),\n\t\t\t\tswCache: ODATA_COLLECTION_UPDATES_SW_CACHE\n\t\t\t},\n\t\t\t{ signal }\n\t\t);\n\n\t\treturn normalizeCollectionUpdates(response.data, Math.max(requestStartedAt, Date.now()));\n\t};\n}\n\n/**\n * Описывает общий TanStack Query со списком обновлённых справочников.\n * Query сохраняется в IndexedDB и дополнительно кешируется Service Worker на короткий TTL.\n */\nexport const odataCollectionUpdatesQueryOptions = (options: ODataCollectionUpdatesOptions = {}) =>\n\tqueryOptions({\n\t\tqueryKey: createODataCollectionUpdatesQueryKey(),\n\t\tqueryFn: fetchODataCollectionUpdates(),\n\t\tmeta: persistedQueryMeta,\n\t\tenabled: Boolean(getODataProjectAdapter().collectionUpdates),\n\t\tstaleTime: options.staleTime ?? COLLECTION_UPDATES_STALE_TIME,\n\t\tgcTime: Infinity\n\t});\n\nexport function useODataCollectionUpdatesQuery(options: ODataCollectionUpdatesOptions = {}) {\n\treturn useQuery(odataCollectionUpdatesQueryOptions(options));\n}\n","import { useODataMetadataQuery } from \"./useODataMetadataQuery\";\n\nimport type { ODataServiceConfig } from \"@ryuzaki13/react-foundation-lib/odata-service\";\n\n/**\n * Возвращает metadata конкретной OData-сущности по имени сервиса и сущности.\n *\n * Хук не добавляет собственную бизнес-логику и служит публичной тонкой\n * прослойкой над `useODataMetadataQuery(...)`.\n */\nexport function useODataMetadata(odata: ODataServiceConfig) {\n\tconst { data, dataUpdatedAt = 0, isLoading, isError } = useODataMetadataQuery({ service: odata.service });\n\tconst metadata = data?.entities[odata.target];\n\n\tif (!isLoading && !metadata && data?.functionImports[odata.target]) {\n\t\tthrow new Error(`OData target '${odata.target}' является FunctionImport и не может использоваться как сущность`);\n\t}\n\n\tif (isError) {\n\t\tthrow new Error(`Ошибка загрузки метаданных сервиса ${odata.service}`);\n\t}\n\n\treturn { metadata, metadataUpdatedAt: dataUpdatedAt, isLoading };\n}\n","import { useMemo } from \"react\";\n\nimport { buildEntityPath, type ODataServiceConfig, type ODataValue } from \"@ryuzaki13/react-foundation-lib/odata-service\";\n\nimport { useODataMetadata } from \"./useODataMetadata\";\n\nimport type { CollectionPair } from \"@ryuzaki13/react-foundation-lib/odata\";\n\nconst throwErrorText = \"Использование actions недопустимо до окончания загрузки metadata\";\n\n// function throwNoMetadata() {\n// \tif (__DEV__) {\n// \t\tthrow new Error(throwErrorText);\n// \t}\n// \treturn undefined;\n// }\n\nexport type ODataEntity = Omit<ReturnType<typeof useODataEntity>, \"isLoading\">;\n\nexport function useODataEntity(odata: ODataServiceConfig) {\n\tconst { metadata, metadataUpdatedAt, isLoading } = useODataMetadata(odata);\n\n\tconst actions = useMemo(() => {\n\t\tconst getEntityPath = (values: Record<string, ODataValue> = {}) => {\n\t\t\tif (!metadata) throw new Error(throwErrorText);\n\t\t\treturn buildEntityPath(metadata, odata, values);\n\t\t};\n\t\tconst getKeys = () => {\n\t\t\tif (!metadata) throw new Error(throwErrorText);\n\t\t\treturn metadata.columns?.map((c) => c.id);\n\t\t};\n\t\tconst getKeyPairs = () => {\n\t\t\tif (!metadata) throw new Error(throwErrorText);\n\t\t\treturn metadata.columns\n\t\t\t\t?.filter((c) => c.semanticType === \"code\" && c.linkedColumnId)\n\t\t\t\t.map((c) => ({ codeKey: c.id, textKey: c.linkedColumnId }) as CollectionPair);\n\t\t};\n\t\tconst getKeyPairsMap = () => {\n\t\t\tif (!metadata) throw new Error(throwErrorText);\n\t\t\tconst pairs: Record<string, string> = {};\n\n\t\t\tfor (const column of metadata.columns ?? []) {\n\t\t\t\tif (column.semanticType === \"code\" && column.linkedColumnId) {\n\t\t\t\t\tpairs[column.id] = column.linkedColumnId;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn pairs;\n\t\t};\n\n\t\treturn {\n\t\t\t/**\n\t\t\t * Получить строку запроса `/service/entity(parameters)/Results`\n\t\t\t */\n\t\t\tgetEntityPath,\n\t\t\t/**\n\t\t\t * Получить все ключи сущности\n\t\t\t */\n\t\t\tgetKeys,\n\t\t\t/**\n\t\t\t * Получить список ключей в формате `{ codeKey, textKey }`\n\t\t\t */\n\t\t\tgetKeyPairs,\n\t\t\t/**\n\t\t\t * Получить словать ключей в формате `{ code: text }`\n\t\t\t */\n\t\t\tgetKeyPairsMap\n\t\t};\n\t}, [odata, metadata]);\n\n\treturn { config: odata, metadata, metadataUpdatedAt, isLoading, actions };\n}\n","import { useEffect, useMemo } from \"react\";\n\nimport { buildSeparatedArrays, type CollectionItem, type CollectionPair } from \"@ryuzaki13/react-foundation-lib/odata\";\nimport { persistedQueryMeta } from \"@ryuzaki13/react-foundation-lib/query-client\";\nimport { useQuery, useQueryClient, UseQueryResult } from \"@tanstack/react-query\";\n\nimport { createODataCollectionQueryKey } from \"./createODataCollectionQueryKey\";\nimport { fetchCollectionData } from \"./fetchCollectionData\";\nimport { ODataCollectionConfig } from \"./types\";\nimport {\n\tODATA_COLLECTION_BUST_SW_CACHE,\n\tODATA_COLLECTION_DEFAULT_SW_CACHE,\n\tODataCollectionUpdateItem,\n\tuseODataCollectionUpdatesQuery\n} from \"./useODataCollectionUpdatesQuery\";\nimport { useODataEntity } from \"./useODataEntity\";\n\nexport interface ODataCollectionResult<T extends CollectionItem> {\n\titems: T[];\n\tkeyPairs: CollectionPair[];\n\tkeyPairsMap: Record<string, string>;\n\tseparated: Record<string, T[]>;\n\tchain: { codeKey: string; count: number }[];\n\tcount: number;\n\tcacheUpdatedAt: number;\n}\n\ninterface ODataCollectionCacheRefreshContext {\n\tupdate?: ODataCollectionUpdateItem;\n\tmetadataUpdatedAt?: number;\n\tupdatesCoverageStartedAt?: number;\n}\n\nexport function resolveODataCollectionSwCachePolicy(swCache: string, shouldBust: boolean) {\n\tif (!shouldBust) return swCache;\n\n\tconst normalized = swCache.trim().toLowerCase();\n\tif (normalized === \"off\" || normalized.startsWith(\"bust=\")) return swCache;\n\tif (normalized.startsWith(\"ttl=\")) return swCache.replace(/^\\s*ttl=/i, \"bust=\");\n\n\treturn ODATA_COLLECTION_BUST_SW_CACHE;\n}\n\nfunction isUsableTimestamp(value: number | undefined): value is number {\n\treturn typeof value === \"number\" && Number.isFinite(value) && value > 0;\n}\n\n/**\n * Определяет, нужно ли обновить конкретный справочник по списку изменений.\n * Сравнение идёт с cacheUpdatedAt, который сохраняется вместе с данными справочника.\n */\nexport function shouldRefreshODataCollectionCache<T extends CollectionItem>(\n\tcontext: ODataCollectionCacheRefreshContext,\n\tcachedData: ODataCollectionResult<T> | undefined\n) {\n\tconst cacheUpdatedAt = cachedData?.cacheUpdatedAt ?? 0;\n\tconst updateChangedAt = context.update?.lastChangedAt?.getTime();\n\n\tif (isUsableTimestamp(updateChangedAt)) {\n\t\tif (!cachedData || !cacheUpdatedAt) return true;\n\t\tif (updateChangedAt > cacheUpdatedAt) return true;\n\t}\n\n\tif (isUsableTimestamp(context.metadataUpdatedAt)) {\n\t\tif (!cachedData || !cacheUpdatedAt) return true;\n\t\tif (context.metadataUpdatedAt > cacheUpdatedAt) return true;\n\t}\n\n\t/**\n\t * Бэкенд отдаёт список изменений справочников только за последнюю неделю.\n\t * Если локальный справочник старше этого окна, отсутствие target в списке\n\t * больше не доказывает актуальность, поэтому обновляем только открытый справочник.\n\t */\n\tif (isUsableTimestamp(context.updatesCoverageStartedAt)) {\n\t\tif (!cachedData || !cacheUpdatedAt) return true;\n\t\tif (cacheUpdatedAt < context.updatesCoverageStartedAt) return true;\n\t}\n\n\treturn false;\n}\n\n/**\n * Универсальный хук для получения данных из OData сервиса.\n * Заменяет функционал TextDataService из SAP UI5.\n */\nexport function useODataCollectionQuery<T extends CollectionItem>(odata: ODataCollectionConfig): UseQueryResult<ODataCollectionResult<T>> {\n\tconst {\n\t\tservice,\n\t\ttarget,\n\t\tlimitedKeys,\n\t\texcludeEmpty,\n\t\tsortByCode,\n\t\tserverFilter,\n\t\tclientFilter,\n\t\tswCache = ODATA_COLLECTION_DEFAULT_SW_CACHE\n\t} = odata;\n\tconst queryClient = useQueryClient();\n\tconst { actions, metadata, metadataUpdatedAt, isLoading } = useODataEntity(odata);\n\tconst updatesQuery = useODataCollectionUpdatesQuery();\n\n\tconst queryKey = useMemo(\n\t\t() => createODataCollectionQueryKey({ service, target, limitedKeys, serverFilter }),\n\t\t[service, target, limitedKeys, serverFilter]\n\t);\n\tconst cachedData = queryClient.getQueryData<ODataCollectionResult<T>>(queryKey);\n\tconst collectionUpdate = updatesQuery.data?.byEntityName[target];\n\tconst shouldBustCollectionCache = shouldRefreshODataCollectionCache(\n\t\t{\n\t\t\tupdate: collectionUpdate,\n\t\t\tmetadataUpdatedAt,\n\t\t\tupdatesCoverageStartedAt: updatesQuery.data?.coverageStartedAt\n\t\t},\n\t\tcachedData\n\t);\n\tconst effectiveSwCache = resolveODataCollectionSwCachePolicy(swCache, shouldBustCollectionCache);\n\tconst updatesReady = updatesQuery.isError || (updatesQuery.isSuccess && !updatesQuery.isFetching);\n\n\tuseEffect(() => {\n\t\tif (!cachedData || !shouldBustCollectionCache) return;\n\n\t\tvoid queryClient.invalidateQueries({ queryKey });\n\t}, [cachedData, queryClient, queryKey, shouldBustCollectionCache]);\n\n\treturn useQuery({\n\t\tqueryKey,\n\t\tqueryFn: async ({ signal }) => {\n\t\t\tconst requestStartedAt = Date.now();\n\t\t\tconst selectKeys = limitedKeys ? [...limitedKeys] : actions.getKeys();\n\t\t\tconst keyPairs = actions.getKeyPairs();\n\t\t\tconst keyPairsMap = actions.getKeyPairsMap();\n\n\t\t\tif (limitedKeys) {\n\t\t\t\tfor (const k of limitedKeys) {\n\t\t\t\t\tconst keyText = keyPairsMap[k];\n\t\t\t\t\tif (keyText && !selectKeys.includes(keyText)) {\n\t\t\t\t\t\tselectKeys.push(keyText);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst { items } = await fetchCollectionData<T>({\n\t\t\t\turl: `/${service}/${target}`,\n\t\t\t\tquery: {\n\t\t\t\t\tselect: selectKeys,\n\t\t\t\t\texpression: serverFilter,\n\t\t\t\t\tswCache: effectiveSwCache\n\t\t\t\t},\n\t\t\t\tsignal\n\t\t\t});\n\n\t\t\tlet filterdItems = items;\n\t\t\tif (clientFilter) {\n\t\t\t\tfilterdItems = items.filter(clientFilter);\n\t\t\t}\n\n\t\t\tconst separated = buildSeparatedArrays<T>(filterdItems, keyPairs, excludeEmpty, sortByCode);\n\n\t\t\t// Рассчитать порядок от меньшего к большему\n\t\t\tconst chain = keyPairs\n\t\t\t\t.map((pair) => ({ codeKey: pair.codeKey, count: separated[pair.codeKey].length }))\n\t\t\t\t.sort((a, b) => a.count - b.count);\n\n\t\t\treturn {\n\t\t\t\titems: filterdItems,\n\t\t\t\tkeyPairs,\n\t\t\t\tkeyPairsMap,\n\t\t\t\tseparated,\n\t\t\t\tchain,\n\t\t\t\tcount: filterdItems.length,\n\t\t\t\tcacheUpdatedAt: Math.max(requestStartedAt, Date.now(), collectionUpdate?.lastChangedAt?.getTime() ?? 0, metadataUpdatedAt)\n\t\t\t};\n\t\t},\n\t\tenabled: Boolean(!isLoading && metadata && service && target && updatesReady),\n\t\tmeta: persistedQueryMeta,\n\t\t/**\n\t\t * Клиентский кеш можно держать не долго, чтобы он мог чаще дергать SW\n\t\t */\n\t\tstaleTime: 1000 * 60 * 60 * 2,\n\t\t/**\n\t\t * Если справочник не используется более часа, то можно из памяти выгрузить.\n\t\t */\n\t\tgcTime: 1000 * 60 * 60 * 1\n\t});\n}\n","import { useCallback, useMemo, useRef, useState } from \"react\";\n\nimport { useQueryClient } from \"@tanstack/react-query\";\n\nimport { createODataCollectionQueryKey } from \"./createODataCollectionQueryKey\";\nimport { ODataCollectionConfig, ODataCollectionModel } from \"./types\";\nimport { useODataCollectionQuery } from \"./useODataCollectionQuery\";\n\nimport type { CollectionItem } from \"@ryuzaki13/react-foundation-lib/odata\";\n\ninterface UseODataCollectionProps {\n\todata: ODataCollectionConfig;\n\tmodel: Required<ODataCollectionModel>;\n\n\t/**\n\t * Размер страницы для виртуализации.\n\t */\n\tpageSize?: number;\n\n\tfilter?: (item: CollectionItem) => boolean;\n}\n\nexport function useODataCollection({\n\todata,\n\tmodel,\n\t// filter,\n\tpageSize = 50\n}: UseODataCollectionProps) {\n\tconst { codeKey, maxVisibleItems } = model;\n\tconst { data: rawData, isLoading, isError, refetch } = useODataCollectionQuery(odata);\n\n\tconst textKey = rawData?.keyPairsMap[codeKey] ?? \"\";\n\n\t// Клиент для инвалидации запросов\n\tconst queryClient = useQueryClient();\n\n\tconst [filteredKeys, setFilteredKeys] = useState<Set<string>>();\n\n\tconst debounceTimers = useRef<Map<string, ReturnType<typeof setTimeout>>>(new Map());\n\n\t/**\n\t * itemsMap - индекс элементов для быстрого поиска\n\t * orderedKeys - упорядоченный список ключей для сохранения порядка\n\t */\n\tconst { itemsMap, separatedItems, orderedKeys } = useMemo(() => {\n\t\tconst itemsMap = new Map<string, CollectionItem>();\n\t\tconst orderedKeys = [] as string[];\n\t\tlet separatedItems: CollectionItem[] = [];\n\n\t\tif (rawData && rawData.separated[codeKey]) {\n\t\t\tseparatedItems = rawData.separated[codeKey];\n\n\t\t\tfor (const item of separatedItems) {\n\t\t\t\tconst key = item[codeKey];\n\t\t\t\tif (key) {\n\t\t\t\t\titemsMap.set(key, item);\n\t\t\t\t\torderedKeys.push(key);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn { itemsMap, separatedItems, orderedKeys };\n\t}, [rawData, codeKey]);\n\n\t// Создание индекса поиска для текстовых полей\n\tconst buildSearchIndex = useCallback(\n\t\t(field: string) => {\n\t\t\tconst items = rawData?.separated[codeKey];\n\n\t\t\tif (!items) {\n\t\t\t\treturn new Map<string, Set<string>>();\n\t\t\t}\n\n\t\t\tconst index = new Map<string, Set<string>>();\n\n\t\t\t// Создаем индекс по префиксам для быстрого поиска\n\t\t\tfor (const item of items) {\n\t\t\t\tconst value = item[field]?.toLowerCase();\n\t\t\t\tif (!value) continue;\n\n\t\t\t\t// Индексируем по префиксам длиной 1-5 символов\n\t\t\t\tfor (let i = 1; i <= Math.min(5, value.length); i++) {\n\t\t\t\t\tconst prefix = value.substring(0, i);\n\t\t\t\t\tif (!index.has(prefix)) {\n\t\t\t\t\t\tindex.set(prefix, new Set<string>());\n\t\t\t\t\t}\n\t\t\t\t\tindex.get(prefix)!.add(item[codeKey]);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn index;\n\t\t},\n\t\t[rawData, codeKey]\n\t);\n\n\t/**\n\t * Устанавливает несколько фильтров зависимостей.\n\t *\n\t * Сформированный список ключей пойдёт в фильтрацию элементов текущей коллекции по `codeKey`\n\t */\n\tconst setFilteredItems = useCallback(\n\t\t(filters: CollectionItem[] | undefined) => {\n\t\t\tsetFilteredKeys(() => {\n\t\t\t\tif (filters?.length) {\n\t\t\t\t\treturn new Set(filters.map((item) => item[codeKey]));\n\t\t\t\t}\n\n\t\t\t\treturn undefined;\n\t\t\t});\n\t\t},\n\t\t[codeKey]\n\t);\n\n\tconst getItems = useCallback(\n\t\t(\n\t\t\tpredicate?: (codeValue: string, textValue: string) => boolean,\n\t\t\tcurrentSelectedKeys?: readonly CollectionItem[]\n\t\t): CollectionItem[] => {\n\t\t\tif (!orderedKeys.length) return [];\n\n\t\t\tconst limit = maxVisibleItems;\n\t\t\tconst selectedKeysSet = new Set<string>();\n\t\t\tconst resultItems: CollectionItem[] = [];\n\n\t\t\tif (currentSelectedKeys?.length) {\n\t\t\t\t// Быстрое заполнение Set без создания временного массива\n\t\t\t\tfor (let i = 0; i < currentSelectedKeys.length; i++) {\n\t\t\t\t\tselectedKeysSet.add(currentSelectedKeys[i][codeKey]);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tlet count = 0;\n\n\t\t\tconst existsDependencies = filteredKeys && filteredKeys.size > 0;\n\n\t\t\t// Единый проход с ранним выходом по лимиту\n\t\t\tfor (const key of orderedKeys) {\n\t\t\t\tif (count >= limit) break;\n\n\t\t\t\tconst item = itemsMap.get(key);\n\t\t\t\tif (!item) continue;\n\n\t\t\t\t// Проверка на исключение выбранных ключей\n\t\t\t\tif (selectedKeysSet.size > 0 && selectedKeysSet.has(key)) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tconst itemCode = item[codeKey];\n\n\t\t\t\tif (existsDependencies && !filteredKeys.has(itemCode)) continue;\n\n\t\t\t\t// Проверка внешнего предиката\n\t\t\t\tif (predicate && !predicate(itemCode, item[textKey])) continue;\n\n\t\t\t\tresultItems.push(item);\n\t\t\t\tcount++;\n\t\t\t}\n\n\t\t\treturn resultItems;\n\t\t},\n\t\t[orderedKeys, maxVisibleItems, codeKey, itemsMap, filteredKeys, textKey]\n\t);\n\n\t/**\n\t * Получает страницу данных для виртуализации.\n\t */\n\tconst getPage = useCallback(\n\t\t(pageIndex: number): CollectionItem[] => {\n\t\t\tconst allItems = rawData?.separated[codeKey] || [];\n\t\t\tconst start = pageIndex * pageSize;\n\t\t\tconst end = start + pageSize;\n\t\t\treturn allItems.slice(start, end);\n\t\t},\n\t\t[rawData, pageSize, codeKey]\n\t);\n\n\t/**\n\t * Находит несколько элементов по ключам.\n\t */\n\tconst findSourceItemsByKeys = useCallback(\n\t\t(key: string, keys: string[]) => {\n\t\t\tif (!rawData) return [];\n\n\t\t\tconst keysSet = new Set<string>(keys);\n\t\t\treturn rawData.items.filter((item) => keysSet.has(item[key]));\n\t\t},\n\t\t[rawData]\n\t);\n\n\t/**\n\t * Дебаунсинг для частых операций.\n\t */\n\tconst debounce = useCallback((key: string, fn: () => void, delay: number = 200) => {\n\t\t// Очищаем предыдущий таймер\n\t\tif (debounceTimers.current.has(key)) {\n\t\t\tclearTimeout(debounceTimers.current.get(key)!);\n\t\t}\n\n\t\t// Устанавливаем новый таймер\n\t\tconst timer = setTimeout(fn, delay);\n\t\tdebounceTimers.current.set(key, timer);\n\t}, []);\n\n\t/**\n\t * Очищает все дебаунс таймеры.\n\t */\n\tconst clearDebounceTimers = useCallback(() => {\n\t\tfor (const timer of debounceTimers.current.values()) {\n\t\t\tclearTimeout(timer);\n\t\t}\n\t\tdebounceTimers.current.clear();\n\t}, []);\n\n\t// Очистка таймеров при размонтировании\n\tuseMemo(() => {\n\t\treturn () => {\n\t\t\tclearDebounceTimers();\n\t\t};\n\t}, [clearDebounceTimers]);\n\n\treturn {\n\t\t// Состояние данных\n\t\tdata: rawData,\n\t\tisLoading,\n\t\tisError,\n\n\t\tcodeKey,\n\t\ttextKey,\n\n\t\t// Функции для работы с коллекцией\n\t\tgetItems,\n\t\tfindSourceItemsByKeys,\n\t\tsetFilteredItems,\n\t\tgetPage,\n\t\tbuildSearchIndex,\n\t\tdebounce,\n\n\t\t// Вспомогательные данные\n\t\titemsMap,\n\t\tseparatedItems,\n\t\torderedKeys,\n\n\t\t// Управление запросом\n\n\t\t/**\n\t\t * @deprecated нужен только на этапе проектирования, скоро будет удален\n\t\t */\n\t\trefetch,\n\t\t/**\n\t\t * @deprecated нужен только на этапе проектирования, скоро будет удален\n\t\t */\n\t\tinvalidate: () => queryClient.invalidateQueries({ queryKey: createODataCollectionQueryKey(odata) }),\n\n\t\t// Метаданные для виртуализации\n\t\ttotalCount: rawData?.separated[codeKey]?.length || 0,\n\t\tpageSize\n\t};\n}\n","import { useEffect, useMemo, useState } from \"react\";\n\nimport { Query, useQueryClient } from \"@tanstack/react-query\";\n\nimport { createODataCollectionQueryKey } from \"./createODataCollectionQueryKey\";\nimport { ODataServiceCollectionConfig } from \"./types\";\n\nimport type { ODataChainsMap } from \"@ryuzaki13/react-foundation-lib/odata-service\";\n\n/**\n * Используется для получения последовательностей кодов.\n */\nexport function useODataCollectionChains(params: ODataServiceCollectionConfig[]) {\n\tconst queryClient = useQueryClient();\n\tconst [chains, setChains] = useState<ODataChainsMap>({});\n\n\tconst trackedKeys = useMemo(() => params.map((p) => createODataCollectionQueryKey(p)), [params]);\n\n\tuseEffect(() => {\n\t\tfunction updateChains() {\n\t\t\tconst newChains: ODataChainsMap = {};\n\n\t\t\tfor (const p of params) {\n\t\t\t\tconst key = createODataCollectionQueryKey(p);\n\t\t\t\tconst cached = queryClient.getQueryData<{ chain: { codeKey: string; count: number }[] }>(key);\n\t\t\t\tif (cached?.chain) {\n\t\t\t\t\tnewChains[`${p.service}.${p.target}`] = cached.chain;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tsetChains((prev) => {\n\t\t\t\t// не обновлять стейт, если данные не изменились (во избежание лишних рендеров)\n\t\t\t\tconst same =\n\t\t\t\t\tObject.keys(prev).length === Object.keys(newChains).length &&\n\t\t\t\t\tObject.entries(newChains).every(([k, v]) => prev[k] === v);\n\t\t\t\treturn same ? prev : newChains;\n\t\t\t});\n\t\t}\n\n\t\t// Первичная загрузка (на случай, если данные уже в кэше)\n\t\tupdateChains();\n\n\t\t// Подписка на изменения кэша\n\t\tconst unsubscribe = queryClient.getQueryCache().subscribe((event) => {\n\t\t\t// Проверяем, затрагивает ли событие один из наших trackedKeys\n\t\t\tif (event?.query) {\n\t\t\t\tconst query = event.query as Query;\n\t\t\t\tconst isTracked = trackedKeys.some((key) => JSON.stringify(key) === JSON.stringify(query.queryKey));\n\t\t\t\tif (isTracked) {\n\t\t\t\t\tupdateChains();\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\n\t\treturn unsubscribe;\n\t}, [params, queryClient, trackedKeys]);\n\n\treturn chains;\n}\n","import { useState } from \"react\";\n\nimport { useODataCollectionStore } from \"@ryuzaki13/react-foundation-lib/odata\";\n\nimport { ODataCollectionModel } from \"./types\";\n\nexport function useODataCollectionModel(model: ODataCollectionModel): Required<ODataCollectionModel> {\n\t// NOTE: без подписки, потому что эти данные в рантайме не предполагается изменять в ближайшее время.\n\n\t// const defaultMaxVisibleItems = odataCollectionConfig.useMaxVisibleItems();\n\t// const defaultMinSearchCodeLength = odataCollectionConfig.useMinSearchCodeLength();\n\t// const defaultMinSearchTextLength = odataCollectionConfig.useMinSearchTextLength();\n\t// const defaultSearchDebounceDelay = odataCollectionConfig.useSearchDebounce();\n\n\tconst [stableModel] = useState(() => {\n\t\tconst defaultState = useODataCollectionStore.getState();\n\n\t\tconst {\n\t\t\tcodeKey,\n\t\t\tmaxVisibleItems = defaultState.defaultMaxVisibleItems,\n\t\t\tminSearchCodeLength = defaultState.defaultMinSearchCodeLength,\n\t\t\tminSearchTextLength = defaultState.defaultMinSearchTextLength,\n\t\t\tsearchDebounceDelay = defaultState.defaultSearchDebounceDelay\n\t\t} = model;\n\t\treturn {\n\t\t\tcodeKey,\n\t\t\tmaxVisibleItems,\n\t\t\tminSearchCodeLength,\n\t\t\tminSearchTextLength,\n\t\t\tsearchDebounceDelay\n\t\t};\n\t});\n\n\treturn stableModel;\n}\n","import { useMemo } from \"react\";\n\nimport {\n\ttype TableColumnDef,\n\ttype TableColumnFormattingMetaInput,\n\tcreateTableColumnVisibilityFromODataMetadata,\n\tcreateTableColumnsFromODataMetadata,\n\tenrichTableColumnsWithODataFormatting,\n\tresolveStableColumnId\n} from \"@ryuzaki13/react-foundation-lib/table\";\n\nimport { useODataMetadata } from \"./useODataMetadata\";\n\nimport type { EntityColumnProperty, EntityMetadata, ODataServiceConfig } from \"@ryuzaki13/react-foundation-lib/odata-service\";\n\n/**\n * Собирает visibility-state только для тех leaf-колонок, которые сопоставились с metadata.\n */\nfunction collectMatchedColumnVisibility<TData extends object>(\n\tcolumns: readonly TableColumnDef<TData>[],\n\tvisibilityById: Readonly<Record<string, boolean>>\n): Record<string, boolean> {\n\tconst matchedVisibility: Record<string, boolean> = {};\n\n\tconst visitLeafColumns = (nestedColumns: readonly TableColumnDef<TData>[]) => {\n\t\tfor (const column of nestedColumns) {\n\t\t\tif (\"columns\" in column && Array.isArray(column.columns) && column.columns.length > 0) {\n\t\t\t\tvisitLeafColumns(column.columns as TableColumnDef<TData>[]);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst columnId = resolveStableColumnId(column);\n\t\t\tif (!columnId || !(columnId in visibilityById)) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tmatchedVisibility[columnId] = visibilityById[columnId];\n\t\t}\n\t};\n\n\tvisitLeafColumns(columns);\n\n\treturn matchedVisibility;\n}\n\n/**\n * Конфиг hook-адаптера колонок в режиме `build`.\n */\nexport interface UseODataTableColumnsBuildConfig extends Pick<ODataServiceConfig, \"service\" | \"target\"> {\n\t/**\n\t * Режим генерации колонок только по metadata.\n\t */\n\tmode: \"build\";\n\t/**\n\t * Позволяет определить видимость колонки при генерации.\n\t */\n\tresolveVisible?: (column: EntityColumnProperty) => boolean;\n\t/**\n\t * Позволяет переопределить заголовок колонки при генерации.\n\t */\n\tresolveHeader?: (column: EntityColumnProperty) => string;\n\t/**\n\t * Позволяет сразу навесить formatting-конфиг на generated column.\n\t */\n\tresolveFormatting?: (column: EntityColumnProperty) => TableColumnFormattingMetaInput | undefined;\n}\n\n/**\n * Конфиг hook-адаптера колонок в режиме `enrich`.\n */\nexport interface UseODataTableColumnsEnrichConfig<TData extends object> extends Pick<ODataServiceConfig, \"service\" | \"target\"> {\n\t/**\n\t * Режим обогащения уже существующих колонок.\n\t */\n\tmode: \"enrich\";\n\t/**\n\t * Существующий набор колонок для дозаполнения `meta.formatting.role/type`.\n\t */\n\tcolumns: readonly TableColumnDef<TData>[];\n}\n\n/**\n * Универсальный конфиг hook-адаптера колонок.\n */\nexport type UseODataTableColumnsConfig<TData extends object = Record<string, unknown>> =\n\tUseODataTableColumnsBuildConfig | UseODataTableColumnsEnrichConfig<TData>;\n\n/**\n * Результат работы hook-адаптера колонок.\n */\nexport interface UseODataTableColumnsResult<TData extends object> {\n\t/**\n\t * Итоговый набор колонок для `Table` или `TreeTable`.\n\t */\n\tcolumns: TableColumnDef<TData>[];\n\t/**\n\t * Стартовая карта видимости колонок для TanStack Table.\n\t */\n\tdefaultColumnVisibility: Record<string, boolean> | undefined;\n\t/**\n\t * Метаданные сущности, если они уже загружены.\n\t */\n\tmetadata: EntityMetadata | undefined;\n\t/**\n\t * Признак загрузки metadata.\n\t */\n\tisLoading: boolean;\n}\n\n/**\n * Возвращает колонки для `Table`/`TreeTable` на основе OData metadata.\n *\n * В режиме `build` генерирует базовый набор колонок из `metadata.columns`.\n * В режиме `enrich` дозаполняет уже существующие колонки typed-formatting контекстом.\n */\nexport function useODataTableColumns<TData extends object = Record<string, unknown>>(\n\tconfig: UseODataTableColumnsConfig<TData>\n): UseODataTableColumnsResult<TData> {\n\tconst { metadata, isLoading } = useODataMetadata(config);\n\n\tconst columns = useMemo(() => {\n\t\tif (!metadata) {\n\t\t\treturn config.mode === \"build\" ? [] : [...config.columns];\n\t\t}\n\n\t\tif (config.mode === \"build\") {\n\t\t\treturn createTableColumnsFromODataMetadata<TData>(metadata.columns, {\n\t\t\t\tresolveHeader: config.resolveHeader,\n\t\t\t\tresolveFormatting: config.resolveFormatting\n\t\t\t});\n\t\t}\n\n\t\treturn enrichTableColumnsWithODataFormatting(config.columns, metadata.columns);\n\t}, [config, metadata]);\n\n\tconst defaultColumnVisibility = useMemo(() => {\n\t\tif (!metadata) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tif (config.mode === \"build\") {\n\t\t\treturn createTableColumnVisibilityFromODataMetadata(metadata.columns, {\n\t\t\t\tresolveVisible: config.resolveVisible\n\t\t\t});\n\t\t}\n\n\t\tconst visibilityById = createTableColumnVisibilityFromODataMetadata(metadata.columns);\n\n\t\treturn collectMatchedColumnVisibility(config.columns, visibilityById);\n\t}, [config, metadata]);\n\n\treturn {\n\t\tcolumns,\n\t\tdefaultColumnVisibility,\n\t\tmetadata,\n\t\tisLoading\n\t};\n}\n","import { useODataCollectionQuery } from \"./useODataCollectionQuery\";\n\nimport type { CollectionItem } from \"@ryuzaki13/react-foundation-lib/odata\";\n\nexport function useTextServiceQuery<T extends CollectionItem>(target: string) {\n\treturn useODataCollectionQuery<T>({ service: \"TEXT_DICTIONARY_SRV\", target });\n}\n","import { notify } from \"@ryuzaki13/react-foundation-lib/notifications\";\nimport { QueryClient } from \"@tanstack/react-query\";\n\nimport { buildODataFetchRequest, ODataFetchRequestPreview } from \"./odataFetch\";\nimport {\n\tODataArrayOperationMethod,\n\tODataCreateFnOptions,\n\tODataDeleteFnOptions,\n\todataFetchFn,\n\tODataFetchFnImplementationArgs,\n\tODataFetchFnRequest,\n\tODataFetchFnRunner,\n\tODataFetchFnSharedOptions,\n\tODataFunctionImportFnOptions,\n\tODataQueryArrayTransform,\n\tODataQueryFnOptions,\n\tODataQuerySingleTransform,\n\tODataReadFnOptions,\n\tODataSingleFetchFnRequest,\n\tODataSingleOperationMethod,\n\tODataSingleTransform,\n\tODataUpdateFnOptions\n} from \"./odataFetchFn\";\nimport {\n\tbuildTargetPath,\n\tisFunctionImportMetadata,\n\tresolveODataTarget,\n\tresolveRequestBody,\n\tresolveRequestMethod,\n\tvalidateODataOperation\n} from \"./odataFetchFnHelpers\";\nimport { resolveODataBaseUrl } from \"./transport\";\nimport { getODataMetadataData } from \"./useODataMetadataQuery\";\n\nimport type {\n\tODataOperationMethod,\n\tODataServiceConfig,\n\tODataTargetMetadata,\n\tUnwrappedODataParameters,\n\tWrappedODataParameters\n} from \"@ryuzaki13/react-foundation-lib/odata-service\";\n\ntype ODataDevHelperName =\n\t| \"odataFetchFnDev\"\n\t| \"odataCreateFnDev\"\n\t| \"odataUpdateFnDev\"\n\t| \"odataDeleteFnDev\"\n\t| \"odataReadFnDev\"\n\t| \"odataQueryFnDev\"\n\t| \"odataFunctionImportFnDev\";\n\ntype ODataFetchFnDevOptions<I> = ODataFetchFnSharedOptions<I> & {\n\tparams?: WrappedODataParameters;\n\tbody?: unknown;\n\ttransform?: unknown;\n};\n\ntype ODataDevRequestLogInfo = {\n\thelperName: ODataDevHelperName;\n\toperation: ODataOperationMethod;\n\todata: ODataServiceConfig;\n\ttarget: ODataTargetMetadata;\n\ttargetPath: string;\n\trequest: ODataFetchRequestPreview;\n\trequestMethod: string;\n\tparams: WrappedODataParameters;\n\tqueryOptions: unknown;\n\tbody: string | undefined;\n\tautoParse: boolean | undefined;\n\thasTransform: boolean;\n};\n\nfunction getConsole() {\n\treturn globalThis.console;\n}\n\nfunction headersToRecord(headers: HeadersInit | undefined) {\n\tconst result: Record<string, string> = {};\n\tnew Headers(headers).forEach((value, key) => {\n\t\tresult[key] = value;\n\t});\n\n\treturn result;\n}\n\nfunction parseRequestBodyForLog(body: BodyInit | null | undefined): unknown {\n\tif (body === undefined || body === null) return undefined;\n\tif (typeof body !== \"string\") return body;\n\n\ttry {\n\t\tconst parsed: unknown = JSON.parse(body);\n\t\treturn parsed;\n\t} catch {\n\t\treturn body;\n\t}\n}\n\nfunction isWriteRequest(method: string | undefined) {\n\treturn method !== undefined && ![\"GET\", \"HEAD\"].includes(method.toUpperCase());\n}\n\nfunction isSapRequestPreview(request: ODataFetchRequestPreview) {\n\tconst baseUrl = request.baseUrl ?? \"odata\";\n\tif (baseUrl !== \"\") return true;\n\n\treturn request.path.startsWith(\"/sap/\") || request.path.startsWith(\"/sap-dp0/\");\n}\n\nfunction hasHeader(headers: Record<string, string>, name: string) {\n\tconst normalizedName = name.toLowerCase();\n\treturn Object.keys(headers).some((key) => key.toLowerCase() === normalizedName);\n}\n\nfunction setDefaultHeader(headers: Record<string, string>, name: string, value: string) {\n\tif (hasHeader(headers, name)) return;\n\theaders[name] = value;\n}\n\nfunction buildTransportHeadersPreview(request: ODataFetchRequestPreview) {\n\tconst headers = headersToRecord(request.init.headers);\n\tconst method = request.init.method;\n\tconst sapRequest = isSapRequestPreview(request);\n\n\tsetDefaultHeader(headers, \"DataServiceVersion\", \"2.0\");\n\tsetDefaultHeader(headers, \"MaxDataServiceVersion\", \"2.0\");\n\tsetDefaultHeader(headers, \"Accept\", \"application/json\");\n\n\theaders[\"sap-language\"] = \"ru\";\n\n\tif (sapRequest) {\n\t\theaders[\"sap-contextid-accept\"] = \"header\";\n\t}\n\n\tif (isWriteRequest(method) && request.init.body) {\n\t\tsetDefaultHeader(headers, \"Content-Type\", \"application/json\");\n\t}\n\n\tif (isWriteRequest(method) && sapRequest) {\n\t\tsetDefaultHeader(headers, \"x-csrf-token\", \"<получается отдельным GET перед реальным write-запросом>\");\n\t}\n\n\treturn headers;\n}\n\nfunction getTargetKind(target: ODataTargetMetadata) {\n\tif (isFunctionImportMetadata(target)) return \"FunctionImport\";\n\treturn target.result ? \"Parameterized Entity\" : \"Entity\";\n}\n\nfunction logObjectSection(title: string, value: unknown) {\n\tconst logger = getConsole();\n\tlogger.groupCollapsed(title);\n\tlogger.info(value);\n\tlogger.groupEnd();\n}\n\nfunction logODataDevRequest(info: ODataDevRequestLogInfo) {\n\tconst logger = getConsole();\n\tconst bodyPreview = parseRequestBodyForLog(info.request.init.body);\n\tconst initHeaders = headersToRecord(info.request.init.headers);\n\tconst transportHeaders = buildTransportHeadersPreview(info.request);\n\tconst requestInitPreview = {\n\t\tmethod: info.request.init.method,\n\t\theaders: initHeaders,\n\t\tbody: bodyPreview,\n\t\thasSignal: Boolean(info.request.init.signal)\n\t};\n\n\tlogger.groupCollapsed(`[OData DEV] ${info.requestMethod} ${info.request.fullUrl}`);\n\tlogger.table([\n\t\t{\n\t\t\thelper: info.helperName,\n\t\t\toperation: info.operation,\n\t\t\ttarget: info.odata.target,\n\t\t\ttargetKind: getTargetKind(info.target),\n\t\t\tservice: info.odata.service,\n\t\t\trealFetch: \"не выполнялся\"\n\t\t}\n\t]);\n\tlogger.info(\"Итоговый URL:\", info.request.fullUrl);\n\tlogger.info(\"Path без base URL:\", info.request.path);\n\tlogger.info(\"Target path до query options:\", info.targetPath);\n\tlogger.info(\"Query string:\", info.request.queryString || \"<пусто>\");\n\tlogger.info(\"Body:\", bodyPreview ?? \"<пусто>\");\n\tlogger.info(\"Auto parse:\", info.autoParse ?? false);\n\tlogger.info(\"Transform:\", info.hasTransform ? \"передан, но не вызывается без ответа backend\" : \"не передан\");\n\tlogger.info(\"Dry-run result:\", info.operation === \"query\" ? { data: [], totalCount: 0 } : { data: undefined });\n\tlogObjectSection(\"OData config\", info.odata);\n\tlogObjectSection(\"Target metadata\", info.target);\n\tlogObjectSection(\"Target params\", info.params);\n\tlogObjectSection(\"Query options\", info.queryOptions);\n\tlogObjectSection(\"RequestInit, переданный в transport\", requestInitPreview);\n\tlogObjectSection(\"Заголовки после transport defaults (без реального fetch)\", transportHeaders);\n\tlogger.groupEnd();\n}\n\nfunction notifyODataDevHelperCall(helperName: ODataDevHelperName) {\n\tnotify.warning(`${helperName}: DEV dry-run OData запроса. Реальный запрос не выполняется, payload выведен в console.`, {\n\t\ttitle: \"OData DEV helper\"\n\t});\n}\n\nfunction createODataFetchFnDevRunner<I>(\n\tmethod: ODataOperationMethod,\n\topts: ODataFetchFnDevOptions<I>,\n\thelperName: ODataDevHelperName\n): ODataFetchFnRunner<unknown> {\n\tconst { odata, options = {}, init = {}, autoParse, swCache } = opts;\n\tconst params = opts.params ?? {};\n\n\treturn async ({ client, signal }: { client: QueryClient; signal?: AbortSignal }) => {\n\t\tnotifyODataDevHelperCall(helperName);\n\n\t\tconst baseUrl = resolveODataBaseUrl(odata.service, options.baseUrl);\n\t\tconst serviceMetadata = await getODataMetadataData({ service: odata.service, baseUrl }, client);\n\t\tif (!serviceMetadata) {\n\t\t\tthrow new Error(`Не удалось загрузить metadata OData-сервиса '${odata.service}'`);\n\t\t}\n\n\t\tconst target = resolveODataTarget(serviceMetadata, odata.target);\n\n\t\tvalidateODataOperation(target, method, odata);\n\n\t\tconst body = resolveRequestBody(opts.body, method);\n\t\tconst requestMethod = resolveRequestMethod(target, method);\n\t\tconst targetPath = buildTargetPath(target, odata, params, method);\n\n\t\tconst queryOptions = swCache ? { ...options, baseUrl, swCache } : { ...options, baseUrl };\n\t\tconst requestInit = { ...init, method: requestMethod, body, signal };\n\t\tconst request = buildODataFetchRequest(targetPath, queryOptions, requestInit);\n\n\t\tlogODataDevRequest({\n\t\t\thelperName,\n\t\t\toperation: method,\n\t\t\todata,\n\t\t\ttarget,\n\t\t\ttargetPath,\n\t\t\trequest,\n\t\t\trequestMethod,\n\t\t\tparams,\n\t\t\tqueryOptions,\n\t\t\tbody,\n\t\t\tautoParse,\n\t\t\thasTransform: Boolean(opts.transform)\n\t\t});\n\n\t\tif (method === \"query\") {\n\t\t\treturn { data: [], totalCount: 0 };\n\t\t}\n\n\t\treturn { data: undefined };\n\t};\n}\n\nexport function odataFetchFnDev<\n\tI,\n\tO = I,\n\tP extends UnwrappedODataParameters = UnwrappedODataParameters,\n\tM extends ODataArrayOperationMethod = ODataArrayOperationMethod\n>(method: M, opts: ODataQueryFnOptions<I, O, P> & { transform: ODataQueryArrayTransform<I, O> }): ODataFetchFnRunner<O[]>;\nexport function odataFetchFnDev<\n\tI,\n\tO = I,\n\tP extends UnwrappedODataParameters = UnwrappedODataParameters,\n\tM extends ODataArrayOperationMethod = ODataArrayOperationMethod\n>(method: M, opts: ODataQueryFnOptions<I, O, P> & { transform: ODataQuerySingleTransform<I, O> }): ODataFetchFnRunner<O>;\nexport function odataFetchFnDev<\n\tI,\n\tP extends UnwrappedODataParameters = UnwrappedODataParameters,\n\tM extends ODataArrayOperationMethod = ODataArrayOperationMethod\n>(method: M, opts: ODataQueryFnOptions<I, I, P> & { transform?: undefined }): ODataFetchFnRunner<I[]>;\nexport function odataFetchFnDev<\n\tI,\n\tT = I,\n\tP extends UnwrappedODataParameters = UnwrappedODataParameters,\n\tM extends ODataSingleOperationMethod = ODataSingleOperationMethod\n>(method: M, opts: ODataSingleFetchFnRequest<M, I, I, T, P> & { transform?: undefined }): ODataFetchFnRunner<I>;\nexport function odataFetchFnDev<I, O = I, T = I, M extends ODataSingleOperationMethod = ODataSingleOperationMethod>(\n\tmethod: M,\n\topts: ODataSingleFetchFnRequest<M, I, O, T> & { transform: ODataSingleTransform<I, O> }\n): ODataFetchFnRunner<O>;\nexport function odataFetchFnDev<\n\tI,\n\tO = I,\n\tT = I,\n\tP extends UnwrappedODataParameters = UnwrappedODataParameters,\n\tM extends ODataOperationMethod = ODataOperationMethod\n>(method: M, opts: ODataFetchFnRequest<M, I, O, T, P>): ODataFetchFnRunner<unknown>;\nexport function odataFetchFnDev(...args: ODataFetchFnImplementationArgs): ODataFetchFnRunner<unknown> {\n\tif (!__DEV__) {\n\t\tswitch (args[0]) {\n\t\t\tcase \"create\": {\n\t\t\t\treturn odataFetchFn(\"create\", args[1]);\n\t\t\t}\n\n\t\t\tcase \"update\": {\n\t\t\t\treturn odataFetchFn(\"update\", args[1]);\n\t\t\t}\n\n\t\t\tcase \"delete\": {\n\t\t\t\treturn odataFetchFn(\"delete\", args[1]);\n\t\t\t}\n\n\t\t\tcase \"read\": {\n\t\t\t\treturn odataFetchFn(\"read\", args[1]);\n\t\t\t}\n\n\t\t\tcase \"query\": {\n\t\t\t\treturn odataFetchFn(\"query\", args[1]);\n\t\t\t}\n\n\t\t\tcase \"fi\": {\n\t\t\t\treturn odataFetchFn(\"fi\", args[1]);\n\t\t\t}\n\n\t\t\tdefault: {\n\t\t\t\tconst checker: never = args[0];\n\t\t\t\tvoid checker;\n\n\t\t\t\tthrow new Error(\"Неподдерживаемая OData operation в odataFetchFnDev\");\n\t\t\t}\n\t\t}\n\t}\n\n\tconst [method, opts] = args;\n\treturn createODataFetchFnDevRunner(method, opts, \"odataFetchFnDev\");\n}\n\nexport function odataCreateFnDev<I, T = I>(opts: ODataCreateFnOptions<I, I, T> & { transform?: undefined }): ODataFetchFnRunner<I>;\nexport function odataCreateFnDev<I, O = I, T = I>(\n\topts: ODataCreateFnOptions<I, O, T> & { transform: ODataSingleTransform<I, O> }\n): ODataFetchFnRunner<O>;\nexport function odataCreateFnDev<I, O = I, T = I>(opts: ODataCreateFnOptions<I, O, T>): ODataFetchFnRunner<unknown> {\n\tif (!__DEV__) {\n\t\treturn odataFetchFn<I, O, T, never, \"create\">(\"create\", opts);\n\t}\n\n\treturn createODataFetchFnDevRunner<I>(\"create\", opts, \"odataCreateFnDev\");\n}\n\nexport function odataUpdateFnDev<I, T = I, P extends UnwrappedODataParameters = UnwrappedODataParameters>(\n\topts: ODataUpdateFnOptions<I, I, T, P> & { transform?: undefined }\n): ODataFetchFnRunner<I>;\nexport function odataUpdateFnDev<I, O = I, T = I, P extends UnwrappedODataParameters = UnwrappedODataParameters>(\n\topts: ODataUpdateFnOptions<I, O, T, P> & { transform: ODataSingleTransform<I, O> }\n): ODataFetchFnRunner<O>;\nexport function odataUpdateFnDev<I, O = I, T = I, P extends UnwrappedODataParameters = UnwrappedODataParameters>(\n\topts: ODataUpdateFnOptions<I, O, T, P>\n): ODataFetchFnRunner<unknown> {\n\tif (!__DEV__) {\n\t\treturn odataFetchFn<I, O, T, P, \"update\">(\"update\", opts);\n\t}\n\n\treturn createODataFetchFnDevRunner<I>(\"update\", opts, \"odataUpdateFnDev\");\n}\n\nexport function odataDeleteFnDev<I, P extends UnwrappedODataParameters = UnwrappedODataParameters>(\n\topts: ODataDeleteFnOptions<I, I, P> & { transform?: undefined }\n): ODataFetchFnRunner<I>;\nexport function odataDeleteFnDev<I, O = I, P extends UnwrappedODataParameters = UnwrappedODataParameters>(\n\topts: ODataDeleteFnOptions<I, O, P> & { transform: ODataSingleTransform<I, O> }\n): ODataFetchFnRunner<O>;\nexport function odataDeleteFnDev<I, O = I, P extends UnwrappedODataParameters = UnwrappedODataParameters>(\n\topts: ODataDeleteFnOptions<I, O, P>\n): ODataFetchFnRunner<unknown> {\n\tif (!__DEV__) {\n\t\treturn odataFetchFn<I, O, I, P, \"delete\">(\"delete\", opts);\n\t}\n\n\treturn createODataFetchFnDevRunner<I>(\"delete\", opts, \"odataDeleteFnDev\");\n}\n\nexport function odataReadFnDev<I, P extends UnwrappedODataParameters = UnwrappedODataParameters>(\n\topts: ODataReadFnOptions<I, I, P> & { transform?: undefined }\n): ODataFetchFnRunner<I>;\nexport function odataReadFnDev<I, O = I, P extends UnwrappedODataParameters = UnwrappedODataParameters>(\n\topts: ODataReadFnOptions<I, O, P> & { transform: ODataSingleTransform<I, O> }\n): ODataFetchFnRunner<O>;\nexport function odataReadFnDev<I, O = I, P extends UnwrappedODataParameters = UnwrappedODataParameters>(\n\topts: ODataReadFnOptions<I, O, P>\n): ODataFetchFnRunner<unknown> {\n\tif (!__DEV__) {\n\t\treturn odataFetchFn<I, O, I, P, \"read\">(\"read\", opts);\n\t}\n\n\treturn createODataFetchFnDevRunner<I>(\"read\", opts, \"odataReadFnDev\");\n}\n\nexport function odataQueryFnDev<I, O = I, P extends UnwrappedODataParameters = UnwrappedODataParameters>(\n\topts: ODataQueryFnOptions<I, O, P> & { transform: ODataQueryArrayTransform<I, O> }\n): ODataFetchFnRunner<O[]>;\nexport function odataQueryFnDev<I, O = I, P extends UnwrappedODataParameters = UnwrappedODataParameters>(\n\topts: ODataQueryFnOptions<I, O, P> & { transform: ODataQuerySingleTransform<I, O> }\n): ODataFetchFnRunner<O>;\nexport function odataQueryFnDev<I, O = I, P extends UnwrappedODataParameters = UnwrappedODataParameters>(\n\topts: ODataQueryFnOptions<I, O, P> & { transform?: undefined }\n): ODataFetchFnRunner<I[]>;\nexport function odataQueryFnDev<I, O = I, P extends UnwrappedODataParameters = UnwrappedODataParameters>(\n\topts: ODataQueryFnOptions<I, O, P>\n): ODataFetchFnRunner<unknown> {\n\tif (!__DEV__) {\n\t\treturn odataFetchFn<I, O, void, P, \"query\">(\"query\", opts);\n\t}\n\n\treturn createODataFetchFnDevRunner<I>(\"query\", opts, \"odataQueryFnDev\");\n}\n\nexport function odataFunctionImportFnDev<I, P extends UnwrappedODataParameters = UnwrappedODataParameters>(\n\topts: ODataFunctionImportFnOptions<I, I, P> & { transform?: undefined }\n): ODataFetchFnRunner<I>;\nexport function odataFunctionImportFnDev<I, O = I, P extends UnwrappedODataParameters = UnwrappedODataParameters>(\n\topts: ODataFunctionImportFnOptions<I, O, P> & { transform: ODataSingleTransform<I, O> }\n): ODataFetchFnRunner<O>;\nexport function odataFunctionImportFnDev<I, O = I, P extends UnwrappedODataParameters = UnwrappedODataParameters>(\n\topts: ODataFunctionImportFnOptions<I, O, P>\n): ODataFetchFnRunner<unknown> {\n\tif (!__DEV__) {\n\t\treturn odataFetchFn<I, O, I, P, \"fi\">(\"fi\", opts);\n\t}\n\n\treturn createODataFetchFnDevRunner<I>(\"fi\", opts, \"odataFunctionImportFnDev\");\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"odata-BvLTiawF.js","names":[],"sources":["../../src/odata/createODataCollectionQueryKey.ts","../../src/odata/flattenODataDependentServices.ts","../../src/odata/sortODataDependentSegmentItemsByChains.ts","../../src/odata/sortODataDependentServicesByChains.ts","../../src/odata/fetchCollectionData.ts","../../src/odata/useODataCollectionUpdatesQuery.ts","../../src/odata/useODataMetadata.ts","../../src/odata/useODataEntity.ts","../../src/odata/useODataCollectionQuery.ts","../../src/odata/useODataCollection.ts","../../src/odata/useODataCollectionChains.ts","../../src/odata/useODataCollectionModel.ts","../../src/odata/useODataTableColumns.ts","../../src/odata/useTextServiceQuery.ts","../../src/odata/odataFetchFnDev.ts"],"sourcesContent":["import { odataBaseQueryKey } from \"./odataBaseQueryKey\";\nimport { ODataServiceCollectionConfig } from \"./types\";\n\nexport const createODataCollectionBaseQueryKey = () => [...odataBaseQueryKey, \"collection\"] as const;\n\nexport const createODataCollectionQueryKey = ({ service, target, limitedKeys, serverFilter }: ODataServiceCollectionConfig) =>\n\t[...createODataCollectionBaseQueryKey(), { service, target, limitedKeys, serverFilter }] as const;\n","import type { ODataDependentBaseProps, ODataDependentSegmentItem } from \"./types\";\n\n/**\n * Разворачивает зависимые OData-сервисы в плоский список segment-level элементов.\n */\nexport function flattenODataDependentServices(services: readonly ODataDependentBaseProps[]): ODataDependentSegmentItem[] {\n\tconst out: ODataDependentSegmentItem[] = [];\n\n\tfor (const [serviceIndex, service] of services.entries()) {\n\t\tconst serviceKey = `${service.odata.service}.${service.odata.target}`;\n\n\t\tfor (const [segmentIndex, [id, segment]] of Object.entries(service.segments).entries()) {\n\t\t\tout.push({\n\t\t\t\tid,\n\t\t\t\tserviceKey,\n\t\t\t\tserviceIndex,\n\t\t\t\tsegmentIndex,\n\t\t\t\todata: service.odata,\n\t\t\t\tsegment,\n\t\t\t\tmodel: {\n\t\t\t\t\t...service.model,\n\t\t\t\t\tcodeKey: id\n\t\t\t\t},\n\t\t\t\tpanelVisibility: segment.panelVisibility ?? \"user\"\n\t\t\t});\n\t\t}\n\t}\n\n\treturn out;\n}\n","import { ODataDependentSegmentItem } from \"./types\";\n\nimport type { ODataChainsMap } from \"@ryuzaki13/react-foundation-lib/odata-service\";\n\n/**\n * Сортирует плоские segment-level элементы по chain-порядку\n * и опционально накладывает пользовательский override.\n */\nexport function sortODataDependentSegmentItemsByChains(\n\titems: readonly ODataDependentSegmentItem[],\n\tchains: ODataChainsMap,\n\torderOverrideIds?: readonly string[]\n): ODataDependentSegmentItem[] {\n\tconst chainOrderByService = new Map<string, Map<string, number>>();\n\n\tfor (const [serviceKey, chain] of Object.entries(chains)) {\n\t\tchainOrderByService.set(serviceKey, new Map(chain.map((item, index) => [item.codeKey, index])));\n\t}\n\n\tconst baseOrdered = [...items]\n\t\t.map((item, index) => ({\n\t\t\titem,\n\t\t\tindex\n\t\t}))\n\t\t.sort((left, right) => {\n\t\t\tif (left.item.serviceIndex !== right.item.serviceIndex) {\n\t\t\t\treturn left.item.serviceIndex - right.item.serviceIndex;\n\t\t\t}\n\n\t\t\tconst chainOrder = chainOrderByService.get(left.item.serviceKey);\n\t\t\tconst leftChainOrder = chainOrder?.get(left.item.id);\n\t\t\tconst rightChainOrder = chainOrder?.get(right.item.id);\n\n\t\t\tif (leftChainOrder !== undefined && rightChainOrder !== undefined) {\n\t\t\t\treturn leftChainOrder - rightChainOrder;\n\t\t\t}\n\t\t\tif (leftChainOrder !== undefined) return -1;\n\t\t\tif (rightChainOrder !== undefined) return 1;\n\n\t\t\tif (left.item.segmentIndex !== right.item.segmentIndex) {\n\t\t\t\treturn left.item.segmentIndex - right.item.segmentIndex;\n\t\t\t}\n\n\t\t\treturn left.index - right.index;\n\t\t});\n\n\tif (!orderOverrideIds?.length) {\n\t\treturn baseOrdered.map(({ item }) => item);\n\t}\n\n\tconst availableIds = new Set(baseOrdered.map(({ item }) => item.id));\n\tconst normalizedOverride = [...new Set(orderOverrideIds)].filter((id) => availableIds.has(id));\n\tif (normalizedOverride.length === 0) {\n\t\treturn baseOrdered.map(({ item }) => item);\n\t}\n\n\tconst overrideRank = new Map(normalizedOverride.map((id, index) => [id, index]));\n\n\treturn [...baseOrdered]\n\t\t.sort((left, right) => {\n\t\t\tconst leftOverrideRank = overrideRank.get(left.item.id);\n\t\t\tconst rightOverrideRank = overrideRank.get(right.item.id);\n\n\t\t\tif (leftOverrideRank !== undefined && rightOverrideRank !== undefined) {\n\t\t\t\treturn leftOverrideRank - rightOverrideRank;\n\t\t\t}\n\t\t\tif (leftOverrideRank !== undefined) return -1;\n\t\t\tif (rightOverrideRank !== undefined) return 1;\n\n\t\t\treturn left.index - right.index;\n\t\t})\n\t\t.map(({ item }) => item);\n}\n","import { compareStrings } from \"@ryuzaki13/react-foundation-lib/string-comparison\";\n\nimport { ODataDependentBaseProps } from \"./types\";\n\nimport type { ODataChainsMap } from \"@ryuzaki13/react-foundation-lib/odata-service\";\n\n/**\n * Применяет пользовательский override порядка сегментов поверх уже рассчитанного базового порядка.\n *\n * Алгоритм:\n * 1. берёт только валидные id из `orderOverrideIds` (без дублей);\n * 2. поднимает эти id в начало в указанной последовательности;\n * 3. все остальные сегменты оставляет в исходном относительном порядке.\n */\nfunction applySegmentsOrderOverride(\n\tservices: readonly ODataDependentBaseProps[],\n\torderOverrideIds?: readonly string[]\n): ODataDependentBaseProps[] {\n\tif (!orderOverrideIds?.length) return [...services];\n\n\tconst visibleIds = new Set<string>();\n\tfor (const service of services) {\n\t\tfor (const segmentId of Object.keys(service.segments)) {\n\t\t\tvisibleIds.add(segmentId);\n\t\t}\n\t}\n\n\tconst normalizedOverride = [...new Set(orderOverrideIds)].filter((id) => visibleIds.has(id));\n\tif (normalizedOverride.length === 0) return [...services];\n\n\tconst overrideRank = new Map(normalizedOverride.map((id, index) => [id, index]));\n\tconst fallbackRankStart = normalizedOverride.length;\n\tconst segmentRank = new Map<string, number>();\n\tlet fallbackRank = fallbackRankStart;\n\n\tfor (const service of services) {\n\t\tfor (const segmentId of Object.keys(service.segments)) {\n\t\t\tif (segmentRank.has(segmentId)) continue;\n\t\t\tsegmentRank.set(segmentId, overrideRank.get(segmentId) ?? fallbackRank++);\n\t\t}\n\t}\n\n\tconst withOrderedSegments = services.map((service) => {\n\t\tconst orderedEntries = Object.entries(service.segments).sort(\n\t\t\t([leftId], [rightId]) =>\n\t\t\t\t(segmentRank.get(leftId) ?? Number.MAX_SAFE_INTEGER) - (segmentRank.get(rightId) ?? Number.MAX_SAFE_INTEGER)\n\t\t);\n\n\t\treturn {\n\t\t\t...service,\n\t\t\tsegments: Object.fromEntries(orderedEntries)\n\t\t};\n\t});\n\n\treturn [...withOrderedSegments].sort((leftService, rightService) => {\n\t\tconst leftFirstSegmentId = Object.keys(leftService.segments)[0];\n\t\tconst rightFirstSegmentId = Object.keys(rightService.segments)[0];\n\t\tconst leftRank = leftFirstSegmentId ? (segmentRank.get(leftFirstSegmentId) ?? Number.MAX_SAFE_INTEGER) : Number.MAX_SAFE_INTEGER;\n\t\tconst rightRank = rightFirstSegmentId ? (segmentRank.get(rightFirstSegmentId) ?? Number.MAX_SAFE_INTEGER) : Number.MAX_SAFE_INTEGER;\n\n\t\treturn leftRank - rightRank;\n\t});\n}\n\n/**\n * Сортирует сегменты сервисов по chain-порядку (от меньшего к большему)\n * и опционально накладывает пользовательский override.\n *\n * Если chain недоступен, сохраняет исходный порядок сегментов.\n *\n * @deprecated функционал должен быть вырезан и оставлен только с `sortODataDependentSegmentItemsByChains`\n */\nexport function sortODataDependentServicesByChains(\n\tservices: readonly ODataDependentBaseProps[],\n\tchains: ODataChainsMap,\n\torderOverrideIds?: readonly string[]\n): ODataDependentBaseProps[] {\n\tconst sortedByChains = services.map((service) => {\n\t\tconst serviceKey = `${service.odata.service}.${service.odata.target}`;\n\t\tconst chain = chains[serviceKey];\n\t\tif (!chain?.length) return service;\n\n\t\tconst chainOrder = new Map(chain.map((item, index) => [item.codeKey, index]));\n\t\tconst orderedEntries = Object.entries(service.segments).sort(([leftId], [rightId]) => {\n\t\t\tconst leftOrder = chainOrder.get(leftId);\n\t\t\tconst rightOrder = chainOrder.get(rightId);\n\n\t\t\tif (leftOrder !== undefined && rightOrder !== undefined) return leftOrder - rightOrder;\n\t\t\tif (leftOrder !== undefined) return -1;\n\t\t\tif (rightOrder !== undefined) return 1;\n\t\t\treturn compareStrings(leftId, rightId);\n\t\t});\n\n\t\treturn {\n\t\t\t...service,\n\t\t\tsegments: Object.fromEntries(orderedEntries)\n\t\t};\n\t});\n\n\treturn applySegmentsOrderOverride(sortedByChains, orderOverrideIds);\n}\n","import { type CollectionItem } from \"@ryuzaki13/react-foundation-lib/odata\";\nimport { logError } from \"@ryuzaki13/react-foundation-lib/utils\";\n\nimport { odataFetch, type ODataFetchOptions } from \"./odataFetch\";\nimport { isNoContentResponse } from \"./transport\";\n\n// Тип для результата запроса справочника\ninterface ODataServiceResult<T extends CollectionItem> {\n\titems: T[];\n}\n\n/**\n * Загрузка данных справочника из OData сервиса\n */\nexport async function fetchCollectionData<T extends CollectionItem>(params: {\n\turl: string;\n\tquery?: ODataFetchOptions<T>;\n\tsignal: AbortSignal;\n}): Promise<ODataServiceResult<T>> {\n\tconst { url, query, signal } = params;\n\n\ttry {\n\t\t// Загружаем данные из OData сервиса\n\t\tconst response = await odataFetch<T, T[]>(url, query, { signal });\n\n\t\t// Считаем отсутствие данных ошибкой, ведь query запрос обязан вернуть корректное тело json\n\t\tif (isNoContentResponse(response)) {\n\t\t\tthrow new Error(\"отсутствует тело ответа\");\n\t\t}\n\n\t\tconst data = response.data;\n\n\t\t// Удаление ненужных полей.\n\n\t\treturn {\n\t\t\t// eslint-disable-next-line @typescript-eslint/naming-convention, @typescript-eslint/no-unused-vars\n\t\t\titems: data.map(({ ID, CNT, __metadata, __Parameters, ...item }) => item as T) /*, pairs, pairsMap */\n\t\t};\n\t} catch (error) {\n\t\tlogError(\"Ошибка загрузки справочника:\", error);\n\t\t// throw error;\n\n\t\treturn { items: [] };\n\t}\n}\n","import { parseDate } from \"@ryuzaki13/react-foundation-lib/formatters\";\nimport { persistedQueryMeta } from \"@ryuzaki13/react-foundation-lib/query-client\";\nimport { queryOptions, useQuery } from \"@tanstack/react-query\";\n\nimport { odataBaseQueryKey } from \"./odataBaseQueryKey\";\nimport { odataFetch } from \"./odataFetch\";\nimport { getODataProjectAdapter, resolveODataBaseUrl } from \"./odataProjectAdapter\";\n\nconst COLLECTION_UPDATES_BUILD_ID = __APP_BUILD_ID__;\nconst COLLECTION_UPDATES_STALE_TIME = 1000 * 60 * 60 * 4;\nexport const ODATA_COLLECTION_UPDATES_LOOKBACK_MS = 1000 * 60 * 60 * 24 * 7;\nexport const ODATA_COLLECTION_DEFAULT_SW_CACHE = \"ttl=forever;name=ref\";\nexport const ODATA_COLLECTION_BUST_SW_CACHE = \"bust=forever;name=ref\";\nexport const ODATA_COLLECTION_UPDATES_SW_CACHE = \"ttl=4h;name=ref-updates\";\n\ninterface ODataCollectionUpdateRecord {\n\tentityName: string;\n\tlastChanged: string;\n}\n\nexport interface ODataCollectionUpdateItem extends ODataCollectionUpdateRecord {\n\tlastChangedAt: Date | null;\n}\n\nexport interface ODataCollectionUpdatesResult {\n\titems: ODataCollectionUpdateItem[];\n\tbyEntityName: Record<string, ODataCollectionUpdateItem>;\n\tfetchedAt: number;\n\tcoverageStartedAt: number;\n}\n\nexport interface ODataCollectionUpdatesOptions {\n\tstaleTime?: number;\n}\n\nexport const createODataCollectionUpdatesQueryKey = () =>\n\t[...odataBaseQueryKey, \"collection-updates\", { buildId: COLLECTION_UPDATES_BUILD_ID }] as const;\n\nfunction normalizeCollectionUpdateRecord(record: ODataCollectionUpdateRecord): ODataCollectionUpdateItem {\n\treturn {\n\t\t...record,\n\t\tlastChangedAt: parseDate(record.lastChanged)\n\t};\n}\n\nfunction normalizeCollectionUpdates(records: ODataCollectionUpdateRecord[], fetchedAt: number): ODataCollectionUpdatesResult {\n\tconst items = records.map(normalizeCollectionUpdateRecord);\n\tconst byEntityName = items.reduce<Record<string, ODataCollectionUpdateItem>>((acc, item) => {\n\t\tif (item.entityName) {\n\t\t\tacc[item.entityName] = item;\n\t\t}\n\n\t\treturn acc;\n\t}, {});\n\n\treturn { items, byEntityName, fetchedAt, coverageStartedAt: fetchedAt - ODATA_COLLECTION_UPDATES_LOOKBACK_MS };\n}\n\n/**\n * Загружает компактный список справочников, изменённых за последние 7 дней.\n * Сам список живёт отдельно от данных справочников и управляет их точечной инвалидацией.\n */\nexport function fetchODataCollectionUpdates() {\n\treturn async ({ signal }: { signal: AbortSignal }): Promise<ODataCollectionUpdatesResult> => {\n\t\tconst requestStartedAt = Date.now();\n\t\tconst endpoint = getODataProjectAdapter().collectionUpdates;\n\t\tif (!endpoint) return normalizeCollectionUpdates([], requestStartedAt);\n\n\t\tconst response = await odataFetch<ODataCollectionUpdateRecord, ODataCollectionUpdateRecord[]>(\n\t\t\t`/${endpoint.service}/${endpoint.target}`,\n\t\t\t{\n\t\t\t\tbaseUrl: resolveODataBaseUrl(endpoint.service, endpoint.baseUrl),\n\t\t\t\tswCache: ODATA_COLLECTION_UPDATES_SW_CACHE\n\t\t\t},\n\t\t\t{ signal }\n\t\t);\n\n\t\treturn normalizeCollectionUpdates(response.data, Math.max(requestStartedAt, Date.now()));\n\t};\n}\n\n/**\n * Описывает общий TanStack Query со списком обновлённых справочников.\n * Query сохраняется в IndexedDB и дополнительно кешируется Service Worker на короткий TTL.\n */\nexport const odataCollectionUpdatesQueryOptions = (options: ODataCollectionUpdatesOptions = {}) =>\n\tqueryOptions({\n\t\tqueryKey: createODataCollectionUpdatesQueryKey(),\n\t\tqueryFn: fetchODataCollectionUpdates(),\n\t\tmeta: persistedQueryMeta,\n\t\tenabled: Boolean(getODataProjectAdapter().collectionUpdates),\n\t\tstaleTime: options.staleTime ?? COLLECTION_UPDATES_STALE_TIME,\n\t\tgcTime: Infinity\n\t});\n\nexport function useODataCollectionUpdatesQuery(options: ODataCollectionUpdatesOptions = {}) {\n\treturn useQuery(odataCollectionUpdatesQueryOptions(options));\n}\n","import { useODataMetadataQuery } from \"./useODataMetadataQuery\";\n\nimport type { ODataServiceConfig } from \"@ryuzaki13/react-foundation-lib/odata-service\";\n\n/**\n * Возвращает metadata конкретной OData-сущности по имени сервиса и сущности.\n *\n * Хук не добавляет собственную бизнес-логику и служит публичной тонкой\n * прослойкой над `useODataMetadataQuery(...)`.\n */\nexport function useODataMetadata(odata: ODataServiceConfig) {\n\tconst { data, dataUpdatedAt = 0, isLoading, isError } = useODataMetadataQuery({ service: odata.service });\n\tconst metadata = data?.entities[odata.target];\n\n\tif (!isLoading && !metadata && data?.functionImports[odata.target]) {\n\t\tthrow new Error(`OData target '${odata.target}' является FunctionImport и не может использоваться как сущность`);\n\t}\n\n\tif (isError) {\n\t\tthrow new Error(`Ошибка загрузки метаданных сервиса ${odata.service}`);\n\t}\n\n\treturn { metadata, metadataUpdatedAt: dataUpdatedAt, isLoading };\n}\n","import { useMemo } from \"react\";\n\nimport { buildEntityPath, type ODataServiceConfig, type ODataValue } from \"@ryuzaki13/react-foundation-lib/odata-service\";\n\nimport { useODataMetadata } from \"./useODataMetadata\";\n\nimport type { CollectionPair } from \"@ryuzaki13/react-foundation-lib/odata\";\n\nconst throwErrorText = \"Использование actions недопустимо до окончания загрузки metadata\";\n\n// function throwNoMetadata() {\n// \tif (__DEV__) {\n// \t\tthrow new Error(throwErrorText);\n// \t}\n// \treturn undefined;\n// }\n\nexport type ODataEntity = Omit<ReturnType<typeof useODataEntity>, \"isLoading\">;\n\nexport function useODataEntity(odata: ODataServiceConfig) {\n\tconst { metadata, metadataUpdatedAt, isLoading } = useODataMetadata(odata);\n\n\tconst actions = useMemo(() => {\n\t\tconst getEntityPath = (values: Record<string, ODataValue> = {}) => {\n\t\t\tif (!metadata) throw new Error(throwErrorText);\n\t\t\treturn buildEntityPath(metadata, odata, values);\n\t\t};\n\t\tconst getKeys = () => {\n\t\t\tif (!metadata) throw new Error(throwErrorText);\n\t\t\treturn metadata.columns?.map((c) => c.id);\n\t\t};\n\t\tconst getKeyPairs = () => {\n\t\t\tif (!metadata) throw new Error(throwErrorText);\n\t\t\treturn metadata.columns\n\t\t\t\t?.filter((c) => c.semanticType === \"code\" && c.linkedColumnId)\n\t\t\t\t.map((c) => ({ codeKey: c.id, textKey: c.linkedColumnId }) as CollectionPair);\n\t\t};\n\t\tconst getKeyPairsMap = () => {\n\t\t\tif (!metadata) throw new Error(throwErrorText);\n\t\t\tconst pairs: Record<string, string> = {};\n\n\t\t\tfor (const column of metadata.columns ?? []) {\n\t\t\t\tif (column.semanticType === \"code\" && column.linkedColumnId) {\n\t\t\t\t\tpairs[column.id] = column.linkedColumnId;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn pairs;\n\t\t};\n\n\t\treturn {\n\t\t\t/**\n\t\t\t * Получить строку запроса `/service/entity(parameters)/Results`\n\t\t\t */\n\t\t\tgetEntityPath,\n\t\t\t/**\n\t\t\t * Получить все ключи сущности\n\t\t\t */\n\t\t\tgetKeys,\n\t\t\t/**\n\t\t\t * Получить список ключей в формате `{ codeKey, textKey }`\n\t\t\t */\n\t\t\tgetKeyPairs,\n\t\t\t/**\n\t\t\t * Получить словать ключей в формате `{ code: text }`\n\t\t\t */\n\t\t\tgetKeyPairsMap\n\t\t};\n\t}, [odata, metadata]);\n\n\treturn { config: odata, metadata, metadataUpdatedAt, isLoading, actions };\n}\n","import { useEffect, useMemo } from \"react\";\n\nimport { buildSeparatedArrays, type CollectionItem, type CollectionPair } from \"@ryuzaki13/react-foundation-lib/odata\";\nimport { persistedQueryMeta } from \"@ryuzaki13/react-foundation-lib/query-client\";\nimport { useQuery, useQueryClient, UseQueryResult } from \"@tanstack/react-query\";\n\nimport { createODataCollectionQueryKey } from \"./createODataCollectionQueryKey\";\nimport { fetchCollectionData } from \"./fetchCollectionData\";\nimport { ODataCollectionConfig } from \"./types\";\nimport {\n\tODATA_COLLECTION_BUST_SW_CACHE,\n\tODATA_COLLECTION_DEFAULT_SW_CACHE,\n\tODataCollectionUpdateItem,\n\tuseODataCollectionUpdatesQuery\n} from \"./useODataCollectionUpdatesQuery\";\nimport { useODataEntity } from \"./useODataEntity\";\n\nexport interface ODataCollectionResult<T extends CollectionItem> {\n\titems: T[];\n\tkeyPairs: CollectionPair[];\n\tkeyPairsMap: Record<string, string>;\n\tseparated: Record<string, T[]>;\n\tchain: { codeKey: string; count: number }[];\n\tcount: number;\n\tcacheUpdatedAt: number;\n}\n\ninterface ODataCollectionCacheRefreshContext {\n\tupdate?: ODataCollectionUpdateItem;\n\tmetadataUpdatedAt?: number;\n\tupdatesCoverageStartedAt?: number;\n}\n\nexport function resolveODataCollectionSwCachePolicy(swCache: string, shouldBust: boolean) {\n\tif (!shouldBust) return swCache;\n\n\tconst normalized = swCache.trim().toLowerCase();\n\tif (normalized === \"off\" || normalized.startsWith(\"bust=\")) return swCache;\n\tif (normalized.startsWith(\"ttl=\")) return swCache.replace(/^\\s*ttl=/i, \"bust=\");\n\n\treturn ODATA_COLLECTION_BUST_SW_CACHE;\n}\n\nfunction isUsableTimestamp(value: number | undefined): value is number {\n\treturn typeof value === \"number\" && Number.isFinite(value) && value > 0;\n}\n\n/**\n * Определяет, нужно ли обновить конкретный справочник по списку изменений.\n * Сравнение идёт с cacheUpdatedAt, который сохраняется вместе с данными справочника.\n */\nexport function shouldRefreshODataCollectionCache<T extends CollectionItem>(\n\tcontext: ODataCollectionCacheRefreshContext,\n\tcachedData: ODataCollectionResult<T> | undefined\n) {\n\tconst cacheUpdatedAt = cachedData?.cacheUpdatedAt ?? 0;\n\tconst updateChangedAt = context.update?.lastChangedAt?.getTime();\n\n\tif (isUsableTimestamp(updateChangedAt)) {\n\t\tif (!cachedData || !cacheUpdatedAt) return true;\n\t\tif (updateChangedAt > cacheUpdatedAt) return true;\n\t}\n\n\tif (isUsableTimestamp(context.metadataUpdatedAt)) {\n\t\tif (!cachedData || !cacheUpdatedAt) return true;\n\t\tif (context.metadataUpdatedAt > cacheUpdatedAt) return true;\n\t}\n\n\t/**\n\t * Бэкенд отдаёт список изменений справочников только за последнюю неделю.\n\t * Если локальный справочник старше этого окна, отсутствие target в списке\n\t * больше не доказывает актуальность, поэтому обновляем только открытый справочник.\n\t */\n\tif (isUsableTimestamp(context.updatesCoverageStartedAt)) {\n\t\tif (!cachedData || !cacheUpdatedAt) return true;\n\t\tif (cacheUpdatedAt < context.updatesCoverageStartedAt) return true;\n\t}\n\n\treturn false;\n}\n\n/**\n * Универсальный хук для получения данных из OData сервиса.\n * Заменяет функционал TextDataService из SAP UI5.\n */\nexport function useODataCollectionQuery<T extends CollectionItem>(odata: ODataCollectionConfig): UseQueryResult<ODataCollectionResult<T>> {\n\tconst {\n\t\tservice,\n\t\ttarget,\n\t\tlimitedKeys,\n\t\texcludeEmpty,\n\t\tsortByCode,\n\t\tserverFilter,\n\t\tclientFilter,\n\t\tswCache = ODATA_COLLECTION_DEFAULT_SW_CACHE\n\t} = odata;\n\tconst queryClient = useQueryClient();\n\tconst { actions, metadata, metadataUpdatedAt, isLoading } = useODataEntity(odata);\n\tconst updatesQuery = useODataCollectionUpdatesQuery();\n\n\tconst queryKey = useMemo(\n\t\t() => createODataCollectionQueryKey({ service, target, limitedKeys, serverFilter }),\n\t\t[service, target, limitedKeys, serverFilter]\n\t);\n\tconst cachedData = queryClient.getQueryData<ODataCollectionResult<T>>(queryKey);\n\tconst collectionUpdate = updatesQuery.data?.byEntityName[target];\n\tconst shouldBustCollectionCache = shouldRefreshODataCollectionCache(\n\t\t{\n\t\t\tupdate: collectionUpdate,\n\t\t\tmetadataUpdatedAt,\n\t\t\tupdatesCoverageStartedAt: updatesQuery.data?.coverageStartedAt\n\t\t},\n\t\tcachedData\n\t);\n\tconst effectiveSwCache = resolveODataCollectionSwCachePolicy(swCache, shouldBustCollectionCache);\n\tconst updatesReady = updatesQuery.isError || (updatesQuery.isSuccess && !updatesQuery.isFetching);\n\n\tuseEffect(() => {\n\t\tif (!cachedData || !shouldBustCollectionCache) return;\n\n\t\tvoid queryClient.invalidateQueries({ queryKey });\n\t}, [cachedData, queryClient, queryKey, shouldBustCollectionCache]);\n\n\treturn useQuery({\n\t\tqueryKey,\n\t\tqueryFn: async ({ signal }) => {\n\t\t\tconst requestStartedAt = Date.now();\n\t\t\tconst selectKeys = limitedKeys ? [...limitedKeys] : actions.getKeys();\n\t\t\tconst keyPairs = actions.getKeyPairs();\n\t\t\tconst keyPairsMap = actions.getKeyPairsMap();\n\n\t\t\tif (limitedKeys) {\n\t\t\t\tfor (const k of limitedKeys) {\n\t\t\t\t\tconst keyText = keyPairsMap[k];\n\t\t\t\t\tif (keyText && !selectKeys.includes(keyText)) {\n\t\t\t\t\t\tselectKeys.push(keyText);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tconst { items } = await fetchCollectionData<T>({\n\t\t\t\turl: `/${service}/${target}`,\n\t\t\t\tquery: {\n\t\t\t\t\tselect: selectKeys,\n\t\t\t\t\texpression: serverFilter,\n\t\t\t\t\tswCache: effectiveSwCache\n\t\t\t\t},\n\t\t\t\tsignal\n\t\t\t});\n\n\t\t\tlet filterdItems = items;\n\t\t\tif (clientFilter) {\n\t\t\t\tfilterdItems = items.filter(clientFilter);\n\t\t\t}\n\n\t\t\tconst separated = buildSeparatedArrays<T>(filterdItems, keyPairs, excludeEmpty, sortByCode);\n\n\t\t\t// Рассчитать порядок от меньшего к большему\n\t\t\tconst chain = keyPairs\n\t\t\t\t.map((pair) => ({ codeKey: pair.codeKey, count: separated[pair.codeKey].length }))\n\t\t\t\t.sort((a, b) => a.count - b.count);\n\n\t\t\treturn {\n\t\t\t\titems: filterdItems,\n\t\t\t\tkeyPairs,\n\t\t\t\tkeyPairsMap,\n\t\t\t\tseparated,\n\t\t\t\tchain,\n\t\t\t\tcount: filterdItems.length,\n\t\t\t\tcacheUpdatedAt: Math.max(requestStartedAt, Date.now(), collectionUpdate?.lastChangedAt?.getTime() ?? 0, metadataUpdatedAt)\n\t\t\t};\n\t\t},\n\t\tenabled: Boolean(!isLoading && metadata && service && target && updatesReady),\n\t\tmeta: persistedQueryMeta,\n\t\t/**\n\t\t * Клиентский кеш можно держать не долго, чтобы он мог чаще дергать SW\n\t\t */\n\t\tstaleTime: 1000 * 60 * 60 * 2,\n\t\t/**\n\t\t * Если справочник не используется более часа, то можно из памяти выгрузить.\n\t\t */\n\t\tgcTime: 1000 * 60 * 60 * 1\n\t});\n}\n","import { useCallback, useMemo, useRef, useState } from \"react\";\n\nimport { useQueryClient } from \"@tanstack/react-query\";\n\nimport { createODataCollectionQueryKey } from \"./createODataCollectionQueryKey\";\nimport { ODataCollectionConfig, ODataCollectionModel } from \"./types\";\nimport { useODataCollectionQuery } from \"./useODataCollectionQuery\";\n\nimport type { CollectionItem } from \"@ryuzaki13/react-foundation-lib/odata\";\n\ninterface UseODataCollectionProps {\n\todata: ODataCollectionConfig;\n\tmodel: Required<ODataCollectionModel>;\n\n\t/**\n\t * Размер страницы для виртуализации.\n\t */\n\tpageSize?: number;\n\n\tfilter?: (item: CollectionItem) => boolean;\n}\n\nexport function useODataCollection({\n\todata,\n\tmodel,\n\t// filter,\n\tpageSize = 50\n}: UseODataCollectionProps) {\n\tconst { codeKey, maxVisibleItems } = model;\n\tconst { data: rawData, isLoading, isError, refetch } = useODataCollectionQuery(odata);\n\n\tconst textKey = rawData?.keyPairsMap[codeKey] ?? \"\";\n\n\t// Клиент для инвалидации запросов\n\tconst queryClient = useQueryClient();\n\n\tconst [filteredKeys, setFilteredKeys] = useState<Set<string>>();\n\n\tconst debounceTimers = useRef<Map<string, ReturnType<typeof setTimeout>>>(new Map());\n\n\t/**\n\t * itemsMap - индекс элементов для быстрого поиска\n\t * orderedKeys - упорядоченный список ключей для сохранения порядка\n\t */\n\tconst { itemsMap, separatedItems, orderedKeys } = useMemo(() => {\n\t\tconst itemsMap = new Map<string, CollectionItem>();\n\t\tconst orderedKeys = [] as string[];\n\t\tlet separatedItems: CollectionItem[] = [];\n\n\t\tif (rawData && rawData.separated[codeKey]) {\n\t\t\tseparatedItems = rawData.separated[codeKey];\n\n\t\t\tfor (const item of separatedItems) {\n\t\t\t\tconst key = item[codeKey];\n\t\t\t\tif (key) {\n\t\t\t\t\titemsMap.set(key, item);\n\t\t\t\t\torderedKeys.push(key);\n\t\t\t\t}\n\t\t\t}\n\t\t}\n\n\t\treturn { itemsMap, separatedItems, orderedKeys };\n\t}, [rawData, codeKey]);\n\n\t// Создание индекса поиска для текстовых полей\n\tconst buildSearchIndex = useCallback(\n\t\t(field: string) => {\n\t\t\tconst items = rawData?.separated[codeKey];\n\n\t\t\tif (!items) {\n\t\t\t\treturn new Map<string, Set<string>>();\n\t\t\t}\n\n\t\t\tconst index = new Map<string, Set<string>>();\n\n\t\t\t// Создаем индекс по префиксам для быстрого поиска\n\t\t\tfor (const item of items) {\n\t\t\t\tconst value = item[field]?.toLowerCase();\n\t\t\t\tif (!value) continue;\n\n\t\t\t\t// Индексируем по префиксам длиной 1-5 символов\n\t\t\t\tfor (let i = 1; i <= Math.min(5, value.length); i++) {\n\t\t\t\t\tconst prefix = value.substring(0, i);\n\t\t\t\t\tif (!index.has(prefix)) {\n\t\t\t\t\t\tindex.set(prefix, new Set<string>());\n\t\t\t\t\t}\n\t\t\t\t\tindex.get(prefix)!.add(item[codeKey]);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\treturn index;\n\t\t},\n\t\t[rawData, codeKey]\n\t);\n\n\t/**\n\t * Устанавливает несколько фильтров зависимостей.\n\t *\n\t * Сформированный список ключей пойдёт в фильтрацию элементов текущей коллекции по `codeKey`\n\t */\n\tconst setFilteredItems = useCallback(\n\t\t(filters: CollectionItem[] | undefined) => {\n\t\t\tsetFilteredKeys(() => {\n\t\t\t\tif (filters?.length) {\n\t\t\t\t\treturn new Set(filters.map((item) => item[codeKey]));\n\t\t\t\t}\n\n\t\t\t\treturn undefined;\n\t\t\t});\n\t\t},\n\t\t[codeKey]\n\t);\n\n\tconst getItems = useCallback(\n\t\t(\n\t\t\tpredicate?: (codeValue: string, textValue: string) => boolean,\n\t\t\tcurrentSelectedKeys?: readonly CollectionItem[]\n\t\t): CollectionItem[] => {\n\t\t\tif (!orderedKeys.length) return [];\n\n\t\t\tconst limit = maxVisibleItems;\n\t\t\tconst selectedKeysSet = new Set<string>();\n\t\t\tconst resultItems: CollectionItem[] = [];\n\n\t\t\tif (currentSelectedKeys?.length) {\n\t\t\t\t// Быстрое заполнение Set без создания временного массива\n\t\t\t\tfor (let i = 0; i < currentSelectedKeys.length; i++) {\n\t\t\t\t\tselectedKeysSet.add(currentSelectedKeys[i][codeKey]);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tlet count = 0;\n\n\t\t\tconst existsDependencies = filteredKeys && filteredKeys.size > 0;\n\n\t\t\t// Единый проход с ранним выходом по лимиту\n\t\t\tfor (const key of orderedKeys) {\n\t\t\t\tif (count >= limit) break;\n\n\t\t\t\tconst item = itemsMap.get(key);\n\t\t\t\tif (!item) continue;\n\n\t\t\t\t// Проверка на исключение выбранных ключей\n\t\t\t\tif (selectedKeysSet.size > 0 && selectedKeysSet.has(key)) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\n\t\t\t\tconst itemCode = item[codeKey];\n\n\t\t\t\tif (existsDependencies && !filteredKeys.has(itemCode)) continue;\n\n\t\t\t\t// Проверка внешнего предиката\n\t\t\t\tif (predicate && !predicate(itemCode, item[textKey])) continue;\n\n\t\t\t\tresultItems.push(item);\n\t\t\t\tcount++;\n\t\t\t}\n\n\t\t\treturn resultItems;\n\t\t},\n\t\t[orderedKeys, maxVisibleItems, codeKey, itemsMap, filteredKeys, textKey]\n\t);\n\n\t/**\n\t * Получает страницу данных для виртуализации.\n\t */\n\tconst getPage = useCallback(\n\t\t(pageIndex: number): CollectionItem[] => {\n\t\t\tconst allItems = rawData?.separated[codeKey] || [];\n\t\t\tconst start = pageIndex * pageSize;\n\t\t\tconst end = start + pageSize;\n\t\t\treturn allItems.slice(start, end);\n\t\t},\n\t\t[rawData, pageSize, codeKey]\n\t);\n\n\t/**\n\t * Находит несколько элементов по ключам.\n\t */\n\tconst findSourceItemsByKeys = useCallback(\n\t\t(key: string, keys: string[]) => {\n\t\t\tif (!rawData) return [];\n\n\t\t\tconst keysSet = new Set<string>(keys);\n\t\t\treturn rawData.items.filter((item) => keysSet.has(item[key]));\n\t\t},\n\t\t[rawData]\n\t);\n\n\t/**\n\t * Дебаунсинг для частых операций.\n\t */\n\tconst debounce = useCallback((key: string, fn: () => void, delay: number = 200) => {\n\t\t// Очищаем предыдущий таймер\n\t\tif (debounceTimers.current.has(key)) {\n\t\t\tclearTimeout(debounceTimers.current.get(key)!);\n\t\t}\n\n\t\t// Устанавливаем новый таймер\n\t\tconst timer = setTimeout(fn, delay);\n\t\tdebounceTimers.current.set(key, timer);\n\t}, []);\n\n\t/**\n\t * Очищает все дебаунс таймеры.\n\t */\n\tconst clearDebounceTimers = useCallback(() => {\n\t\tfor (const timer of debounceTimers.current.values()) {\n\t\t\tclearTimeout(timer);\n\t\t}\n\t\tdebounceTimers.current.clear();\n\t}, []);\n\n\t// Очистка таймеров при размонтировании\n\tuseMemo(() => {\n\t\treturn () => {\n\t\t\tclearDebounceTimers();\n\t\t};\n\t}, [clearDebounceTimers]);\n\n\treturn {\n\t\t// Состояние данных\n\t\tdata: rawData,\n\t\tisLoading,\n\t\tisError,\n\n\t\tcodeKey,\n\t\ttextKey,\n\n\t\t// Функции для работы с коллекцией\n\t\tgetItems,\n\t\tfindSourceItemsByKeys,\n\t\tsetFilteredItems,\n\t\tgetPage,\n\t\tbuildSearchIndex,\n\t\tdebounce,\n\n\t\t// Вспомогательные данные\n\t\titemsMap,\n\t\tseparatedItems,\n\t\torderedKeys,\n\n\t\t// Управление запросом\n\n\t\t/**\n\t\t * @deprecated нужен только на этапе проектирования, скоро будет удален\n\t\t */\n\t\trefetch,\n\t\t/**\n\t\t * @deprecated нужен только на этапе проектирования, скоро будет удален\n\t\t */\n\t\tinvalidate: () => queryClient.invalidateQueries({ queryKey: createODataCollectionQueryKey(odata) }),\n\n\t\t// Метаданные для виртуализации\n\t\ttotalCount: rawData?.separated[codeKey]?.length || 0,\n\t\tpageSize\n\t};\n}\n","import { useEffect, useMemo, useState } from \"react\";\n\nimport { Query, useQueryClient } from \"@tanstack/react-query\";\n\nimport { createODataCollectionQueryKey } from \"./createODataCollectionQueryKey\";\nimport { ODataServiceCollectionConfig } from \"./types\";\n\nimport type { ODataChainsMap } from \"@ryuzaki13/react-foundation-lib/odata-service\";\n\n/**\n * Используется для получения последовательностей кодов.\n */\nexport function useODataCollectionChains(params: ODataServiceCollectionConfig[]) {\n\tconst queryClient = useQueryClient();\n\tconst [chains, setChains] = useState<ODataChainsMap>({});\n\n\tconst trackedKeys = useMemo(() => params.map((p) => createODataCollectionQueryKey(p)), [params]);\n\n\tuseEffect(() => {\n\t\tfunction updateChains() {\n\t\t\tconst newChains: ODataChainsMap = {};\n\n\t\t\tfor (const p of params) {\n\t\t\t\tconst key = createODataCollectionQueryKey(p);\n\t\t\t\tconst cached = queryClient.getQueryData<{ chain: { codeKey: string; count: number }[] }>(key);\n\t\t\t\tif (cached?.chain) {\n\t\t\t\t\tnewChains[`${p.service}.${p.target}`] = cached.chain;\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tsetChains((prev) => {\n\t\t\t\t// не обновлять стейт, если данные не изменились (во избежание лишних рендеров)\n\t\t\t\tconst same =\n\t\t\t\t\tObject.keys(prev).length === Object.keys(newChains).length &&\n\t\t\t\t\tObject.entries(newChains).every(([k, v]) => prev[k] === v);\n\t\t\t\treturn same ? prev : newChains;\n\t\t\t});\n\t\t}\n\n\t\t// Первичная загрузка (на случай, если данные уже в кэше)\n\t\tupdateChains();\n\n\t\t// Подписка на изменения кэша\n\t\tconst unsubscribe = queryClient.getQueryCache().subscribe((event) => {\n\t\t\t// Проверяем, затрагивает ли событие один из наших trackedKeys\n\t\t\tif (event?.query) {\n\t\t\t\tconst query = event.query as Query;\n\t\t\t\tconst isTracked = trackedKeys.some((key) => JSON.stringify(key) === JSON.stringify(query.queryKey));\n\t\t\t\tif (isTracked) {\n\t\t\t\t\tupdateChains();\n\t\t\t\t}\n\t\t\t}\n\t\t});\n\n\t\treturn unsubscribe;\n\t}, [params, queryClient, trackedKeys]);\n\n\treturn chains;\n}\n","import { useState } from \"react\";\n\nimport { useODataCollectionStore } from \"@ryuzaki13/react-foundation-lib/odata\";\n\nimport { ODataCollectionModel } from \"./types\";\n\nexport function useODataCollectionModel(model: ODataCollectionModel): Required<ODataCollectionModel> {\n\t// NOTE: без подписки, потому что эти данные в рантайме не предполагается изменять в ближайшее время.\n\n\t// const defaultMaxVisibleItems = odataCollectionConfig.useMaxVisibleItems();\n\t// const defaultMinSearchCodeLength = odataCollectionConfig.useMinSearchCodeLength();\n\t// const defaultMinSearchTextLength = odataCollectionConfig.useMinSearchTextLength();\n\t// const defaultSearchDebounceDelay = odataCollectionConfig.useSearchDebounce();\n\n\tconst [stableModel] = useState(() => {\n\t\tconst defaultState = useODataCollectionStore.getState();\n\n\t\tconst {\n\t\t\tcodeKey,\n\t\t\tmaxVisibleItems = defaultState.defaultMaxVisibleItems,\n\t\t\tminSearchCodeLength = defaultState.defaultMinSearchCodeLength,\n\t\t\tminSearchTextLength = defaultState.defaultMinSearchTextLength,\n\t\t\tsearchDebounceDelay = defaultState.defaultSearchDebounceDelay\n\t\t} = model;\n\t\treturn {\n\t\t\tcodeKey,\n\t\t\tmaxVisibleItems,\n\t\t\tminSearchCodeLength,\n\t\t\tminSearchTextLength,\n\t\t\tsearchDebounceDelay\n\t\t};\n\t});\n\n\treturn stableModel;\n}\n","import { useMemo } from \"react\";\n\nimport {\n\ttype TableColumnDef,\n\ttype TableColumnFormattingMetaInput,\n\tcreateTableColumnVisibilityFromODataMetadata,\n\tcreateTableColumnsFromODataMetadata,\n\tenrichTableColumnsWithODataFormatting,\n\tresolveStableColumnId\n} from \"@ryuzaki13/react-foundation-lib/table\";\n\nimport { useODataMetadata } from \"./useODataMetadata\";\n\nimport type { EntityColumnProperty, EntityMetadata, ODataServiceConfig } from \"@ryuzaki13/react-foundation-lib/odata-service\";\n\n/**\n * Собирает visibility-state только для тех leaf-колонок, которые сопоставились с metadata.\n */\nfunction collectMatchedColumnVisibility<TData extends object>(\n\tcolumns: readonly TableColumnDef<TData>[],\n\tvisibilityById: Readonly<Record<string, boolean>>\n): Record<string, boolean> {\n\tconst matchedVisibility: Record<string, boolean> = {};\n\n\tconst visitLeafColumns = (nestedColumns: readonly TableColumnDef<TData>[]) => {\n\t\tfor (const column of nestedColumns) {\n\t\t\tif (\"columns\" in column && Array.isArray(column.columns) && column.columns.length > 0) {\n\t\t\t\tvisitLeafColumns(column.columns as TableColumnDef<TData>[]);\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst columnId = resolveStableColumnId(column);\n\t\t\tif (!columnId || !(columnId in visibilityById)) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tmatchedVisibility[columnId] = visibilityById[columnId];\n\t\t}\n\t};\n\n\tvisitLeafColumns(columns);\n\n\treturn matchedVisibility;\n}\n\n/**\n * Конфиг hook-адаптера колонок в режиме `build`.\n */\nexport interface UseODataTableColumnsBuildConfig extends Pick<ODataServiceConfig, \"service\" | \"target\"> {\n\t/**\n\t * Режим генерации колонок только по metadata.\n\t */\n\tmode: \"build\";\n\t/**\n\t * Позволяет определить видимость колонки при генерации.\n\t */\n\tresolveVisible?: (column: EntityColumnProperty) => boolean;\n\t/**\n\t * Позволяет переопределить заголовок колонки при генерации.\n\t */\n\tresolveHeader?: (column: EntityColumnProperty) => string;\n\t/**\n\t * Позволяет сразу навесить formatting-конфиг на generated column.\n\t */\n\tresolveFormatting?: (column: EntityColumnProperty) => TableColumnFormattingMetaInput | undefined;\n}\n\n/**\n * Конфиг hook-адаптера колонок в режиме `enrich`.\n */\nexport interface UseODataTableColumnsEnrichConfig<TData extends object> extends Pick<ODataServiceConfig, \"service\" | \"target\"> {\n\t/**\n\t * Режим обогащения уже существующих колонок.\n\t */\n\tmode: \"enrich\";\n\t/**\n\t * Существующий набор колонок для дозаполнения `meta.formatting.role/type`.\n\t */\n\tcolumns: readonly TableColumnDef<TData>[];\n}\n\n/**\n * Универсальный конфиг hook-адаптера колонок.\n */\nexport type UseODataTableColumnsConfig<TData extends object = Record<string, unknown>> =\n\tUseODataTableColumnsBuildConfig | UseODataTableColumnsEnrichConfig<TData>;\n\n/**\n * Результат работы hook-адаптера колонок.\n */\nexport interface UseODataTableColumnsResult<TData extends object> {\n\t/**\n\t * Итоговый набор колонок для `Table` или `TreeTable`.\n\t */\n\tcolumns: TableColumnDef<TData>[];\n\t/**\n\t * Стартовая карта видимости колонок для TanStack Table.\n\t */\n\tdefaultColumnVisibility: Record<string, boolean> | undefined;\n\t/**\n\t * Метаданные сущности, если они уже загружены.\n\t */\n\tmetadata: EntityMetadata | undefined;\n\t/**\n\t * Признак загрузки metadata.\n\t */\n\tisLoading: boolean;\n}\n\n/**\n * Возвращает колонки для `Table`/`TreeTable` на основе OData metadata.\n *\n * В режиме `build` генерирует базовый набор колонок из `metadata.columns`.\n * В режиме `enrich` дозаполняет уже существующие колонки typed-formatting контекстом.\n */\nexport function useODataTableColumns<TData extends object = Record<string, unknown>>(\n\tconfig: UseODataTableColumnsConfig<TData>\n): UseODataTableColumnsResult<TData> {\n\tconst { metadata, isLoading } = useODataMetadata(config);\n\n\tconst columns = useMemo(() => {\n\t\tif (!metadata) {\n\t\t\treturn config.mode === \"build\" ? [] : [...config.columns];\n\t\t}\n\n\t\tif (config.mode === \"build\") {\n\t\t\treturn createTableColumnsFromODataMetadata<TData>(metadata.columns, {\n\t\t\t\tresolveHeader: config.resolveHeader,\n\t\t\t\tresolveFormatting: config.resolveFormatting\n\t\t\t});\n\t\t}\n\n\t\treturn enrichTableColumnsWithODataFormatting(config.columns, metadata.columns);\n\t}, [config, metadata]);\n\n\tconst defaultColumnVisibility = useMemo(() => {\n\t\tif (!metadata) {\n\t\t\treturn undefined;\n\t\t}\n\n\t\tif (config.mode === \"build\") {\n\t\t\treturn createTableColumnVisibilityFromODataMetadata(metadata.columns, {\n\t\t\t\tresolveVisible: config.resolveVisible\n\t\t\t});\n\t\t}\n\n\t\tconst visibilityById = createTableColumnVisibilityFromODataMetadata(metadata.columns);\n\n\t\treturn collectMatchedColumnVisibility(config.columns, visibilityById);\n\t}, [config, metadata]);\n\n\treturn {\n\t\tcolumns,\n\t\tdefaultColumnVisibility,\n\t\tmetadata,\n\t\tisLoading\n\t};\n}\n","import { useODataCollectionQuery } from \"./useODataCollectionQuery\";\n\nimport type { CollectionItem } from \"@ryuzaki13/react-foundation-lib/odata\";\n\nexport function useTextServiceQuery<T extends CollectionItem>(target: string) {\n\treturn useODataCollectionQuery<T>({ service: \"TEXT_DICTIONARY_SRV\", target });\n}\n","import { notify } from \"@ryuzaki13/react-foundation-lib/notifications\";\nimport { QueryClient } from \"@tanstack/react-query\";\n\nimport { buildODataFetchRequest, ODataFetchRequestPreview } from \"./odataFetch\";\nimport {\n\tODataArrayOperationMethod,\n\tODataCreateFnOptions,\n\tODataDeleteFnOptions,\n\todataFetchFn,\n\tODataFetchFnImplementationArgs,\n\tODataFetchFnRequest,\n\tODataFetchFnRunner,\n\tODataFetchFnSharedOptions,\n\tODataFunctionImportFnOptions,\n\tODataQueryArrayTransform,\n\tODataQueryFnOptions,\n\tODataQuerySingleTransform,\n\tODataReadFnOptions,\n\tODataSingleFetchFnRequest,\n\tODataSingleOperationMethod,\n\tODataSingleTransform,\n\tODataUpdateFnOptions\n} from \"./odataFetchFn\";\nimport {\n\tbuildTargetPath,\n\tisFunctionImportMetadata,\n\tresolveODataTarget,\n\tresolveRequestBody,\n\tresolveRequestMethod,\n\tvalidateODataOperation\n} from \"./odataFetchFnHelpers\";\nimport { resolveODataBaseUrl } from \"./transport\";\nimport { getODataMetadataData } from \"./useODataMetadataQuery\";\n\nimport type {\n\tODataOperationMethod,\n\tODataServiceConfig,\n\tODataTargetMetadata,\n\tUnwrappedODataParameters,\n\tWrappedODataParameters\n} from \"@ryuzaki13/react-foundation-lib/odata-service\";\n\ntype ODataDevHelperName =\n\t| \"odataFetchFnDev\"\n\t| \"odataCreateFnDev\"\n\t| \"odataUpdateFnDev\"\n\t| \"odataDeleteFnDev\"\n\t| \"odataReadFnDev\"\n\t| \"odataQueryFnDev\"\n\t| \"odataFunctionImportFnDev\";\n\ntype ODataFetchFnDevOptions<I> = ODataFetchFnSharedOptions<I> & {\n\tparams?: WrappedODataParameters;\n\tbody?: unknown;\n\ttransform?: unknown;\n};\n\ntype ODataDevRequestLogInfo = {\n\thelperName: ODataDevHelperName;\n\toperation: ODataOperationMethod;\n\todata: ODataServiceConfig;\n\ttarget: ODataTargetMetadata;\n\ttargetPath: string;\n\trequest: ODataFetchRequestPreview;\n\trequestMethod: string;\n\tparams: WrappedODataParameters;\n\tqueryOptions: unknown;\n\tbody: string | undefined;\n\tautoParse: boolean | undefined;\n\thasTransform: boolean;\n};\n\nfunction getConsole() {\n\treturn globalThis.console;\n}\n\nfunction headersToRecord(headers: HeadersInit | undefined) {\n\tconst result: Record<string, string> = {};\n\tnew Headers(headers).forEach((value, key) => {\n\t\tresult[key] = value;\n\t});\n\n\treturn result;\n}\n\nfunction parseRequestBodyForLog(body: BodyInit | null | undefined): unknown {\n\tif (body === undefined || body === null) return undefined;\n\tif (typeof body !== \"string\") return body;\n\n\ttry {\n\t\tconst parsed: unknown = JSON.parse(body);\n\t\treturn parsed;\n\t} catch {\n\t\treturn body;\n\t}\n}\n\nfunction isWriteRequest(method: string | undefined) {\n\treturn method !== undefined && ![\"GET\", \"HEAD\"].includes(method.toUpperCase());\n}\n\nfunction isSapRequestPreview(request: ODataFetchRequestPreview) {\n\tconst baseUrl = request.baseUrl ?? \"odata\";\n\tif (baseUrl !== \"\") return true;\n\n\treturn request.path.startsWith(\"/sap/\") || request.path.startsWith(\"/sap-dp0/\");\n}\n\nfunction hasHeader(headers: Record<string, string>, name: string) {\n\tconst normalizedName = name.toLowerCase();\n\treturn Object.keys(headers).some((key) => key.toLowerCase() === normalizedName);\n}\n\nfunction setDefaultHeader(headers: Record<string, string>, name: string, value: string) {\n\tif (hasHeader(headers, name)) return;\n\theaders[name] = value;\n}\n\nfunction buildTransportHeadersPreview(request: ODataFetchRequestPreview) {\n\tconst headers = headersToRecord(request.init.headers);\n\tconst method = request.init.method;\n\tconst sapRequest = isSapRequestPreview(request);\n\n\tsetDefaultHeader(headers, \"DataServiceVersion\", \"2.0\");\n\tsetDefaultHeader(headers, \"MaxDataServiceVersion\", \"2.0\");\n\tsetDefaultHeader(headers, \"Accept\", \"application/json\");\n\n\theaders[\"sap-language\"] = \"ru\";\n\n\tif (sapRequest) {\n\t\theaders[\"sap-contextid-accept\"] = \"header\";\n\t}\n\n\tif (isWriteRequest(method) && request.init.body) {\n\t\tsetDefaultHeader(headers, \"Content-Type\", \"application/json\");\n\t}\n\n\tif (isWriteRequest(method) && sapRequest) {\n\t\tsetDefaultHeader(headers, \"x-csrf-token\", \"<получается отдельным GET перед реальным write-запросом>\");\n\t}\n\n\treturn headers;\n}\n\nfunction getTargetKind(target: ODataTargetMetadata) {\n\tif (isFunctionImportMetadata(target)) return \"FunctionImport\";\n\treturn target.result ? \"Parameterized Entity\" : \"Entity\";\n}\n\nfunction logObjectSection(title: string, value: unknown) {\n\tconst logger = getConsole();\n\tlogger.groupCollapsed(title);\n\tlogger.info(value);\n\tlogger.groupEnd();\n}\n\nfunction logODataDevRequest(info: ODataDevRequestLogInfo) {\n\tconst logger = getConsole();\n\tconst bodyPreview = parseRequestBodyForLog(info.request.init.body);\n\tconst initHeaders = headersToRecord(info.request.init.headers);\n\tconst transportHeaders = buildTransportHeadersPreview(info.request);\n\tconst requestInitPreview = {\n\t\tmethod: info.request.init.method,\n\t\theaders: initHeaders,\n\t\tbody: bodyPreview,\n\t\thasSignal: Boolean(info.request.init.signal)\n\t};\n\n\tlogger.groupCollapsed(`[OData DEV] ${info.requestMethod} ${info.request.fullUrl}`);\n\tlogger.table([\n\t\t{\n\t\t\thelper: info.helperName,\n\t\t\toperation: info.operation,\n\t\t\ttarget: info.odata.target,\n\t\t\ttargetKind: getTargetKind(info.target),\n\t\t\tservice: info.odata.service,\n\t\t\trealFetch: \"не выполнялся\"\n\t\t}\n\t]);\n\tlogger.info(\"Итоговый URL:\", info.request.fullUrl);\n\tlogger.info(\"Path без base URL:\", info.request.path);\n\tlogger.info(\"Target path до query options:\", info.targetPath);\n\tlogger.info(\"Query string:\", info.request.queryString || \"<пусто>\");\n\tlogger.info(\"Body:\", bodyPreview ?? \"<пусто>\");\n\tlogger.info(\"Auto parse:\", info.autoParse ?? false);\n\tlogger.info(\"Transform:\", info.hasTransform ? \"передан, но не вызывается без ответа backend\" : \"не передан\");\n\tlogger.info(\"Dry-run result:\", info.operation === \"query\" ? { data: [], totalCount: 0 } : { data: undefined });\n\tlogObjectSection(\"OData config\", info.odata);\n\tlogObjectSection(\"Target metadata\", info.target);\n\tlogObjectSection(\"Target params\", info.params);\n\tlogObjectSection(\"Query options\", info.queryOptions);\n\tlogObjectSection(\"RequestInit, переданный в transport\", requestInitPreview);\n\tlogObjectSection(\"Заголовки после transport defaults (без реального fetch)\", transportHeaders);\n\tlogger.groupEnd();\n}\n\nfunction notifyODataDevHelperCall(helperName: ODataDevHelperName) {\n\tnotify.warning(`${helperName}: DEV dry-run OData запроса. Реальный запрос не выполняется, payload выведен в console.`, {\n\t\ttitle: \"OData DEV helper\"\n\t});\n}\n\nfunction createODataFetchFnDevRunner<I>(\n\tmethod: ODataOperationMethod,\n\topts: ODataFetchFnDevOptions<I>,\n\thelperName: ODataDevHelperName\n): ODataFetchFnRunner<unknown> {\n\tconst { odata, options = {}, init = {}, autoParse, swCache } = opts;\n\tconst params = opts.params ?? {};\n\n\treturn async ({ client, signal }: { client: QueryClient; signal?: AbortSignal }) => {\n\t\tnotifyODataDevHelperCall(helperName);\n\n\t\tconst baseUrl = resolveODataBaseUrl(odata.service, options.baseUrl);\n\t\tconst serviceMetadata = await getODataMetadataData({ service: odata.service, baseUrl }, client);\n\t\tif (!serviceMetadata) {\n\t\t\tthrow new Error(`Не удалось загрузить metadata OData-сервиса '${odata.service}'`);\n\t\t}\n\n\t\tconst target = resolveODataTarget(serviceMetadata, odata.target);\n\n\t\tvalidateODataOperation(target, method, odata);\n\n\t\tconst body = resolveRequestBody(opts.body, method);\n\t\tconst requestMethod = resolveRequestMethod(target, method);\n\t\tconst targetPath = buildTargetPath(target, odata, params, method);\n\n\t\tconst queryOptions = swCache ? { ...options, baseUrl, swCache } : { ...options, baseUrl };\n\t\tconst requestInit = { ...init, method: requestMethod, body, signal };\n\t\tconst request = buildODataFetchRequest(targetPath, queryOptions, requestInit);\n\n\t\tlogODataDevRequest({\n\t\t\thelperName,\n\t\t\toperation: method,\n\t\t\todata,\n\t\t\ttarget,\n\t\t\ttargetPath,\n\t\t\trequest,\n\t\t\trequestMethod,\n\t\t\tparams,\n\t\t\tqueryOptions,\n\t\t\tbody,\n\t\t\tautoParse,\n\t\t\thasTransform: Boolean(opts.transform)\n\t\t});\n\n\t\tif (method === \"query\") {\n\t\t\treturn { data: [], totalCount: 0 };\n\t\t}\n\n\t\treturn { data: undefined };\n\t};\n}\n\nexport function odataFetchFnDev<\n\tI,\n\tO = I,\n\tP extends UnwrappedODataParameters = UnwrappedODataParameters,\n\tM extends ODataArrayOperationMethod = ODataArrayOperationMethod\n>(method: M, opts: ODataQueryFnOptions<I, O, P> & { transform: ODataQueryArrayTransform<I, O> }): ODataFetchFnRunner<O[]>;\nexport function odataFetchFnDev<\n\tI,\n\tO = I,\n\tP extends UnwrappedODataParameters = UnwrappedODataParameters,\n\tM extends ODataArrayOperationMethod = ODataArrayOperationMethod\n>(method: M, opts: ODataQueryFnOptions<I, O, P> & { transform: ODataQuerySingleTransform<I, O> }): ODataFetchFnRunner<O>;\nexport function odataFetchFnDev<\n\tI,\n\tP extends UnwrappedODataParameters = UnwrappedODataParameters,\n\tM extends ODataArrayOperationMethod = ODataArrayOperationMethod\n>(method: M, opts: ODataQueryFnOptions<I, I, P> & { transform?: undefined }): ODataFetchFnRunner<I[]>;\nexport function odataFetchFnDev<\n\tI,\n\tT = I,\n\tP extends UnwrappedODataParameters = UnwrappedODataParameters,\n\tM extends ODataSingleOperationMethod = ODataSingleOperationMethod\n>(method: M, opts: ODataSingleFetchFnRequest<M, I, I, T, P> & { transform?: undefined }): ODataFetchFnRunner<I>;\nexport function odataFetchFnDev<I, O = I, T = I, M extends ODataSingleOperationMethod = ODataSingleOperationMethod>(\n\tmethod: M,\n\topts: ODataSingleFetchFnRequest<M, I, O, T> & { transform: ODataSingleTransform<I, O> }\n): ODataFetchFnRunner<O>;\nexport function odataFetchFnDev<\n\tI,\n\tO = I,\n\tT = I,\n\tP extends UnwrappedODataParameters = UnwrappedODataParameters,\n\tM extends ODataOperationMethod = ODataOperationMethod\n>(method: M, opts: ODataFetchFnRequest<M, I, O, T, P>): ODataFetchFnRunner<unknown>;\nexport function odataFetchFnDev(...args: ODataFetchFnImplementationArgs): ODataFetchFnRunner<unknown> {\n\tif (!__DEV__) {\n\t\tswitch (args[0]) {\n\t\t\tcase \"create\": {\n\t\t\t\treturn odataFetchFn(\"create\", args[1]);\n\t\t\t}\n\n\t\t\tcase \"update\": {\n\t\t\t\treturn odataFetchFn(\"update\", args[1]);\n\t\t\t}\n\n\t\t\tcase \"delete\": {\n\t\t\t\treturn odataFetchFn(\"delete\", args[1]);\n\t\t\t}\n\n\t\t\tcase \"read\": {\n\t\t\t\treturn odataFetchFn(\"read\", args[1]);\n\t\t\t}\n\n\t\t\tcase \"query\": {\n\t\t\t\treturn odataFetchFn(\"query\", args[1]);\n\t\t\t}\n\n\t\t\tcase \"fi\": {\n\t\t\t\treturn odataFetchFn(\"fi\", args[1]);\n\t\t\t}\n\n\t\t\tdefault: {\n\t\t\t\tconst checker: never = args[0];\n\t\t\t\tvoid checker;\n\n\t\t\t\tthrow new Error(\"Неподдерживаемая OData operation в odataFetchFnDev\");\n\t\t\t}\n\t\t}\n\t}\n\n\tconst [method, opts] = args;\n\treturn createODataFetchFnDevRunner(method, opts, \"odataFetchFnDev\");\n}\n\nexport function odataCreateFnDev<I, T = I>(opts: ODataCreateFnOptions<I, I, T> & { transform?: undefined }): ODataFetchFnRunner<I>;\nexport function odataCreateFnDev<I, O = I, T = I>(\n\topts: ODataCreateFnOptions<I, O, T> & { transform: ODataSingleTransform<I, O> }\n): ODataFetchFnRunner<O>;\nexport function odataCreateFnDev<I, O = I, T = I>(opts: ODataCreateFnOptions<I, O, T>): ODataFetchFnRunner<unknown> {\n\tif (!__DEV__) {\n\t\treturn odataFetchFn<I, O, T, never, \"create\">(\"create\", opts);\n\t}\n\n\treturn createODataFetchFnDevRunner<I>(\"create\", opts, \"odataCreateFnDev\");\n}\n\nexport function odataUpdateFnDev<I, T = I, P extends UnwrappedODataParameters = UnwrappedODataParameters>(\n\topts: ODataUpdateFnOptions<I, I, T, P> & { transform?: undefined }\n): ODataFetchFnRunner<I>;\nexport function odataUpdateFnDev<I, O = I, T = I, P extends UnwrappedODataParameters = UnwrappedODataParameters>(\n\topts: ODataUpdateFnOptions<I, O, T, P> & { transform: ODataSingleTransform<I, O> }\n): ODataFetchFnRunner<O>;\nexport function odataUpdateFnDev<I, O = I, T = I, P extends UnwrappedODataParameters = UnwrappedODataParameters>(\n\topts: ODataUpdateFnOptions<I, O, T, P>\n): ODataFetchFnRunner<unknown> {\n\tif (!__DEV__) {\n\t\treturn odataFetchFn<I, O, T, P, \"update\">(\"update\", opts);\n\t}\n\n\treturn createODataFetchFnDevRunner<I>(\"update\", opts, \"odataUpdateFnDev\");\n}\n\nexport function odataDeleteFnDev<I, P extends UnwrappedODataParameters = UnwrappedODataParameters>(\n\topts: ODataDeleteFnOptions<I, I, P> & { transform?: undefined }\n): ODataFetchFnRunner<I>;\nexport function odataDeleteFnDev<I, O = I, P extends UnwrappedODataParameters = UnwrappedODataParameters>(\n\topts: ODataDeleteFnOptions<I, O, P> & { transform: ODataSingleTransform<I, O> }\n): ODataFetchFnRunner<O>;\nexport function odataDeleteFnDev<I, O = I, P extends UnwrappedODataParameters = UnwrappedODataParameters>(\n\topts: ODataDeleteFnOptions<I, O, P>\n): ODataFetchFnRunner<unknown> {\n\tif (!__DEV__) {\n\t\treturn odataFetchFn<I, O, I, P, \"delete\">(\"delete\", opts);\n\t}\n\n\treturn createODataFetchFnDevRunner<I>(\"delete\", opts, \"odataDeleteFnDev\");\n}\n\nexport function odataReadFnDev<I, P extends UnwrappedODataParameters = UnwrappedODataParameters>(\n\topts: ODataReadFnOptions<I, I, P> & { transform?: undefined }\n): ODataFetchFnRunner<I>;\nexport function odataReadFnDev<I, O = I, P extends UnwrappedODataParameters = UnwrappedODataParameters>(\n\topts: ODataReadFnOptions<I, O, P> & { transform: ODataSingleTransform<I, O> }\n): ODataFetchFnRunner<O>;\nexport function odataReadFnDev<I, O = I, P extends UnwrappedODataParameters = UnwrappedODataParameters>(\n\topts: ODataReadFnOptions<I, O, P>\n): ODataFetchFnRunner<unknown> {\n\tif (!__DEV__) {\n\t\treturn odataFetchFn<I, O, I, P, \"read\">(\"read\", opts);\n\t}\n\n\treturn createODataFetchFnDevRunner<I>(\"read\", opts, \"odataReadFnDev\");\n}\n\nexport function odataQueryFnDev<I, O = I, P extends UnwrappedODataParameters = UnwrappedODataParameters>(\n\topts: ODataQueryFnOptions<I, O, P> & { transform: ODataQueryArrayTransform<I, O> }\n): ODataFetchFnRunner<O[]>;\nexport function odataQueryFnDev<I, O = I, P extends UnwrappedODataParameters = UnwrappedODataParameters>(\n\topts: ODataQueryFnOptions<I, O, P> & { transform: ODataQuerySingleTransform<I, O> }\n): ODataFetchFnRunner<O>;\nexport function odataQueryFnDev<I, O = I, P extends UnwrappedODataParameters = UnwrappedODataParameters>(\n\topts: ODataQueryFnOptions<I, O, P> & { transform?: undefined }\n): ODataFetchFnRunner<I[]>;\nexport function odataQueryFnDev<I, O = I, P extends UnwrappedODataParameters = UnwrappedODataParameters>(\n\topts: ODataQueryFnOptions<I, O, P>\n): ODataFetchFnRunner<unknown> {\n\tif (!__DEV__) {\n\t\treturn odataFetchFn<I, O, void, P, \"query\">(\"query\", opts);\n\t}\n\n\treturn createODataFetchFnDevRunner<I>(\"query\", opts, \"odataQueryFnDev\");\n}\n\nexport function odataFunctionImportFnDev<I, P extends UnwrappedODataParameters = UnwrappedODataParameters>(\n\topts: ODataFunctionImportFnOptions<I, I, P> & { transform?: undefined }\n): ODataFetchFnRunner<I>;\nexport function odataFunctionImportFnDev<I, O = I, P extends UnwrappedODataParameters = UnwrappedODataParameters>(\n\topts: ODataFunctionImportFnOptions<I, O, P> & { transform: ODataSingleTransform<I, O> }\n): ODataFetchFnRunner<O>;\nexport function odataFunctionImportFnDev<I, O = I, P extends UnwrappedODataParameters = UnwrappedODataParameters>(\n\topts: ODataFunctionImportFnOptions<I, O, P>\n): ODataFetchFnRunner<unknown> {\n\tif (!__DEV__) {\n\t\treturn odataFetchFn<I, O, I, P, \"fi\">(\"fi\", opts);\n\t}\n\n\treturn createODataFetchFnDevRunner<I>(\"fi\", opts, \"odataFunctionImportFnDev\");\n}\n"],"mappings":"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"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { C as e, S as t, _ as n, c as r, o as i, s as a, x as o } from "./fetch-
|
|
1
|
+
import { C as e, S as t, _ as n, c as r, o as i, s as a, x as o } from "./fetch-teHV5e4t.js";
|
|
2
2
|
import { isRecord as s } from "@ryuzaki13/react-foundation-lib/validators";
|
|
3
3
|
import { formatDateAsODataDatetime as c, parseDate as l } from "@ryuzaki13/react-foundation-lib/formatters";
|
|
4
4
|
import { useEffect as u, useMemo as d } from "react";
|
|
@@ -41,7 +41,7 @@ async function T(e, t = {}, n = {}) {
|
|
|
41
41
|
}
|
|
42
42
|
//#endregion
|
|
43
43
|
//#region src/odata/metadataVersionCheck.ts
|
|
44
|
-
var E = "@ryuzaki13/react-foundation-api@1.0.
|
|
44
|
+
var E = "@ryuzaki13/react-foundation-api@1.0.1", D = 1e3 * 60 * 60 * 24;
|
|
45
45
|
function O(e) {
|
|
46
46
|
if (e) return Array.isArray(e) ? e[0] : e;
|
|
47
47
|
}
|
|
@@ -299,4 +299,4 @@ function ie(e) {
|
|
|
299
299
|
//#endregion
|
|
300
300
|
export { re as a, L as c, I as d, R as f, S as h, ie as i, F as l, T as m, te as n, ne as o, z as p, Q as r, ee as s, $ as t, V as u };
|
|
301
301
|
|
|
302
|
-
//# sourceMappingURL=odataFetchFn-
|
|
302
|
+
//# sourceMappingURL=odataFetchFn-CJIPv-CJ.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"odataFetchFn-BXVJxOou.js","names":[],"sources":["../../src/odata/odataBaseQueryKey.ts","../../src/odata/odataFetch.ts","../../src/odata/metadataVersionCheck.ts","../../src/odata/useODataMetadataQuery.ts","../../src/odata/odataFetchFnHelpers.ts","../../src/odata/parseODataResponseByMetadata.ts","../../src/odata/odataFetchFn.ts"],"sourcesContent":["export const odataBaseQueryKey = [\"odata\"] as const;\n","import { buildODataFilter, buildODataOrder, type FilterExpression, type Sort } from \"@ryuzaki13/react-foundation-lib/odata-service\";\n\nimport { BaseUrlMap, BaseURLType, fetchODataJson } from \"./transport\";\n\nexport type ODataFetchOptions<T> = {\n\t/**\n\t * Фильтры.\n\t *\n\t * Корневой объект всегда определяет выражение, которое может состоять из вложенных условий (`conditions: FilterCondition<T>[]`),\n\t * либо из других выражений (`filters: FilterExpression<T>[]`).\n\t *\n\t * @example\n\t *\n\t * // С использование фабричных функций (рекомендуется)\n\t *\n\t * expression: {\n\t * and: true,\n\t * filters: [\n\t * createFilterBetween(\"FKDAT\", range),\n\t * createFilterEqual(\"TEXT_NODE\", branches),\n\t * createFilterContains(\"VSTEL\", branchStocks),\n\t * ]\n\t * }\n\t *\n\t * // Без использования фабричных функций (КРАЙНЕ НЕ РЕКОМЕНДУЕТСЯ ТАК ДЕЛАТЬ!)\n\t *\n\t * expression: {\n\t * and: true,\n\t * filters: [\n\t * {\n\t * and: true,\n\t * conditions: [\n\t * { key: \"FKDAT\", value: range[0], operation: \"ge\" },\n\t * { key: \"FKDAT\", value: range[1], operation: \"le\" }\n\t * ]\n\t * },\n\t * {\n\t * conditions: [\n\t * { key: \"TEXT_NODE\", value: \"0202\", operation: \"eq\" },\n\t * { key: \"TEXT_NODE\", value: \"0204\", operation: \"eq\" }\n\t * ]\n\t * },\n\t * {\n\t * conditions: [\n\t * { key: \"VSTEL\", value: \"1158\", operation: \"contains\" },\n\t * { key: \"VSTEL\", value: \"1988\", operation: \"contains\" }\n\t * ]\n\t * }\n\t * ]\n\t * }\n\t */\n\texpression?: FilterExpression<T>;\n\n\t// grouping?: (keyof T)[];\n\tsorts?: Sort<keyof T>[];\n\tselect?: (keyof T)[];\n\texpand?: (keyof T)[];\n\ttop?: number;\n\tskip?: number;\n\n\tinlinecount?: string;\n\tformat?: \"json\";\n\tbaseUrl?: BaseURLType;\n\n\t/**\n\t * Политика кеширования в Service Worker.\n\t *\n\t * - `\"off\"` — network-only (по умолчанию)\n\t * - `\"ttl=24h\"` — cache-first с TTL\n\t * - `\"ttl=10m;max=200;name=ui\"` — TTL с лимитом записей и именованным кешем\n\t * - `\"bust=24h;name=ref\"` — принудительное обновление кеша из сети\n\t */\n\tswCache?: string;\n};\n\nfunction appendQueryOption(query: URLSearchParams, key: string, value?: string | number) {\n\tif (value === undefined || value === \"\") return;\n\tquery.set(key, String(value));\n}\n\nexport type ODataFetchRequestPreview = {\n\tpath: string;\n\tfullUrl: string;\n\tbaseUrl: BaseURLType | undefined;\n\tinit: RequestInit;\n\tqueryString: string;\n};\n\nexport function buildODataFetchRequest<T>(entitySetPath: string, options: ODataFetchOptions<T> = {}, init: RequestInit = {}) {\n\tconst [rawPath, rawQuery = \"\"] = entitySetPath.split(\"?\"); // Если был вызов FI\n\tconst query = new URLSearchParams(rawQuery);\n\n\tif (options.expression) {\n\t\tconst filter = buildODataFilter(options.expression);\n\t\tif (filter) query.set(\"$filter\", filter);\n\t}\n\tif (options.sorts) query.set(\"$orderby\", buildODataOrder(options.sorts));\n\tif (options.select) query.set(\"$select\", options.select.join(\",\"));\n\tif (options.expand) query.set(\"$expand\", options.expand.join(\",\"));\n\n\tappendQueryOption(query, \"$top\", options.top);\n\tappendQueryOption(query, \"$skip\", options.skip);\n\tappendQueryOption(query, \"$inlinecount\", options.inlinecount);\n\n\tconst path = rawPath.replace(/\\/+$/, \"\");\n\tconst queryString = query.toString();\n\tconst fullUrl = queryString ? `${path}?${queryString}` : path;\n\tlet requestInit = init;\n\n\t// Передаём политику SW-кеширования через заголовок x-sw-cache\n\tif (options.swCache) {\n\t\tconst headers = new Headers(init.headers);\n\t\theaders.set(\"x-sw-cache\", options.swCache);\n\t\trequestInit = { ...init, headers };\n\t}\n\n\treturn {\n\t\tpath: fullUrl,\n\t\tfullUrl: `${BaseUrlMap[options.baseUrl ?? \"odata\"]}${fullUrl}`,\n\t\tbaseUrl: options.baseUrl,\n\t\tinit: requestInit,\n\t\tqueryString\n\t} satisfies ODataFetchRequestPreview;\n}\n\nexport async function odataFetch<T, I = T>(entitySetPath: string, options: ODataFetchOptions<T> = {}, init: RequestInit = {}) {\n\tconst request = buildODataFetchRequest(entitySetPath, options, init);\n\n\treturn fetchODataJson<I>(request.path, request.init, options.baseUrl);\n}\n","import { formatDateAsODataDatetime, parseDate } from \"@ryuzaki13/react-foundation-lib/formatters\";\nimport { persistedQueryMeta } from \"@ryuzaki13/react-foundation-lib/query-client\";\nimport { QueryClient, queryOptions, QueryState } from \"@tanstack/react-query\";\n\nimport { odataBaseQueryKey } from \"./odataBaseQueryKey\";\nimport { odataFetch } from \"./odataFetch\";\nimport { getODataProjectAdapter, normalizeODataServiceName, resolveODataBaseUrl } from \"./odataProjectAdapter\";\n\nimport type { ODataServiceConfig } from \"@ryuzaki13/react-foundation-lib/odata-service\";\n\nconst METADATA_VERSION_BUILD_ID = __APP_BUILD_ID__;\nconst METADATA_VERSION_STALE_TIME = 1000 * 60 * 60 * 24;\n\nexport interface ODataMetadataVersionOptions extends Pick<ODataServiceConfig, \"service\"> {\n\tstaleTime?: number;\n}\n\ninterface ODataMetadataVersionRecord {\n\tserviceName: string;\n\tlastChanged: string;\n}\n\nexport interface ODataMetadataVersionResult {\n\tservice: string;\n\tchangedAt: Date | null;\n\tversion: string | null;\n}\n\nfunction selectMetadataVersionRecord(records: ODataMetadataVersionRecord[] | ODataMetadataVersionRecord | undefined) {\n\tif (!records) return undefined;\n\treturn Array.isArray(records) ? records[0] : records;\n}\n\nexport const createODataMetadataVersionQueryKey = ({ service }: Pick<ODataServiceConfig, \"service\">) =>\n\t[...odataBaseQueryKey, \"metadata-version\", { service, buildId: METADATA_VERSION_BUILD_ID }] as const;\n\nfunction createEmptyMetadataVersionResult(service: string): ODataMetadataVersionResult {\n\treturn {\n\t\tservice,\n\t\tchangedAt: null,\n\t\tversion: null\n\t};\n}\n\n/**\n * Загружает время последней генерации OData-сервиса из технического CDS.\n * Эти данные не заменяют metadata, а служат версией для точечной инвалидации metadata query.\n */\nexport function fetchMetadataVersion(options: Pick<ODataServiceConfig, \"service\">) {\n\treturn async ({ signal }: { signal: AbortSignal }): Promise<ODataMetadataVersionResult> => {\n\t\tconst endpoint = getODataProjectAdapter().metadataVersion;\n\t\tif (!endpoint) return createEmptyMetadataVersionResult(options.service);\n\n\t\tconst response = await odataFetch<ODataMetadataVersionRecord, ODataMetadataVersionRecord[]>(\n\t\t\t`/${endpoint.service}/${endpoint.target}('${normalizeODataServiceName(options.service)}')`,\n\t\t\t{\n\t\t\t\tbaseUrl: resolveODataBaseUrl(endpoint.service, endpoint.baseUrl)\n\t\t\t},\n\t\t\t{ signal }\n\t\t);\n\n\t\tconst record = selectMetadataVersionRecord(response.data);\n\t\tconst changedAt = parseDate(record?.lastChanged);\n\n\t\treturn {\n\t\t\tservice: options.service,\n\t\t\tchangedAt,\n\t\t\tversion: changedAt ? formatDateAsODataDatetime(changedAt) : null\n\t\t};\n\t};\n}\n\n/**\n * Описывает отдельный TanStack Query для версии metadata.\n * Query хранится отдельно от самих metadata, чтобы частоту проверки можно было регулировать независимо.\n */\nexport const odataMetadataVersionQueryOptions = (options: ODataMetadataVersionOptions) =>\n\tqueryOptions({\n\t\tqueryKey: createODataMetadataVersionQueryKey(options),\n\t\tqueryFn: fetchMetadataVersion(options),\n\t\tmeta: persistedQueryMeta,\n\t\tenabled: Boolean(options.service && getODataProjectAdapter().metadataVersion),\n\t\tstaleTime: options.staleTime ?? METADATA_VERSION_STALE_TIME,\n\t\tgcTime: Infinity\n\t});\n\n/**\n * Инвалидирует только metadata query указанного сервиса.\n * Version-check query и metadata других сервисов при этом остаются нетронутыми.\n */\nexport function invalidateODataMetadataQueries(queryClient: QueryClient, service: string) {\n\treturn queryClient.invalidateQueries({\n\t\tpredicate: (query) => {\n\t\t\tconst [baseKey, queryType, queryOptionsValue] = query.queryKey;\n\t\t\tif (baseKey !== odataBaseQueryKey[0] || queryType !== \"metadata\") return false;\n\t\t\tif (!queryOptionsValue || typeof queryOptionsValue !== \"object\") return false;\n\n\t\t\treturn \"service\" in queryOptionsValue && queryOptionsValue.service === service;\n\t\t}\n\t});\n}\n\nexport function shouldRefreshODataMetadataByVersion(\n\tmetadataState: QueryState<unknown, Error> | undefined,\n\tversion: ODataMetadataVersionResult\n) {\n\tif (metadataState?.data === undefined) return false;\n\tif (!version.changedAt) return false;\n\treturn version.changedAt.getTime() > metadataState.dataUpdatedAt;\n}\n","import { useEffect, useMemo } from \"react\";\n\nimport { parseServiceMetadata } from \"@ryuzaki13/react-foundation-lib/odata-service\";\nimport { persistedQueryMeta } from \"@ryuzaki13/react-foundation-lib/query-client\";\nimport { QueryClient, queryOptions, useQuery, useQueryClient } from \"@tanstack/react-query\";\n\nimport {\n\tinvalidateODataMetadataQueries,\n\tODataMetadataVersionOptions,\n\todataMetadataVersionQueryOptions,\n\tODataMetadataVersionResult,\n\tshouldRefreshODataMetadataByVersion\n} from \"./metadataVersionCheck\";\nimport { odataBaseQueryKey } from \"./odataBaseQueryKey\";\nimport { BaseURLType, fetchQueryFn, resolveODataBaseUrl } from \"./transport\";\n\nimport type { ODataServiceConfig } from \"@ryuzaki13/react-foundation-lib/odata-service\";\n\ntype ODataMetadataOptions = Pick<ODataServiceConfig, \"service\"> & { baseUrl?: BaseURLType };\n\nexport function fetchMetadata(options: ODataMetadataOptions) {\n\treturn fetchQueryFn(`/${options.service}/$metadata`, {\n\t\tbaseUrl: resolveODataBaseUrl(options.service, options.baseUrl),\n\t\tinit: {\n\t\t\theaders: {\n\t\t\t\tAccept: \"*/*\",\n\t\t\t\t\"Content-Type\": \"application/xml\"\n\t\t\t}\n\t\t},\n\t\ttransform: async (data) => {\n\t\t\ttry {\n\t\t\t\treturn parseServiceMetadata(await data.text());\n\t\t\t} catch (error) {\n\t\t\t\tthrow new Error(`Сервис ${options.service} содержит необработанную ошибку: ${String(error)}`);\n\t\t\t}\n\t\t}\n\t});\n}\n\nexport const odataMetadataQueryOptions = (options: ODataMetadataOptions) =>\n\tqueryOptions({\n\t\tqueryKey: [...odataBaseQueryKey, \"metadata\", options],\n\t\tqueryFn: fetchMetadata(options),\n\t\tmeta: persistedQueryMeta,\n\t\tenabled: Boolean(options.service),\n\t\t/**\n\t\t * Метаданные хранятся без временного протухания.\n\t\t * Актуальность контролируется отдельным version-check query по времени генерации сервиса.\n\t\t */\n\t\tstaleTime: Infinity,\n\t\tgcTime: Infinity\n\t});\n\n/**\n * Применяет результат version-check к metadata query на уровне общего QueryClient.\n * Metadata refetch нужен только если серверная версия новее времени обновления metadata cache.\n */\nexport async function applyODataMetadataVersion(\n\tqueryClient: QueryClient,\n\toptions: ODataMetadataOptions,\n\tversion: ODataMetadataVersionResult\n) {\n\tif (!options.service) return;\n\n\tconst metadataQueryKey = odataMetadataQueryOptions(options).queryKey;\n\tconst metadataState = queryClient.getQueryState(metadataQueryKey);\n\tconst shouldRefresh = shouldRefreshODataMetadataByVersion(metadataState, version);\n\n\tif (shouldRefresh) {\n\t\tawait invalidateODataMetadataQueries(queryClient, options.service);\n\t}\n}\n\nexport function useODataMetadataQuery(options: ODataMetadataOptions) {\n\tconst queryClient = useQueryClient();\n\tconst metadataOptions = useMemo(() => ({ service: options.service, baseUrl: options.baseUrl }), [options.baseUrl, options.service]);\n\tconst versionOptions = useMemo(() => ({ service: options.service }), [options.service]);\n\tconst versionQuery = useQuery(odataMetadataVersionQueryOptions(versionOptions));\n\tconst metadataQuery = useQuery(odataMetadataQueryOptions(metadataOptions));\n\n\tuseEffect(() => {\n\t\tif (!options.service || !versionQuery.isSuccess) return;\n\n\t\tapplyODataMetadataVersion(queryClient, metadataOptions, versionQuery.data);\n\t}, [metadataOptions, metadataQuery.dataUpdatedAt, options.service, queryClient, versionQuery.data, versionQuery.isSuccess]);\n\n\treturn metadataQuery;\n}\n\n/**\n * Публичный доступ к результату version-check без загрузки самих metadata.\n * Полезно для глобальной диагностики и ручного управления частотой опроса.\n */\nexport function useODataMetadataVersionQuery(options: ODataMetadataVersionOptions) {\n\treturn useQuery(odataMetadataVersionQueryOptions(options));\n}\n\nasync function syncODataMetadataVersion(options: ODataMetadataOptions, queryClient: QueryClient) {\n\tconst versionOptions = { service: options.service };\n\n\ttry {\n\t\tconst nextVersion = await queryClient.fetchQuery(odataMetadataVersionQueryOptions(versionOptions));\n\t\tawait applyODataMetadataVersion(queryClient, options, nextVersion);\n\t} catch {\n\t\t// NOTE: Пока держим за правило:\n\t\t// Если технический version-check временно недоступен,\n\t\t// сохранённые metadata остаются рабочим источником для OData-запросов.\n\t}\n}\n\nexport async function getODataMetadataData(options: ODataMetadataOptions, queryClient: QueryClient) {\n\tif (!options.service) return undefined;\n\tawait queryClient.fetchQuery(odataMetadataQueryOptions(options));\n\tawait syncODataMetadataVersion(options, queryClient);\n\treturn queryClient.fetchQuery(odataMetadataQueryOptions(options));\n}\n","import {\n\tBaseMethod,\n\tbuildEntityOperationPath,\n\tbuildFunctionImportPath,\n\tFunctionImportMetadata,\n\tODataOperationMethod,\n\tODataServiceConfig,\n\tODataTargetMetadata,\n\tServiceMetadata,\n\tWrappedODataParameters\n} from \"@ryuzaki13/react-foundation-lib/odata-service\";\n\nexport function normalizeMethod(method?: string): BaseMethod | undefined {\n\tif (!method) return undefined;\n\n\tconst normalized = method.toUpperCase();\n\tif (normalized === \"GET\" || normalized === \"POST\" || normalized === \"PUT\" || normalized === \"DELETE\") {\n\t\treturn normalized;\n\t}\n\n\treturn undefined;\n}\n\nexport function isFunctionImportMetadata(target: ODataTargetMetadata): target is FunctionImportMetadata {\n\treturn \"returnType\" in target;\n}\n\nexport function resolveODataTarget(serviceData: ServiceMetadata, targetName: string): ODataTargetMetadata {\n\tconst entity = serviceData?.entities[targetName];\n\tconst functionImport = serviceData?.functionImports[targetName];\n\n\tif (entity && functionImport) {\n\t\tthrow new Error(`Найден конфликт metadata: '${targetName}' существует и как Entity, и как FunctionImport`);\n\t}\n\n\tif (entity) return entity;\n\tif (functionImport) return functionImport;\n\n\tthrow new Error(`OData target '${targetName}' не был загружен`);\n}\n\nexport function validateODataOperation(target: ODataTargetMetadata, method: ODataOperationMethod, odata: ODataServiceConfig): void {\n\tif (isFunctionImportMetadata(target)) {\n\t\tif (method !== \"fi\") {\n\t\t\tthrow new Error(\n\t\t\t\t`OData operation '${method}' несовместима с FunctionImport '${target.name}'. Для FunctionImport используйте method: 'fi'.`\n\t\t\t);\n\t\t}\n\n\t\treturn;\n\t}\n\n\tif (method === \"fi\") {\n\t\tthrow new Error(\n\t\t\t`OData operation 'fi' несовместима с Entity '${odata.target}'. Для Entity используйте один из методов: 'create', 'update', 'delete', 'read', 'query', 'fm'.`\n\t\t);\n\t}\n\n\tif (method === \"read\" && target.result) {\n\t\tthrow new Error(\n\t\t\t`OData operation '${method}' несовместима с parameterized query entity '${odata.target}'. Для target с result='${target.result}' используйте method: 'query'.`\n\t\t);\n\t}\n}\n\nexport function resolveRequestMethod(target: ODataTargetMetadata, method: ODataOperationMethod): BaseMethod {\n\tif (method === \"create\") return \"POST\";\n\tif (method === \"update\") return \"PUT\";\n\tif (method === \"delete\") return \"DELETE\";\n\tif (method === \"read\" || method === \"query\") return \"GET\";\n\n\tif (isFunctionImportMetadata(target)) {\n\t\tif (!target.httpMethod) {\n\t\t\tthrow new Error(`FunctionImport '${target.name}' не содержит httpMethod в metadata, поэтому operation 'fi' выполнить нельзя.`);\n\t\t}\n\n\t\treturn target.httpMethod;\n\t}\n\n\tthrow new Error(`OData operation '${method}' не поддерживается для target '${\"title\" in target ? target.title : \"unknown\"}'.`);\n}\n\nexport function resolveRequestBody<T = unknown>(body: T | undefined, method: ODataOperationMethod): string | undefined {\n\tif (body && (method === \"create\" || method === \"update\")) {\n\t\treturn JSON.stringify(body);\n\t}\n\treturn undefined;\n}\n\nexport function buildTargetPath(\n\ttarget: ODataTargetMetadata,\n\todata: ODataServiceConfig,\n\tparams: WrappedODataParameters,\n\tmethod: ODataOperationMethod\n): string {\n\tif (isFunctionImportMetadata(target)) {\n\t\treturn buildFunctionImportPath(target, odata, params);\n\t}\n\n\tif (method === \"fi\") {\n\t\tthrow new Error(`OData operation 'fi' несовместима с Entity '${odata.target}'.`);\n\t}\n\n\treturn buildEntityOperationPath(target, odata, params, method);\n}\n","import { odataParseValueByMetadata } from \"@ryuzaki13/react-foundation-lib/odata-service\";\nimport { isRecord } from \"@ryuzaki13/react-foundation-lib/validators\";\n\nimport { isFunctionImportMetadata } from \"./odataFetchFnHelpers\";\n\nimport type { EntityColumnProperty, ODataTargetMetadata, ServiceMetadata } from \"@ryuzaki13/react-foundation-lib/odata-service\";\n\ntype ParsingColumnDescriptor = Pick<EntityColumnProperty, \"id\" | \"type\" | \"abapBooleanLike\">;\n\nfunction resolveParsingColumns(target: ODataTargetMetadata, serviceMetadata: ServiceMetadata): EntityColumnProperty[] | undefined {\n\tif (!isFunctionImportMetadata(target)) {\n\t\treturn target.columns;\n\t}\n\n\tif (!target.resultEntity) return undefined;\n\treturn serviceMetadata.entities[target.resultEntity]?.columns;\n}\n\nfunction createParsingPlan(columns: EntityColumnProperty[]): ParsingColumnDescriptor[] {\n\tconst parsingPlan: ParsingColumnDescriptor[] = [];\n\n\tfor (let index = 0; index < columns.length; index += 1) {\n\t\tconst column = columns[index];\n\t\tparsingPlan.push({\n\t\t\tid: column.id,\n\t\t\ttype: column.type,\n\t\t\tabapBooleanLike: column.abapBooleanLike\n\t\t});\n\t}\n\n\treturn parsingPlan;\n}\n\nfunction parsePlainRecord(record: Record<string, unknown>, parsingPlan: ParsingColumnDescriptor[]) {\n\tlet parsedRecord: Record<string, unknown> | undefined;\n\n\tfor (let index = 0; index < parsingPlan.length; index += 1) {\n\t\tconst descriptor = parsingPlan[index];\n\t\tif (!Object.prototype.hasOwnProperty.call(record, descriptor.id)) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst sourceValue = record[descriptor.id];\n\t\tconst parsedValue = odataParseValueByMetadata(descriptor, sourceValue);\n\t\tif (parsedValue === sourceValue) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (!parsedRecord) {\n\t\t\tparsedRecord = { ...record };\n\t\t}\n\n\t\tparsedRecord[descriptor.id] = parsedValue;\n\t}\n\n\treturn parsedRecord ?? record;\n}\n\nexport function parseODataResponseByMetadata<I>(data: I[], target: ODataTargetMetadata, serviceMetadata: ServiceMetadata): I[];\nexport function parseODataResponseByMetadata<I>(data: I, target: ODataTargetMetadata, serviceMetadata: ServiceMetadata): I;\nexport function parseODataResponseByMetadata<I>(data: I | I[], target: ODataTargetMetadata, serviceMetadata: ServiceMetadata): I | I[] {\n\tconst columns = resolveParsingColumns(target, serviceMetadata);\n\tif (!columns?.length) return data;\n\n\tconst parsingPlan = createParsingPlan(columns);\n\n\tif (Array.isArray(data)) {\n\t\tlet parsedItems: unknown[] | undefined;\n\n\t\tfor (let index = 0; index < data.length; index += 1) {\n\t\t\tconst item = data[index];\n\t\t\tif (!isRecord(item)) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst parsedItem = parsePlainRecord(item, parsingPlan);\n\t\t\tif (parsedItem === item) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (!parsedItems) {\n\t\t\t\tparsedItems = data.slice();\n\t\t\t}\n\n\t\t\tparsedItems[index] = parsedItem;\n\t\t}\n\n\t\treturn (parsedItems ?? data) as I[];\n\t}\n\n\tif (isRecord(data)) {\n\t\treturn parsePlainRecord(data, parsingPlan) as I;\n\t}\n\n\treturn data;\n}\n","/* eslint-disable @typescript-eslint/no-unused-vars */\nimport { QueryClient } from \"@tanstack/react-query\";\n\nimport { odataFetch, ODataFetchOptions } from \"./odataFetch\";\nimport {\n\tbuildTargetPath,\n\tresolveODataTarget,\n\tresolveRequestBody,\n\tresolveRequestMethod,\n\tvalidateODataOperation\n} from \"./odataFetchFnHelpers\";\nimport { parseODataResponseByMetadata } from \"./parseODataResponseByMetadata\";\nimport { isNoContentResponse, resolveODataBaseUrl } from \"./transport/fetch\";\nimport { getODataMetadataData } from \"./useODataMetadataQuery\";\n\nimport type {\n\tODataOperationMethod,\n\tODataServiceConfig,\n\tODataTargetMetadata,\n\tUnwrappedODataParameters,\n\tWrapODataParameters\n} from \"@ryuzaki13/react-foundation-lib/odata-service\";\n\nexport interface ODataFetchFnSharedOptions<I> {\n\t/**\n\t * Параметры OData сервиса\n\t */\n\todata: ODataServiceConfig;\n\n\t/**\n\t * Параметры для формирования дополнительных query param.\n\t */\n\toptions?: NoInfer<ODataFetchOptions<I>>;\n\n\t/**\n\t * Параметры fetch запроса\n\t */\n\tinit?: Omit<RequestInit, \"signal\" | \"method\" | \"body\">;\n\n\tautoParse?: boolean;\n\n\t/**\n\t * Политика кеширования в Service Worker.\n\t * @see ODataFetchOptions.swCache\n\t */\n\tswCache?: string;\n}\n\nexport type ODataSingleTransform<I, O> = (data: NoInfer<I>, target: ODataTargetMetadata) => NoInfer<O>;\nexport type ODataQueryArrayTransform<I, O> = (data: NoInfer<I>[], target: ODataTargetMetadata) => NoInfer<O>[];\nexport type ODataQuerySingleTransform<I, O> = (data: NoInfer<I>[], target: ODataTargetMetadata) => NoInfer<O>;\nexport type ODataQueryTransform<I, O> = (data: NoInfer<I>[], target: ODataTargetMetadata) => NoInfer<O>[] | NoInfer<O>;\n\nexport type ODataFetchFnSingleOptions<I, O = I> = ODataFetchFnSharedOptions<I> & {\n\ttransform?: ODataSingleTransform<I, O>;\n};\n\nexport type ODataFetchFnQueryOptions<\n\tI,\n\tO = I,\n\tP extends UnwrappedODataParameters = UnwrappedODataParameters\n> = ODataFetchFnSharedOptions<I> & {\n\tparams?: WrapODataParameters<P>;\n\ttransform?: ODataQueryTransform<I, O>;\n};\n\nexport type ODataCreateFnOptions<I, O = I, T = I> = ODataFetchFnSingleOptions<I, O> & {\n\tbody: T;\n};\n\nexport type ODataUpdateFnOptions<\n\tI,\n\tO = I,\n\tT = I,\n\tP extends UnwrappedODataParameters = UnwrappedODataParameters\n> = ODataFetchFnSingleOptions<I, O> & {\n\tparams: WrapODataParameters<P>;\n\tbody: T;\n};\n\nexport type ODataDeleteFnOptions<I, O = I, P extends UnwrappedODataParameters = UnwrappedODataParameters> = ODataFetchFnSingleOptions<\n\tI,\n\tO\n> & {\n\tparams: WrapODataParameters<P>;\n};\n\nexport type ODataReadFnOptions<I, O = I, P extends UnwrappedODataParameters = UnwrappedODataParameters> = ODataFetchFnSingleOptions<\n\tI,\n\tO\n> & {\n\tparams: WrapODataParameters<P>;\n};\n\nexport type ODataQueryFnOptions<I, O = I, P extends UnwrappedODataParameters = UnwrappedODataParameters> = ODataFetchFnQueryOptions<\n\tI,\n\tO,\n\tP\n>;\n\nexport type ODataFunctionImportFnOptions<\n\tI,\n\tO = I,\n\tP extends UnwrappedODataParameters = UnwrappedODataParameters\n> = ODataFetchFnSingleOptions<I, O> & {\n\tparams: WrapODataParameters<P>;\n};\n\nexport type ODataSingleOperationMethod = Exclude<ODataOperationMethod, \"query\">;\nexport type ODataArrayOperationMethod = \"query\";\n\nexport type ODataSingleFetchFnRequest<\n\tM extends ODataSingleOperationMethod,\n\tI,\n\tO = I,\n\tT = I,\n\tP extends UnwrappedODataParameters = UnwrappedODataParameters\n> = M extends \"create\"\n\t? ODataCreateFnOptions<I, O, T>\n\t: M extends \"update\"\n\t\t? ODataUpdateFnOptions<I, O, T, P>\n\t\t: M extends \"delete\"\n\t\t\t? ODataDeleteFnOptions<I, O, P>\n\t\t\t: M extends \"read\"\n\t\t\t\t? ODataReadFnOptions<I, O, P>\n\t\t\t\t: M extends \"fi\"\n\t\t\t\t\t? ODataFunctionImportFnOptions<I, O, P>\n\t\t\t\t\t: never;\n\nexport type ODataFetchFnRequest<\n\tM extends ODataOperationMethod,\n\tI,\n\tO = I,\n\tT = I,\n\tP extends UnwrappedODataParameters = UnwrappedODataParameters\n> = M extends \"query\"\n\t? ODataQueryFnOptions<I, O, P>\n\t: M extends ODataSingleOperationMethod\n\t\t? ODataSingleFetchFnRequest<M, I, O, T, P>\n\t\t: never;\n\nexport type ODataFetchFnImplementationArgs =\n\t| [method: \"create\", opts: ODataCreateFnOptions<unknown, unknown, unknown>]\n\t| [method: \"update\", opts: ODataUpdateFnOptions<unknown, unknown, unknown, UnwrappedODataParameters>]\n\t| [method: \"delete\", opts: ODataDeleteFnOptions<unknown, unknown, UnwrappedODataParameters>]\n\t| [method: \"read\", opts: ODataReadFnOptions<unknown, unknown, UnwrappedODataParameters>]\n\t| [method: \"query\", opts: ODataQueryFnOptions<unknown, unknown, UnwrappedODataParameters>]\n\t| [method: \"fi\", opts: ODataFunctionImportFnOptions<unknown, unknown, UnwrappedODataParameters>];\n\nexport type ODataFetchFnRunnerResult<TData> = { data: TData; totalCount?: number };\nexport type ODataFetchFnRunner<TData> = ({\n\tclient,\n\tsignal\n}: {\n\tclient: QueryClient;\n\tsignal?: AbortSignal;\n}) => Promise<ODataFetchFnRunnerResult<TData>>;\n\n/**\n * Базовый конструктор OData queryFn с явным указанием операции.\n *\n * Это низкоуровневый helper, на котором построены публичные функции:\n *\n * - `odataCreateFn`\n * - `odataUpdateFn`\n * - `odataDeleteFn`\n * - `odataReadFn`\n * - `odataQueryFn`\n * - `odataFunctionImportFn`\n *\n * В обычном прикладном коде рекомендуется использовать именно эти специализированные\n * helpers, а не вызывать `odataFetchFn` напрямую.\n *\n * Что делает функция:\n *\n * - загружает metadata OData-сервиса через `react-query`;\n * - определяет тип target: `Entity` или `FunctionImport`;\n * - валидирует совместимость target и операции;\n * - вычисляет HTTP-метод;\n * - строит path target с учётом metadata;\n * - объединяет `params` target и `options` уровня query string;\n * - при наличии `body` сериализует его через `JSON.stringify`;\n * - может автоматически распарсить ответ по metadata;\n * - может преобразовать результат через `transform`.\n *\n * Параметр `method` описывает семантику OData-операции, а не сырой HTTP-метод:\n *\n * - `\"create\"`\n * - `\"update\"`\n * - `\"delete\"`\n * - `\"read\"`\n * - `\"query\"`\n * - `\"fi\"`\n *\n * Возвращаемое значение — queryFn-совместимая функция, которую можно передавать в\n * `useQuery`, `useInfiniteQuery`, `useMutation` или вызывать вручную.\n *\n * @example\n * ```ts\n * const queryFn = odataFetchFn(\"query\", {\n * \todata: { service: \"TEXT_REPORT_SRV\", target: \"TEXT_REPORT_ENTITY\" },\n * \tparams: wrapODataParams({\n * \t\tp_date: new Date(),\n * \t\tp_date_to: new Date(),\n * \t\ttype_manager: \"main\"\n * \t}),\n * \tautoParse: true\n * });\n *\n * const result = await queryFn({ client });\n * ```\n */\nexport function odataFetchFn<\n\tI,\n\tO = I,\n\tP extends UnwrappedODataParameters = UnwrappedODataParameters,\n\tM extends ODataArrayOperationMethod = ODataArrayOperationMethod\n>(method: M, opts: ODataQueryFnOptions<I, O, P> & { transform: ODataQueryArrayTransform<I, O> }): ODataFetchFnRunner<O[]>;\nexport function odataFetchFn<\n\tI,\n\tO = I,\n\tP extends UnwrappedODataParameters = UnwrappedODataParameters,\n\tM extends ODataArrayOperationMethod = ODataArrayOperationMethod\n>(method: M, opts: ODataQueryFnOptions<I, O, P> & { transform: ODataQuerySingleTransform<I, O> }): ODataFetchFnRunner<O>;\nexport function odataFetchFn<\n\tI,\n\tP extends UnwrappedODataParameters = UnwrappedODataParameters,\n\tM extends ODataArrayOperationMethod = ODataArrayOperationMethod\n>(method: M, opts: ODataQueryFnOptions<I, I, P> & { transform?: undefined }): ODataFetchFnRunner<I[]>;\nexport function odataFetchFn<\n\tI,\n\tT = I,\n\tP extends UnwrappedODataParameters = UnwrappedODataParameters,\n\tM extends ODataSingleOperationMethod = ODataSingleOperationMethod\n>(method: M, opts: ODataSingleFetchFnRequest<M, I, I, T, P> & { transform?: undefined }): ODataFetchFnRunner<I>;\nexport function odataFetchFn<I, O = I, T = I, M extends ODataSingleOperationMethod = ODataSingleOperationMethod>(\n\tmethod: M,\n\topts: ODataSingleFetchFnRequest<M, I, O, T> & { transform: ODataSingleTransform<I, O> }\n): ODataFetchFnRunner<O>;\nexport function odataFetchFn<\n\tI,\n\tO = I,\n\tT = I,\n\tP extends UnwrappedODataParameters = UnwrappedODataParameters,\n\tM extends ODataOperationMethod = ODataOperationMethod\n>(method: M, opts: ODataFetchFnRequest<M, I, O, T, P>): ODataFetchFnRunner<unknown>;\nexport function odataFetchFn(...args: ODataFetchFnImplementationArgs): ODataFetchFnRunner<unknown> {\n\tconst [method, opts] = args;\n\tconst { odata, options = {}, init = {}, autoParse, swCache } = opts;\n\tconst params = \"params\" in opts ? (opts.params ?? {}) : {};\n\t// const body = \"body\" in opts ? opts.body : undefined;\n\n\t/**\n\t * `client` нужен для использования кеша\n\t */\n\treturn async ({ client, signal }: { client: QueryClient; signal?: AbortSignal }) => {\n\t\tconst baseUrl = resolveODataBaseUrl(odata.service, options.baseUrl);\n\n\t\tconst serviceMetadata = await getODataMetadataData({ service: odata.service, baseUrl }, client);\n\t\tif (!serviceMetadata) {\n\t\t\tthrow new Error(`Не удалось загрузить metadata OData-сервиса '${odata.service}'`);\n\t\t}\n\n\t\tconst target = resolveODataTarget(serviceMetadata, odata.target);\n\n\t\tvalidateODataOperation(target, method, odata);\n\n\t\tconst body = \"body\" in opts ? resolveRequestBody(opts.body, method) : undefined;\n\t\tconst requestMethod = resolveRequestMethod(target, method);\n\n\t\tif (__DEV__ && method === \"query\" && !(\"result\" in target) && Object.keys(params).length > 0) {\n\t\t\tconsole.warn(\n\t\t\t\t`OData query для plain entity \"${odata.service}/${odata.target}\" получил params, но они будут проигнорированы. Для чтения сущности по ключу используйте odataReadFn.`\n\t\t\t);\n\t\t}\n\n\t\tconst targetPath = buildTargetPath(target, odata, params, method);\n\n\t\tconst queryOptions = swCache ? { ...options, baseUrl, swCache } : { ...options, baseUrl };\n\t\tconst requestInit = { ...init, method: requestMethod, body, signal };\n\n\t\tif (method === \"query\") {\n\t\t\tconst response = await odataFetch<unknown, unknown[]>(targetPath, queryOptions, requestInit);\n\n\t\t\tif (isNoContentResponse(response)) {\n\t\t\t\tthrow new Error(\"OData query не должен возвращать 204 No Content\");\n\t\t\t}\n\n\t\t\tconst parsedData = autoParse ? parseODataResponseByMetadata(response.data, target, serviceMetadata) : response.data;\n\t\t\tconst transformedData = opts.transform ? opts.transform(parsedData, target) : parsedData;\n\n\t\t\treturn { data: transformedData, totalCount: response.totalCount };\n\t\t}\n\n\t\t// NOTE: немного дублирования кода ради правильной типизации без использования 'as' это нормальный компромисс и часто используемая практика\n\n\t\tconst response = await odataFetch<unknown>(targetPath, queryOptions, requestInit);\n\n\t\tif (isNoContentResponse(response)) {\n\t\t\treturn { data: response.data };\n\t\t}\n\n\t\tconst parsedData = autoParse ? parseODataResponseByMetadata(response.data, target, serviceMetadata) : response.data;\n\t\tconst transformedData = opts.transform ? opts.transform(parsedData, target) : parsedData;\n\n\t\treturn { data: transformedData, totalCount: response.totalCount };\n\t};\n}\n\n/**\n * Создаёт queryFn для OData `create`-операции.\n *\n * Только для `Entity`.\n *\n * Обязательные поля конфигурации:\n *\n * ```ts\n * {\n * \todata: ODataServiceConfig;\n * \tbody: T;\n * }\n * ```\n *\n * Поведение:\n *\n * - HTTP-метод: `POST`;\n * - `body` обязателен;\n * - `body` сериализуется внутри `odataFetchFn`;\n * - `params` запрещены;\n * - путь: `/SERVICE/ENTITY`;\n * - target должен быть обычной `Entity`, а не `FunctionImport`.\n *\n * Используйте эту функцию для сценариев создания записи по телу запроса, когда\n * ключи в URL не требуются.\n *\n * Обычно `I` — raw-тип ответа, а `T` — тип тела.\n * В большинстве случаев они совпадают, но при необходимости тело можно типизировать отдельно.\n *\n * Пример:\n *\n * ```ts\n * const mutationFn = odataCreateFn<Variant>({\n * \todata: { service: \"TEXT_CONFIG_SRV\", target: \"TEXT_VARIANT\" },\n * \tbody: {\n * \t\tid: \"uuid-4\",\n * \t\tname: \"Новый вариант\"\n * \t}\n * });\n * ```\n */\nexport function odataCreateFn<I, T = I>(opts: ODataCreateFnOptions<I, I, T> & { transform?: undefined }): ODataFetchFnRunner<I>;\nexport function odataCreateFn<I, O = I, T = I>(\n\topts: ODataCreateFnOptions<I, O, T> & { transform: ODataSingleTransform<I, O> }\n): ODataFetchFnRunner<O>;\nexport function odataCreateFn<I, O = I, T = I>(opts: ODataCreateFnOptions<I, O, T>) {\n\treturn odataFetchFn<I, O, T, never, \"create\">(\"create\", opts);\n}\n\n/**\n * Создаёт queryFn для OData `update`-операции.\n *\n * Только для `Entity`.\n *\n * Обязательные поля конфигурации:\n *\n * ```ts\n * {\n * \todata: ODataServiceConfig;\n * \tparams: UnwrappedODataParameters;\n * \tbody: T;\n * }\n * ```\n *\n * Поведение:\n *\n * - HTTP-метод: `PUT`;\n * - `params` обязательны и используются для построения key/path части URL;\n * - `body` обязателен и сериализуется внутри функции;\n * - путь: `/SERVICE/ENTITY(params...)`;\n * - target должен быть `Entity`.\n *\n * Используйте эту функцию, когда backend ожидает одновременную передачу ключа\n * в URL и обновляемого состояния в теле запроса.\n *\n * @example\n * ```ts\n * const mutationFn = odataUpdateFn<ThemePayload>({\n * \todata: { service: \"TEXT_CONFIG_SRV\", target: \"TEXT_THEME\" },\n * \tparams: wrapODataParams({ name: value }),\n * \tbody: { name: value }\n * });\n * ```\n */\nexport function odataUpdateFn<I, T = I, P extends UnwrappedODataParameters = UnwrappedODataParameters>(\n\topts: ODataUpdateFnOptions<I, I, T, P> & { transform?: undefined }\n): ODataFetchFnRunner<I>;\nexport function odataUpdateFn<I, O = I, T = I, P extends UnwrappedODataParameters = UnwrappedODataParameters>(\n\topts: ODataUpdateFnOptions<I, O, T, P> & { transform: ODataSingleTransform<I, O> }\n): ODataFetchFnRunner<O>;\nexport function odataUpdateFn<I, O = I, T = I, P extends UnwrappedODataParameters = UnwrappedODataParameters>(\n\topts: ODataUpdateFnOptions<I, O, T, P>\n) {\n\treturn odataFetchFn<I, O, T, P, \"update\">(\"update\", opts);\n}\n\n/**\n * Создаёт queryFn для OData `delete`-операции.\n *\n * Только для `Entity`.\n *\n * Обязательные поля конфигурации:\n *\n * ```ts\n * {\n * \todata: ODataServiceConfig;\n * \tparams: UnwrappedODataParameters;\n * }\n * ```\n *\n * Поведение:\n *\n * - HTTP-метод: `DELETE`;\n * - `params` обязательны;\n * - `body` не поддерживается;\n * - путь: `/SERVICE/ENTITY(params...)`;\n * - target должен быть `Entity`.\n *\n * Подходит для удаления записи по ключу, когда backend игнорирует тело запроса\n * и определяет удаляемую сущность только по параметрам URL.\n *\n * @example\n * ```ts\n * const mutationFn = odataDeleteFn({\n * \todata: { service: \"TEXT_CONFIG_SRV\", target: \"TextPresetSet\" },\n * \tparams: wrapODataParams({ recId: \"uuid-1\" })\n * });\n * ```\n */\nexport function odataDeleteFn<I, T = I, P extends UnwrappedODataParameters = UnwrappedODataParameters>(\n\topts: ODataDeleteFnOptions<I, I, P> & { transform?: undefined }\n): ODataFetchFnRunner<I>;\nexport function odataDeleteFn<I, O = I, T = I, P extends UnwrappedODataParameters = UnwrappedODataParameters>(\n\topts: ODataDeleteFnOptions<I, O, P> & { transform: ODataSingleTransform<I, O> }\n): ODataFetchFnRunner<O>;\nexport function odataDeleteFn<I, O = I, T = I, P extends UnwrappedODataParameters = UnwrappedODataParameters>(\n\topts: ODataDeleteFnOptions<I, O, P>\n) {\n\treturn odataFetchFn<I, O, T, P, \"delete\">(\"delete\", opts);\n}\n\n/**\n * Создаёт queryFn для OData `read`-операции.\n *\n * Только для `Entity`.\n *\n * Обязательные поля конфигурации:\n *\n * ```ts\n * {\n * \todata: ODataServiceConfig;\n * \tparams: UnwrappedODataParameters;\n * }\n * ```\n *\n * Поведение:\n *\n * - HTTP-метод: `GET`;\n * - `params` обязательны;\n * - `body` не поддерживается;\n * - путь: `/SERVICE/ENTITY(params...)`;\n * - нельзя использовать для parameterized query entity, у которой в metadata есть `result`.\n *\n * Это режим чтения конкретной сущности или key-based target.\n * Если target на самом деле является query-сущностью с `/Set` или `/Results`,\n * нужно использовать `odataQueryFn`.\n *\n * @example\n * ```ts\n * const queryFn = odataReadFn<Variant>({\n * \todata: { service: \"TEXT_CONFIG_SRV\", target: \"TEXT_VARIANT\" },\n * \tparams: wrapODataParams({ variantId: \"uuid-1\" })\n * });\n * ```\n */\nexport function odataReadFn<I, T = I, P extends UnwrappedODataParameters = UnwrappedODataParameters>(\n\topts: ODataReadFnOptions<I, I, P> & { transform?: undefined }\n): ODataFetchFnRunner<I>;\nexport function odataReadFn<I, O = I, T = I, P extends UnwrappedODataParameters = UnwrappedODataParameters>(\n\topts: ODataReadFnOptions<I, O, P> & { transform: ODataSingleTransform<I, O> }\n): ODataFetchFnRunner<O>;\nexport function odataReadFn<I, O = I, T = I, P extends UnwrappedODataParameters = UnwrappedODataParameters>(\n\topts: ODataReadFnOptions<I, O, P>\n) {\n\treturn odataFetchFn<I, O, T, P, \"read\">(\"read\", opts);\n}\n\n/**\n * Создаёт queryFn для OData `query`-операции.\n *\n * Это основной helper для чтения списков и query-сущностей.\n *\n * Поведение зависит от metadata target:\n *\n * - для обычной `Entity` путь будет `/SERVICE/ENTITY`;\n * - для parameterized query entity путь будет `/SERVICE/ENTITY(params...)/Set` или `/Results`.\n *\n * Конфигурация:\n *\n * ```ts\n * {\n * \todata: ODataServiceConfig;\n * \tparams?: UnwrappedODataParameters;\n * \toptions?: ODataFetchOptions<T>;\n * }\n * ```\n *\n * Особенности:\n *\n * - HTTP-метод всегда `GET`;\n * - `params` необязательны на уровне типов;\n * - для plain entity переданные `params` будут проигнорированы;\n * - для query entity с `metadata.result` параметры реально участвуют в URL;\n * - `body` не поддерживается.\n *\n * Это функция по умолчанию для большинства `useQuery`-сценариев в проекте.\n *\n * @example\n * ```ts\n * const queryFn = odataQueryFn<RawRow, Row>({\n * \todata: { service: \"TEXT_REPORT_SRV\", target: \"TEXT_REPORT_ENTITY\" },\n * \tparams: wrapODataParams({\n * \t\tp_date: new Date(),\n * \t\tp_date_to: new Date(),\n * \t\ttype_manager: \"main\"\n * \t}),\n * \tautoParse: true,\n * \ttransform: (rows) => rows.map(mapRow)\n * });\n * ```\n */\nexport function odataQueryFn<I, O = I, P extends UnwrappedODataParameters = UnwrappedODataParameters>(\n\topts: ODataQueryFnOptions<I, O, P> & { transform: ODataQueryArrayTransform<I, O> }\n): ODataFetchFnRunner<O[]>;\nexport function odataQueryFn<I, O = I, P extends UnwrappedODataParameters = UnwrappedODataParameters>(\n\topts: ODataQueryFnOptions<I, O, P> & { transform: ODataQuerySingleTransform<I, O> }\n): ODataFetchFnRunner<O>;\nexport function odataQueryFn<I, O = I, P extends UnwrappedODataParameters = UnwrappedODataParameters>(\n\topts: ODataQueryFnOptions<I, I, P> & { transform?: undefined }\n): ODataFetchFnRunner<I[]>;\nexport function odataQueryFn<I, O = I, P extends UnwrappedODataParameters = UnwrappedODataParameters>(opts: ODataQueryFnOptions<I, O, P>) {\n\treturn odataFetchFn<I, O, void, P, \"query\">(\"query\", opts);\n}\n\n/**\n * Создаёт queryFn для вызова OData `FunctionImport`.\n *\n * Используйте эту функцию только для target, который опубликован в metadata как `FunctionImport`.\n *\n * Конфигурация:\n *\n * ```ts\n * {\n * \todata: ODataServiceConfig;\n * \tparams: UnwrappedODataParameters;\n * }\n * ```\n *\n * Поведение:\n *\n * - HTTP-метод берётся из metadata `FunctionImport`;\n * - если metadata не содержит `httpMethod`, будет выброшена ошибка;\n * - `params` обязательны;\n * - `body` не поддерживается;\n * - параметры target попадают в query string;\n * - `options` (`$select`, `$top`, `$filter` и т.д.) дописываются в тот же query string.\n *\n * Эта функция нужна для вызовов backend-операций, опубликованных как `FunctionImport`,\n * когда transport-семантика определяется самим OData-сервисом.\n *\n * @example\n * ```ts\n * const mutationFn = odataFunctionImportFn<CreateTransportRequestRaw, TransportRequest>({\n * \todata: { service: \"TEXT_CONFIG_SRV\", target: \"createTextRequest\" },\n * \tparams: wrapODataParams({\n * \t\ttype: \"workbench\",\n * \t\ttext: \"Новый транспорт\"\n * \t}),\n * \ttransform: (raw) => mapCreatedTransportRequest(raw, \"workbench\")\n * });\n * ```\n */\nexport function odataFunctionImportFn<I, T = I, P extends UnwrappedODataParameters = UnwrappedODataParameters>(\n\topts: ODataFunctionImportFnOptions<I, I, P> & { transform?: undefined }\n): ODataFetchFnRunner<I>;\nexport function odataFunctionImportFn<I, O = I, T = I, P extends UnwrappedODataParameters = UnwrappedODataParameters>(\n\topts: ODataFunctionImportFnOptions<I, O, P> & { transform: ODataSingleTransform<I, O> }\n): ODataFetchFnRunner<O>;\nexport function odataFunctionImportFn<I, O = I, T = I, P extends UnwrappedODataParameters = UnwrappedODataParameters>(\n\topts: ODataFunctionImportFnOptions<I, O, P>\n) {\n\treturn odataFetchFn<I, O, T, P, \"fi\">(\"fi\", opts);\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"odataFetchFn-CJIPv-CJ.js","names":[],"sources":["../../src/odata/odataBaseQueryKey.ts","../../src/odata/odataFetch.ts","../../src/odata/metadataVersionCheck.ts","../../src/odata/useODataMetadataQuery.ts","../../src/odata/odataFetchFnHelpers.ts","../../src/odata/parseODataResponseByMetadata.ts","../../src/odata/odataFetchFn.ts"],"sourcesContent":["export const odataBaseQueryKey = [\"odata\"] as const;\n","import { buildODataFilter, buildODataOrder, type FilterExpression, type Sort } from \"@ryuzaki13/react-foundation-lib/odata-service\";\n\nimport { BaseUrlMap, BaseURLType, fetchODataJson } from \"./transport\";\n\nexport type ODataFetchOptions<T> = {\n\t/**\n\t * Фильтры.\n\t *\n\t * Корневой объект всегда определяет выражение, которое может состоять из вложенных условий (`conditions: FilterCondition<T>[]`),\n\t * либо из других выражений (`filters: FilterExpression<T>[]`).\n\t *\n\t * @example\n\t *\n\t * // С использование фабричных функций (рекомендуется)\n\t *\n\t * expression: {\n\t * and: true,\n\t * filters: [\n\t * createFilterBetween(\"FKDAT\", range),\n\t * createFilterEqual(\"TEXT_NODE\", branches),\n\t * createFilterContains(\"VSTEL\", branchStocks),\n\t * ]\n\t * }\n\t *\n\t * // Без использования фабричных функций (КРАЙНЕ НЕ РЕКОМЕНДУЕТСЯ ТАК ДЕЛАТЬ!)\n\t *\n\t * expression: {\n\t * and: true,\n\t * filters: [\n\t * {\n\t * and: true,\n\t * conditions: [\n\t * { key: \"FKDAT\", value: range[0], operation: \"ge\" },\n\t * { key: \"FKDAT\", value: range[1], operation: \"le\" }\n\t * ]\n\t * },\n\t * {\n\t * conditions: [\n\t * { key: \"TEXT_NODE\", value: \"0202\", operation: \"eq\" },\n\t * { key: \"TEXT_NODE\", value: \"0204\", operation: \"eq\" }\n\t * ]\n\t * },\n\t * {\n\t * conditions: [\n\t * { key: \"VSTEL\", value: \"1158\", operation: \"contains\" },\n\t * { key: \"VSTEL\", value: \"1988\", operation: \"contains\" }\n\t * ]\n\t * }\n\t * ]\n\t * }\n\t */\n\texpression?: FilterExpression<T>;\n\n\t// grouping?: (keyof T)[];\n\tsorts?: Sort<keyof T>[];\n\tselect?: (keyof T)[];\n\texpand?: (keyof T)[];\n\ttop?: number;\n\tskip?: number;\n\n\tinlinecount?: string;\n\tformat?: \"json\";\n\tbaseUrl?: BaseURLType;\n\n\t/**\n\t * Политика кеширования в Service Worker.\n\t *\n\t * - `\"off\"` — network-only (по умолчанию)\n\t * - `\"ttl=24h\"` — cache-first с TTL\n\t * - `\"ttl=10m;max=200;name=ui\"` — TTL с лимитом записей и именованным кешем\n\t * - `\"bust=24h;name=ref\"` — принудительное обновление кеша из сети\n\t */\n\tswCache?: string;\n};\n\nfunction appendQueryOption(query: URLSearchParams, key: string, value?: string | number) {\n\tif (value === undefined || value === \"\") return;\n\tquery.set(key, String(value));\n}\n\nexport type ODataFetchRequestPreview = {\n\tpath: string;\n\tfullUrl: string;\n\tbaseUrl: BaseURLType | undefined;\n\tinit: RequestInit;\n\tqueryString: string;\n};\n\nexport function buildODataFetchRequest<T>(entitySetPath: string, options: ODataFetchOptions<T> = {}, init: RequestInit = {}) {\n\tconst [rawPath, rawQuery = \"\"] = entitySetPath.split(\"?\"); // Если был вызов FI\n\tconst query = new URLSearchParams(rawQuery);\n\n\tif (options.expression) {\n\t\tconst filter = buildODataFilter(options.expression);\n\t\tif (filter) query.set(\"$filter\", filter);\n\t}\n\tif (options.sorts) query.set(\"$orderby\", buildODataOrder(options.sorts));\n\tif (options.select) query.set(\"$select\", options.select.join(\",\"));\n\tif (options.expand) query.set(\"$expand\", options.expand.join(\",\"));\n\n\tappendQueryOption(query, \"$top\", options.top);\n\tappendQueryOption(query, \"$skip\", options.skip);\n\tappendQueryOption(query, \"$inlinecount\", options.inlinecount);\n\n\tconst path = rawPath.replace(/\\/+$/, \"\");\n\tconst queryString = query.toString();\n\tconst fullUrl = queryString ? `${path}?${queryString}` : path;\n\tlet requestInit = init;\n\n\t// Передаём политику SW-кеширования через заголовок x-sw-cache\n\tif (options.swCache) {\n\t\tconst headers = new Headers(init.headers);\n\t\theaders.set(\"x-sw-cache\", options.swCache);\n\t\trequestInit = { ...init, headers };\n\t}\n\n\treturn {\n\t\tpath: fullUrl,\n\t\tfullUrl: `${BaseUrlMap[options.baseUrl ?? \"odata\"]}${fullUrl}`,\n\t\tbaseUrl: options.baseUrl,\n\t\tinit: requestInit,\n\t\tqueryString\n\t} satisfies ODataFetchRequestPreview;\n}\n\nexport async function odataFetch<T, I = T>(entitySetPath: string, options: ODataFetchOptions<T> = {}, init: RequestInit = {}) {\n\tconst request = buildODataFetchRequest(entitySetPath, options, init);\n\n\treturn fetchODataJson<I>(request.path, request.init, options.baseUrl);\n}\n","import { formatDateAsODataDatetime, parseDate } from \"@ryuzaki13/react-foundation-lib/formatters\";\nimport { persistedQueryMeta } from \"@ryuzaki13/react-foundation-lib/query-client\";\nimport { QueryClient, queryOptions, QueryState } from \"@tanstack/react-query\";\n\nimport { odataBaseQueryKey } from \"./odataBaseQueryKey\";\nimport { odataFetch } from \"./odataFetch\";\nimport { getODataProjectAdapter, normalizeODataServiceName, resolveODataBaseUrl } from \"./odataProjectAdapter\";\n\nimport type { ODataServiceConfig } from \"@ryuzaki13/react-foundation-lib/odata-service\";\n\nconst METADATA_VERSION_BUILD_ID = __APP_BUILD_ID__;\nconst METADATA_VERSION_STALE_TIME = 1000 * 60 * 60 * 24;\n\nexport interface ODataMetadataVersionOptions extends Pick<ODataServiceConfig, \"service\"> {\n\tstaleTime?: number;\n}\n\ninterface ODataMetadataVersionRecord {\n\tserviceName: string;\n\tlastChanged: string;\n}\n\nexport interface ODataMetadataVersionResult {\n\tservice: string;\n\tchangedAt: Date | null;\n\tversion: string | null;\n}\n\nfunction selectMetadataVersionRecord(records: ODataMetadataVersionRecord[] | ODataMetadataVersionRecord | undefined) {\n\tif (!records) return undefined;\n\treturn Array.isArray(records) ? records[0] : records;\n}\n\nexport const createODataMetadataVersionQueryKey = ({ service }: Pick<ODataServiceConfig, \"service\">) =>\n\t[...odataBaseQueryKey, \"metadata-version\", { service, buildId: METADATA_VERSION_BUILD_ID }] as const;\n\nfunction createEmptyMetadataVersionResult(service: string): ODataMetadataVersionResult {\n\treturn {\n\t\tservice,\n\t\tchangedAt: null,\n\t\tversion: null\n\t};\n}\n\n/**\n * Загружает время последней генерации OData-сервиса из технического CDS.\n * Эти данные не заменяют metadata, а служат версией для точечной инвалидации metadata query.\n */\nexport function fetchMetadataVersion(options: Pick<ODataServiceConfig, \"service\">) {\n\treturn async ({ signal }: { signal: AbortSignal }): Promise<ODataMetadataVersionResult> => {\n\t\tconst endpoint = getODataProjectAdapter().metadataVersion;\n\t\tif (!endpoint) return createEmptyMetadataVersionResult(options.service);\n\n\t\tconst response = await odataFetch<ODataMetadataVersionRecord, ODataMetadataVersionRecord[]>(\n\t\t\t`/${endpoint.service}/${endpoint.target}('${normalizeODataServiceName(options.service)}')`,\n\t\t\t{\n\t\t\t\tbaseUrl: resolveODataBaseUrl(endpoint.service, endpoint.baseUrl)\n\t\t\t},\n\t\t\t{ signal }\n\t\t);\n\n\t\tconst record = selectMetadataVersionRecord(response.data);\n\t\tconst changedAt = parseDate(record?.lastChanged);\n\n\t\treturn {\n\t\t\tservice: options.service,\n\t\t\tchangedAt,\n\t\t\tversion: changedAt ? formatDateAsODataDatetime(changedAt) : null\n\t\t};\n\t};\n}\n\n/**\n * Описывает отдельный TanStack Query для версии metadata.\n * Query хранится отдельно от самих metadata, чтобы частоту проверки можно было регулировать независимо.\n */\nexport const odataMetadataVersionQueryOptions = (options: ODataMetadataVersionOptions) =>\n\tqueryOptions({\n\t\tqueryKey: createODataMetadataVersionQueryKey(options),\n\t\tqueryFn: fetchMetadataVersion(options),\n\t\tmeta: persistedQueryMeta,\n\t\tenabled: Boolean(options.service && getODataProjectAdapter().metadataVersion),\n\t\tstaleTime: options.staleTime ?? METADATA_VERSION_STALE_TIME,\n\t\tgcTime: Infinity\n\t});\n\n/**\n * Инвалидирует только metadata query указанного сервиса.\n * Version-check query и metadata других сервисов при этом остаются нетронутыми.\n */\nexport function invalidateODataMetadataQueries(queryClient: QueryClient, service: string) {\n\treturn queryClient.invalidateQueries({\n\t\tpredicate: (query) => {\n\t\t\tconst [baseKey, queryType, queryOptionsValue] = query.queryKey;\n\t\t\tif (baseKey !== odataBaseQueryKey[0] || queryType !== \"metadata\") return false;\n\t\t\tif (!queryOptionsValue || typeof queryOptionsValue !== \"object\") return false;\n\n\t\t\treturn \"service\" in queryOptionsValue && queryOptionsValue.service === service;\n\t\t}\n\t});\n}\n\nexport function shouldRefreshODataMetadataByVersion(\n\tmetadataState: QueryState<unknown, Error> | undefined,\n\tversion: ODataMetadataVersionResult\n) {\n\tif (metadataState?.data === undefined) return false;\n\tif (!version.changedAt) return false;\n\treturn version.changedAt.getTime() > metadataState.dataUpdatedAt;\n}\n","import { useEffect, useMemo } from \"react\";\n\nimport { parseServiceMetadata } from \"@ryuzaki13/react-foundation-lib/odata-service\";\nimport { persistedQueryMeta } from \"@ryuzaki13/react-foundation-lib/query-client\";\nimport { QueryClient, queryOptions, useQuery, useQueryClient } from \"@tanstack/react-query\";\n\nimport {\n\tinvalidateODataMetadataQueries,\n\tODataMetadataVersionOptions,\n\todataMetadataVersionQueryOptions,\n\tODataMetadataVersionResult,\n\tshouldRefreshODataMetadataByVersion\n} from \"./metadataVersionCheck\";\nimport { odataBaseQueryKey } from \"./odataBaseQueryKey\";\nimport { BaseURLType, fetchQueryFn, resolveODataBaseUrl } from \"./transport\";\n\nimport type { ODataServiceConfig } from \"@ryuzaki13/react-foundation-lib/odata-service\";\n\ntype ODataMetadataOptions = Pick<ODataServiceConfig, \"service\"> & { baseUrl?: BaseURLType };\n\nexport function fetchMetadata(options: ODataMetadataOptions) {\n\treturn fetchQueryFn(`/${options.service}/$metadata`, {\n\t\tbaseUrl: resolveODataBaseUrl(options.service, options.baseUrl),\n\t\tinit: {\n\t\t\theaders: {\n\t\t\t\tAccept: \"*/*\",\n\t\t\t\t\"Content-Type\": \"application/xml\"\n\t\t\t}\n\t\t},\n\t\ttransform: async (data) => {\n\t\t\ttry {\n\t\t\t\treturn parseServiceMetadata(await data.text());\n\t\t\t} catch (error) {\n\t\t\t\tthrow new Error(`Сервис ${options.service} содержит необработанную ошибку: ${String(error)}`);\n\t\t\t}\n\t\t}\n\t});\n}\n\nexport const odataMetadataQueryOptions = (options: ODataMetadataOptions) =>\n\tqueryOptions({\n\t\tqueryKey: [...odataBaseQueryKey, \"metadata\", options],\n\t\tqueryFn: fetchMetadata(options),\n\t\tmeta: persistedQueryMeta,\n\t\tenabled: Boolean(options.service),\n\t\t/**\n\t\t * Метаданные хранятся без временного протухания.\n\t\t * Актуальность контролируется отдельным version-check query по времени генерации сервиса.\n\t\t */\n\t\tstaleTime: Infinity,\n\t\tgcTime: Infinity\n\t});\n\n/**\n * Применяет результат version-check к metadata query на уровне общего QueryClient.\n * Metadata refetch нужен только если серверная версия новее времени обновления metadata cache.\n */\nexport async function applyODataMetadataVersion(\n\tqueryClient: QueryClient,\n\toptions: ODataMetadataOptions,\n\tversion: ODataMetadataVersionResult\n) {\n\tif (!options.service) return;\n\n\tconst metadataQueryKey = odataMetadataQueryOptions(options).queryKey;\n\tconst metadataState = queryClient.getQueryState(metadataQueryKey);\n\tconst shouldRefresh = shouldRefreshODataMetadataByVersion(metadataState, version);\n\n\tif (shouldRefresh) {\n\t\tawait invalidateODataMetadataQueries(queryClient, options.service);\n\t}\n}\n\nexport function useODataMetadataQuery(options: ODataMetadataOptions) {\n\tconst queryClient = useQueryClient();\n\tconst metadataOptions = useMemo(() => ({ service: options.service, baseUrl: options.baseUrl }), [options.baseUrl, options.service]);\n\tconst versionOptions = useMemo(() => ({ service: options.service }), [options.service]);\n\tconst versionQuery = useQuery(odataMetadataVersionQueryOptions(versionOptions));\n\tconst metadataQuery = useQuery(odataMetadataQueryOptions(metadataOptions));\n\n\tuseEffect(() => {\n\t\tif (!options.service || !versionQuery.isSuccess) return;\n\n\t\tapplyODataMetadataVersion(queryClient, metadataOptions, versionQuery.data);\n\t}, [metadataOptions, metadataQuery.dataUpdatedAt, options.service, queryClient, versionQuery.data, versionQuery.isSuccess]);\n\n\treturn metadataQuery;\n}\n\n/**\n * Публичный доступ к результату version-check без загрузки самих metadata.\n * Полезно для глобальной диагностики и ручного управления частотой опроса.\n */\nexport function useODataMetadataVersionQuery(options: ODataMetadataVersionOptions) {\n\treturn useQuery(odataMetadataVersionQueryOptions(options));\n}\n\nasync function syncODataMetadataVersion(options: ODataMetadataOptions, queryClient: QueryClient) {\n\tconst versionOptions = { service: options.service };\n\n\ttry {\n\t\tconst nextVersion = await queryClient.fetchQuery(odataMetadataVersionQueryOptions(versionOptions));\n\t\tawait applyODataMetadataVersion(queryClient, options, nextVersion);\n\t} catch {\n\t\t// NOTE: Пока держим за правило:\n\t\t// Если технический version-check временно недоступен,\n\t\t// сохранённые metadata остаются рабочим источником для OData-запросов.\n\t}\n}\n\nexport async function getODataMetadataData(options: ODataMetadataOptions, queryClient: QueryClient) {\n\tif (!options.service) return undefined;\n\tawait queryClient.fetchQuery(odataMetadataQueryOptions(options));\n\tawait syncODataMetadataVersion(options, queryClient);\n\treturn queryClient.fetchQuery(odataMetadataQueryOptions(options));\n}\n","import {\n\tBaseMethod,\n\tbuildEntityOperationPath,\n\tbuildFunctionImportPath,\n\tFunctionImportMetadata,\n\tODataOperationMethod,\n\tODataServiceConfig,\n\tODataTargetMetadata,\n\tServiceMetadata,\n\tWrappedODataParameters\n} from \"@ryuzaki13/react-foundation-lib/odata-service\";\n\nexport function normalizeMethod(method?: string): BaseMethod | undefined {\n\tif (!method) return undefined;\n\n\tconst normalized = method.toUpperCase();\n\tif (normalized === \"GET\" || normalized === \"POST\" || normalized === \"PUT\" || normalized === \"DELETE\") {\n\t\treturn normalized;\n\t}\n\n\treturn undefined;\n}\n\nexport function isFunctionImportMetadata(target: ODataTargetMetadata): target is FunctionImportMetadata {\n\treturn \"returnType\" in target;\n}\n\nexport function resolveODataTarget(serviceData: ServiceMetadata, targetName: string): ODataTargetMetadata {\n\tconst entity = serviceData?.entities[targetName];\n\tconst functionImport = serviceData?.functionImports[targetName];\n\n\tif (entity && functionImport) {\n\t\tthrow new Error(`Найден конфликт metadata: '${targetName}' существует и как Entity, и как FunctionImport`);\n\t}\n\n\tif (entity) return entity;\n\tif (functionImport) return functionImport;\n\n\tthrow new Error(`OData target '${targetName}' не был загружен`);\n}\n\nexport function validateODataOperation(target: ODataTargetMetadata, method: ODataOperationMethod, odata: ODataServiceConfig): void {\n\tif (isFunctionImportMetadata(target)) {\n\t\tif (method !== \"fi\") {\n\t\t\tthrow new Error(\n\t\t\t\t`OData operation '${method}' несовместима с FunctionImport '${target.name}'. Для FunctionImport используйте method: 'fi'.`\n\t\t\t);\n\t\t}\n\n\t\treturn;\n\t}\n\n\tif (method === \"fi\") {\n\t\tthrow new Error(\n\t\t\t`OData operation 'fi' несовместима с Entity '${odata.target}'. Для Entity используйте один из методов: 'create', 'update', 'delete', 'read', 'query', 'fm'.`\n\t\t);\n\t}\n\n\tif (method === \"read\" && target.result) {\n\t\tthrow new Error(\n\t\t\t`OData operation '${method}' несовместима с parameterized query entity '${odata.target}'. Для target с result='${target.result}' используйте method: 'query'.`\n\t\t);\n\t}\n}\n\nexport function resolveRequestMethod(target: ODataTargetMetadata, method: ODataOperationMethod): BaseMethod {\n\tif (method === \"create\") return \"POST\";\n\tif (method === \"update\") return \"PUT\";\n\tif (method === \"delete\") return \"DELETE\";\n\tif (method === \"read\" || method === \"query\") return \"GET\";\n\n\tif (isFunctionImportMetadata(target)) {\n\t\tif (!target.httpMethod) {\n\t\t\tthrow new Error(`FunctionImport '${target.name}' не содержит httpMethod в metadata, поэтому operation 'fi' выполнить нельзя.`);\n\t\t}\n\n\t\treturn target.httpMethod;\n\t}\n\n\tthrow new Error(`OData operation '${method}' не поддерживается для target '${\"title\" in target ? target.title : \"unknown\"}'.`);\n}\n\nexport function resolveRequestBody<T = unknown>(body: T | undefined, method: ODataOperationMethod): string | undefined {\n\tif (body && (method === \"create\" || method === \"update\")) {\n\t\treturn JSON.stringify(body);\n\t}\n\treturn undefined;\n}\n\nexport function buildTargetPath(\n\ttarget: ODataTargetMetadata,\n\todata: ODataServiceConfig,\n\tparams: WrappedODataParameters,\n\tmethod: ODataOperationMethod\n): string {\n\tif (isFunctionImportMetadata(target)) {\n\t\treturn buildFunctionImportPath(target, odata, params);\n\t}\n\n\tif (method === \"fi\") {\n\t\tthrow new Error(`OData operation 'fi' несовместима с Entity '${odata.target}'.`);\n\t}\n\n\treturn buildEntityOperationPath(target, odata, params, method);\n}\n","import { odataParseValueByMetadata } from \"@ryuzaki13/react-foundation-lib/odata-service\";\nimport { isRecord } from \"@ryuzaki13/react-foundation-lib/validators\";\n\nimport { isFunctionImportMetadata } from \"./odataFetchFnHelpers\";\n\nimport type { EntityColumnProperty, ODataTargetMetadata, ServiceMetadata } from \"@ryuzaki13/react-foundation-lib/odata-service\";\n\ntype ParsingColumnDescriptor = Pick<EntityColumnProperty, \"id\" | \"type\" | \"abapBooleanLike\">;\n\nfunction resolveParsingColumns(target: ODataTargetMetadata, serviceMetadata: ServiceMetadata): EntityColumnProperty[] | undefined {\n\tif (!isFunctionImportMetadata(target)) {\n\t\treturn target.columns;\n\t}\n\n\tif (!target.resultEntity) return undefined;\n\treturn serviceMetadata.entities[target.resultEntity]?.columns;\n}\n\nfunction createParsingPlan(columns: EntityColumnProperty[]): ParsingColumnDescriptor[] {\n\tconst parsingPlan: ParsingColumnDescriptor[] = [];\n\n\tfor (let index = 0; index < columns.length; index += 1) {\n\t\tconst column = columns[index];\n\t\tparsingPlan.push({\n\t\t\tid: column.id,\n\t\t\ttype: column.type,\n\t\t\tabapBooleanLike: column.abapBooleanLike\n\t\t});\n\t}\n\n\treturn parsingPlan;\n}\n\nfunction parsePlainRecord(record: Record<string, unknown>, parsingPlan: ParsingColumnDescriptor[]) {\n\tlet parsedRecord: Record<string, unknown> | undefined;\n\n\tfor (let index = 0; index < parsingPlan.length; index += 1) {\n\t\tconst descriptor = parsingPlan[index];\n\t\tif (!Object.prototype.hasOwnProperty.call(record, descriptor.id)) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tconst sourceValue = record[descriptor.id];\n\t\tconst parsedValue = odataParseValueByMetadata(descriptor, sourceValue);\n\t\tif (parsedValue === sourceValue) {\n\t\t\tcontinue;\n\t\t}\n\n\t\tif (!parsedRecord) {\n\t\t\tparsedRecord = { ...record };\n\t\t}\n\n\t\tparsedRecord[descriptor.id] = parsedValue;\n\t}\n\n\treturn parsedRecord ?? record;\n}\n\nexport function parseODataResponseByMetadata<I>(data: I[], target: ODataTargetMetadata, serviceMetadata: ServiceMetadata): I[];\nexport function parseODataResponseByMetadata<I>(data: I, target: ODataTargetMetadata, serviceMetadata: ServiceMetadata): I;\nexport function parseODataResponseByMetadata<I>(data: I | I[], target: ODataTargetMetadata, serviceMetadata: ServiceMetadata): I | I[] {\n\tconst columns = resolveParsingColumns(target, serviceMetadata);\n\tif (!columns?.length) return data;\n\n\tconst parsingPlan = createParsingPlan(columns);\n\n\tif (Array.isArray(data)) {\n\t\tlet parsedItems: unknown[] | undefined;\n\n\t\tfor (let index = 0; index < data.length; index += 1) {\n\t\t\tconst item = data[index];\n\t\t\tif (!isRecord(item)) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tconst parsedItem = parsePlainRecord(item, parsingPlan);\n\t\t\tif (parsedItem === item) {\n\t\t\t\tcontinue;\n\t\t\t}\n\n\t\t\tif (!parsedItems) {\n\t\t\t\tparsedItems = data.slice();\n\t\t\t}\n\n\t\t\tparsedItems[index] = parsedItem;\n\t\t}\n\n\t\treturn (parsedItems ?? data) as I[];\n\t}\n\n\tif (isRecord(data)) {\n\t\treturn parsePlainRecord(data, parsingPlan) as I;\n\t}\n\n\treturn data;\n}\n","/* eslint-disable @typescript-eslint/no-unused-vars */\nimport { QueryClient } from \"@tanstack/react-query\";\n\nimport { odataFetch, ODataFetchOptions } from \"./odataFetch\";\nimport {\n\tbuildTargetPath,\n\tresolveODataTarget,\n\tresolveRequestBody,\n\tresolveRequestMethod,\n\tvalidateODataOperation\n} from \"./odataFetchFnHelpers\";\nimport { parseODataResponseByMetadata } from \"./parseODataResponseByMetadata\";\nimport { isNoContentResponse, resolveODataBaseUrl } from \"./transport/fetch\";\nimport { getODataMetadataData } from \"./useODataMetadataQuery\";\n\nimport type {\n\tODataOperationMethod,\n\tODataServiceConfig,\n\tODataTargetMetadata,\n\tUnwrappedODataParameters,\n\tWrapODataParameters\n} from \"@ryuzaki13/react-foundation-lib/odata-service\";\n\nexport interface ODataFetchFnSharedOptions<I> {\n\t/**\n\t * Параметры OData сервиса\n\t */\n\todata: ODataServiceConfig;\n\n\t/**\n\t * Параметры для формирования дополнительных query param.\n\t */\n\toptions?: NoInfer<ODataFetchOptions<I>>;\n\n\t/**\n\t * Параметры fetch запроса\n\t */\n\tinit?: Omit<RequestInit, \"signal\" | \"method\" | \"body\">;\n\n\tautoParse?: boolean;\n\n\t/**\n\t * Политика кеширования в Service Worker.\n\t * @see ODataFetchOptions.swCache\n\t */\n\tswCache?: string;\n}\n\nexport type ODataSingleTransform<I, O> = (data: NoInfer<I>, target: ODataTargetMetadata) => NoInfer<O>;\nexport type ODataQueryArrayTransform<I, O> = (data: NoInfer<I>[], target: ODataTargetMetadata) => NoInfer<O>[];\nexport type ODataQuerySingleTransform<I, O> = (data: NoInfer<I>[], target: ODataTargetMetadata) => NoInfer<O>;\nexport type ODataQueryTransform<I, O> = (data: NoInfer<I>[], target: ODataTargetMetadata) => NoInfer<O>[] | NoInfer<O>;\n\nexport type ODataFetchFnSingleOptions<I, O = I> = ODataFetchFnSharedOptions<I> & {\n\ttransform?: ODataSingleTransform<I, O>;\n};\n\nexport type ODataFetchFnQueryOptions<\n\tI,\n\tO = I,\n\tP extends UnwrappedODataParameters = UnwrappedODataParameters\n> = ODataFetchFnSharedOptions<I> & {\n\tparams?: WrapODataParameters<P>;\n\ttransform?: ODataQueryTransform<I, O>;\n};\n\nexport type ODataCreateFnOptions<I, O = I, T = I> = ODataFetchFnSingleOptions<I, O> & {\n\tbody: T;\n};\n\nexport type ODataUpdateFnOptions<\n\tI,\n\tO = I,\n\tT = I,\n\tP extends UnwrappedODataParameters = UnwrappedODataParameters\n> = ODataFetchFnSingleOptions<I, O> & {\n\tparams: WrapODataParameters<P>;\n\tbody: T;\n};\n\nexport type ODataDeleteFnOptions<I, O = I, P extends UnwrappedODataParameters = UnwrappedODataParameters> = ODataFetchFnSingleOptions<\n\tI,\n\tO\n> & {\n\tparams: WrapODataParameters<P>;\n};\n\nexport type ODataReadFnOptions<I, O = I, P extends UnwrappedODataParameters = UnwrappedODataParameters> = ODataFetchFnSingleOptions<\n\tI,\n\tO\n> & {\n\tparams: WrapODataParameters<P>;\n};\n\nexport type ODataQueryFnOptions<I, O = I, P extends UnwrappedODataParameters = UnwrappedODataParameters> = ODataFetchFnQueryOptions<\n\tI,\n\tO,\n\tP\n>;\n\nexport type ODataFunctionImportFnOptions<\n\tI,\n\tO = I,\n\tP extends UnwrappedODataParameters = UnwrappedODataParameters\n> = ODataFetchFnSingleOptions<I, O> & {\n\tparams: WrapODataParameters<P>;\n};\n\nexport type ODataSingleOperationMethod = Exclude<ODataOperationMethod, \"query\">;\nexport type ODataArrayOperationMethod = \"query\";\n\nexport type ODataSingleFetchFnRequest<\n\tM extends ODataSingleOperationMethod,\n\tI,\n\tO = I,\n\tT = I,\n\tP extends UnwrappedODataParameters = UnwrappedODataParameters\n> = M extends \"create\"\n\t? ODataCreateFnOptions<I, O, T>\n\t: M extends \"update\"\n\t\t? ODataUpdateFnOptions<I, O, T, P>\n\t\t: M extends \"delete\"\n\t\t\t? ODataDeleteFnOptions<I, O, P>\n\t\t\t: M extends \"read\"\n\t\t\t\t? ODataReadFnOptions<I, O, P>\n\t\t\t\t: M extends \"fi\"\n\t\t\t\t\t? ODataFunctionImportFnOptions<I, O, P>\n\t\t\t\t\t: never;\n\nexport type ODataFetchFnRequest<\n\tM extends ODataOperationMethod,\n\tI,\n\tO = I,\n\tT = I,\n\tP extends UnwrappedODataParameters = UnwrappedODataParameters\n> = M extends \"query\"\n\t? ODataQueryFnOptions<I, O, P>\n\t: M extends ODataSingleOperationMethod\n\t\t? ODataSingleFetchFnRequest<M, I, O, T, P>\n\t\t: never;\n\nexport type ODataFetchFnImplementationArgs =\n\t| [method: \"create\", opts: ODataCreateFnOptions<unknown, unknown, unknown>]\n\t| [method: \"update\", opts: ODataUpdateFnOptions<unknown, unknown, unknown, UnwrappedODataParameters>]\n\t| [method: \"delete\", opts: ODataDeleteFnOptions<unknown, unknown, UnwrappedODataParameters>]\n\t| [method: \"read\", opts: ODataReadFnOptions<unknown, unknown, UnwrappedODataParameters>]\n\t| [method: \"query\", opts: ODataQueryFnOptions<unknown, unknown, UnwrappedODataParameters>]\n\t| [method: \"fi\", opts: ODataFunctionImportFnOptions<unknown, unknown, UnwrappedODataParameters>];\n\nexport type ODataFetchFnRunnerResult<TData> = { data: TData; totalCount?: number };\nexport type ODataFetchFnRunner<TData> = ({\n\tclient,\n\tsignal\n}: {\n\tclient: QueryClient;\n\tsignal?: AbortSignal;\n}) => Promise<ODataFetchFnRunnerResult<TData>>;\n\n/**\n * Базовый конструктор OData queryFn с явным указанием операции.\n *\n * Это низкоуровневый helper, на котором построены публичные функции:\n *\n * - `odataCreateFn`\n * - `odataUpdateFn`\n * - `odataDeleteFn`\n * - `odataReadFn`\n * - `odataQueryFn`\n * - `odataFunctionImportFn`\n *\n * В обычном прикладном коде рекомендуется использовать именно эти специализированные\n * helpers, а не вызывать `odataFetchFn` напрямую.\n *\n * Что делает функция:\n *\n * - загружает metadata OData-сервиса через `react-query`;\n * - определяет тип target: `Entity` или `FunctionImport`;\n * - валидирует совместимость target и операции;\n * - вычисляет HTTP-метод;\n * - строит path target с учётом metadata;\n * - объединяет `params` target и `options` уровня query string;\n * - при наличии `body` сериализует его через `JSON.stringify`;\n * - может автоматически распарсить ответ по metadata;\n * - может преобразовать результат через `transform`.\n *\n * Параметр `method` описывает семантику OData-операции, а не сырой HTTP-метод:\n *\n * - `\"create\"`\n * - `\"update\"`\n * - `\"delete\"`\n * - `\"read\"`\n * - `\"query\"`\n * - `\"fi\"`\n *\n * Возвращаемое значение — queryFn-совместимая функция, которую можно передавать в\n * `useQuery`, `useInfiniteQuery`, `useMutation` или вызывать вручную.\n *\n * @example\n * ```ts\n * const queryFn = odataFetchFn(\"query\", {\n * \todata: { service: \"TEXT_REPORT_SRV\", target: \"TEXT_REPORT_ENTITY\" },\n * \tparams: wrapODataParams({\n * \t\tp_date: new Date(),\n * \t\tp_date_to: new Date(),\n * \t\ttype_manager: \"main\"\n * \t}),\n * \tautoParse: true\n * });\n *\n * const result = await queryFn({ client });\n * ```\n */\nexport function odataFetchFn<\n\tI,\n\tO = I,\n\tP extends UnwrappedODataParameters = UnwrappedODataParameters,\n\tM extends ODataArrayOperationMethod = ODataArrayOperationMethod\n>(method: M, opts: ODataQueryFnOptions<I, O, P> & { transform: ODataQueryArrayTransform<I, O> }): ODataFetchFnRunner<O[]>;\nexport function odataFetchFn<\n\tI,\n\tO = I,\n\tP extends UnwrappedODataParameters = UnwrappedODataParameters,\n\tM extends ODataArrayOperationMethod = ODataArrayOperationMethod\n>(method: M, opts: ODataQueryFnOptions<I, O, P> & { transform: ODataQuerySingleTransform<I, O> }): ODataFetchFnRunner<O>;\nexport function odataFetchFn<\n\tI,\n\tP extends UnwrappedODataParameters = UnwrappedODataParameters,\n\tM extends ODataArrayOperationMethod = ODataArrayOperationMethod\n>(method: M, opts: ODataQueryFnOptions<I, I, P> & { transform?: undefined }): ODataFetchFnRunner<I[]>;\nexport function odataFetchFn<\n\tI,\n\tT = I,\n\tP extends UnwrappedODataParameters = UnwrappedODataParameters,\n\tM extends ODataSingleOperationMethod = ODataSingleOperationMethod\n>(method: M, opts: ODataSingleFetchFnRequest<M, I, I, T, P> & { transform?: undefined }): ODataFetchFnRunner<I>;\nexport function odataFetchFn<I, O = I, T = I, M extends ODataSingleOperationMethod = ODataSingleOperationMethod>(\n\tmethod: M,\n\topts: ODataSingleFetchFnRequest<M, I, O, T> & { transform: ODataSingleTransform<I, O> }\n): ODataFetchFnRunner<O>;\nexport function odataFetchFn<\n\tI,\n\tO = I,\n\tT = I,\n\tP extends UnwrappedODataParameters = UnwrappedODataParameters,\n\tM extends ODataOperationMethod = ODataOperationMethod\n>(method: M, opts: ODataFetchFnRequest<M, I, O, T, P>): ODataFetchFnRunner<unknown>;\nexport function odataFetchFn(...args: ODataFetchFnImplementationArgs): ODataFetchFnRunner<unknown> {\n\tconst [method, opts] = args;\n\tconst { odata, options = {}, init = {}, autoParse, swCache } = opts;\n\tconst params = \"params\" in opts ? (opts.params ?? {}) : {};\n\t// const body = \"body\" in opts ? opts.body : undefined;\n\n\t/**\n\t * `client` нужен для использования кеша\n\t */\n\treturn async ({ client, signal }: { client: QueryClient; signal?: AbortSignal }) => {\n\t\tconst baseUrl = resolveODataBaseUrl(odata.service, options.baseUrl);\n\n\t\tconst serviceMetadata = await getODataMetadataData({ service: odata.service, baseUrl }, client);\n\t\tif (!serviceMetadata) {\n\t\t\tthrow new Error(`Не удалось загрузить metadata OData-сервиса '${odata.service}'`);\n\t\t}\n\n\t\tconst target = resolveODataTarget(serviceMetadata, odata.target);\n\n\t\tvalidateODataOperation(target, method, odata);\n\n\t\tconst body = \"body\" in opts ? resolveRequestBody(opts.body, method) : undefined;\n\t\tconst requestMethod = resolveRequestMethod(target, method);\n\n\t\tif (__DEV__ && method === \"query\" && !(\"result\" in target) && Object.keys(params).length > 0) {\n\t\t\tconsole.warn(\n\t\t\t\t`OData query для plain entity \"${odata.service}/${odata.target}\" получил params, но они будут проигнорированы. Для чтения сущности по ключу используйте odataReadFn.`\n\t\t\t);\n\t\t}\n\n\t\tconst targetPath = buildTargetPath(target, odata, params, method);\n\n\t\tconst queryOptions = swCache ? { ...options, baseUrl, swCache } : { ...options, baseUrl };\n\t\tconst requestInit = { ...init, method: requestMethod, body, signal };\n\n\t\tif (method === \"query\") {\n\t\t\tconst response = await odataFetch<unknown, unknown[]>(targetPath, queryOptions, requestInit);\n\n\t\t\tif (isNoContentResponse(response)) {\n\t\t\t\tthrow new Error(\"OData query не должен возвращать 204 No Content\");\n\t\t\t}\n\n\t\t\tconst parsedData = autoParse ? parseODataResponseByMetadata(response.data, target, serviceMetadata) : response.data;\n\t\t\tconst transformedData = opts.transform ? opts.transform(parsedData, target) : parsedData;\n\n\t\t\treturn { data: transformedData, totalCount: response.totalCount };\n\t\t}\n\n\t\t// NOTE: немного дублирования кода ради правильной типизации без использования 'as' это нормальный компромисс и часто используемая практика\n\n\t\tconst response = await odataFetch<unknown>(targetPath, queryOptions, requestInit);\n\n\t\tif (isNoContentResponse(response)) {\n\t\t\treturn { data: response.data };\n\t\t}\n\n\t\tconst parsedData = autoParse ? parseODataResponseByMetadata(response.data, target, serviceMetadata) : response.data;\n\t\tconst transformedData = opts.transform ? opts.transform(parsedData, target) : parsedData;\n\n\t\treturn { data: transformedData, totalCount: response.totalCount };\n\t};\n}\n\n/**\n * Создаёт queryFn для OData `create`-операции.\n *\n * Только для `Entity`.\n *\n * Обязательные поля конфигурации:\n *\n * ```ts\n * {\n * \todata: ODataServiceConfig;\n * \tbody: T;\n * }\n * ```\n *\n * Поведение:\n *\n * - HTTP-метод: `POST`;\n * - `body` обязателен;\n * - `body` сериализуется внутри `odataFetchFn`;\n * - `params` запрещены;\n * - путь: `/SERVICE/ENTITY`;\n * - target должен быть обычной `Entity`, а не `FunctionImport`.\n *\n * Используйте эту функцию для сценариев создания записи по телу запроса, когда\n * ключи в URL не требуются.\n *\n * Обычно `I` — raw-тип ответа, а `T` — тип тела.\n * В большинстве случаев они совпадают, но при необходимости тело можно типизировать отдельно.\n *\n * Пример:\n *\n * ```ts\n * const mutationFn = odataCreateFn<Variant>({\n * \todata: { service: \"TEXT_CONFIG_SRV\", target: \"TEXT_VARIANT\" },\n * \tbody: {\n * \t\tid: \"uuid-4\",\n * \t\tname: \"Новый вариант\"\n * \t}\n * });\n * ```\n */\nexport function odataCreateFn<I, T = I>(opts: ODataCreateFnOptions<I, I, T> & { transform?: undefined }): ODataFetchFnRunner<I>;\nexport function odataCreateFn<I, O = I, T = I>(\n\topts: ODataCreateFnOptions<I, O, T> & { transform: ODataSingleTransform<I, O> }\n): ODataFetchFnRunner<O>;\nexport function odataCreateFn<I, O = I, T = I>(opts: ODataCreateFnOptions<I, O, T>) {\n\treturn odataFetchFn<I, O, T, never, \"create\">(\"create\", opts);\n}\n\n/**\n * Создаёт queryFn для OData `update`-операции.\n *\n * Только для `Entity`.\n *\n * Обязательные поля конфигурации:\n *\n * ```ts\n * {\n * \todata: ODataServiceConfig;\n * \tparams: UnwrappedODataParameters;\n * \tbody: T;\n * }\n * ```\n *\n * Поведение:\n *\n * - HTTP-метод: `PUT`;\n * - `params` обязательны и используются для построения key/path части URL;\n * - `body` обязателен и сериализуется внутри функции;\n * - путь: `/SERVICE/ENTITY(params...)`;\n * - target должен быть `Entity`.\n *\n * Используйте эту функцию, когда backend ожидает одновременную передачу ключа\n * в URL и обновляемого состояния в теле запроса.\n *\n * @example\n * ```ts\n * const mutationFn = odataUpdateFn<ThemePayload>({\n * \todata: { service: \"TEXT_CONFIG_SRV\", target: \"TEXT_THEME\" },\n * \tparams: wrapODataParams({ name: value }),\n * \tbody: { name: value }\n * });\n * ```\n */\nexport function odataUpdateFn<I, T = I, P extends UnwrappedODataParameters = UnwrappedODataParameters>(\n\topts: ODataUpdateFnOptions<I, I, T, P> & { transform?: undefined }\n): ODataFetchFnRunner<I>;\nexport function odataUpdateFn<I, O = I, T = I, P extends UnwrappedODataParameters = UnwrappedODataParameters>(\n\topts: ODataUpdateFnOptions<I, O, T, P> & { transform: ODataSingleTransform<I, O> }\n): ODataFetchFnRunner<O>;\nexport function odataUpdateFn<I, O = I, T = I, P extends UnwrappedODataParameters = UnwrappedODataParameters>(\n\topts: ODataUpdateFnOptions<I, O, T, P>\n) {\n\treturn odataFetchFn<I, O, T, P, \"update\">(\"update\", opts);\n}\n\n/**\n * Создаёт queryFn для OData `delete`-операции.\n *\n * Только для `Entity`.\n *\n * Обязательные поля конфигурации:\n *\n * ```ts\n * {\n * \todata: ODataServiceConfig;\n * \tparams: UnwrappedODataParameters;\n * }\n * ```\n *\n * Поведение:\n *\n * - HTTP-метод: `DELETE`;\n * - `params` обязательны;\n * - `body` не поддерживается;\n * - путь: `/SERVICE/ENTITY(params...)`;\n * - target должен быть `Entity`.\n *\n * Подходит для удаления записи по ключу, когда backend игнорирует тело запроса\n * и определяет удаляемую сущность только по параметрам URL.\n *\n * @example\n * ```ts\n * const mutationFn = odataDeleteFn({\n * \todata: { service: \"TEXT_CONFIG_SRV\", target: \"TextPresetSet\" },\n * \tparams: wrapODataParams({ recId: \"uuid-1\" })\n * });\n * ```\n */\nexport function odataDeleteFn<I, T = I, P extends UnwrappedODataParameters = UnwrappedODataParameters>(\n\topts: ODataDeleteFnOptions<I, I, P> & { transform?: undefined }\n): ODataFetchFnRunner<I>;\nexport function odataDeleteFn<I, O = I, T = I, P extends UnwrappedODataParameters = UnwrappedODataParameters>(\n\topts: ODataDeleteFnOptions<I, O, P> & { transform: ODataSingleTransform<I, O> }\n): ODataFetchFnRunner<O>;\nexport function odataDeleteFn<I, O = I, T = I, P extends UnwrappedODataParameters = UnwrappedODataParameters>(\n\topts: ODataDeleteFnOptions<I, O, P>\n) {\n\treturn odataFetchFn<I, O, T, P, \"delete\">(\"delete\", opts);\n}\n\n/**\n * Создаёт queryFn для OData `read`-операции.\n *\n * Только для `Entity`.\n *\n * Обязательные поля конфигурации:\n *\n * ```ts\n * {\n * \todata: ODataServiceConfig;\n * \tparams: UnwrappedODataParameters;\n * }\n * ```\n *\n * Поведение:\n *\n * - HTTP-метод: `GET`;\n * - `params` обязательны;\n * - `body` не поддерживается;\n * - путь: `/SERVICE/ENTITY(params...)`;\n * - нельзя использовать для parameterized query entity, у которой в metadata есть `result`.\n *\n * Это режим чтения конкретной сущности или key-based target.\n * Если target на самом деле является query-сущностью с `/Set` или `/Results`,\n * нужно использовать `odataQueryFn`.\n *\n * @example\n * ```ts\n * const queryFn = odataReadFn<Variant>({\n * \todata: { service: \"TEXT_CONFIG_SRV\", target: \"TEXT_VARIANT\" },\n * \tparams: wrapODataParams({ variantId: \"uuid-1\" })\n * });\n * ```\n */\nexport function odataReadFn<I, T = I, P extends UnwrappedODataParameters = UnwrappedODataParameters>(\n\topts: ODataReadFnOptions<I, I, P> & { transform?: undefined }\n): ODataFetchFnRunner<I>;\nexport function odataReadFn<I, O = I, T = I, P extends UnwrappedODataParameters = UnwrappedODataParameters>(\n\topts: ODataReadFnOptions<I, O, P> & { transform: ODataSingleTransform<I, O> }\n): ODataFetchFnRunner<O>;\nexport function odataReadFn<I, O = I, T = I, P extends UnwrappedODataParameters = UnwrappedODataParameters>(\n\topts: ODataReadFnOptions<I, O, P>\n) {\n\treturn odataFetchFn<I, O, T, P, \"read\">(\"read\", opts);\n}\n\n/**\n * Создаёт queryFn для OData `query`-операции.\n *\n * Это основной helper для чтения списков и query-сущностей.\n *\n * Поведение зависит от metadata target:\n *\n * - для обычной `Entity` путь будет `/SERVICE/ENTITY`;\n * - для parameterized query entity путь будет `/SERVICE/ENTITY(params...)/Set` или `/Results`.\n *\n * Конфигурация:\n *\n * ```ts\n * {\n * \todata: ODataServiceConfig;\n * \tparams?: UnwrappedODataParameters;\n * \toptions?: ODataFetchOptions<T>;\n * }\n * ```\n *\n * Особенности:\n *\n * - HTTP-метод всегда `GET`;\n * - `params` необязательны на уровне типов;\n * - для plain entity переданные `params` будут проигнорированы;\n * - для query entity с `metadata.result` параметры реально участвуют в URL;\n * - `body` не поддерживается.\n *\n * Это функция по умолчанию для большинства `useQuery`-сценариев в проекте.\n *\n * @example\n * ```ts\n * const queryFn = odataQueryFn<RawRow, Row>({\n * \todata: { service: \"TEXT_REPORT_SRV\", target: \"TEXT_REPORT_ENTITY\" },\n * \tparams: wrapODataParams({\n * \t\tp_date: new Date(),\n * \t\tp_date_to: new Date(),\n * \t\ttype_manager: \"main\"\n * \t}),\n * \tautoParse: true,\n * \ttransform: (rows) => rows.map(mapRow)\n * });\n * ```\n */\nexport function odataQueryFn<I, O = I, P extends UnwrappedODataParameters = UnwrappedODataParameters>(\n\topts: ODataQueryFnOptions<I, O, P> & { transform: ODataQueryArrayTransform<I, O> }\n): ODataFetchFnRunner<O[]>;\nexport function odataQueryFn<I, O = I, P extends UnwrappedODataParameters = UnwrappedODataParameters>(\n\topts: ODataQueryFnOptions<I, O, P> & { transform: ODataQuerySingleTransform<I, O> }\n): ODataFetchFnRunner<O>;\nexport function odataQueryFn<I, O = I, P extends UnwrappedODataParameters = UnwrappedODataParameters>(\n\topts: ODataQueryFnOptions<I, I, P> & { transform?: undefined }\n): ODataFetchFnRunner<I[]>;\nexport function odataQueryFn<I, O = I, P extends UnwrappedODataParameters = UnwrappedODataParameters>(opts: ODataQueryFnOptions<I, O, P>) {\n\treturn odataFetchFn<I, O, void, P, \"query\">(\"query\", opts);\n}\n\n/**\n * Создаёт queryFn для вызова OData `FunctionImport`.\n *\n * Используйте эту функцию только для target, который опубликован в metadata как `FunctionImport`.\n *\n * Конфигурация:\n *\n * ```ts\n * {\n * \todata: ODataServiceConfig;\n * \tparams: UnwrappedODataParameters;\n * }\n * ```\n *\n * Поведение:\n *\n * - HTTP-метод берётся из metadata `FunctionImport`;\n * - если metadata не содержит `httpMethod`, будет выброшена ошибка;\n * - `params` обязательны;\n * - `body` не поддерживается;\n * - параметры target попадают в query string;\n * - `options` (`$select`, `$top`, `$filter` и т.д.) дописываются в тот же query string.\n *\n * Эта функция нужна для вызовов backend-операций, опубликованных как `FunctionImport`,\n * когда transport-семантика определяется самим OData-сервисом.\n *\n * @example\n * ```ts\n * const mutationFn = odataFunctionImportFn<CreateTransportRequestRaw, TransportRequest>({\n * \todata: { service: \"TEXT_CONFIG_SRV\", target: \"createTextRequest\" },\n * \tparams: wrapODataParams({\n * \t\ttype: \"workbench\",\n * \t\ttext: \"Новый транспорт\"\n * \t}),\n * \ttransform: (raw) => mapCreatedTransportRequest(raw, \"workbench\")\n * });\n * ```\n */\nexport function odataFunctionImportFn<I, T = I, P extends UnwrappedODataParameters = UnwrappedODataParameters>(\n\topts: ODataFunctionImportFnOptions<I, I, P> & { transform?: undefined }\n): ODataFetchFnRunner<I>;\nexport function odataFunctionImportFn<I, O = I, T = I, P extends UnwrappedODataParameters = UnwrappedODataParameters>(\n\topts: ODataFunctionImportFnOptions<I, O, P> & { transform: ODataSingleTransform<I, O> }\n): ODataFetchFnRunner<O>;\nexport function odataFunctionImportFn<I, O = I, T = I, P extends UnwrappedODataParameters = UnwrappedODataParameters>(\n\topts: ODataFunctionImportFnOptions<I, O, P>\n) {\n\treturn odataFetchFn<I, O, T, P, \"fi\">(\"fi\", opts);\n}\n"],"mappings":";;;;;;;;AAAA,IAAa,IAAoB,CAAC,OAAO;;;AC2EzC,SAAS,EAAkB,GAAwB,GAAa,GAAyB;CACpF,MAAU,KAAA,KAAa,MAAU,MACrC,EAAM,IAAI,GAAK,OAAO,CAAK,CAAC;AAC7B;AAUA,SAAgB,EAA0B,GAAuB,IAAgC,CAAC,GAAG,IAAoB,CAAC,GAAG;CAC5H,IAAM,CAAC,GAAS,IAAW,MAAM,EAAc,MAAM,GAAG,GAClD,IAAQ,IAAI,gBAAgB,CAAQ;CAE1C,IAAI,EAAQ,YAAY;EACvB,IAAM,IAAS,EAAiB,EAAQ,UAAU;EAClD,AAAI,KAAQ,EAAM,IAAI,WAAW,CAAM;CACxC;CAOA,AANI,EAAQ,SAAO,EAAM,IAAI,YAAY,EAAgB,EAAQ,KAAK,CAAC,GACnE,EAAQ,UAAQ,EAAM,IAAI,WAAW,EAAQ,OAAO,KAAK,GAAG,CAAC,GAC7D,EAAQ,UAAQ,EAAM,IAAI,WAAW,EAAQ,OAAO,KAAK,GAAG,CAAC,GAEjE,EAAkB,GAAO,QAAQ,EAAQ,GAAG,GAC5C,EAAkB,GAAO,SAAS,EAAQ,IAAI,GAC9C,EAAkB,GAAO,gBAAgB,EAAQ,WAAW;CAE5D,IAAM,IAAO,EAAQ,QAAQ,QAAQ,EAAE,GACjC,IAAc,EAAM,SAAS,GAC7B,IAAU,IAAc,GAAG,EAAK,GAAG,MAAgB,GACrD,IAAc;CAGlB,IAAI,EAAQ,SAAS;EACpB,IAAM,IAAU,IAAI,QAAQ,EAAK,OAAO;EAExC,AADA,EAAQ,IAAI,cAAc,EAAQ,OAAO,GACzC,IAAc;GAAE,GAAG;GAAM;EAAQ;CAClC;CAEA,OAAO;EACN,MAAM;EACN,SAAS,GAAG,EAAW,EAAQ,WAAW,WAAW;EACrD,SAAS,EAAQ;EACjB,MAAM;EACN;CACD;AACD;AAEA,eAAsB,EAAqB,GAAuB,IAAgC,CAAC,GAAG,IAAoB,CAAC,GAAG;CAC7H,IAAM,IAAU,EAAuB,GAAe,GAAS,CAAI;CAEnE,OAAO,EAAkB,EAAQ,MAAM,EAAQ,MAAM,EAAQ,OAAO;AACrE;;;ACvHA,IAAM,IAAA,yCACA,IAA8B,MAAO,KAAK,KAAK;AAiBrD,SAAS,EAA4B,GAAgF;CAC/G,OACL,OAAO,MAAM,QAAQ,CAAO,IAAI,EAAQ,KAAK;AAC9C;AAEA,IAAa,KAAsC,EAAE,iBACpD;CAAC,GAAG;CAAmB;CAAoB;EAAE;EAAS,SAAS;CAA0B;AAAC;AAE3F,SAAS,EAAiC,GAA6C;CACtF,OAAO;EACN;EACA,WAAW;EACX,SAAS;CACV;AACD;AAMA,SAAgB,EAAqB,GAA8C;CAClF,OAAO,OAAO,EAAE,gBAA2E;EAC1F,IAAM,IAAW,EAAuB,CAAC,CAAC;EAC1C,IAAI,CAAC,GAAU,OAAO,EAAiC,EAAQ,OAAO;EAWtE,IAAM,IAAY,EADH,GAA4B,MARpB,EACtB,IAAI,EAAS,QAAQ,GAAG,EAAS,OAAO,IAAI,EAA0B,EAAQ,OAAO,EAAE,KACvF,EACC,SAAS,EAAoB,EAAS,SAAS,EAAS,OAAO,EAChE,GACA,EAAE,UAAO,CACV,EAAA,CAEoD,IACxB,CAAA,EAAQ,WAAW;EAE/C,OAAO;GACN,SAAS,EAAQ;GACjB;GACA,SAAS,IAAY,EAA0B,CAAS,IAAI;EAC7D;CACD;AACD;AAMA,IAAa,KAAoC,MAChD,EAAa;CACZ,UAAU,EAAmC,CAAO;CACpD,SAAS,EAAqB,CAAO;CACrC,MAAM;CACN,SAAS,GAAQ,EAAQ,WAAW,EAAuB,CAAC,CAAC;CAC7D,WAAW,EAAQ,aAAa;CAChC,QAAQ;AACT,CAAC;AAMF,SAAgB,EAA+B,GAA0B,GAAiB;CACzF,OAAO,EAAY,kBAAkB,EACpC,YAAY,MAAU;EACrB,IAAM,CAAC,GAAS,GAAW,KAAqB,EAAM;EAItD,OAHI,MAAY,EAAkB,MAAM,MAAc,cAClD,CAAC,KAAqB,OAAO,KAAsB,WAAiB,KAEjE,aAAa,KAAqB,EAAkB,YAAY;CACxE,EACD,CAAC;AACF;AAEA,SAAgB,EACf,GACA,GACC;CAGD,OAFI,GAAe,SAAS,KAAA,KACxB,CAAC,EAAQ,YAAkB,KACxB,EAAQ,UAAU,QAAQ,IAAI,EAAc;AACpD;;;ACzFA,SAAgB,EAAc,GAA+B;CAC5D,OAAO,EAAa,IAAI,EAAQ,QAAQ,aAAa;EACpD,SAAS,EAAoB,EAAQ,SAAS,EAAQ,OAAO;EAC7D,MAAM,EACL,SAAS;GACR,QAAQ;GACR,gBAAgB;EACjB,EACD;EACA,WAAW,OAAO,MAAS;GAC1B,IAAI;IACH,OAAO,EAAqB,MAAM,EAAK,KAAK,CAAC;GAC9C,SAAS,GAAO;IACf,MAAU,MAAM,UAAU,EAAQ,QAAQ,mCAAmC,OAAO,CAAK,GAAG;GAC7F;EACD;CACD,CAAC;AACF;AAEA,IAAa,KAA6B,MACzC,EAAa;CACZ,UAAU;EAAC,GAAG;EAAmB;EAAY;CAAO;CACpD,SAAS,EAAc,CAAO;CAC9B,MAAM;CACN,SAAS,EAAQ,EAAQ;CAKzB,WAAW;CACX,QAAQ;AACT,CAAC;AAMF,eAAsB,EACrB,GACA,GACA,GACC;CACD,IAAI,CAAC,EAAQ,SAAS;CAEtB,IAAM,IAAmB,EAA0B,CAAO,CAAC,CAAC;CAI5D,AAFsB,EADA,EAAY,cAAc,CACU,GAAe,CAErE,KACH,MAAM,EAA+B,GAAa,EAAQ,OAAO;AAEnE;AAEA,SAAgB,EAAsB,GAA+B;CACpE,IAAM,IAAc,EAAe,GAC7B,IAAkB,SAAe;EAAE,SAAS,EAAQ;EAAS,SAAS,EAAQ;CAAQ,IAAI,CAAC,EAAQ,SAAS,EAAQ,OAAO,CAAC,GAE5H,IAAe,EAAS,EADP,SAAe,EAAE,SAAS,EAAQ,QAAQ,IAAI,CAAC,EAAQ,OAAO,CACtB,CAAc,CAAC,GACxE,IAAgB,EAAS,EAA0B,CAAe,CAAC;CAQzE,OANA,QAAgB;EACX,CAAC,EAAQ,WAAW,CAAC,EAAa,aAEtC,EAA0B,GAAa,GAAiB,EAAa,IAAI;CAC1E,GAAG;EAAC;EAAiB,EAAc;EAAe,EAAQ;EAAS;EAAa,EAAa;EAAM,EAAa;CAAS,CAAC,GAEnH;AACR;AAMA,SAAgB,EAA6B,GAAsC;CAClF,OAAO,EAAS,EAAiC,CAAO,CAAC;AAC1D;AAEA,eAAe,EAAyB,GAA+B,GAA0B;CAChG,IAAM,IAAiB,EAAE,SAAS,EAAQ,QAAQ;CAElD,IAAI;EAEH,MAAM,EAA0B,GAAa,GAAS,MAD5B,EAAY,WAAW,EAAiC,CAAc,CAAC,CAChC;CAClE,QAAQ,CAIR;AACD;AAEA,eAAsB,EAAqB,GAA+B,GAA0B;CAC9F,MAAQ,SAGb,OAFA,MAAM,EAAY,WAAW,EAA0B,CAAO,CAAC,GAC/D,MAAM,EAAyB,GAAS,CAAW,GAC5C,EAAY,WAAW,EAA0B,CAAO,CAAC;AACjE;;;AC5FA,SAAgB,EAAyB,GAA+D;CACvG,OAAO,gBAAgB;AACxB;AAEA,SAAgB,EAAmB,GAA8B,GAAyC;CACzG,IAAM,IAAS,GAAa,SAAS,IAC/B,IAAiB,GAAa,gBAAgB;CAEpD,IAAI,KAAU,GACb,MAAU,MAAM,8BAA8B,EAAW,gDAAgD;CAG1G,IAAI,GAAQ,OAAO;CACnB,IAAI,GAAgB,OAAO;CAE3B,MAAU,MAAM,iBAAiB,EAAW,kBAAkB;AAC/D;AAEA,SAAgB,EAAuB,GAA6B,GAA8B,GAAiC;CAClI,IAAI,EAAyB,CAAM,GAAG;EACrC,IAAI,MAAW,MACd,MAAU,MACT,oBAAoB,EAAO,mCAAmC,EAAO,KAAK,gDAC3E;EAGD;CACD;CAEA,IAAI,MAAW,MACd,MAAU,MACT,+CAA+C,EAAM,OAAO,gGAC7D;CAGD,IAAI,MAAW,UAAU,EAAO,QAC/B,MAAU,MACT,oBAAoB,EAAO,+CAA+C,EAAM,OAAO,0BAA0B,EAAO,OAAO,+BAChI;AAEF;AAEA,SAAgB,EAAqB,GAA6B,GAA0C;CAC3G,IAAI,MAAW,UAAU,OAAO;CAChC,IAAI,MAAW,UAAU,OAAO;CAChC,IAAI,MAAW,UAAU,OAAO;CAChC,IAAI,MAAW,UAAU,MAAW,SAAS,OAAO;CAEpD,IAAI,EAAyB,CAAM,GAAG;EACrC,IAAI,CAAC,EAAO,YACX,MAAU,MAAM,mBAAmB,EAAO,KAAK,8EAA8E;EAG9H,OAAO,EAAO;CACf;CAEA,MAAU,MAAM,oBAAoB,EAAO,kCAAkC,WAAW,IAAS,EAAO,QAAQ,UAAU,GAAG;AAC9H;AAEA,SAAgB,EAAgC,GAAqB,GAAkD;CACtH,IAAI,MAAS,MAAW,YAAY,MAAW,WAC9C,OAAO,KAAK,UAAU,CAAI;AAG5B;AAEA,SAAgB,EACf,GACA,GACA,GACA,GACS;CACT,IAAI,EAAyB,CAAM,GAClC,OAAO,EAAwB,GAAQ,GAAO,CAAM;CAGrD,IAAI,MAAW,MACd,MAAU,MAAM,+CAA+C,EAAM,OAAO,GAAG;CAGhF,OAAO,EAAyB,GAAQ,GAAO,GAAQ,CAAM;AAC9D;;;AC/FA,SAAS,EAAsB,GAA6B,GAAsE;CACjI,IAAI,CAAC,EAAyB,CAAM,GACnC,OAAO,EAAO;CAGV,MAAO,cACZ,OAAO,EAAgB,SAAS,EAAO,aAAa,EAAE;AACvD;AAEA,SAAS,EAAkB,GAA4D;CACtF,IAAM,IAAyC,CAAC;CAEhD,KAAK,IAAI,IAAQ,GAAG,IAAQ,EAAQ,QAAQ,KAAS,GAAG;EACvD,IAAM,IAAS,EAAQ;EACvB,EAAY,KAAK;GAChB,IAAI,EAAO;GACX,MAAM,EAAO;GACb,iBAAiB,EAAO;EACzB,CAAC;CACF;CAEA,OAAO;AACR;AAEA,SAAS,EAAiB,GAAiC,GAAwC;CAClG,IAAI;CAEJ,KAAK,IAAI,IAAQ,GAAG,IAAQ,EAAY,QAAQ,KAAS,GAAG;EAC3D,IAAM,IAAa,EAAY;EAC/B,IAAI,CAAC,OAAO,UAAU,eAAe,KAAK,GAAQ,EAAW,EAAE,GAC9D;EAGD,IAAM,IAAc,EAAO,EAAW,KAChC,IAAc,EAA0B,GAAY,CAAW;EACjE,MAAgB,MAIpB,AACC,MAAe,EAAE,GAAG,EAAO,GAG5B,EAAa,EAAW,MAAM;CAC/B;CAEA,OAAO,KAAgB;AACxB;AAIA,SAAgB,EAAgC,GAAe,GAA6B,GAA2C;CACtI,IAAM,IAAU,EAAsB,GAAQ,CAAe;CAC7D,IAAI,CAAC,GAAS,QAAQ,OAAO;CAE7B,IAAM,IAAc,EAAkB,CAAO;CAE7C,IAAI,MAAM,QAAQ,CAAI,GAAG;EACxB,IAAI;EAEJ,KAAK,IAAI,IAAQ,GAAG,IAAQ,EAAK,QAAQ,KAAS,GAAG;GACpD,IAAM,IAAO,EAAK;GAClB,IAAI,CAAC,EAAS,CAAI,GACjB;GAGD,IAAM,IAAa,EAAiB,GAAM,CAAW;GACjD,MAAe,MAInB,AACC,MAAc,EAAK,MAAM,GAG1B,EAAY,KAAS;EACtB;EAEA,OAAQ,KAAe;CACxB;CAMA,OAJI,EAAS,CAAI,IACT,EAAiB,GAAM,CAAW,IAGnC;AACR;;;ACuJA,SAAgB,EAAa,GAAG,GAAmE;CAClG,IAAM,CAAC,GAAQ,KAAQ,GACjB,EAAE,UAAO,aAAU,CAAC,GAAG,UAAO,CAAC,GAAG,cAAW,eAAY,GACzD,IAAS,YAAY,IAAQ,EAAK,UAAU,CAAC,IAAK,CAAC;CAMzD,OAAO,OAAO,EAAE,WAAQ,gBAA4D;EACnF,IAAM,IAAU,EAAoB,EAAM,SAAS,EAAQ,OAAO,GAE5D,IAAkB,MAAM,EAAqB;GAAE,SAAS,EAAM;GAAS;EAAQ,GAAG,CAAM;EAC9F,IAAI,CAAC,GACJ,MAAU,MAAM,gDAAgD,EAAM,QAAQ,EAAE;EAGjF,IAAM,IAAS,EAAmB,GAAiB,EAAM,MAAM;EAE/D,EAAuB,GAAQ,GAAQ,CAAK;EAE5C,IAAM,IAAO,UAAU,IAAO,EAAmB,EAAK,MAAM,CAAM,IAAI,KAAA,GAChE,IAAgB,EAAqB,GAAQ,CAAM,GAQnD,IAAa,EAAgB,GAAQ,GAAO,GAAQ,CAAM,GAE1D,IAAe,IAAU;GAAE,GAAG;GAAS;GAAS;EAAQ,IAAI;GAAE,GAAG;GAAS;EAAQ,GAClF,IAAc;GAAE,GAAG;GAAM,QAAQ;GAAe;GAAM;EAAO;EAEnE,IAAI,MAAW,SAAS;GACvB,IAAM,IAAW,MAAM,EAA+B,GAAY,GAAc,CAAW;GAE3F,IAAI,EAAoB,CAAQ,GAC/B,MAAU,MAAM,iDAAiD;GAGlE,IAAM,IAAa,IAAY,EAA6B,EAAS,MAAM,GAAQ,CAAe,IAAI,EAAS;GAG/G,OAAO;IAAE,MAFe,EAAK,YAAY,EAAK,UAAU,GAAY,CAAM,IAAI;IAE9C,YAAY,EAAS;GAAW;EACjE;EAIA,IAAM,IAAW,MAAM,EAAoB,GAAY,GAAc,CAAW;EAEhF,IAAI,EAAoB,CAAQ,GAC/B,OAAO,EAAE,MAAM,EAAS,KAAK;EAG9B,IAAM,IAAa,IAAY,EAA6B,EAAS,MAAM,GAAQ,CAAe,IAAI,EAAS;EAG/G,OAAO;GAAE,MAFe,EAAK,YAAY,EAAK,UAAU,GAAY,CAAM,IAAI;GAE9C,YAAY,EAAS;EAAW;CACjE;AACD;AA+CA,SAAgB,EAA+B,GAAqC;CACnF,OAAO,EAAuC,UAAU,CAAI;AAC7D;AA2CA,SAAgB,GACf,GACC;CACD,OAAO,EAAmC,UAAU,CAAI;AACzD;AAyCA,SAAgB,GACf,GACC;CACD,OAAO,EAAmC,UAAU,CAAI;AACzD;AA0CA,SAAgB,GACf,GACC;CACD,OAAO,EAAiC,QAAQ,CAAI;AACrD;AAuDA,SAAgB,GAAsF,GAAoC;CACzI,OAAO,EAAqC,SAAS,CAAI;AAC1D;AA8CA,SAAgB,GACf,GACC;CACD,OAAO,EAA+B,MAAM,CAAI;AACjD"}
|
package/dist/odata/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { C as e, S as t, _ as n, a as r, b as i, c as a, d as o, f as s, g as c, h as l, i as u, l as d, m as f, n as p, o as m, p as h, r as g, s as _, t as v, u as y, v as b, w as x, x as S, y as C } from "../chunks/fetch-
|
|
2
|
-
import { a as w, c as T, d as E, f as D, i as O, l as k, m as A, n as j, o as M, p as N, s as P, t as F, u as I } from "../chunks/odataFetchFn-
|
|
3
|
-
import { C as L, D as R, E as z, O as B, S as V, T as H, _ as U, a as W, b as G, c as K, d as q, f as J, g as Y, h as X, i as Z, k as Q, l as $, m as ee, n as te, o as ne, p as re, r as ie, s as ae, t as oe, u as se, v as ce, w as le, x as ue, y as de } from "../chunks/odata-
|
|
1
|
+
import { C as e, S as t, _ as n, a as r, b as i, c as a, d as o, f as s, g as c, h as l, i as u, l as d, m as f, n as p, o as m, p as h, r as g, s as _, t as v, u as y, v as b, w as x, x as S, y as C } from "../chunks/fetch-teHV5e4t.js";
|
|
2
|
+
import { a as w, c as T, d as E, f as D, i as O, l as k, m as A, n as j, o as M, p as N, s as P, t as F, u as I } from "../chunks/odataFetchFn-CJIPv-CJ.js";
|
|
3
|
+
import { C as L, D as R, E as z, O as B, S as V, T as H, _ as U, a as W, b as G, c as K, d as q, f as J, g as Y, h as X, i as Z, k as Q, l as $, m as ee, n as te, o as ne, p as re, r as ie, s as ae, t as oe, u as se, v as ce, w as le, x as ue, y as de } from "../chunks/odata-BvLTiawF.js";
|
|
4
4
|
export { h as BaseAppConfigURL, f as BaseODataDp0URL, l as BaseODataUI2URL, c as BaseODataURL, n as BaseUrlMap, U as ODATA_COLLECTION_BUST_SW_CACHE, ce as ODATA_COLLECTION_DEFAULT_SW_CACHE, de as ODATA_COLLECTION_UPDATES_LOOKBACK_MS, G as ODATA_COLLECTION_UPDATES_SW_CACHE, d as SsoRequiredError, T as applyODataMetadataVersion, i as configureODataProjectAdapter, B as createODataCollectionBaseQueryKey, Q as createODataCollectionQueryKey, ue as createODataCollectionUpdatesQueryKey, v as fetchBase, p as fetchDeleteFn, g as fetchJson, u as fetchJsonMutationFn, r as fetchJsonQueryFn, k as fetchMetadata, V as fetchODataCollectionUpdates, m as fetchODataJson, _ as fetchQueryFn, R as flattenODataDependentServices, b as getInputUrl, I as getODataMetadataData, S as getODataProjectAdapter, a as isNoContentResponse, y as isSsoForm, t as normalizeODataServiceName, C as normalizeRelativePath, L as odataCollectionUpdatesQueryOptions, F as odataCreateFn, oe as odataCreateFnDev, j as odataDeleteFn, te as odataDeleteFnDev, A as odataFetch, O as odataFunctionImportFn, ie as odataFunctionImportFnDev, E as odataMetadataQueryOptions, w as odataQueryFn, Z as odataQueryFnDev, M as odataReadFn, W as odataReadFnDev, P as odataUpdateFn, ne as odataUpdateFnDev, o as recoverSsoSession, e as resolveODataBaseUrl, J as resolveODataCollectionSwCachePolicy, x as resolveODataSapClient, re as shouldRefreshODataCollectionCache, z as sortODataDependentSegmentItemsByChains, H as sortODataDependentServicesByChains, s as submitSsoForm, q as useODataCollection, se as useODataCollectionChains, $ as useODataCollectionModel, ee as useODataCollectionQuery, le as useODataCollectionUpdatesQuery, X as useODataEntity, Y as useODataMetadata, D as useODataMetadataQuery, N as useODataMetadataVersionQuery, K as useODataTableColumns, ae as useTextServiceQuery };
|
package/dist/persisted/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { httpFetchPayload as e } from "../http/index.js";
|
|
2
|
-
import { r as t } from "../chunks/odataFetchFn-
|
|
2
|
+
import { r as t } from "../chunks/odataFetchFn-CJIPv-CJ.js";
|
|
3
3
|
import { createResourceKeys as n } from "../resource/index.js";
|
|
4
4
|
import { queryOptions as r, useMutation as i, useQuery as a, useQueryClient as o } from "@tanstack/react-query";
|
|
5
5
|
//#region src/persisted/cache.ts
|
package/dist/s3/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { r as e } from "../chunks/fetch-
|
|
2
|
-
import { o as t } from "../chunks/odataFetchFn-
|
|
1
|
+
import { r as e } from "../chunks/fetch-teHV5e4t.js";
|
|
2
|
+
import { o as t } from "../chunks/odataFetchFn-CJIPv-CJ.js";
|
|
3
3
|
import { wrapODataParams as n } from "@ryuzaki13/react-foundation-lib/odata-service";
|
|
4
4
|
import { uuidv4 as r } from "@ryuzaki13/react-foundation-lib/crypto";
|
|
5
5
|
//#region src/s3/constants.ts
|
package/dist/transport/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { r as e } from "../chunks/fetch-
|
|
1
|
+
import { r as e } from "../chunks/fetch-teHV5e4t.js";
|
|
2
2
|
import { normalizeTextWithFallback as t } from "@ryuzaki13/react-foundation-lib/formatters";
|
|
3
3
|
//#region src/transport/normalizeTransportRequests.ts
|
|
4
4
|
function n(e, n) {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ryuzaki13/react-foundation-api",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.1",
|
|
4
4
|
"description": "Reusable React and TypeScript foundation API helpers and transport adapters.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Ryuzaki13",
|
|
@@ -134,7 +134,7 @@
|
|
|
134
134
|
"zustand": "^5.0.14"
|
|
135
135
|
},
|
|
136
136
|
"devDependencies": {
|
|
137
|
-
"@ryuzaki13/react-foundation-lib": "
|
|
137
|
+
"@ryuzaki13/react-foundation-lib": ">=0.1.0 <2.0.0",
|
|
138
138
|
"@tanstack/query-broadcast-client-experimental": "^5.101.1",
|
|
139
139
|
"@tanstack/query-persist-client-core": "^5.101.1",
|
|
140
140
|
"@tanstack/react-query": "^5.101.1",
|