@intlayer/api 9.5.12 → 9.7.0

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 (177) hide show
  1. package/dist/cjs/distantDictionary/fetchDistantDictionaries.cjs.map +1 -1
  2. package/dist/cjs/distantDictionary/fetchDistantDictionary.cjs.map +1 -1
  3. package/dist/cjs/fetcher.cjs.map +1 -1
  4. package/dist/cjs/getIntlayerAPI/ai.cjs +76 -22
  5. package/dist/cjs/getIntlayerAPI/ai.cjs.map +1 -1
  6. package/dist/cjs/getIntlayerAPI/analytics.cjs +44 -10
  7. package/dist/cjs/getIntlayerAPI/analytics.cjs.map +1 -1
  8. package/dist/cjs/getIntlayerAPI/asset.cjs +38 -8
  9. package/dist/cjs/getIntlayerAPI/asset.cjs.map +1 -1
  10. package/dist/cjs/getIntlayerAPI/audit.cjs +70 -16
  11. package/dist/cjs/getIntlayerAPI/audit.cjs.map +1 -1
  12. package/dist/cjs/getIntlayerAPI/bitbucket.cjs +39 -9
  13. package/dist/cjs/getIntlayerAPI/bitbucket.cjs.map +1 -1
  14. package/dist/cjs/getIntlayerAPI/codeberg.cjs +21 -0
  15. package/dist/cjs/getIntlayerAPI/codeberg.cjs.map +1 -0
  16. package/dist/cjs/getIntlayerAPI/dictionary.cjs +59 -13
  17. package/dist/cjs/getIntlayerAPI/dictionary.cjs.map +1 -1
  18. package/dist/cjs/getIntlayerAPI/editor.cjs.map +1 -1
  19. package/dist/cjs/getIntlayerAPI/environment.cjs +44 -10
  20. package/dist/cjs/getIntlayerAPI/environment.cjs.map +1 -1
  21. package/dist/cjs/getIntlayerAPI/forge.cjs +64 -0
  22. package/dist/cjs/getIntlayerAPI/forge.cjs.map +1 -0
  23. package/dist/cjs/getIntlayerAPI/gitee.cjs +21 -0
  24. package/dist/cjs/getIntlayerAPI/gitee.cjs.map +1 -0
  25. package/dist/cjs/getIntlayerAPI/github.cjs +44 -10
  26. package/dist/cjs/getIntlayerAPI/github.cjs.map +1 -1
  27. package/dist/cjs/getIntlayerAPI/gitlab.cjs +39 -9
  28. package/dist/cjs/getIntlayerAPI/gitlab.cjs.map +1 -1
  29. package/dist/cjs/getIntlayerAPI/index.cjs +4 -0
  30. package/dist/cjs/getIntlayerAPI/index.cjs.map +1 -1
  31. package/dist/cjs/getIntlayerAPI/newsletter.cjs +28 -6
  32. package/dist/cjs/getIntlayerAPI/newsletter.cjs.map +1 -1
  33. package/dist/cjs/getIntlayerAPI/oAuth.cjs +31 -5
  34. package/dist/cjs/getIntlayerAPI/oAuth.cjs.map +1 -1
  35. package/dist/cjs/getIntlayerAPI/organization.cjs +72 -20
  36. package/dist/cjs/getIntlayerAPI/organization.cjs.map +1 -1
  37. package/dist/cjs/getIntlayerAPI/project.cjs +112 -29
  38. package/dist/cjs/getIntlayerAPI/project.cjs.map +1 -1
  39. package/dist/cjs/getIntlayerAPI/reviewer.cjs +142 -31
  40. package/dist/cjs/getIntlayerAPI/reviewer.cjs.map +1 -1
  41. package/dist/cjs/getIntlayerAPI/search.cjs +15 -3
  42. package/dist/cjs/getIntlayerAPI/search.cjs.map +1 -1
  43. package/dist/cjs/getIntlayerAPI/showcaseProject.cjs +61 -15
  44. package/dist/cjs/getIntlayerAPI/showcaseProject.cjs.map +1 -1
  45. package/dist/cjs/getIntlayerAPI/status.cjs +16 -3
  46. package/dist/cjs/getIntlayerAPI/status.cjs.map +1 -1
  47. package/dist/cjs/getIntlayerAPI/stripe.cjs +141 -35
  48. package/dist/cjs/getIntlayerAPI/stripe.cjs.map +1 -1
  49. package/dist/cjs/getIntlayerAPI/tag.cjs +33 -7
  50. package/dist/cjs/getIntlayerAPI/tag.cjs.map +1 -1
  51. package/dist/cjs/getIntlayerAPI/translate.cjs +46 -8
  52. package/dist/cjs/getIntlayerAPI/translate.cjs.map +1 -1
  53. package/dist/cjs/getIntlayerAPI/user.cjs +58 -14
  54. package/dist/cjs/getIntlayerAPI/user.cjs.map +1 -1
  55. package/dist/cjs/index.cjs +8 -0
  56. package/dist/cjs/proxy.cjs +4 -0
  57. package/dist/cjs/proxy.cjs.map +1 -1
  58. package/dist/cjs/public/createPublicClient.cjs +25 -5
  59. package/dist/cjs/public/createPublicClient.cjs.map +1 -1
  60. package/dist/esm/distantDictionary/fetchDistantDictionaries.mjs.map +1 -1
  61. package/dist/esm/distantDictionary/fetchDistantDictionary.mjs.map +1 -1
  62. package/dist/esm/fetcher.mjs.map +1 -1
  63. package/dist/esm/getIntlayerAPI/ai.mjs +76 -22
  64. package/dist/esm/getIntlayerAPI/ai.mjs.map +1 -1
  65. package/dist/esm/getIntlayerAPI/analytics.mjs +44 -10
  66. package/dist/esm/getIntlayerAPI/analytics.mjs.map +1 -1
  67. package/dist/esm/getIntlayerAPI/asset.mjs +38 -8
  68. package/dist/esm/getIntlayerAPI/asset.mjs.map +1 -1
  69. package/dist/esm/getIntlayerAPI/audit.mjs +70 -16
  70. package/dist/esm/getIntlayerAPI/audit.mjs.map +1 -1
  71. package/dist/esm/getIntlayerAPI/bitbucket.mjs +39 -9
  72. package/dist/esm/getIntlayerAPI/bitbucket.mjs.map +1 -1
  73. package/dist/esm/getIntlayerAPI/codeberg.mjs +19 -0
  74. package/dist/esm/getIntlayerAPI/codeberg.mjs.map +1 -0
  75. package/dist/esm/getIntlayerAPI/dictionary.mjs +59 -13
  76. package/dist/esm/getIntlayerAPI/dictionary.mjs.map +1 -1
  77. package/dist/esm/getIntlayerAPI/editor.mjs.map +1 -1
  78. package/dist/esm/getIntlayerAPI/environment.mjs +44 -10
  79. package/dist/esm/getIntlayerAPI/environment.mjs.map +1 -1
  80. package/dist/esm/getIntlayerAPI/forge.mjs +63 -0
  81. package/dist/esm/getIntlayerAPI/forge.mjs.map +1 -0
  82. package/dist/esm/getIntlayerAPI/gitee.mjs +19 -0
  83. package/dist/esm/getIntlayerAPI/gitee.mjs.map +1 -0
  84. package/dist/esm/getIntlayerAPI/github.mjs +44 -10
  85. package/dist/esm/getIntlayerAPI/github.mjs.map +1 -1
  86. package/dist/esm/getIntlayerAPI/gitlab.mjs +39 -9
  87. package/dist/esm/getIntlayerAPI/gitlab.mjs.map +1 -1
  88. package/dist/esm/getIntlayerAPI/index.mjs +4 -0
  89. package/dist/esm/getIntlayerAPI/index.mjs.map +1 -1
  90. package/dist/esm/getIntlayerAPI/newsletter.mjs +28 -6
  91. package/dist/esm/getIntlayerAPI/newsletter.mjs.map +1 -1
  92. package/dist/esm/getIntlayerAPI/oAuth.mjs +31 -5
  93. package/dist/esm/getIntlayerAPI/oAuth.mjs.map +1 -1
  94. package/dist/esm/getIntlayerAPI/organization.mjs +72 -20
  95. package/dist/esm/getIntlayerAPI/organization.mjs.map +1 -1
  96. package/dist/esm/getIntlayerAPI/project.mjs +112 -29
  97. package/dist/esm/getIntlayerAPI/project.mjs.map +1 -1
  98. package/dist/esm/getIntlayerAPI/reviewer.mjs +142 -31
  99. package/dist/esm/getIntlayerAPI/reviewer.mjs.map +1 -1
  100. package/dist/esm/getIntlayerAPI/search.mjs +15 -3
  101. package/dist/esm/getIntlayerAPI/search.mjs.map +1 -1
  102. package/dist/esm/getIntlayerAPI/showcaseProject.mjs +61 -15
  103. package/dist/esm/getIntlayerAPI/showcaseProject.mjs.map +1 -1
  104. package/dist/esm/getIntlayerAPI/status.mjs +16 -3
  105. package/dist/esm/getIntlayerAPI/status.mjs.map +1 -1
  106. package/dist/esm/getIntlayerAPI/stripe.mjs +141 -35
  107. package/dist/esm/getIntlayerAPI/stripe.mjs.map +1 -1
  108. package/dist/esm/getIntlayerAPI/tag.mjs +33 -7
  109. package/dist/esm/getIntlayerAPI/tag.mjs.map +1 -1
  110. package/dist/esm/getIntlayerAPI/translate.mjs +46 -8
  111. package/dist/esm/getIntlayerAPI/translate.mjs.map +1 -1
  112. package/dist/esm/getIntlayerAPI/user.mjs +58 -14
  113. package/dist/esm/getIntlayerAPI/user.mjs.map +1 -1
  114. package/dist/esm/index.mjs +4 -1
  115. package/dist/esm/proxy.mjs +4 -0
  116. package/dist/esm/proxy.mjs.map +1 -1
  117. package/dist/esm/public/createPublicClient.mjs +25 -5
  118. package/dist/esm/public/createPublicClient.mjs.map +1 -1
  119. package/dist/types/distantDictionary/fetchDistantDictionaries.d.ts +1 -1
  120. package/dist/types/distantDictionary/fetchDistantDictionary.d.ts +1 -1
  121. package/dist/types/fetcher.d.ts +1 -1
  122. package/dist/types/fetcher.d.ts.map +1 -1
  123. package/dist/types/getIntlayerAPI/ai.d.ts +1 -1
  124. package/dist/types/getIntlayerAPI/ai.d.ts.map +1 -1
  125. package/dist/types/getIntlayerAPI/analytics.d.ts +1 -1
  126. package/dist/types/getIntlayerAPI/analytics.d.ts.map +1 -1
  127. package/dist/types/getIntlayerAPI/asset.d.ts +1 -0
  128. package/dist/types/getIntlayerAPI/asset.d.ts.map +1 -1
  129. package/dist/types/getIntlayerAPI/audit.d.ts +47 -3
  130. package/dist/types/getIntlayerAPI/audit.d.ts.map +1 -1
  131. package/dist/types/getIntlayerAPI/bitbucket.d.ts.map +1 -1
  132. package/dist/types/getIntlayerAPI/codeberg.d.ts +23 -0
  133. package/dist/types/getIntlayerAPI/codeberg.d.ts.map +1 -0
  134. package/dist/types/getIntlayerAPI/dictionary.d.ts +1 -1
  135. package/dist/types/getIntlayerAPI/dictionary.d.ts.map +1 -1
  136. package/dist/types/getIntlayerAPI/editor.d.ts +2 -1
  137. package/dist/types/getIntlayerAPI/editor.d.ts.map +1 -1
  138. package/dist/types/getIntlayerAPI/environment.d.ts +1 -1
  139. package/dist/types/getIntlayerAPI/environment.d.ts.map +1 -1
  140. package/dist/types/getIntlayerAPI/forge.d.ts +17 -0
  141. package/dist/types/getIntlayerAPI/forge.d.ts.map +1 -0
  142. package/dist/types/getIntlayerAPI/gitee.d.ts +23 -0
  143. package/dist/types/getIntlayerAPI/gitee.d.ts.map +1 -0
  144. package/dist/types/getIntlayerAPI/github.d.ts.map +1 -1
  145. package/dist/types/getIntlayerAPI/gitlab.d.ts.map +1 -1
  146. package/dist/types/getIntlayerAPI/index.d.ts +4 -0
  147. package/dist/types/getIntlayerAPI/index.d.ts.map +1 -1
  148. package/dist/types/getIntlayerAPI/newsletter.d.ts +1 -1
  149. package/dist/types/getIntlayerAPI/newsletter.d.ts.map +1 -1
  150. package/dist/types/getIntlayerAPI/oAuth.d.ts +2 -0
  151. package/dist/types/getIntlayerAPI/oAuth.d.ts.map +1 -1
  152. package/dist/types/getIntlayerAPI/organization.d.ts +1 -3
  153. package/dist/types/getIntlayerAPI/organization.d.ts.map +1 -1
  154. package/dist/types/getIntlayerAPI/project.d.ts +2 -1
  155. package/dist/types/getIntlayerAPI/project.d.ts.map +1 -1
  156. package/dist/types/getIntlayerAPI/reviewer.d.ts +680 -35
  157. package/dist/types/getIntlayerAPI/reviewer.d.ts.map +1 -1
  158. package/dist/types/getIntlayerAPI/search.d.ts +1 -1
  159. package/dist/types/getIntlayerAPI/search.d.ts.map +1 -1
  160. package/dist/types/getIntlayerAPI/showcaseProject.d.ts +1 -1
  161. package/dist/types/getIntlayerAPI/showcaseProject.d.ts.map +1 -1
  162. package/dist/types/getIntlayerAPI/status.d.ts +3 -4
  163. package/dist/types/getIntlayerAPI/status.d.ts.map +1 -1
  164. package/dist/types/getIntlayerAPI/stripe.d.ts +1 -1
  165. package/dist/types/getIntlayerAPI/stripe.d.ts.map +1 -1
  166. package/dist/types/getIntlayerAPI/tag.d.ts +1 -1
  167. package/dist/types/getIntlayerAPI/tag.d.ts.map +1 -1
  168. package/dist/types/getIntlayerAPI/translate.d.ts +1 -1
  169. package/dist/types/getIntlayerAPI/translate.d.ts.map +1 -1
  170. package/dist/types/getIntlayerAPI/user.d.ts +4 -4
  171. package/dist/types/getIntlayerAPI/user.d.ts.map +1 -1
  172. package/dist/types/index.d.ts +7 -4
  173. package/dist/types/proxy.d.ts.map +1 -1
  174. package/dist/types/public/createPublicClient.d.ts +1 -7
  175. package/dist/types/public/createPublicClient.d.ts.map +1 -1
  176. package/dist/types/types.d.ts +5 -2
  177. package/package.json +22 -5
@@ -1,17 +1,71 @@
1
1
  import { fetcher } from "../fetcher.mjs";
2
2
  import { createEndpoint } from "../cms/createIntlayerCMS.mjs";
3
3
  import { editor } from "@intlayer/config/built";
4
+ import { buildRouteURL } from "@intlayer/backend-contract/defineRoute";
5
+ import { BACKEND_URL } from "@intlayer/config/defaultValues";
4
6
 
5
7
  //#region src/getIntlayerAPI/ai.ts
8
+ /** Prefix of the routes, checked against the backend contract. */
9
+ const aiGroup = { prefix: "/api/ai" };
10
+ /**
11
+ * Method and path of every route, checked against the backend contract at
12
+ * compile time (the contract's zod schemas are never loaded).
13
+ */
14
+ const aiEndpoints = {
15
+ customQuery: {
16
+ method: "POST",
17
+ path: "/"
18
+ },
19
+ translateJSON: {
20
+ method: "POST",
21
+ path: "/translate/json"
22
+ },
23
+ auditContentDeclaration: {
24
+ method: "POST",
25
+ path: "/audit/dictionary"
26
+ },
27
+ auditContentDeclarationField: {
28
+ method: "POST",
29
+ path: "/audit/dictionary/field"
30
+ },
31
+ auditContentDeclarationMetadata: {
32
+ method: "POST",
33
+ path: "/audit/dictionary/metadata"
34
+ },
35
+ auditTag: {
36
+ method: "POST",
37
+ path: "/audit/tag"
38
+ },
39
+ ask: {
40
+ method: "POST",
41
+ path: "/ask"
42
+ },
43
+ chat: {
44
+ method: "POST",
45
+ path: "/chat"
46
+ },
47
+ autocomplete: {
48
+ method: "POST",
49
+ path: "/autocomplete"
50
+ },
51
+ getDiscussions: {
52
+ method: "GET",
53
+ path: "/discussions"
54
+ },
55
+ getAIStats: {
56
+ method: "GET",
57
+ path: "/stats"
58
+ }
59
+ };
6
60
  const getAiAPI = (authAPIOptions = {}, intlayerConfig) => {
7
- const AI_API_ROUTE = `${intlayerConfig?.editor?.backendURL ?? editor.backendURL}/api/ai`;
61
+ const backendURL = intlayerConfig?.editor?.backendURL ?? editor.backendURL ?? BACKEND_URL;
8
62
  /**
9
63
  * Custom query
10
64
  * @param body - Custom query parameters.
11
65
  * @returns Custom query result.
12
66
  */
13
- const customQuery = async (body, otherOptions = {}) => await fetcher(AI_API_ROUTE, authAPIOptions, otherOptions, {
14
- method: "POST",
67
+ const customQuery = async (body, otherOptions = {}) => await fetcher(buildRouteURL(backendURL, aiGroup, aiEndpoints.customQuery), authAPIOptions, otherOptions, {
68
+ method: aiEndpoints.customQuery.method,
15
69
  body
16
70
  });
17
71
  /**
@@ -19,8 +73,8 @@ const getAiAPI = (authAPIOptions = {}, intlayerConfig) => {
19
73
  * @param body - Audit file parameters.
20
74
  * @returns Audited file content.
21
75
  */
22
- const translateJSON = async (body, otherOptions = {}) => await fetcher(`${AI_API_ROUTE}/translate/json`, authAPIOptions, otherOptions, {
23
- method: "POST",
76
+ const translateJSON = async (body, otherOptions = {}) => await fetcher(buildRouteURL(backendURL, aiGroup, aiEndpoints.translateJSON), authAPIOptions, otherOptions, {
77
+ method: aiEndpoints.translateJSON.method,
24
78
  body
25
79
  });
26
80
  /**
@@ -28,8 +82,8 @@ const getAiAPI = (authAPIOptions = {}, intlayerConfig) => {
28
82
  * @param body - Audit file parameters.
29
83
  * @returns Audited file content.
30
84
  */
31
- const auditContentDeclaration = async (body, otherOptions = {}) => await fetcher(`${AI_API_ROUTE}/audit/dictionary`, authAPIOptions, otherOptions, {
32
- method: "POST",
85
+ const auditContentDeclaration = async (body, otherOptions = {}) => await fetcher(buildRouteURL(backendURL, aiGroup, aiEndpoints.auditContentDeclaration), authAPIOptions, otherOptions, {
86
+ method: aiEndpoints.auditContentDeclaration.method,
33
87
  body
34
88
  });
35
89
  /**
@@ -37,8 +91,8 @@ const getAiAPI = (authAPIOptions = {}, intlayerConfig) => {
37
91
  * @param body - Audit file parameters.
38
92
  * @returns Audited file content.
39
93
  */
40
- const auditContentDeclarationField = async (body, otherOptions = {}) => await fetcher(`${AI_API_ROUTE}/audit/dictionary/field`, authAPIOptions, otherOptions, {
41
- method: "POST",
94
+ const auditContentDeclarationField = async (body, otherOptions = {}) => await fetcher(buildRouteURL(backendURL, aiGroup, aiEndpoints.auditContentDeclarationField), authAPIOptions, otherOptions, {
95
+ method: aiEndpoints.auditContentDeclarationField.method,
42
96
  body
43
97
  });
44
98
  /**
@@ -46,8 +100,8 @@ const getAiAPI = (authAPIOptions = {}, intlayerConfig) => {
46
100
  * @param body - Audit file parameters.
47
101
  * @returns Audited file content.
48
102
  */
49
- const auditContentDeclarationMetadata = async (body, otherOptions = {}) => await fetcher(`${AI_API_ROUTE}/audit/dictionary/metadata`, authAPIOptions, otherOptions, {
50
- method: "POST",
103
+ const auditContentDeclarationMetadata = async (body, otherOptions = {}) => await fetcher(buildRouteURL(backendURL, aiGroup, aiEndpoints.auditContentDeclarationMetadata), authAPIOptions, otherOptions, {
104
+ method: aiEndpoints.auditContentDeclarationMetadata.method,
51
105
  body
52
106
  });
53
107
  /**
@@ -55,8 +109,8 @@ const getAiAPI = (authAPIOptions = {}, intlayerConfig) => {
55
109
  * @param body - Audit tag parameters.
56
110
  * @returns Audited tag content.
57
111
  */
58
- const auditTag = async (body, otherOptions = {}) => await fetcher(`${AI_API_ROUTE}/audit/tag`, authAPIOptions, otherOptions, {
59
- method: "POST",
112
+ const auditTag = async (body, otherOptions = {}) => await fetcher(buildRouteURL(backendURL, aiGroup, aiEndpoints.auditTag), authAPIOptions, otherOptions, {
113
+ method: aiEndpoints.auditTag.method,
60
114
  body
61
115
  });
62
116
  /**
@@ -83,8 +137,8 @@ const getAiAPI = (authAPIOptions = {}, intlayerConfig) => {
83
137
  const { onMessage, onDone, ...rest } = body;
84
138
  const abortController = new AbortController();
85
139
  try {
86
- const response = await fetch(`${AI_API_ROUTE}/ask`, {
87
- method: "POST",
140
+ const response = await fetch(buildRouteURL(backendURL, aiGroup, aiEndpoints.ask), {
141
+ method: aiEndpoints.ask.method,
88
142
  headers: {
89
143
  "Content-Type": "application/json",
90
144
  ...authAPIOptions.headers,
@@ -140,8 +194,8 @@ const getAiAPI = (authAPIOptions = {}, intlayerConfig) => {
140
194
  const { onMessage, onDone, onAction, ...rest } = body;
141
195
  const abortController = new AbortController();
142
196
  try {
143
- const response = await fetch(`${AI_API_ROUTE}/chat`, {
144
- method: "POST",
197
+ const response = await fetch(buildRouteURL(backendURL, aiGroup, aiEndpoints.chat), {
198
+ method: aiEndpoints.chat.method,
145
199
  headers: {
146
200
  "Content-Type": "application/json",
147
201
  ...authAPIOptions.headers,
@@ -193,22 +247,22 @@ const getAiAPI = (authAPIOptions = {}, intlayerConfig) => {
193
247
  throw error;
194
248
  }
195
249
  };
196
- const autocomplete = async (body, otherOptions = {}) => await fetcher(`${AI_API_ROUTE}/autocomplete`, authAPIOptions, otherOptions, {
197
- method: "POST",
250
+ const autocomplete = async (body, otherOptions = {}) => await fetcher(buildRouteURL(backendURL, aiGroup, aiEndpoints.autocomplete), authAPIOptions, otherOptions, {
251
+ method: aiEndpoints.autocomplete.method,
198
252
  body
199
253
  });
200
254
  /**
201
255
  * Retrieves discussions with filters and pagination. Only user or admin can access.
202
256
  */
203
- const getDiscussions = async (params, otherOptions = {}) => await fetcher(`${AI_API_ROUTE}/discussions`, authAPIOptions, otherOptions, {
204
- method: "GET",
257
+ const getDiscussions = async (params, otherOptions = {}) => await fetcher(buildRouteURL(backendURL, aiGroup, aiEndpoints.getDiscussions), authAPIOptions, otherOptions, {
258
+ method: aiEndpoints.getDiscussions.method,
205
259
  params
206
260
  });
207
261
  /**
208
262
  * Retrieves aggregated AI token-usage statistics for the currently selected
209
263
  * project.
210
264
  */
211
- const getAIStats = async (otherOptions = {}) => await fetcher(`${AI_API_ROUTE}/stats`, authAPIOptions, otherOptions, { method: "GET" });
265
+ const getAIStats = async (otherOptions = {}) => await fetcher(buildRouteURL(backendURL, aiGroup, aiEndpoints.getAIStats), authAPIOptions, otherOptions, { method: aiEndpoints.getAIStats.method });
212
266
  return {
213
267
  customQuery,
214
268
  translateJSON,
@@ -1 +1 @@
1
- {"version":3,"file":"ai.mjs","names":[],"sources":["../../../src/getIntlayerAPI/ai.ts"],"sourcesContent":["import type {\n AIOptions,\n AskDocQuestionResult,\n AuditContentDeclarationBody,\n AuditContentDeclarationFieldBody,\n AuditContentDeclarationFieldResult,\n AuditContentDeclarationMetadataBody,\n AuditContentDeclarationMetadataResult,\n AuditContentDeclarationResult,\n AuditTagBody,\n AuditTagResult,\n AutocompleteResponse,\n ChatCompletionRequestMessage,\n ChatResult,\n CustomQueryBody,\n CustomQueryResult,\n GetAIStatsResult,\n GetDiscussionsParams,\n GetDiscussionsResult,\n TranslateJSONBody,\n TranslateJSONResult,\n} from '@intlayer/backend';\nimport { editor } from '@intlayer/config/built';\nimport type { IntlayerConfig } from '@intlayer/types/config';\nimport { createEndpoint } from '../cms/createIntlayerCMS';\nimport { type FetcherOptions, fetcher } from '../fetcher';\n\nexport type AutocompleteBody = {\n text: string;\n aiOptions?: AIOptions;\n contextBefore?: string;\n currentLine?: string;\n contextAfter?: string;\n};\n\nexport type AskDocQuestionBody = {\n messages: ChatCompletionRequestMessage[];\n discussionId: string;\n onMessage?: (chunk: string) => void;\n onDone?: (response: AskDocQuestionResult) => void;\n};\n\nexport type ClientAction =\n | { type: 'navigate'; path: string }\n | { type: 'invalidate_queries' };\n\nexport type ChatBody = {\n messages: ChatCompletionRequestMessage[];\n discussionId: string;\n onMessage?: (chunk: string) => void;\n onDone?: (response: ChatResult) => void;\n onAction?: (action: ClientAction) => void;\n};\n\nexport type { AskDocQuestionResult, ChatResult };\n\nexport const getAiAPI = (\n authAPIOptions: FetcherOptions = {},\n intlayerConfig?: IntlayerConfig\n) => {\n const backendURL = intlayerConfig?.editor?.backendURL ?? editor.backendURL;\n\n const AI_API_ROUTE = `${backendURL}/api/ai`;\n\n /**\n * Custom query\n * @param body - Custom query parameters.\n * @returns Custom query result.\n */\n const customQuery = async (\n body?: CustomQueryBody,\n otherOptions: FetcherOptions = {}\n ) =>\n await fetcher<CustomQueryResult>(\n AI_API_ROUTE,\n authAPIOptions,\n otherOptions,\n {\n method: 'POST',\n body: body,\n }\n );\n\n /**\n * Translate a JSON\n * @param body - Audit file parameters.\n * @returns Audited file content.\n */\n const translateJSON = async (\n body?: TranslateJSONBody,\n otherOptions: FetcherOptions = {}\n ) =>\n await fetcher<TranslateJSONResult>(\n `${AI_API_ROUTE}/translate/json`,\n authAPIOptions,\n otherOptions,\n {\n method: 'POST',\n body: body,\n }\n );\n\n /**\n * Audits a content declaration file\n * @param body - Audit file parameters.\n * @returns Audited file content.\n */\n const auditContentDeclaration = async (\n body?: AuditContentDeclarationBody,\n otherOptions: FetcherOptions = {}\n ) =>\n await fetcher<AuditContentDeclarationResult>(\n `${AI_API_ROUTE}/audit/dictionary`,\n authAPIOptions,\n otherOptions,\n {\n method: 'POST',\n body: body,\n }\n );\n\n /**\n * Audits a content declaration field\n * @param body - Audit file parameters.\n * @returns Audited file content.\n */\n const auditContentDeclarationField = async (\n body?: AuditContentDeclarationFieldBody,\n otherOptions: FetcherOptions = {}\n ) =>\n await fetcher<AuditContentDeclarationFieldResult>(\n `${AI_API_ROUTE}/audit/dictionary/field`,\n authAPIOptions,\n otherOptions,\n {\n method: 'POST',\n body: body,\n }\n );\n\n /**\n * Audits a content declaration file to retrieve title, description and tags\n * @param body - Audit file parameters.\n * @returns Audited file content.\n */\n const auditContentDeclarationMetadata = async (\n body?: AuditContentDeclarationMetadataBody,\n otherOptions: FetcherOptions = {}\n ) =>\n await fetcher<AuditContentDeclarationMetadataResult>(\n `${AI_API_ROUTE}/audit/dictionary/metadata`,\n authAPIOptions,\n otherOptions,\n {\n method: 'POST',\n body: body,\n }\n );\n\n /**\n * Audits a tag\n * @param body - Audit tag parameters.\n * @returns Audited tag content.\n */\n const auditTag = async (\n body?: AuditTagBody,\n otherOptions: FetcherOptions = {}\n ) =>\n await fetcher<AuditTagResult>(\n `${AI_API_ROUTE}/audit/tag`,\n authAPIOptions,\n otherOptions,\n {\n method: 'POST',\n body: body,\n }\n );\n\n /**\n * Asks a question to the AI related to the documentation **and streams the\n * answer as Server‑Sent Events (SSE)**.\n *\n * The function **returns immediately** with a handle exposing:\n * - `promise` → resolves when the stream completes (or rejects on error)\n * - `abort()` → allows canceling the request on demand\n *\n * Usage example:\n * ```ts\n * const { promise, abort } = ai.askDocQuestion({\n * ...body,\n * onMessage: console.log,\n * onDone: (full) => console.log(\"✔\", full),\n * });\n * // later → abort();\n * await promise; // waits for completion if desired\n * ```\n */\n const askDocQuestion = async (\n body?: AskDocQuestionBody,\n otherOptions: FetcherOptions = {}\n ) => {\n if (!body) return;\n\n const { onMessage, onDone, ...rest } = body;\n const abortController = new AbortController();\n\n try {\n const response = await fetch(`${AI_API_ROUTE}/ask`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n ...authAPIOptions.headers,\n ...otherOptions.headers,\n },\n body: JSON.stringify({\n ...rest,\n ...authAPIOptions.body,\n ...otherOptions.body,\n }),\n signal: abortController.signal,\n credentials: 'include',\n });\n\n if (!response.ok) {\n // Align error handling with generic `fetcher` utility so that callers receive\n // meaningful messages (e.g. for 429 \"Too Many Requests\" responses).\n let errorMessage: string = 'An error occurred';\n\n try {\n // Attempt to parse JSON error payload produced by backend\n const errorData = await response.json();\n const errorObj = errorData.error ?? errorData;\n errorMessage = JSON.stringify(errorObj) ?? 'An error occurred';\n } catch {\n // Fallback to plain-text body or HTTP status text\n try {\n const errorText = await response.text();\n if (errorText) {\n errorMessage = errorText;\n }\n } catch {\n // ignore – we already have a default message\n }\n }\n\n throw new Error(errorMessage);\n }\n\n const reader = response.body?.getReader();\n if (!reader) {\n throw new Error('No reader available');\n }\n\n const decoder = new TextDecoder();\n let buffer = '';\n\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n\n buffer += decoder.decode(value, { stream: true });\n const lines = buffer.split('\\n');\n buffer = lines.pop() ?? '';\n\n for (const line of lines) {\n if (line.startsWith('data: ')) {\n try {\n const data = JSON.parse(line.slice(6));\n if (data.chunk) {\n onMessage?.(data.chunk);\n }\n if (data.done && data.response) {\n onDone?.(data.response);\n }\n } catch (e) {\n console.error('Failed to parse SSE data:', e);\n }\n }\n }\n }\n } catch (error) {\n console.error('Error in askDocQuestion:', error);\n throw error;\n }\n };\n\n const chat = async (body?: ChatBody, otherOptions: FetcherOptions = {}) => {\n if (!body) return;\n\n const { onMessage, onDone, onAction, ...rest } = body;\n const abortController = new AbortController();\n\n try {\n const response = await fetch(`${AI_API_ROUTE}/chat`, {\n method: 'POST',\n headers: {\n 'Content-Type': 'application/json',\n ...authAPIOptions.headers,\n ...otherOptions.headers,\n },\n body: JSON.stringify({\n ...rest,\n ...authAPIOptions.body,\n ...otherOptions.body,\n }),\n signal: abortController.signal,\n credentials: 'include',\n });\n\n if (!response.ok) {\n let errorMessage: string = 'An error occurred';\n\n try {\n const errorData = await response.json();\n const errorObj = errorData.error ?? errorData;\n errorMessage = JSON.stringify(errorObj) ?? 'An error occurred';\n } catch {\n try {\n const errorText = await response.text();\n if (errorText) {\n errorMessage = errorText;\n }\n } catch {\n // ignore\n }\n }\n\n throw new Error(errorMessage);\n }\n\n const reader = response.body?.getReader();\n if (!reader) {\n throw new Error('No reader available');\n }\n\n const decoder = new TextDecoder();\n let buffer = '';\n\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n\n buffer += decoder.decode(value, { stream: true });\n const lines = buffer.split('\\n');\n buffer = lines.pop() ?? '';\n\n for (const line of lines) {\n if (line.startsWith('data: ')) {\n try {\n const data = JSON.parse(line.slice(6));\n if (data.chunk) {\n onMessage?.(data.chunk);\n }\n if (data.action) {\n onAction?.(data.action);\n }\n if (data.done && data.response) {\n onDone?.(data.response);\n }\n } catch (e) {\n console.error('Failed to parse SSE data:', e);\n }\n }\n }\n }\n } catch (error) {\n console.error('Error in chat:', error);\n throw error;\n }\n };\n\n const autocomplete = async (\n body?: AutocompleteBody,\n otherOptions: FetcherOptions = {}\n ) =>\n await fetcher<AutocompleteResponse>(\n `${AI_API_ROUTE}/autocomplete`,\n authAPIOptions,\n otherOptions,\n {\n method: 'POST',\n body: body,\n }\n );\n\n /**\n * Retrieves discussions with filters and pagination. Only user or admin can access.\n */\n const getDiscussions = async (\n params?: GetDiscussionsParams,\n otherOptions: FetcherOptions = {}\n ) =>\n await fetcher<GetDiscussionsResult>(\n `${AI_API_ROUTE}/discussions`,\n authAPIOptions,\n otherOptions,\n {\n method: 'GET',\n // @ts-ignore Number of parameter will be stringified by the fetcher\n params,\n }\n );\n\n /**\n * Retrieves aggregated AI token-usage statistics for the currently selected\n * project.\n */\n const getAIStats = async (otherOptions: FetcherOptions = {}) =>\n await fetcher<GetAIStatsResult>(\n `${AI_API_ROUTE}/stats`,\n authAPIOptions,\n otherOptions,\n {\n method: 'GET',\n }\n );\n\n return {\n customQuery,\n translateJSON,\n auditContentDeclaration,\n auditContentDeclarationField,\n auditContentDeclarationMetadata,\n auditTag,\n askDocQuestion,\n chat,\n autocomplete,\n getDiscussions,\n getAIStats,\n };\n};\n\n/**\n * Authenticated `ai` endpoint bound to an Intlayer CMS authenticator.\n *\n * Pass an authenticator created with `createIntlayerCMS`, or omit it to use\n * the build-time configuration (`@intlayer/config/built`).\n */\nexport const aiEndpoint = createEndpoint(getAiAPI);\n"],"mappings":";;;;;AAwDA,MAAa,YACX,iBAAiC,CAAC,GAClC,mBACG;CAGH,MAAM,eAAe,GAFF,gBAAgB,QAAQ,cAAc,OAAO,WAE7B;;;;;;CAOnC,MAAM,cAAc,OAClB,MACA,eAA+B,CAAC,MAEhC,MAAM,QACJ,cACA,gBACA,cACA;EACE,QAAQ;EACF;CACR,CACF;;;;;;CAOF,MAAM,gBAAgB,OACpB,MACA,eAA+B,CAAC,MAEhC,MAAM,QACJ,GAAG,aAAa,kBAChB,gBACA,cACA;EACE,QAAQ;EACF;CACR,CACF;;;;;;CAOF,MAAM,0BAA0B,OAC9B,MACA,eAA+B,CAAC,MAEhC,MAAM,QACJ,GAAG,aAAa,oBAChB,gBACA,cACA;EACE,QAAQ;EACF;CACR,CACF;;;;;;CAOF,MAAM,+BAA+B,OACnC,MACA,eAA+B,CAAC,MAEhC,MAAM,QACJ,GAAG,aAAa,0BAChB,gBACA,cACA;EACE,QAAQ;EACF;CACR,CACF;;;;;;CAOF,MAAM,kCAAkC,OACtC,MACA,eAA+B,CAAC,MAEhC,MAAM,QACJ,GAAG,aAAa,6BAChB,gBACA,cACA;EACE,QAAQ;EACF;CACR,CACF;;;;;;CAOF,MAAM,WAAW,OACf,MACA,eAA+B,CAAC,MAEhC,MAAM,QACJ,GAAG,aAAa,aAChB,gBACA,cACA;EACE,QAAQ;EACF;CACR,CACF;;;;;;;;;;;;;;;;;;;;CAqBF,MAAM,iBAAiB,OACrB,MACA,eAA+B,CAAC,MAC7B;EACH,IAAI,CAAC,MAAM;EAEX,MAAM,EAAE,WAAW,QAAQ,GAAG,SAAS;EACvC,MAAM,kBAAkB,IAAI,gBAAgB;EAE5C,IAAI;GACF,MAAM,WAAW,MAAM,MAAM,GAAG,aAAa,OAAO;IAClD,QAAQ;IACR,SAAS;KACP,gBAAgB;KAChB,GAAG,eAAe;KAClB,GAAG,aAAa;IAClB;IACA,MAAM,KAAK,UAAU;KACnB,GAAG;KACH,GAAG,eAAe;KAClB,GAAG,aAAa;IAClB,CAAC;IACD,QAAQ,gBAAgB;IACxB,aAAa;GACf,CAAC;GAED,IAAI,CAAC,SAAS,IAAI;IAGhB,IAAI,eAAuB;IAE3B,IAAI;KAEF,MAAM,YAAY,MAAM,SAAS,KAAK;KACtC,MAAM,WAAW,UAAU,SAAS;KACpC,eAAe,KAAK,UAAU,QAAQ,KAAK;IAC7C,QAAQ;KAEN,IAAI;MACF,MAAM,YAAY,MAAM,SAAS,KAAK;MACtC,IAAI,WACF,eAAe;KAEnB,QAAQ,CAER;IACF;IAEA,MAAM,IAAI,MAAM,YAAY;GAC9B;GAEA,MAAM,SAAS,SAAS,MAAM,UAAU;GACxC,IAAI,CAAC,QACH,MAAM,IAAI,MAAM,qBAAqB;GAGvC,MAAM,UAAU,IAAI,YAAY;GAChC,IAAI,SAAS;GAEb,OAAO,MAAM;IACX,MAAM,EAAE,MAAM,UAAU,MAAM,OAAO,KAAK;IAC1C,IAAI,MAAM;IAEV,UAAU,QAAQ,OAAO,OAAO,EAAE,QAAQ,KAAK,CAAC;IAChD,MAAM,QAAQ,OAAO,MAAM,IAAI;IAC/B,SAAS,MAAM,IAAI,KAAK;IAExB,KAAK,MAAM,QAAQ,OACjB,IAAI,KAAK,WAAW,QAAQ,GAC1B,IAAI;KACF,MAAM,OAAO,KAAK,MAAM,KAAK,MAAM,CAAC,CAAC;KACrC,IAAI,KAAK,OACP,YAAY,KAAK,KAAK;KAExB,IAAI,KAAK,QAAQ,KAAK,UACpB,SAAS,KAAK,QAAQ;IAE1B,SAAS,GAAG;KACV,QAAQ,MAAM,6BAA6B,CAAC;IAC9C;GAGN;EACF,SAAS,OAAO;GACd,QAAQ,MAAM,4BAA4B,KAAK;GAC/C,MAAM;EACR;CACF;CAEA,MAAM,OAAO,OAAO,MAAiB,eAA+B,CAAC,MAAM;EACzE,IAAI,CAAC,MAAM;EAEX,MAAM,EAAE,WAAW,QAAQ,UAAU,GAAG,SAAS;EACjD,MAAM,kBAAkB,IAAI,gBAAgB;EAE5C,IAAI;GACF,MAAM,WAAW,MAAM,MAAM,GAAG,aAAa,QAAQ;IACnD,QAAQ;IACR,SAAS;KACP,gBAAgB;KAChB,GAAG,eAAe;KAClB,GAAG,aAAa;IAClB;IACA,MAAM,KAAK,UAAU;KACnB,GAAG;KACH,GAAG,eAAe;KAClB,GAAG,aAAa;IAClB,CAAC;IACD,QAAQ,gBAAgB;IACxB,aAAa;GACf,CAAC;GAED,IAAI,CAAC,SAAS,IAAI;IAChB,IAAI,eAAuB;IAE3B,IAAI;KACF,MAAM,YAAY,MAAM,SAAS,KAAK;KACtC,MAAM,WAAW,UAAU,SAAS;KACpC,eAAe,KAAK,UAAU,QAAQ,KAAK;IAC7C,QAAQ;KACN,IAAI;MACF,MAAM,YAAY,MAAM,SAAS,KAAK;MACtC,IAAI,WACF,eAAe;KAEnB,QAAQ,CAER;IACF;IAEA,MAAM,IAAI,MAAM,YAAY;GAC9B;GAEA,MAAM,SAAS,SAAS,MAAM,UAAU;GACxC,IAAI,CAAC,QACH,MAAM,IAAI,MAAM,qBAAqB;GAGvC,MAAM,UAAU,IAAI,YAAY;GAChC,IAAI,SAAS;GAEb,OAAO,MAAM;IACX,MAAM,EAAE,MAAM,UAAU,MAAM,OAAO,KAAK;IAC1C,IAAI,MAAM;IAEV,UAAU,QAAQ,OAAO,OAAO,EAAE,QAAQ,KAAK,CAAC;IAChD,MAAM,QAAQ,OAAO,MAAM,IAAI;IAC/B,SAAS,MAAM,IAAI,KAAK;IAExB,KAAK,MAAM,QAAQ,OACjB,IAAI,KAAK,WAAW,QAAQ,GAC1B,IAAI;KACF,MAAM,OAAO,KAAK,MAAM,KAAK,MAAM,CAAC,CAAC;KACrC,IAAI,KAAK,OACP,YAAY,KAAK,KAAK;KAExB,IAAI,KAAK,QACP,WAAW,KAAK,MAAM;KAExB,IAAI,KAAK,QAAQ,KAAK,UACpB,SAAS,KAAK,QAAQ;IAE1B,SAAS,GAAG;KACV,QAAQ,MAAM,6BAA6B,CAAC;IAC9C;GAGN;EACF,SAAS,OAAO;GACd,QAAQ,MAAM,kBAAkB,KAAK;GACrC,MAAM;EACR;CACF;CAEA,MAAM,eAAe,OACnB,MACA,eAA+B,CAAC,MAEhC,MAAM,QACJ,GAAG,aAAa,gBAChB,gBACA,cACA;EACE,QAAQ;EACF;CACR,CACF;;;;CAKF,MAAM,iBAAiB,OACrB,QACA,eAA+B,CAAC,MAEhC,MAAM,QACJ,GAAG,aAAa,eAChB,gBACA,cACA;EACE,QAAQ;EAER;CACF,CACF;;;;;CAMF,MAAM,aAAa,OAAO,eAA+B,CAAC,MACxD,MAAM,QACJ,GAAG,aAAa,SAChB,gBACA,cACA,EACE,QAAQ,MACV,CACF;CAEF,OAAO;EACL;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CACF;AACF;;;;;;;AAQA,MAAa,aAAa,eAAe,QAAQ"}
1
+ {"version":3,"file":"ai.mjs","names":[],"sources":["../../../src/getIntlayerAPI/ai.ts"],"sourcesContent":["import type {\n AIOptions,\n AIRoutes,\n AskDocQuestionResult,\n AuditContentDeclarationBody,\n AuditContentDeclarationFieldBody,\n AuditContentDeclarationFieldResult,\n AuditContentDeclarationMetadataBody,\n AuditContentDeclarationMetadataResult,\n AuditContentDeclarationResult,\n AuditTagBody,\n AuditTagResult,\n AutocompleteResponse,\n aiContract,\n ChatCompletionRequestMessage,\n ChatResult,\n CustomQueryBody,\n CustomQueryResult,\n GetAIStatsResult,\n GetDiscussionsParams,\n GetDiscussionsResult,\n TranslateJSONBody,\n TranslateJSONResult,\n} from '@intlayer/backend-contract/ai';\nimport type { RouteEndpoints } from '@intlayer/backend-contract/defineRoute';\nimport { buildRouteURL } from '@intlayer/backend-contract/defineRoute';\nimport { editor } from '@intlayer/config/built';\nimport { BACKEND_URL } from '@intlayer/config/defaultValues';\nimport type { IntlayerConfig } from '@intlayer/types/config';\nimport { createEndpoint } from '../cms/createIntlayerCMS';\nimport { type FetcherOptions, fetcher } from '../fetcher';\n\nexport type AutocompleteBody = {\n text: string;\n aiOptions?: AIOptions;\n contextBefore?: string;\n currentLine?: string;\n contextAfter?: string;\n};\n\nexport type AskDocQuestionBody = {\n messages: ChatCompletionRequestMessage[];\n discussionId: string;\n onMessage?: (chunk: string) => void;\n onDone?: (response: AskDocQuestionResult) => void;\n};\n\nexport type ClientAction =\n | { type: 'navigate'; path: string }\n | { type: 'invalidate_queries' };\n\nexport type ChatBody = {\n messages: ChatCompletionRequestMessage[];\n discussionId: string;\n onMessage?: (chunk: string) => void;\n onDone?: (response: ChatResult) => void;\n onAction?: (action: ClientAction) => void;\n};\n\nexport type { AskDocQuestionResult, ChatResult };\n\n/** Prefix of the routes, checked against the backend contract. */\nconst aiGroup = {\n prefix: '/api/ai',\n} as const satisfies Pick<typeof aiContract, 'prefix'>;\n\n/**\n * Method and path of every route, checked against the backend contract at\n * compile time (the contract's zod schemas are never loaded).\n */\nconst aiEndpoints = {\n customQuery: { method: 'POST', path: '/' },\n translateJSON: { method: 'POST', path: '/translate/json' },\n auditContentDeclaration: { method: 'POST', path: '/audit/dictionary' },\n auditContentDeclarationField: {\n method: 'POST',\n path: '/audit/dictionary/field',\n },\n auditContentDeclarationMetadata: {\n method: 'POST',\n path: '/audit/dictionary/metadata',\n },\n auditTag: { method: 'POST', path: '/audit/tag' },\n ask: { method: 'POST', path: '/ask' },\n chat: { method: 'POST', path: '/chat' },\n autocomplete: { method: 'POST', path: '/autocomplete' },\n getDiscussions: { method: 'GET', path: '/discussions' },\n getAIStats: { method: 'GET', path: '/stats' },\n} as const satisfies RouteEndpoints<AIRoutes>;\n\nexport const getAiAPI = (\n authAPIOptions: FetcherOptions = {},\n intlayerConfig?: IntlayerConfig\n) => {\n const backendURL =\n intlayerConfig?.editor?.backendURL ?? editor.backendURL ?? BACKEND_URL;\n\n /**\n * Custom query\n * @param body - Custom query parameters.\n * @returns Custom query result.\n */\n const customQuery = async (\n body?: CustomQueryBody,\n otherOptions: FetcherOptions = {}\n ) =>\n await fetcher<CustomQueryResult>(\n buildRouteURL(backendURL, aiGroup, aiEndpoints.customQuery),\n authAPIOptions,\n otherOptions,\n {\n method: aiEndpoints.customQuery.method,\n body: body,\n }\n );\n\n /**\n * Translate a JSON\n * @param body - Audit file parameters.\n * @returns Audited file content.\n */\n const translateJSON = async (\n body?: TranslateJSONBody,\n otherOptions: FetcherOptions = {}\n ) =>\n await fetcher<TranslateJSONResult>(\n buildRouteURL(backendURL, aiGroup, aiEndpoints.translateJSON),\n authAPIOptions,\n otherOptions,\n {\n method: aiEndpoints.translateJSON.method,\n body: body,\n }\n );\n\n /**\n * Audits a content declaration file\n * @param body - Audit file parameters.\n * @returns Audited file content.\n */\n const auditContentDeclaration = async (\n body?: AuditContentDeclarationBody,\n otherOptions: FetcherOptions = {}\n ) =>\n await fetcher<AuditContentDeclarationResult>(\n buildRouteURL(backendURL, aiGroup, aiEndpoints.auditContentDeclaration),\n authAPIOptions,\n otherOptions,\n {\n method: aiEndpoints.auditContentDeclaration.method,\n body: body,\n }\n );\n\n /**\n * Audits a content declaration field\n * @param body - Audit file parameters.\n * @returns Audited file content.\n */\n const auditContentDeclarationField = async (\n body?: AuditContentDeclarationFieldBody,\n otherOptions: FetcherOptions = {}\n ) =>\n await fetcher<AuditContentDeclarationFieldResult>(\n buildRouteURL(\n backendURL,\n aiGroup,\n aiEndpoints.auditContentDeclarationField\n ),\n authAPIOptions,\n otherOptions,\n {\n method: aiEndpoints.auditContentDeclarationField.method,\n body: body,\n }\n );\n\n /**\n * Audits a content declaration file to retrieve title, description and tags\n * @param body - Audit file parameters.\n * @returns Audited file content.\n */\n const auditContentDeclarationMetadata = async (\n body?: AuditContentDeclarationMetadataBody,\n otherOptions: FetcherOptions = {}\n ) =>\n await fetcher<AuditContentDeclarationMetadataResult>(\n buildRouteURL(\n backendURL,\n aiGroup,\n aiEndpoints.auditContentDeclarationMetadata\n ),\n authAPIOptions,\n otherOptions,\n {\n method: aiEndpoints.auditContentDeclarationMetadata.method,\n body: body,\n }\n );\n\n /**\n * Audits a tag\n * @param body - Audit tag parameters.\n * @returns Audited tag content.\n */\n const auditTag = async (\n body?: AuditTagBody,\n otherOptions: FetcherOptions = {}\n ) =>\n await fetcher<AuditTagResult>(\n buildRouteURL(backendURL, aiGroup, aiEndpoints.auditTag),\n authAPIOptions,\n otherOptions,\n {\n method: aiEndpoints.auditTag.method,\n body: body,\n }\n );\n\n /**\n * Asks a question to the AI related to the documentation **and streams the\n * answer as Server‑Sent Events (SSE)**.\n *\n * The function **returns immediately** with a handle exposing:\n * - `promise` → resolves when the stream completes (or rejects on error)\n * - `abort()` → allows canceling the request on demand\n *\n * Usage example:\n * ```ts\n * const { promise, abort } = ai.askDocQuestion({\n * ...body,\n * onMessage: console.log,\n * onDone: (full) => console.log(\"✔\", full),\n * });\n * // later → abort();\n * await promise; // waits for completion if desired\n * ```\n */\n const askDocQuestion = async (\n body?: AskDocQuestionBody,\n otherOptions: FetcherOptions = {}\n ) => {\n if (!body) return;\n\n const { onMessage, onDone, ...rest } = body;\n const abortController = new AbortController();\n\n try {\n const response = await fetch(\n buildRouteURL(backendURL, aiGroup, aiEndpoints.ask),\n {\n method: aiEndpoints.ask.method,\n headers: {\n 'Content-Type': 'application/json',\n ...authAPIOptions.headers,\n ...otherOptions.headers,\n },\n body: JSON.stringify({\n ...rest,\n ...authAPIOptions.body,\n ...otherOptions.body,\n }),\n signal: abortController.signal,\n credentials: 'include',\n }\n );\n\n if (!response.ok) {\n // Align error handling with generic `fetcher` utility so that callers receive\n // meaningful messages (e.g. for 429 \"Too Many Requests\" responses).\n let errorMessage: string = 'An error occurred';\n\n try {\n // Attempt to parse JSON error payload produced by backend\n const errorData = await response.json();\n const errorObj = errorData.error ?? errorData;\n errorMessage = JSON.stringify(errorObj) ?? 'An error occurred';\n } catch {\n // Fallback to plain-text body or HTTP status text\n try {\n const errorText = await response.text();\n if (errorText) {\n errorMessage = errorText;\n }\n } catch {\n // ignore – we already have a default message\n }\n }\n\n throw new Error(errorMessage);\n }\n\n const reader = response.body?.getReader();\n if (!reader) {\n throw new Error('No reader available');\n }\n\n const decoder = new TextDecoder();\n let buffer = '';\n\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n\n buffer += decoder.decode(value, { stream: true });\n const lines = buffer.split('\\n');\n buffer = lines.pop() ?? '';\n\n for (const line of lines) {\n if (line.startsWith('data: ')) {\n try {\n const data = JSON.parse(line.slice(6));\n if (data.chunk) {\n onMessage?.(data.chunk);\n }\n if (data.done && data.response) {\n onDone?.(data.response);\n }\n } catch (e) {\n console.error('Failed to parse SSE data:', e);\n }\n }\n }\n }\n } catch (error) {\n console.error('Error in askDocQuestion:', error);\n throw error;\n }\n };\n\n const chat = async (body?: ChatBody, otherOptions: FetcherOptions = {}) => {\n if (!body) return;\n\n const { onMessage, onDone, onAction, ...rest } = body;\n const abortController = new AbortController();\n\n try {\n const response = await fetch(\n buildRouteURL(backendURL, aiGroup, aiEndpoints.chat),\n {\n method: aiEndpoints.chat.method,\n headers: {\n 'Content-Type': 'application/json',\n ...authAPIOptions.headers,\n ...otherOptions.headers,\n },\n body: JSON.stringify({\n ...rest,\n ...authAPIOptions.body,\n ...otherOptions.body,\n }),\n signal: abortController.signal,\n credentials: 'include',\n }\n );\n\n if (!response.ok) {\n let errorMessage: string = 'An error occurred';\n\n try {\n const errorData = await response.json();\n const errorObj = errorData.error ?? errorData;\n errorMessage = JSON.stringify(errorObj) ?? 'An error occurred';\n } catch {\n try {\n const errorText = await response.text();\n if (errorText) {\n errorMessage = errorText;\n }\n } catch {\n // ignore\n }\n }\n\n throw new Error(errorMessage);\n }\n\n const reader = response.body?.getReader();\n if (!reader) {\n throw new Error('No reader available');\n }\n\n const decoder = new TextDecoder();\n let buffer = '';\n\n while (true) {\n const { done, value } = await reader.read();\n if (done) break;\n\n buffer += decoder.decode(value, { stream: true });\n const lines = buffer.split('\\n');\n buffer = lines.pop() ?? '';\n\n for (const line of lines) {\n if (line.startsWith('data: ')) {\n try {\n const data = JSON.parse(line.slice(6));\n if (data.chunk) {\n onMessage?.(data.chunk);\n }\n if (data.action) {\n onAction?.(data.action);\n }\n if (data.done && data.response) {\n onDone?.(data.response);\n }\n } catch (e) {\n console.error('Failed to parse SSE data:', e);\n }\n }\n }\n }\n } catch (error) {\n console.error('Error in chat:', error);\n throw error;\n }\n };\n\n const autocomplete = async (\n body?: AutocompleteBody,\n otherOptions: FetcherOptions = {}\n ) =>\n await fetcher<AutocompleteResponse>(\n buildRouteURL(backendURL, aiGroup, aiEndpoints.autocomplete),\n authAPIOptions,\n otherOptions,\n {\n method: aiEndpoints.autocomplete.method,\n body: body,\n }\n );\n\n /**\n * Retrieves discussions with filters and pagination. Only user or admin can access.\n */\n const getDiscussions = async (\n params?: GetDiscussionsParams,\n otherOptions: FetcherOptions = {}\n ) =>\n await fetcher<GetDiscussionsResult>(\n buildRouteURL(backendURL, aiGroup, aiEndpoints.getDiscussions),\n authAPIOptions,\n otherOptions,\n {\n method: aiEndpoints.getDiscussions.method,\n // @ts-ignore Number of parameter will be stringified by the fetcher\n params,\n }\n );\n\n /**\n * Retrieves aggregated AI token-usage statistics for the currently selected\n * project.\n */\n const getAIStats = async (otherOptions: FetcherOptions = {}) =>\n await fetcher<GetAIStatsResult>(\n buildRouteURL(backendURL, aiGroup, aiEndpoints.getAIStats),\n authAPIOptions,\n otherOptions,\n {\n method: aiEndpoints.getAIStats.method,\n }\n );\n\n return {\n customQuery,\n translateJSON,\n auditContentDeclaration,\n auditContentDeclarationField,\n auditContentDeclarationMetadata,\n auditTag,\n askDocQuestion,\n chat,\n autocomplete,\n getDiscussions,\n getAIStats,\n };\n};\n\n/**\n * Authenticated `ai` endpoint bound to an Intlayer CMS authenticator.\n *\n * Pass an authenticator created with `createIntlayerCMS`, or omit it to use\n * the build-time configuration (`@intlayer/config/built`).\n */\nexport const aiEndpoint = createEndpoint(getAiAPI);\n"],"mappings":"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"}
@@ -1,25 +1,59 @@
1
1
  import { fetcher } from "../fetcher.mjs";
2
2
  import { createEndpoint } from "../cms/createIntlayerCMS.mjs";
3
3
  import { editor } from "@intlayer/config/built";
4
+ import { buildRouteURL } from "@intlayer/backend-contract/defineRoute";
5
+ import { BACKEND_URL } from "@intlayer/config/defaultValues";
4
6
 
5
7
  //#region src/getIntlayerAPI/analytics.ts
8
+ /** Prefix of the routes, checked against the backend contract. */
9
+ const analyticsGroup = { prefix: "/api/analytics" };
10
+ /**
11
+ * Method and path of every route, checked against the backend contract at
12
+ * compile time (the contract's zod schemas are never loaded).
13
+ */
14
+ const analyticsEndpoints = {
15
+ ingestAnalyticsEvents: {
16
+ method: "POST",
17
+ path: "/events"
18
+ },
19
+ getAnalyticsOverview: {
20
+ method: "GET",
21
+ path: "/overview"
22
+ },
23
+ getAnalyticsAudience: {
24
+ method: "GET",
25
+ path: "/audience"
26
+ },
27
+ getContentStats: {
28
+ method: "GET",
29
+ path: "/content-stats"
30
+ },
31
+ getExperimentResults: {
32
+ method: "GET",
33
+ path: "/experiments/:experimentKey"
34
+ },
35
+ getPageMetadata: {
36
+ method: "GET",
37
+ path: "/page-metadata"
38
+ }
39
+ };
6
40
  const getAnalyticsAPI = (authAPIOptions = {}, intlayerConfig) => {
7
- const ANALYTICS_API_ROUTE = `${intlayerConfig?.editor?.backendURL ?? editor.backendURL}/api/analytics`;
41
+ const backendURL = intlayerConfig?.editor?.backendURL ?? editor.backendURL ?? BACKEND_URL;
8
42
  /**
9
43
  * Ingest a batch of analytics events. Public — attribution is by the
10
44
  * project's `clientId` in the body.
11
45
  * @param body - Session id, sdk version, and the collected events.
12
46
  * @returns The number of accepted events.
13
47
  */
14
- const sendEvents = async (body, otherOptions = {}) => await fetcher(`${ANALYTICS_API_ROUTE}/events`, authAPIOptions, otherOptions, {
15
- method: "POST",
48
+ const sendEvents = async (body, otherOptions = {}) => await fetcher(buildRouteURL(backendURL, analyticsGroup, analyticsEndpoints.ingestAnalyticsEvents), authAPIOptions, otherOptions, {
49
+ method: analyticsEndpoints.ingestAnalyticsEvents.method,
16
50
  body
17
51
  });
18
52
  /**
19
53
  * Page/locale totals for the authenticated project.
20
54
  * @returns Views grouped by url and locale.
21
55
  */
22
- const getOverview = async (otherOptions = {}) => await fetcher(`${ANALYTICS_API_ROUTE}/overview`, authAPIOptions, otherOptions, { method: "GET" });
56
+ const getOverview = async (otherOptions = {}) => await fetcher(buildRouteURL(backendURL, analyticsGroup, analyticsEndpoints.getAnalyticsOverview), authAPIOptions, otherOptions, { method: analyticsEndpoints.getAnalyticsOverview.method });
23
57
  /**
24
58
  * Audience report: distinct visitors (today / 7d / window), page views, the
25
59
  * evolution series, and locale + country breakdowns.
@@ -27,28 +61,28 @@ const getAnalyticsAPI = (authAPIOptions = {}, intlayerConfig) => {
27
61
  * `30d`, `90d`, `6mo`, `1y`, `3y`) or a number of days (default 30).
28
62
  * @returns The audience statistics.
29
63
  */
30
- const getAudience = async (range = 30, otherOptions = {}) => await fetcher(`${ANALYTICS_API_ROUTE}/audience`, authAPIOptions, otherOptions, {
31
- method: "GET",
64
+ const getAudience = async (range = 30, otherOptions = {}) => await fetcher(buildRouteURL(backendURL, analyticsGroup, analyticsEndpoints.getAnalyticsAudience), authAPIOptions, otherOptions, {
65
+ method: analyticsEndpoints.getAnalyticsAudience.method,
32
66
  params: typeof range === "number" ? { days: String(range) } : { range }
33
67
  });
34
68
  /**
35
69
  * Per-content exposure totals — "which content is actually shown".
36
70
  * @returns Exposures grouped by dictionary key, key path, and locale.
37
71
  */
38
- const getContentStats = async (otherOptions = {}) => await fetcher(`${ANALYTICS_API_ROUTE}/content-stats`, authAPIOptions, otherOptions, { method: "GET" });
72
+ const getContentStats = async (otherOptions = {}) => await fetcher(buildRouteURL(backendURL, analyticsGroup, analyticsEndpoints.getContentStats), authAPIOptions, otherOptions, { method: analyticsEndpoints.getContentStats.method });
39
73
  /**
40
74
  * A/B experiment results with per-variant conversion rates and significance.
41
75
  * @param experimentKey - The experiment to evaluate.
42
76
  * @returns The experiment result set.
43
77
  */
44
- const getExperimentResults = async (experimentKey, otherOptions = {}) => await fetcher(`${ANALYTICS_API_ROUTE}/experiments/${experimentKey}`, authAPIOptions, otherOptions, { method: "GET" });
78
+ const getExperimentResults = async (experimentKey, otherOptions = {}) => await fetcher(buildRouteURL(backendURL, analyticsGroup, analyticsEndpoints.getExperimentResults, { experimentKey }), authAPIOptions, otherOptions, { method: analyticsEndpoints.getExperimentResults.method });
45
79
  /**
46
80
  * Page metadata (title and meta description) for a given url.
47
81
  * @param url - The page url to inspect.
48
82
  * @returns Title and description of the page.
49
83
  */
50
- const getPageMetadata = async (url, otherOptions = {}) => await fetcher(`${ANALYTICS_API_ROUTE}/page-metadata`, authAPIOptions, otherOptions, {
51
- method: "GET",
84
+ const getPageMetadata = async (url, otherOptions = {}) => await fetcher(buildRouteURL(backendURL, analyticsGroup, analyticsEndpoints.getPageMetadata), authAPIOptions, otherOptions, {
85
+ method: analyticsEndpoints.getPageMetadata.method,
52
86
  params: { url }
53
87
  });
54
88
  return {
@@ -1 +1 @@
1
- {"version":3,"file":"analytics.mjs","names":[],"sources":["../../../src/getIntlayerAPI/analytics.ts"],"sourcesContent":["import type {\n AudienceRange,\n GetAnalyticsOverviewResult,\n GetAudienceResult,\n GetContentStatsResult,\n GetExperimentResultsResult,\n GetPageMetadataResult,\n IngestAnalyticsBody,\n IngestAnalyticsResult,\n} from '@intlayer/backend';\nimport { editor } from '@intlayer/config/built';\nimport type { IntlayerConfig } from '@intlayer/types/config';\nimport { createEndpoint } from '../cms/createIntlayerCMS';\nimport { type FetcherOptions, fetcher } from '../fetcher';\n\nexport const getAnalyticsAPI = (\n authAPIOptions: FetcherOptions = {},\n intlayerConfig?: IntlayerConfig\n) => {\n const backendURL = intlayerConfig?.editor?.backendURL ?? editor.backendURL;\n\n const ANALYTICS_API_ROUTE = `${backendURL}/api/analytics`;\n\n /**\n * Ingest a batch of analytics events. Public — attribution is by the\n * project's `clientId` in the body.\n * @param body - Session id, sdk version, and the collected events.\n * @returns The number of accepted events.\n */\n const sendEvents = async (\n body: IngestAnalyticsBody,\n otherOptions: FetcherOptions = {}\n ) =>\n await fetcher<IngestAnalyticsResult>(\n `${ANALYTICS_API_ROUTE}/events`,\n authAPIOptions,\n otherOptions,\n {\n method: 'POST',\n body,\n }\n );\n\n /**\n * Page/locale totals for the authenticated project.\n * @returns Views grouped by url and locale.\n */\n const getOverview = async (otherOptions: FetcherOptions = {}) =>\n await fetcher<GetAnalyticsOverviewResult>(\n `${ANALYTICS_API_ROUTE}/overview`,\n authAPIOptions,\n otherOptions,\n { method: 'GET' }\n );\n\n /**\n * Audience report: distinct visitors (today / 7d / window), page views, the\n * evolution series, and locale + country breakdowns.\n * @param range - Rolling window, either a named range (`1h`, `24h`, `7d`,\n * `30d`, `90d`, `6mo`, `1y`, `3y`) or a number of days (default 30).\n * @returns The audience statistics.\n */\n const getAudience = async (\n range: AudienceRange | number = 30,\n otherOptions: FetcherOptions = {}\n ) =>\n await fetcher<GetAudienceResult>(\n `${ANALYTICS_API_ROUTE}/audience`,\n authAPIOptions,\n otherOptions,\n {\n method: 'GET',\n params: typeof range === 'number' ? { days: String(range) } : { range },\n }\n );\n\n /**\n * Per-content exposure totals — \"which content is actually shown\".\n * @returns Exposures grouped by dictionary key, key path, and locale.\n */\n const getContentStats = async (otherOptions: FetcherOptions = {}) =>\n await fetcher<GetContentStatsResult>(\n `${ANALYTICS_API_ROUTE}/content-stats`,\n authAPIOptions,\n otherOptions,\n { method: 'GET' }\n );\n\n /**\n * A/B experiment results with per-variant conversion rates and significance.\n * @param experimentKey - The experiment to evaluate.\n * @returns The experiment result set.\n */\n const getExperimentResults = async (\n experimentKey: string,\n otherOptions: FetcherOptions = {}\n ) =>\n await fetcher<GetExperimentResultsResult>(\n `${ANALYTICS_API_ROUTE}/experiments/${experimentKey}`,\n authAPIOptions,\n otherOptions,\n { method: 'GET' }\n );\n\n /**\n * Page metadata (title and meta description) for a given url.\n * @param url - The page url to inspect.\n * @returns Title and description of the page.\n */\n const getPageMetadata = async (\n url: string,\n otherOptions: FetcherOptions = {}\n ) =>\n await fetcher<GetPageMetadataResult>(\n `${ANALYTICS_API_ROUTE}/page-metadata`,\n authAPIOptions,\n otherOptions,\n {\n method: 'GET',\n params: { url },\n }\n );\n\n return {\n sendEvents,\n getOverview,\n getAudience,\n getContentStats,\n getExperimentResults,\n getPageMetadata,\n };\n};\n\n/**\n * Authenticated `analytics` endpoint bound to an Intlayer CMS authenticator.\n *\n * Pass an authenticator created with `createIntlayerCMS`, or omit it to use\n * the build-time configuration (`@intlayer/config/built`).\n */\nexport const analyticsEndpoint = createEndpoint(getAnalyticsAPI);\n"],"mappings":";;;;;AAeA,MAAa,mBACX,iBAAiC,CAAC,GAClC,mBACG;CAGH,MAAM,sBAAsB,GAFT,gBAAgB,QAAQ,cAAc,OAAO,WAEtB;;;;;;;CAQ1C,MAAM,aAAa,OACjB,MACA,eAA+B,CAAC,MAEhC,MAAM,QACJ,GAAG,oBAAoB,UACvB,gBACA,cACA;EACE,QAAQ;EACR;CACF,CACF;;;;;CAMF,MAAM,cAAc,OAAO,eAA+B,CAAC,MACzD,MAAM,QACJ,GAAG,oBAAoB,YACvB,gBACA,cACA,EAAE,QAAQ,MAAM,CAClB;;;;;;;;CASF,MAAM,cAAc,OAClB,QAAgC,IAChC,eAA+B,CAAC,MAEhC,MAAM,QACJ,GAAG,oBAAoB,YACvB,gBACA,cACA;EACE,QAAQ;EACR,QAAQ,OAAO,UAAU,WAAW,EAAE,MAAM,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM;CACxE,CACF;;;;;CAMF,MAAM,kBAAkB,OAAO,eAA+B,CAAC,MAC7D,MAAM,QACJ,GAAG,oBAAoB,iBACvB,gBACA,cACA,EAAE,QAAQ,MAAM,CAClB;;;;;;CAOF,MAAM,uBAAuB,OAC3B,eACA,eAA+B,CAAC,MAEhC,MAAM,QACJ,GAAG,oBAAoB,eAAe,iBACtC,gBACA,cACA,EAAE,QAAQ,MAAM,CAClB;;;;;;CAOF,MAAM,kBAAkB,OACtB,KACA,eAA+B,CAAC,MAEhC,MAAM,QACJ,GAAG,oBAAoB,iBACvB,gBACA,cACA;EACE,QAAQ;EACR,QAAQ,EAAE,IAAI;CAChB,CACF;CAEF,OAAO;EACL;EACA;EACA;EACA;EACA;EACA;CACF;AACF;;;;;;;AAQA,MAAa,oBAAoB,eAAe,eAAe"}
1
+ {"version":3,"file":"analytics.mjs","names":[],"sources":["../../../src/getIntlayerAPI/analytics.ts"],"sourcesContent":["import type {\n AnalyticsRoutes,\n AudienceRange,\n analyticsContract,\n GetAnalyticsOverviewResult,\n GetAudienceResult,\n GetContentStatsResult,\n GetExperimentResultsResult,\n GetPageMetadataResult,\n IngestAnalyticsBody,\n IngestAnalyticsResult,\n} from '@intlayer/backend-contract/analytics';\nimport type { RouteEndpoints } from '@intlayer/backend-contract/defineRoute';\nimport { buildRouteURL } from '@intlayer/backend-contract/defineRoute';\nimport { editor } from '@intlayer/config/built';\nimport { BACKEND_URL } from '@intlayer/config/defaultValues';\nimport type { IntlayerConfig } from '@intlayer/types/config';\nimport { createEndpoint } from '../cms/createIntlayerCMS';\nimport { type FetcherOptions, fetcher } from '../fetcher';\n\n/** Prefix of the routes, checked against the backend contract. */\nconst analyticsGroup = {\n prefix: '/api/analytics',\n} as const satisfies Pick<typeof analyticsContract, 'prefix'>;\n\n/**\n * Method and path of every route, checked against the backend contract at\n * compile time (the contract's zod schemas are never loaded).\n */\nconst analyticsEndpoints = {\n ingestAnalyticsEvents: { method: 'POST', path: '/events' },\n getAnalyticsOverview: { method: 'GET', path: '/overview' },\n getAnalyticsAudience: { method: 'GET', path: '/audience' },\n getContentStats: { method: 'GET', path: '/content-stats' },\n getExperimentResults: { method: 'GET', path: '/experiments/:experimentKey' },\n getPageMetadata: { method: 'GET', path: '/page-metadata' },\n} as const satisfies RouteEndpoints<AnalyticsRoutes>;\n\nexport const getAnalyticsAPI = (\n authAPIOptions: FetcherOptions = {},\n intlayerConfig?: IntlayerConfig\n) => {\n const backendURL =\n intlayerConfig?.editor?.backendURL ?? editor.backendURL ?? BACKEND_URL;\n\n /**\n * Ingest a batch of analytics events. Public — attribution is by the\n * project's `clientId` in the body.\n * @param body - Session id, sdk version, and the collected events.\n * @returns The number of accepted events.\n */\n const sendEvents = async (\n body: IngestAnalyticsBody,\n otherOptions: FetcherOptions = {}\n ) =>\n await fetcher<IngestAnalyticsResult>(\n buildRouteURL(\n backendURL,\n analyticsGroup,\n analyticsEndpoints.ingestAnalyticsEvents\n ),\n authAPIOptions,\n otherOptions,\n {\n method: analyticsEndpoints.ingestAnalyticsEvents.method,\n body,\n }\n );\n\n /**\n * Page/locale totals for the authenticated project.\n * @returns Views grouped by url and locale.\n */\n const getOverview = async (otherOptions: FetcherOptions = {}) =>\n await fetcher<GetAnalyticsOverviewResult>(\n buildRouteURL(\n backendURL,\n analyticsGroup,\n analyticsEndpoints.getAnalyticsOverview\n ),\n authAPIOptions,\n otherOptions,\n { method: analyticsEndpoints.getAnalyticsOverview.method }\n );\n\n /**\n * Audience report: distinct visitors (today / 7d / window), page views, the\n * evolution series, and locale + country breakdowns.\n * @param range - Rolling window, either a named range (`1h`, `24h`, `7d`,\n * `30d`, `90d`, `6mo`, `1y`, `3y`) or a number of days (default 30).\n * @returns The audience statistics.\n */\n const getAudience = async (\n range: AudienceRange | number = 30,\n otherOptions: FetcherOptions = {}\n ) =>\n await fetcher<GetAudienceResult>(\n buildRouteURL(\n backendURL,\n analyticsGroup,\n analyticsEndpoints.getAnalyticsAudience\n ),\n authAPIOptions,\n otherOptions,\n {\n method: analyticsEndpoints.getAnalyticsAudience.method,\n params: typeof range === 'number' ? { days: String(range) } : { range },\n }\n );\n\n /**\n * Per-content exposure totals — \"which content is actually shown\".\n * @returns Exposures grouped by dictionary key, key path, and locale.\n */\n const getContentStats = async (otherOptions: FetcherOptions = {}) =>\n await fetcher<GetContentStatsResult>(\n buildRouteURL(\n backendURL,\n analyticsGroup,\n analyticsEndpoints.getContentStats\n ),\n authAPIOptions,\n otherOptions,\n { method: analyticsEndpoints.getContentStats.method }\n );\n\n /**\n * A/B experiment results with per-variant conversion rates and significance.\n * @param experimentKey - The experiment to evaluate.\n * @returns The experiment result set.\n */\n const getExperimentResults = async (\n experimentKey: string,\n otherOptions: FetcherOptions = {}\n ) =>\n await fetcher<GetExperimentResultsResult>(\n buildRouteURL(\n backendURL,\n analyticsGroup,\n analyticsEndpoints.getExperimentResults,\n { experimentKey }\n ),\n authAPIOptions,\n otherOptions,\n { method: analyticsEndpoints.getExperimentResults.method }\n );\n\n /**\n * Page metadata (title and meta description) for a given url.\n * @param url - The page url to inspect.\n * @returns Title and description of the page.\n */\n const getPageMetadata = async (\n url: string,\n otherOptions: FetcherOptions = {}\n ) =>\n await fetcher<GetPageMetadataResult>(\n buildRouteURL(\n backendURL,\n analyticsGroup,\n analyticsEndpoints.getPageMetadata\n ),\n authAPIOptions,\n otherOptions,\n {\n method: analyticsEndpoints.getPageMetadata.method,\n params: { url },\n }\n );\n\n return {\n sendEvents,\n getOverview,\n getAudience,\n getContentStats,\n getExperimentResults,\n getPageMetadata,\n };\n};\n\n/**\n * Authenticated `analytics` endpoint bound to an Intlayer CMS authenticator.\n *\n * Pass an authenticator created with `createIntlayerCMS`, or omit it to use\n * the build-time configuration (`@intlayer/config/built`).\n */\nexport const analyticsEndpoint = createEndpoint(getAnalyticsAPI);\n"],"mappings":";;;;;;;;AAqBA,MAAM,iBAAiB,EACrB,QAAQ,iBACV;;;;;AAMA,MAAM,qBAAqB;CACzB,uBAAuB;EAAE,QAAQ;EAAQ,MAAM;CAAU;CACzD,sBAAsB;EAAE,QAAQ;EAAO,MAAM;CAAY;CACzD,sBAAsB;EAAE,QAAQ;EAAO,MAAM;CAAY;CACzD,iBAAiB;EAAE,QAAQ;EAAO,MAAM;CAAiB;CACzD,sBAAsB;EAAE,QAAQ;EAAO,MAAM;CAA8B;CAC3E,iBAAiB;EAAE,QAAQ;EAAO,MAAM;CAAiB;AAC3D;AAEA,MAAa,mBACX,iBAAiC,CAAC,GAClC,mBACG;CACH,MAAM,aACJ,gBAAgB,QAAQ,cAAc,OAAO,cAAc;;;;;;;CAQ7D,MAAM,aAAa,OACjB,MACA,eAA+B,CAAC,MAEhC,MAAM,QACJ,cACE,YACA,gBACA,mBAAmB,qBACrB,GACA,gBACA,cACA;EACE,QAAQ,mBAAmB,sBAAsB;EACjD;CACF,CACF;;;;;CAMF,MAAM,cAAc,OAAO,eAA+B,CAAC,MACzD,MAAM,QACJ,cACE,YACA,gBACA,mBAAmB,oBACrB,GACA,gBACA,cACA,EAAE,QAAQ,mBAAmB,qBAAqB,OAAO,CAC3D;;;;;;;;CASF,MAAM,cAAc,OAClB,QAAgC,IAChC,eAA+B,CAAC,MAEhC,MAAM,QACJ,cACE,YACA,gBACA,mBAAmB,oBACrB,GACA,gBACA,cACA;EACE,QAAQ,mBAAmB,qBAAqB;EAChD,QAAQ,OAAO,UAAU,WAAW,EAAE,MAAM,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM;CACxE,CACF;;;;;CAMF,MAAM,kBAAkB,OAAO,eAA+B,CAAC,MAC7D,MAAM,QACJ,cACE,YACA,gBACA,mBAAmB,eACrB,GACA,gBACA,cACA,EAAE,QAAQ,mBAAmB,gBAAgB,OAAO,CACtD;;;;;;CAOF,MAAM,uBAAuB,OAC3B,eACA,eAA+B,CAAC,MAEhC,MAAM,QACJ,cACE,YACA,gBACA,mBAAmB,sBACnB,EAAE,cAAc,CAClB,GACA,gBACA,cACA,EAAE,QAAQ,mBAAmB,qBAAqB,OAAO,CAC3D;;;;;;CAOF,MAAM,kBAAkB,OACtB,KACA,eAA+B,CAAC,MAEhC,MAAM,QACJ,cACE,YACA,gBACA,mBAAmB,eACrB,GACA,gBACA,cACA;EACE,QAAQ,mBAAmB,gBAAgB;EAC3C,QAAQ,EAAE,IAAI;CAChB,CACF;CAEF,OAAO;EACL;EACA;EACA;EACA;EACA;EACA;CACF;AACF;;;;;;;AAQA,MAAa,oBAAoB,eAAe,eAAe"}
@@ -1,17 +1,47 @@
1
1
  import { fetcher } from "../fetcher.mjs";
2
2
  import { createEndpoint } from "../cms/createIntlayerCMS.mjs";
3
3
  import { editor } from "@intlayer/config/built";
4
+ import { buildRouteURL } from "@intlayer/backend-contract/defineRoute";
5
+ import { BACKEND_URL } from "@intlayer/config/defaultValues";
4
6
 
5
7
  //#region src/getIntlayerAPI/asset.ts
8
+ /** Prefix of the routes, checked against the backend contract. */
9
+ const assetGroup = { prefix: "/api/assets" };
10
+ /**
11
+ * Method and path of every route, checked against the backend contract at
12
+ * compile time (the contract's zod schemas are never loaded).
13
+ */
14
+ const assetEndpoints = {
15
+ getAssets: {
16
+ method: "GET",
17
+ path: "/"
18
+ },
19
+ getAssetById: {
20
+ method: "GET",
21
+ path: "/:assetId"
22
+ },
23
+ uploadAsset: {
24
+ method: "POST",
25
+ path: "/"
26
+ },
27
+ updateAsset: {
28
+ method: "PATCH",
29
+ path: "/:assetId"
30
+ },
31
+ deleteAsset: {
32
+ method: "DELETE",
33
+ path: "/:assetId"
34
+ }
35
+ };
6
36
  const getAssetAPI = (authAPIOptions = {}, intlayerConfig) => {
7
- const ASSET_API_ROUTE = `${intlayerConfig?.editor?.backendURL ?? editor.backendURL}/api/assets`;
37
+ const backendURL = intlayerConfig?.editor?.backendURL ?? editor.backendURL ?? BACKEND_URL;
8
38
  /**
9
39
  * Retrieves all assets for the current session project, paginated.
10
40
  * @param page - Page number (1-based).
11
41
  * @param pageSize - Number of items per page.
12
42
  * @returns Paginated list of assets.
13
43
  */
14
- const getAssets = async (page, pageSize, otherOptions = {}) => await fetcher(ASSET_API_ROUTE, authAPIOptions, otherOptions, {
44
+ const getAssets = async (page, pageSize, otherOptions = {}) => await fetcher(buildRouteURL(backendURL, assetGroup, assetEndpoints.getAssets), authAPIOptions, otherOptions, {
15
45
  cache: "no-store",
16
46
  params: {
17
47
  ...page !== void 0 && { page: String(page) },
@@ -23,7 +53,7 @@ const getAssetAPI = (authAPIOptions = {}, intlayerConfig) => {
23
53
  * @param assetId - The asset document ID.
24
54
  * @returns The asset.
25
55
  */
26
- const getAssetById = async (assetId, otherOptions = {}) => await fetcher(`${ASSET_API_ROUTE}/${assetId}`, authAPIOptions, otherOptions, { cache: "no-store" });
56
+ const getAssetById = async (assetId, otherOptions = {}) => await fetcher(buildRouteURL(backendURL, assetGroup, assetEndpoints.getAssetById, { assetId: String(assetId) }), authAPIOptions, otherOptions, { cache: "no-store" });
27
57
  /**
28
58
  * Uploads a new asset image.
29
59
  * @param file - The image File object.
@@ -40,8 +70,8 @@ const getAssetAPI = (authAPIOptions = {}, intlayerConfig) => {
40
70
  if (alt) headers["X-Alt-Text"] = alt;
41
71
  if (caption) headers["X-Caption"] = caption;
42
72
  const authHeaders = authAPIOptions.headers ?? {};
43
- const response = await fetch(ASSET_API_ROUTE, {
44
- method: "POST",
73
+ const response = await fetch(buildRouteURL(backendURL, assetGroup, assetEndpoints.uploadAsset), {
74
+ method: assetEndpoints.uploadAsset.method,
45
75
  credentials: "include",
46
76
  headers: {
47
77
  ...authHeaders,
@@ -62,8 +92,8 @@ const getAssetAPI = (authAPIOptions = {}, intlayerConfig) => {
62
92
  * @param data - Fields to update.
63
93
  * @returns The updated asset record.
64
94
  */
65
- const updateAsset = async (assetId, data, otherOptions = {}) => await fetcher(`${ASSET_API_ROUTE}/${assetId}`, authAPIOptions, otherOptions, {
66
- method: "PATCH",
95
+ const updateAsset = async (assetId, data, otherOptions = {}) => await fetcher(buildRouteURL(backendURL, assetGroup, assetEndpoints.updateAsset, { assetId: String(assetId) }), authAPIOptions, otherOptions, {
96
+ method: assetEndpoints.updateAsset.method,
67
97
  body: data
68
98
  });
69
99
  /**
@@ -71,7 +101,7 @@ const getAssetAPI = (authAPIOptions = {}, intlayerConfig) => {
71
101
  * @param assetId - The asset document ID.
72
102
  * @returns Confirmation response.
73
103
  */
74
- const deleteAsset = async (assetId, otherOptions = {}) => await fetcher(`${ASSET_API_ROUTE}/${assetId}`, authAPIOptions, otherOptions, { method: "DELETE" });
104
+ const deleteAsset = async (assetId, otherOptions = {}) => await fetcher(buildRouteURL(backendURL, assetGroup, assetEndpoints.deleteAsset, { assetId: String(assetId) }), authAPIOptions, otherOptions, { method: assetEndpoints.deleteAsset.method });
75
105
  return {
76
106
  getAssets,
77
107
  getAssetById,
@@ -1 +1 @@
1
- {"version":3,"file":"asset.mjs","names":[],"sources":["../../../src/getIntlayerAPI/asset.ts"],"sourcesContent":["import type {\n DeleteAssetResult,\n GetAssetByIdResult,\n GetAssetsResult,\n UpdateAssetResult,\n UploadAssetResult,\n} from '@intlayer/backend';\nimport { editor } from '@intlayer/config/built';\nimport type { IntlayerConfig } from '@intlayer/types/config';\nimport { createEndpoint } from '../cms/createIntlayerCMS';\nimport { type FetcherOptions, fetcher } from '../fetcher';\n\nexport const getAssetAPI = (\n authAPIOptions: FetcherOptions = {},\n intlayerConfig?: IntlayerConfig\n) => {\n const backendURL = intlayerConfig?.editor?.backendURL ?? editor.backendURL;\n\n const ASSET_API_ROUTE = `${backendURL}/api/assets`;\n\n /**\n * Retrieves all assets for the current session project, paginated.\n * @param page - Page number (1-based).\n * @param pageSize - Number of items per page.\n * @returns Paginated list of assets.\n */\n const getAssets = async (\n page?: number,\n pageSize?: number,\n otherOptions: FetcherOptions = {}\n ) =>\n await fetcher<GetAssetsResult>(\n ASSET_API_ROUTE,\n authAPIOptions,\n otherOptions,\n {\n cache: 'no-store',\n params: {\n ...(page !== undefined && { page: String(page) }),\n ...(pageSize !== undefined && { pageSize: String(pageSize) }),\n },\n }\n );\n\n /**\n * Retrieves a single asset by ID.\n * @param assetId - The asset document ID.\n * @returns The asset.\n */\n const getAssetById = async (\n assetId: string,\n otherOptions: FetcherOptions = {}\n ) =>\n await fetcher<GetAssetByIdResult>(\n `${ASSET_API_ROUTE}/${assetId}`,\n authAPIOptions,\n otherOptions,\n { cache: 'no-store' }\n );\n\n /**\n * Uploads a new asset image.\n * @param file - The image File object.\n * @param alt - Optional alt text.\n * @param caption - Optional caption.\n * @returns The created asset record with its public URL.\n */\n const uploadAsset = async (\n file: File,\n alt?: string,\n caption?: string,\n otherOptions: FetcherOptions = {}\n ) => {\n const buffer = await file.arrayBuffer();\n\n const headers: Record<string, string> = {\n 'Content-Type': file.type || 'image/jpeg',\n 'X-File-Name': file.name,\n };\n\n if (alt) headers['X-Alt-Text'] = alt;\n if (caption) headers['X-Caption'] = caption;\n\n const authHeaders =\n (authAPIOptions.headers as Record<string, string> | undefined) ?? {};\n\n const response = await fetch(ASSET_API_ROUTE, {\n method: 'POST',\n credentials: 'include',\n headers: { ...authHeaders, ...headers },\n body: buffer,\n signal: otherOptions.signal as AbortSignal | undefined,\n });\n\n if (!response.ok) {\n const result = await response.json();\n throw new Error(JSON.stringify(result.error) ?? 'Asset upload failed');\n }\n\n return (await response.json()) as UploadAssetResult;\n };\n\n /**\n * Updates mutable metadata (name, alt text, caption) of an asset.\n * @param assetId - The asset document ID.\n * @param data - Fields to update.\n * @returns The updated asset record.\n */\n const updateAsset = async (\n assetId: string,\n data: { originalName?: string; alt?: string; caption?: string },\n otherOptions: FetcherOptions = {}\n ) =>\n await fetcher<UpdateAssetResult>(\n `${ASSET_API_ROUTE}/${assetId}`,\n authAPIOptions,\n otherOptions,\n { method: 'PATCH', body: data as unknown as Record<string, unknown> }\n );\n\n /**\n * Deletes an asset by ID.\n * @param assetId - The asset document ID.\n * @returns Confirmation response.\n */\n const deleteAsset = async (\n assetId: string,\n otherOptions: FetcherOptions = {}\n ) =>\n await fetcher<DeleteAssetResult>(\n `${ASSET_API_ROUTE}/${assetId}`,\n authAPIOptions,\n otherOptions,\n { method: 'DELETE' }\n );\n\n return {\n getAssets,\n getAssetById,\n uploadAsset,\n updateAsset,\n deleteAsset,\n };\n};\n\n/**\n * Authenticated `asset` endpoint bound to an Intlayer CMS authenticator.\n *\n * Pass an authenticator created with `createIntlayerCMS`, or omit it to use\n * the build-time configuration (`@intlayer/config/built`).\n */\nexport const assetEndpoint = createEndpoint(getAssetAPI);\n"],"mappings":";;;;;AAYA,MAAa,eACX,iBAAiC,CAAC,GAClC,mBACG;CAGH,MAAM,kBAAkB,GAFL,gBAAgB,QAAQ,cAAc,OAAO,WAE1B;;;;;;;CAQtC,MAAM,YAAY,OAChB,MACA,UACA,eAA+B,CAAC,MAEhC,MAAM,QACJ,iBACA,gBACA,cACA;EACE,OAAO;EACP,QAAQ;GACN,GAAI,SAAS,UAAa,EAAE,MAAM,OAAO,IAAI,EAAE;GAC/C,GAAI,aAAa,UAAa,EAAE,UAAU,OAAO,QAAQ,EAAE;EAC7D;CACF,CACF;;;;;;CAOF,MAAM,eAAe,OACnB,SACA,eAA+B,CAAC,MAEhC,MAAM,QACJ,GAAG,gBAAgB,GAAG,WACtB,gBACA,cACA,EAAE,OAAO,WAAW,CACtB;;;;;;;;CASF,MAAM,cAAc,OAClB,MACA,KACA,SACA,eAA+B,CAAC,MAC7B;EACH,MAAM,SAAS,MAAM,KAAK,YAAY;EAEtC,MAAM,UAAkC;GACtC,gBAAgB,KAAK,QAAQ;GAC7B,eAAe,KAAK;EACtB;EAEA,IAAI,KAAK,QAAQ,gBAAgB;EACjC,IAAI,SAAS,QAAQ,eAAe;EAEpC,MAAM,cACH,eAAe,WAAkD,CAAC;EAErE,MAAM,WAAW,MAAM,MAAM,iBAAiB;GAC5C,QAAQ;GACR,aAAa;GACb,SAAS;IAAE,GAAG;IAAa,GAAG;GAAQ;GACtC,MAAM;GACN,QAAQ,aAAa;EACvB,CAAC;EAED,IAAI,CAAC,SAAS,IAAI;GAChB,MAAM,SAAS,MAAM,SAAS,KAAK;GACnC,MAAM,IAAI,MAAM,KAAK,UAAU,OAAO,KAAK,KAAK,qBAAqB;EACvE;EAEA,OAAQ,MAAM,SAAS,KAAK;CAC9B;;;;;;;CAQA,MAAM,cAAc,OAClB,SACA,MACA,eAA+B,CAAC,MAEhC,MAAM,QACJ,GAAG,gBAAgB,GAAG,WACtB,gBACA,cACA;EAAE,QAAQ;EAAS,MAAM;CAA2C,CACtE;;;;;;CAOF,MAAM,cAAc,OAClB,SACA,eAA+B,CAAC,MAEhC,MAAM,QACJ,GAAG,gBAAgB,GAAG,WACtB,gBACA,cACA,EAAE,QAAQ,SAAS,CACrB;CAEF,OAAO;EACL;EACA;EACA;EACA;EACA;CACF;AACF;;;;;;;AAQA,MAAa,gBAAgB,eAAe,WAAW"}
1
+ {"version":3,"file":"asset.mjs","names":[],"sources":["../../../src/getIntlayerAPI/asset.ts"],"sourcesContent":["import type {\n AssetRoutes,\n assetContract,\n DeleteAssetResult,\n GetAssetByIdResult,\n GetAssetsResult,\n UpdateAssetResult,\n UploadAssetResult,\n} from '@intlayer/backend-contract/asset';\nimport type { RouteEndpoints } from '@intlayer/backend-contract/defineRoute';\nimport { buildRouteURL } from '@intlayer/backend-contract/defineRoute';\nimport { editor } from '@intlayer/config/built';\nimport { BACKEND_URL } from '@intlayer/config/defaultValues';\nimport type { IntlayerConfig } from '@intlayer/types/config';\nimport { createEndpoint } from '../cms/createIntlayerCMS';\nimport { type FetcherOptions, fetcher } from '../fetcher';\n\n/** Prefix of the routes, checked against the backend contract. */\nconst assetGroup = {\n prefix: '/api/assets',\n} as const satisfies Pick<typeof assetContract, 'prefix'>;\n\n/**\n * Method and path of every route, checked against the backend contract at\n * compile time (the contract's zod schemas are never loaded).\n */\nconst assetEndpoints = {\n getAssets: { method: 'GET', path: '/' },\n getAssetById: { method: 'GET', path: '/:assetId' },\n uploadAsset: { method: 'POST', path: '/' },\n updateAsset: { method: 'PATCH', path: '/:assetId' },\n deleteAsset: { method: 'DELETE', path: '/:assetId' },\n} as const satisfies RouteEndpoints<AssetRoutes>;\n\nexport const getAssetAPI = (\n authAPIOptions: FetcherOptions = {},\n intlayerConfig?: IntlayerConfig\n) => {\n const backendURL =\n intlayerConfig?.editor?.backendURL ?? editor.backendURL ?? BACKEND_URL;\n\n /**\n * Retrieves all assets for the current session project, paginated.\n * @param page - Page number (1-based).\n * @param pageSize - Number of items per page.\n * @returns Paginated list of assets.\n */\n const getAssets = async (\n page?: number,\n pageSize?: number,\n otherOptions: FetcherOptions = {}\n ) =>\n await fetcher<GetAssetsResult>(\n buildRouteURL(backendURL, assetGroup, assetEndpoints.getAssets),\n authAPIOptions,\n otherOptions,\n {\n cache: 'no-store',\n params: {\n ...(page !== undefined && { page: String(page) }),\n ...(pageSize !== undefined && { pageSize: String(pageSize) }),\n },\n }\n );\n\n /**\n * Retrieves a single asset by ID.\n * @param assetId - The asset document ID.\n * @returns The asset.\n */\n const getAssetById = async (\n assetId: string,\n otherOptions: FetcherOptions = {}\n ) =>\n await fetcher<GetAssetByIdResult>(\n buildRouteURL(backendURL, assetGroup, assetEndpoints.getAssetById, {\n assetId: String(assetId),\n }),\n authAPIOptions,\n otherOptions,\n { cache: 'no-store' }\n );\n\n /**\n * Uploads a new asset image.\n * @param file - The image File object.\n * @param alt - Optional alt text.\n * @param caption - Optional caption.\n * @returns The created asset record with its public URL.\n */\n const uploadAsset = async (\n file: File,\n alt?: string,\n caption?: string,\n otherOptions: FetcherOptions = {}\n ) => {\n const buffer = await file.arrayBuffer();\n\n const headers: Record<string, string> = {\n 'Content-Type': file.type || 'image/jpeg',\n 'X-File-Name': file.name,\n };\n\n if (alt) headers['X-Alt-Text'] = alt;\n if (caption) headers['X-Caption'] = caption;\n\n const authHeaders =\n (authAPIOptions.headers as Record<string, string> | undefined) ?? {};\n\n const response = await fetch(\n buildRouteURL(backendURL, assetGroup, assetEndpoints.uploadAsset),\n {\n method: assetEndpoints.uploadAsset.method,\n credentials: 'include',\n headers: { ...authHeaders, ...headers },\n body: buffer,\n signal: otherOptions.signal as AbortSignal | undefined,\n }\n );\n\n if (!response.ok) {\n const result = await response.json();\n throw new Error(JSON.stringify(result.error) ?? 'Asset upload failed');\n }\n\n return (await response.json()) as UploadAssetResult;\n };\n\n /**\n * Updates mutable metadata (name, alt text, caption) of an asset.\n * @param assetId - The asset document ID.\n * @param data - Fields to update.\n * @returns The updated asset record.\n */\n const updateAsset = async (\n assetId: string,\n data: { originalName?: string; alt?: string; caption?: string },\n otherOptions: FetcherOptions = {}\n ) =>\n await fetcher<UpdateAssetResult>(\n buildRouteURL(backendURL, assetGroup, assetEndpoints.updateAsset, {\n assetId: String(assetId),\n }),\n authAPIOptions,\n otherOptions,\n {\n method: assetEndpoints.updateAsset.method,\n body: data as unknown as Record<string, unknown>,\n }\n );\n\n /**\n * Deletes an asset by ID.\n * @param assetId - The asset document ID.\n * @returns Confirmation response.\n */\n const deleteAsset = async (\n assetId: string,\n otherOptions: FetcherOptions = {}\n ) =>\n await fetcher<DeleteAssetResult>(\n buildRouteURL(backendURL, assetGroup, assetEndpoints.deleteAsset, {\n assetId: String(assetId),\n }),\n authAPIOptions,\n otherOptions,\n { method: assetEndpoints.deleteAsset.method }\n );\n\n return {\n getAssets,\n getAssetById,\n uploadAsset,\n updateAsset,\n deleteAsset,\n };\n};\n\n/**\n * Authenticated `asset` endpoint bound to an Intlayer CMS authenticator.\n *\n * Pass an authenticator created with `createIntlayerCMS`, or omit it to use\n * the build-time configuration (`@intlayer/config/built`).\n */\nexport const assetEndpoint = createEndpoint(getAssetAPI);\n"],"mappings":";;;;;;;;AAkBA,MAAM,aAAa,EACjB,QAAQ,cACV;;;;;AAMA,MAAM,iBAAiB;CACrB,WAAW;EAAE,QAAQ;EAAO,MAAM;CAAI;CACtC,cAAc;EAAE,QAAQ;EAAO,MAAM;CAAY;CACjD,aAAa;EAAE,QAAQ;EAAQ,MAAM;CAAI;CACzC,aAAa;EAAE,QAAQ;EAAS,MAAM;CAAY;CAClD,aAAa;EAAE,QAAQ;EAAU,MAAM;CAAY;AACrD;AAEA,MAAa,eACX,iBAAiC,CAAC,GAClC,mBACG;CACH,MAAM,aACJ,gBAAgB,QAAQ,cAAc,OAAO,cAAc;;;;;;;CAQ7D,MAAM,YAAY,OAChB,MACA,UACA,eAA+B,CAAC,MAEhC,MAAM,QACJ,cAAc,YAAY,YAAY,eAAe,SAAS,GAC9D,gBACA,cACA;EACE,OAAO;EACP,QAAQ;GACN,GAAI,SAAS,UAAa,EAAE,MAAM,OAAO,IAAI,EAAE;GAC/C,GAAI,aAAa,UAAa,EAAE,UAAU,OAAO,QAAQ,EAAE;EAC7D;CACF,CACF;;;;;;CAOF,MAAM,eAAe,OACnB,SACA,eAA+B,CAAC,MAEhC,MAAM,QACJ,cAAc,YAAY,YAAY,eAAe,cAAc,EACjE,SAAS,OAAO,OAAO,EACzB,CAAC,GACD,gBACA,cACA,EAAE,OAAO,WAAW,CACtB;;;;;;;;CASF,MAAM,cAAc,OAClB,MACA,KACA,SACA,eAA+B,CAAC,MAC7B;EACH,MAAM,SAAS,MAAM,KAAK,YAAY;EAEtC,MAAM,UAAkC;GACtC,gBAAgB,KAAK,QAAQ;GAC7B,eAAe,KAAK;EACtB;EAEA,IAAI,KAAK,QAAQ,gBAAgB;EACjC,IAAI,SAAS,QAAQ,eAAe;EAEpC,MAAM,cACH,eAAe,WAAkD,CAAC;EAErE,MAAM,WAAW,MAAM,MACrB,cAAc,YAAY,YAAY,eAAe,WAAW,GAChE;GACE,QAAQ,eAAe,YAAY;GACnC,aAAa;GACb,SAAS;IAAE,GAAG;IAAa,GAAG;GAAQ;GACtC,MAAM;GACN,QAAQ,aAAa;EACvB,CACF;EAEA,IAAI,CAAC,SAAS,IAAI;GAChB,MAAM,SAAS,MAAM,SAAS,KAAK;GACnC,MAAM,IAAI,MAAM,KAAK,UAAU,OAAO,KAAK,KAAK,qBAAqB;EACvE;EAEA,OAAQ,MAAM,SAAS,KAAK;CAC9B;;;;;;;CAQA,MAAM,cAAc,OAClB,SACA,MACA,eAA+B,CAAC,MAEhC,MAAM,QACJ,cAAc,YAAY,YAAY,eAAe,aAAa,EAChE,SAAS,OAAO,OAAO,EACzB,CAAC,GACD,gBACA,cACA;EACE,QAAQ,eAAe,YAAY;EACnC,MAAM;CACR,CACF;;;;;;CAOF,MAAM,cAAc,OAClB,SACA,eAA+B,CAAC,MAEhC,MAAM,QACJ,cAAc,YAAY,YAAY,eAAe,aAAa,EAChE,SAAS,OAAO,OAAO,EACzB,CAAC,GACD,gBACA,cACA,EAAE,QAAQ,eAAe,YAAY,OAAO,CAC9C;CAEF,OAAO;EACL;EACA;EACA;EACA;EACA;CACF;AACF;;;;;;;AAQA,MAAa,gBAAgB,eAAe,WAAW"}