@ryuzaki13/react-foundation-api 1.1.16 → 1.1.17

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.
Files changed (36) hide show
  1. package/README.md +32 -43
  2. package/dist/chunks/{odataFetchFn-vnAXC-c0.js → odataFetchFn-B9wSQpUS.js} +11 -11
  3. package/dist/chunks/{odataFetchFn-vnAXC-c0.js.map → odataFetchFn-B9wSQpUS.js.map} +1 -1
  4. package/dist/odata/fetchCollectionData.d.ts +1 -1
  5. package/dist/odata/fetchCollectionData.d.ts.map +1 -1
  6. package/dist/odata/index.js +111 -112
  7. package/dist/odata/index.js.map +1 -1
  8. package/dist/odata/projectODataCollectionSort.d.ts +1 -1
  9. package/dist/odata/projectODataCollectionSort.d.ts.map +1 -1
  10. package/dist/odata/types.d.ts +1 -2
  11. package/dist/odata/types.d.ts.map +1 -1
  12. package/dist/odata/useODataCollection.d.ts +1 -1
  13. package/dist/odata/useODataCollection.d.ts.map +1 -1
  14. package/dist/odata/useODataCollectionQuery.d.ts +1 -1
  15. package/dist/odata/useODataCollectionQuery.d.ts.map +1 -1
  16. package/dist/odata/useODataEntity.d.ts +1 -1
  17. package/dist/odata/useODataEntity.d.ts.map +1 -1
  18. package/dist/persisted/index.js +1 -1
  19. package/package.json +2 -2
  20. package/src/adt/README.mdx +164 -0
  21. package/src/async/README.mdx +253 -0
  22. package/src/error-report/README.mdx +148 -0
  23. package/src/foundationApi.mdx +123 -0
  24. package/src/http/README.mdx +221 -0
  25. package/src/odata/README.mdx +790 -0
  26. package/src/persisted/README.mdx +454 -0
  27. package/src/resource/README.mdx +358 -0
  28. package/src/server-fn/README.mdx +194 -0
  29. package/src/transport/README.mdx +183 -0
  30. package/src/README.md +0 -937
  31. package/src/async/README.md +0 -623
  32. package/src/async/async.mdx +0 -6
  33. package/src/odata/README.md +0 -761
  34. package/src/odata/odataFetchFn.mdx +0 -6
  35. package/src/persisted/README.md +0 -598
  36. package/src/persisted/persisted.mdx +0 -6
package/README.md CHANGED
@@ -1,10 +1,8 @@
1
- # @ryuzaki13/react-foundation-api
1
+ # `@ryuzaki13/react-foundation-api`
2
2
 
3
- Библиотечный пакет для инфраструктуры бывшего `src/shared/api`: HTTP-транспорт, async/resource helpers, persisted resources, OData/SAP Gateway helpers и adapters для transport/server function сценариев.
3
+ Переиспользуемый API-слой для React/TypeScript-приложений: обычный HTTP, OData V2 и SAP Gateway, TanStack Query resource descriptors, persisted records, server-function adapters, пакетные async-задачи, SAP transports и доставка error reports.
4
4
 
5
- Пакет публикуется в npm как публичная библиотека, но его основная задача практическая: вынести повторно используемый API-слой из собственных проектов автора и подключать его одинаково в нескольких host-приложениях. Это не универсальный API SDK. Контракты, transport helpers и OData wrappers в первую очередь оптимизируются под семейство проектов, где общий технический фундамент находится в `@ryuzaki13/react-foundation-lib`, а UI-компоненты живут в `@ryuzaki13/react-foundation-ui`.
6
-
7
- `react-foundation-api` зависит от `@ryuzaki13/react-foundation-lib` и находится между `lib` и host/UI-слоем: `lib` не знает про API, а `api` переиспользует `lib` для форматтеров, OData metadata, query-client policy, validators и error-report infrastructure.
5
+ Документация написана как самостоятельный справочник: для её чтения не нужен доступ к исходникам пакета.
8
6
 
9
7
  ## Установка
10
8
 
@@ -12,65 +10,56 @@
12
10
  npm install @ryuzaki13/react-foundation-api @ryuzaki13/react-foundation-lib
13
11
  ```
14
12
 
15
- Пакет распространяется как ESM и не открывает корневой импорт. Используйте только точечные entrypoints из `exports`:
13
+ Пакет распространяется как ESM и не имеет корневого entrypoint. Импортируйте только опубликованные subpath:
16
14
 
17
15
  ```ts
18
16
  import { httpJsonQueryFn } from "@ryuzaki13/react-foundation-api/http";
19
- import { runAsyncTasks } from "@ryuzaki13/react-foundation-api/async";
17
+ import { odataQueryFn } from "@ryuzaki13/react-foundation-api/odata";
20
18
  import { createResourceDescriptor } from "@ryuzaki13/react-foundation-api/resource";
21
- import { odataQueryFn, useODataCollectionQuery } from "@ryuzaki13/react-foundation-api/odata";
22
- import type { ODataCollectionConfig } from "@ryuzaki13/react-foundation-api/odata";
23
19
  ```
24
20
 
25
- Импорт вида `@ryuzaki13/react-foundation-api` намеренно недоступен. Consumer явно выбирает нужный subpath, а сборщик host-проекта не получает общий barrel со всеми transport adapters и React hooks. Типы экспортируются теми же subpath entrypoints через `exports.types`.
26
-
27
- ## Public Entrypoints
21
+ ```ts
22
+ // Неверно: корневой import не опубликован.
23
+ import { odataQueryFn } from "@ryuzaki13/react-foundation-api";
24
+ ```
28
25
 
29
- | Entry point | Назначение |
30
- | ------------------------------------------------- | -------------------------------------------------------------------------- |
31
- | `@ryuzaki13/react-foundation-api/http` | Обычный HTTP/REST transport без SAP/OData side effects. |
32
- | `@ryuzaki13/react-foundation-api/async` | Batch и concurrent async runners с нормализованными ошибками. |
33
- | `@ryuzaki13/react-foundation-api/resource` | Generic resource descriptors поверх TanStack Query. |
34
- | `@ryuzaki13/react-foundation-api/persisted` | Persisted resource helpers, payload codec, REST/OData adapters. |
35
- | `@ryuzaki13/react-foundation-api/odata` | OData/SAP Gateway fetchers, metadata queries, collection hooks и wrappers. |
36
- | `@ryuzaki13/react-foundation-api/transport` | Нормализация transport request payloads. |
37
- | `@ryuzaki13/react-foundation-api/server-fn` | Adapters для server function query/mutation operations. |
38
- | `@ryuzaki13/react-foundation-api/adt` | ADT user transports: fetch и XML parser. |
39
- | `@ryuzaki13/react-foundation-api/error-report` | API-level adapters для error report delivery и draft lifecycle. |
26
+ ## Каталог документации
40
27
 
41
- Других публичных subpath exports сейчас нет. Если модуль не перечислен в `package.json exports`, его нельзя импортировать из host-проекта.
28
+ | Entrypoint | Когда использовать | Подробная страница |
29
+ | --- | --- | --- |
30
+ | `adt` | Получить пользовательские SAP ADT transports и разобрать XML | [ADT](./src/adt/README.mdx) |
31
+ | `async` | Запустить независимые задачи параллельно или с ограничением concurrency | [Async](./src/async/README.mdx) |
32
+ | `error-report` | Доставить подготовленный в `foundation-lib` черновик отчёта | [Error Report](./src/error-report/README.mdx) |
33
+ | `http` | Обычный HTTP/REST без SAP, OData, SSO и X-CSRF | [HTTP](./src/http/README.mdx) |
34
+ | `odata` | OData V2, SAP Gateway, metadata, SSO, X-CSRF, справочники и таблицы | [OData](./src/odata/README.mdx) |
35
+ | `persisted` | Стандартные сохранённые записи: list/latest/history/save/create/delete | [Persisted](./src/persisted/README.mdx) |
36
+ | `resource` | Произвольный transport-agnostic ресурс поверх TanStack Query | [Resource](./src/resource/README.mdx) |
37
+ | `server-fn` | Адаптировать функцию контракта `{ data }` к resource/persisted operation | [Server Function](./src/server-fn/README.mdx) |
38
+ | `transport` | Получить workbench/customizing transport requests пользователя SAP | [SAP Transport Requests](./src/transport/README.mdx) |
42
39
 
43
- ## Peer-зависимости
40
+ Общая карта пакета, границы ответственности и схема выбора entrypoint находятся на странице [Foundation API: обзор](./src/foundationApi.mdx).
44
41
 
45
- `@ryuzaki13/react-foundation-lib` является обязательной peer-зависимостью: этот пакет использует его как нижний технический слой.
42
+ ## Peer dependencies
46
43
 
47
- Внешние пакеты, которые этот пакет импортирует напрямую, объявлены как optional peers. Это означает только то, что их не нужно ставить для каждого сценария. Дополнительные зависимости entrypoint, поступающие через `@ryuzaki13/react-foundation-lib`, определяются peer-контрактом этого нижнего слоя.
44
+ `@ryuzaki13/react-foundation-lib` обязателен. Остальные peers нужны только тем entrypoint, которые их используют.
48
45
 
49
- | Entry point | Что может потребоваться в host-проекте |
50
- | ----------------------------------- | ----------------------------------------------------------------------------------------------------------- |
51
- | `http`, `async`, `transport` | Обычно не требуют дополнительных runtime-зависимостей сверх `@ryuzaki13/react-foundation-lib`. |
52
- | `resource`, `persisted`, `server-fn` | `@tanstack/react-query`; для persisted/query metadata также могут использоваться query persistence helpers. |
53
- | `odata` | `react`, `@tanstack/react-query`, `@ryuzaki13/react-foundation-lib`; для store/cache сценариев также peers `zustand`, `immer`, `zod` могут приходить через используемые `lib` entrypoints. |
54
- | `adt` | `fast-xml-parser` для разбора ADT XML. |
55
- | `error-report` | `@tanstack/react-query` и error-report helpers из `@ryuzaki13/react-foundation-lib`. |
46
+ | Dependency | Где нужна |
47
+ | --- | --- |
48
+ | `@tanstack/react-query` | `resource`, `persisted`, `server-fn`, `odata`, `error-report` |
49
+ | `@tanstack/react-table` | табличный adapter из `odata` |
50
+ | `react` | React hooks из `odata`, `resource`, `persisted` |
51
+ | `fast-xml-parser` | XML parser из `adt` |
56
52
 
57
- Такая схема оставляет пакет библиотечным: React, TanStack Query, XML parser и остальные runtime-библиотеки контролируются host-приложением, а не зашиваются в bundle.
53
+ Проверяйте фактический peer-контракт установленной версии пакета. Optional peer означает «не нужен каждому entrypoint», а не «будет автоматически установлен при первом использовании».
58
54
 
59
55
  ## Проверка пакета
60
56
 
61
- Основные команды разработки:
62
-
63
57
  ```bash
64
58
  npm run lint
65
59
  npm run typecheck
66
60
  npm run test
67
61
  npm run build
68
- ```
69
-
70
- Перед публикацией можно проверить полный npm-артефакт:
71
-
72
- ```bash
73
62
  npm run pack:dry-run
74
63
  ```
75
64
 
76
- `npm run build` собирает ESM-файлы через Vite и декларации типов через `tsc`. `npm run pack:dry-run` прогоняет `validate` и показывает состав npm package без публикации.
65
+ Если символ не экспортируется через указанный в `package.json#exports` subpath, глубокий импорт из `src` или `dist` не является публичным API.
@@ -3,8 +3,8 @@ 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";
5
5
  import { queryOptions as f, useQuery as p, useQueryClient as m } from "@tanstack/react-query";
6
- import { persistedQueryMeta as h } from "@ryuzaki13/react-foundation-lib/query-client";
7
- import { buildEntityOperationPath as g, buildFunctionImportPath as _, buildODataFilter as v, buildODataOrder as y, odataParseValueByMetadata as b, parseServiceMetadata as x } from "@ryuzaki13/react-foundation-lib/odata-service";
6
+ import { buildEntityOperationPath as h, buildFunctionImportPath as g, buildODataFilter as _, buildODataOrder as v, odataParseValueByMetadata as y, parseServiceMetadata as b } from "@ryuzaki13/react-foundation-lib/odata-service";
7
+ import { persistedQueryMeta as x } from "@ryuzaki13/react-foundation-lib/query-client";
8
8
  //#region src/odata/odataBaseQueryKey.ts
9
9
  var S = ["odata"];
10
10
  //#endregion
@@ -15,10 +15,10 @@ function C(e, t, n) {
15
15
  function w(e, t = {}, r = {}) {
16
16
  let [i, a = ""] = e.split("?"), o = new URLSearchParams(a);
17
17
  if (t.expression) {
18
- let e = v(t.expression);
18
+ let e = _(t.expression);
19
19
  e && o.set("$filter", e);
20
20
  }
21
- t.sorts && o.set("$orderby", y(t.sorts)), t.select && o.set("$select", t.select.join(",")), t.expand && o.set("$expand", t.expand.join(",")), C(o, "$top", t.top), C(o, "$skip", t.skip), C(o, "$inlinecount", t.inlinecount);
21
+ t.sorts && o.set("$orderby", v(t.sorts)), t.select && o.set("$select", t.select.join(",")), t.expand && o.set("$expand", t.expand.join(",")), C(o, "$top", t.top), C(o, "$skip", t.skip), C(o, "$inlinecount", t.inlinecount);
22
22
  let s = i.replace(/\/+$/, ""), c = o.toString(), l = c ? `${s}?${c}` : s, u = r;
23
23
  if (t.swCache) {
24
24
  let e = new Headers(r.headers);
@@ -75,7 +75,7 @@ function j(n) {
75
75
  var M = (e) => f({
76
76
  queryKey: k(e),
77
77
  queryFn: j(e),
78
- meta: h,
78
+ meta: x,
79
79
  enabled: !!(e.service && o().metadataVersion),
80
80
  staleTime: e.staleTime ?? D,
81
81
  gcTime: Infinity
@@ -100,7 +100,7 @@ function F(t) {
100
100
  } },
101
101
  transform: async (e) => {
102
102
  try {
103
- return x(await e.text());
103
+ return b(await e.text());
104
104
  } catch (e) {
105
105
  throw Error(`Сервис ${t.service} содержит необработанную ошибку: ${String(e)}`);
106
106
  }
@@ -119,7 +119,7 @@ var I = (t) => {
119
119
  n
120
120
  ],
121
121
  queryFn: F(n),
122
- meta: h,
122
+ meta: x,
123
123
  enabled: !!t.service,
124
124
  staleTime: Infinity,
125
125
  gcTime: Infinity
@@ -193,9 +193,9 @@ function K(e, t) {
193
193
  if (e && (t === "create" || t === "update")) return JSON.stringify(e);
194
194
  }
195
195
  function q(e, t, n, r) {
196
- if (H(e)) return _(e, t, n);
196
+ if (H(e)) return g(e, t, n);
197
197
  if (r === "fi") throw Error(`OData operation 'fi' несовместима с Entity '${t.target}'.`);
198
- return g(e, t, n, r);
198
+ return h(e, t, n, r);
199
199
  }
200
200
  //#endregion
201
201
  //#region src/odata/parseODataResponseByMetadata.ts
@@ -220,7 +220,7 @@ function X(e, t) {
220
220
  for (let r = 0; r < t.length; r += 1) {
221
221
  let i = t[r];
222
222
  if (!Object.prototype.hasOwnProperty.call(e, i.id)) continue;
223
- let a = e[i.id], o = b(i, a);
223
+ let a = e[i.id], o = y(i, a);
224
224
  o !== a && (n ||= { ...e }, n[i.id] = o);
225
225
  }
226
226
  return n ?? e;
@@ -307,4 +307,4 @@ function ie(e) {
307
307
  //#endregion
308
308
  export { S, I as _, re as a, w as b, q as c, K as d, G as f, V as g, F as h, ie as i, H as l, L as m, te as n, ne as o, W as p, Q as r, ee as s, $ as t, U as u, R as v, T as x, z as y };
309
309
 
310
- //# sourceMappingURL=odataFetchFn-vnAXC-c0.js.map
310
+ //# sourceMappingURL=odataFetchFn-B9wSQpUS.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"odataFetchFn-vnAXC-c0.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 * 2;\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 * Повторная инвалидация не отменяет уже запущенный refetch: один сервис может\n * одновременно использоваться несколькими hooks, а результат version-check у них общий.\n */\nexport function invalidateODataMetadataQueries(queryClient: QueryClient, service: string) {\n\treturn queryClient.invalidateQueries(\n\t\t{\n\t\t\tpredicate: (query) => {\n\t\t\t\tconst [baseKey, queryType, queryOptionsValue] = query.queryKey;\n\t\t\t\tif (baseKey !== odataBaseQueryKey[0] || queryType !== \"metadata\") return false;\n\t\t\t\tif (!queryOptionsValue || typeof queryOptionsValue !== \"object\") return false;\n\n\t\t\t\treturn \"service\" in queryOptionsValue && queryOptionsValue.service === service;\n\t\t\t}\n\t\t},\n\t\t{ cancelRefetch: false }\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\tconst resolvedOptions = {\n\t\tservice: options.service,\n\t\tbaseUrl: resolveODataBaseUrl(options.service, options.baseUrl)\n\t};\n\n\treturn queryOptions({\n\t\tqueryKey: [...odataBaseQueryKey, \"metadata\", resolvedOptions],\n\t\tqueryFn: fetchMetadata(resolvedOptions),\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/**\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\t\tconst isPlainEntityQuery = method === \"query\" && !(\"result\" in target);\n\n\t\tif (__DEV__ && isPlainEntityQuery && 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, isPlainEntityQuery ? {} : 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-B9wSQpUS.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 * 2;\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 * Повторная инвалидация не отменяет уже запущенный refetch: один сервис может\n * одновременно использоваться несколькими hooks, а результат version-check у них общий.\n */\nexport function invalidateODataMetadataQueries(queryClient: QueryClient, service: string) {\n\treturn queryClient.invalidateQueries(\n\t\t{\n\t\t\tpredicate: (query) => {\n\t\t\t\tconst [baseKey, queryType, queryOptionsValue] = query.queryKey;\n\t\t\t\tif (baseKey !== odataBaseQueryKey[0] || queryType !== \"metadata\") return false;\n\t\t\t\tif (!queryOptionsValue || typeof queryOptionsValue !== \"object\") return false;\n\n\t\t\t\treturn \"service\" in queryOptionsValue && queryOptionsValue.service === service;\n\t\t\t}\n\t\t},\n\t\t{ cancelRefetch: false }\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\tconst resolvedOptions = {\n\t\tservice: options.service,\n\t\tbaseUrl: resolveODataBaseUrl(options.service, options.baseUrl)\n\t};\n\n\treturn queryOptions({\n\t\tqueryKey: [...odataBaseQueryKey, \"metadata\", resolvedOptions],\n\t\tqueryFn: fetchMetadata(resolvedOptions),\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/**\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\t\tconst isPlainEntityQuery = method === \"query\" && !(\"result\" in target);\n\n\t\tif (__DEV__ && isPlainEntityQuery && 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, isPlainEntityQuery ? {} : 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,4 +1,4 @@
1
- import { type CollectionItem } from "@ryuzaki13/react-foundation-lib/odata";
1
+ import { type CollectionItem } from "@ryuzaki13/react-foundation-lib/odata-service";
2
2
  import { type ODataFetchOptions } from "./odataFetch";
3
3
  interface ODataServiceResult<T extends CollectionItem> {
4
4
  items: T[];
@@ -1 +1 @@
1
- {"version":3,"file":"fetchCollectionData.d.ts","sourceRoot":"","sources":["../../src/odata/fetchCollectionData.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,cAAc,EAAE,MAAM,uCAAuC,CAAC;AAG5E,OAAO,EAAc,KAAK,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAIlE,UAAU,kBAAkB,CAAC,CAAC,SAAS,cAAc;IACpD,KAAK,EAAE,CAAC,EAAE,CAAC;CACX;AAED;;GAEG;AACH,wBAAsB,mBAAmB,CAAC,CAAC,SAAS,cAAc,EAAE,MAAM,EAAE;IAC3E,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,CAAC,EAAE,iBAAiB,CAAC,CAAC,CAAC,CAAC;IAC7B,MAAM,EAAE,WAAW,CAAC;CACpB,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAAC,CAAC,CAAC,CA0BjC"}
1
+ {"version":3,"file":"fetchCollectionData.d.ts","sourceRoot":"","sources":["../../src/odata/fetchCollectionData.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,cAAc,EAAE,MAAM,+CAA+C,CAAC;AAGpF,OAAO,EAAc,KAAK,iBAAiB,EAAE,MAAM,cAAc,CAAC;AAIlE,UAAU,kBAAkB,CAAC,CAAC,SAAS,cAAc;IACpD,KAAK,EAAE,CAAC,EAAE,CAAC;CACX;AAED;;GAEG;AACH,wBAAsB,mBAAmB,CAAC,CAAC,SAAS,cAAc,EAAE,MAAM,EAAE;IAC3E,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,CAAC,EAAE,iBAAiB,CAAC,CAAC,CAAC,CAAC;IAC7B,MAAM,EAAE,WAAW,CAAC;CACpB,GAAG,OAAO,CAAC,kBAAkB,CAAC,CAAC,CAAC,CAAC,CA0BjC"}