@intlayer/api 9.7.1 → 9.7.2

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 (28) hide show
  1. package/dist/cjs/getIntlayerAPI/ai.cjs +35 -39
  2. package/dist/cjs/getIntlayerAPI/ai.cjs.map +1 -1
  3. package/dist/cjs/getIntlayerAPI/analytics.cjs +29 -0
  4. package/dist/cjs/getIntlayerAPI/analytics.cjs.map +1 -1
  5. package/dist/cjs/getIntlayerAPI/readServerSentEvents.cjs +70 -0
  6. package/dist/cjs/getIntlayerAPI/readServerSentEvents.cjs.map +1 -0
  7. package/dist/esm/getIntlayerAPI/ai.mjs +35 -39
  8. package/dist/esm/getIntlayerAPI/ai.mjs.map +1 -1
  9. package/dist/esm/getIntlayerAPI/analytics.mjs +29 -0
  10. package/dist/esm/getIntlayerAPI/analytics.mjs.map +1 -1
  11. package/dist/esm/getIntlayerAPI/readServerSentEvents.mjs +68 -0
  12. package/dist/esm/getIntlayerAPI/readServerSentEvents.mjs.map +1 -0
  13. package/dist/types/distantDictionary/fetchDistantDictionaries.d.ts +1 -1
  14. package/dist/types/distantDictionary/fetchDistantDictionary.d.ts +1 -1
  15. package/dist/types/getIntlayerAPI/ai.d.ts +7 -1
  16. package/dist/types/getIntlayerAPI/ai.d.ts.map +1 -1
  17. package/dist/types/getIntlayerAPI/analytics.d.ts +5 -1
  18. package/dist/types/getIntlayerAPI/analytics.d.ts.map +1 -1
  19. package/dist/types/getIntlayerAPI/codeberg.d.ts.map +1 -1
  20. package/dist/types/getIntlayerAPI/dictionary.d.ts +1 -1
  21. package/dist/types/getIntlayerAPI/gitee.d.ts.map +1 -1
  22. package/dist/types/getIntlayerAPI/project.d.ts +1 -1
  23. package/dist/types/getIntlayerAPI/readServerSentEvents.d.ts +18 -0
  24. package/dist/types/getIntlayerAPI/readServerSentEvents.d.ts.map +1 -0
  25. package/dist/types/index.d.ts +3 -3
  26. package/dist/types/public/createPublicClient.d.ts +1 -1
  27. package/dist/types/types.d.ts +2 -2
  28. package/package.json +109 -109
@@ -1,6 +1,7 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
2
  const require_cms_createIntlayerCMS = require("../cms/createIntlayerCMS.cjs");
3
3
  const require_fetcher = require("../fetcher.cjs");
4
+ const require_getIntlayerAPI_readServerSentEvents = require("./readServerSentEvents.cjs");
4
5
  let _intlayer_config_built = require("@intlayer/config/built");
5
6
  let _intlayer_backend_contract_defineRoute = require("@intlayer/backend-contract/defineRoute");
6
7
  let _intlayer_config_defaultValues = require("@intlayer/config/defaultValues");
@@ -56,6 +57,14 @@ const aiEndpoints = {
56
57
  getAIStats: {
57
58
  method: "GET",
58
59
  path: "/stats"
60
+ },
61
+ getAICredits: {
62
+ method: "GET",
63
+ path: "/credits"
64
+ },
65
+ getAICreditUsage: {
66
+ method: "GET",
67
+ path: "/credits/usage"
59
68
  }
60
69
  };
61
70
  const getAiAPI = (authAPIOptions = {}, intlayerConfig) => {
@@ -135,7 +144,7 @@ const getAiAPI = (authAPIOptions = {}, intlayerConfig) => {
135
144
  */
136
145
  const askDocQuestion = async (body, otherOptions = {}) => {
137
146
  if (!body) return;
138
- const { onMessage, onDone, ...rest } = body;
147
+ const { onMessage, onReasoning, onDone, ...rest } = body;
139
148
  const abortController = new AbortController();
140
149
  try {
141
150
  const response = await fetch((0, _intlayer_backend_contract_defineRoute.buildRouteURL)(backendURL, aiGroup, aiEndpoints.ask), {
@@ -167,24 +176,11 @@ const getAiAPI = (authAPIOptions = {}, intlayerConfig) => {
167
176
  }
168
177
  throw new Error(errorMessage);
169
178
  }
170
- const reader = response.body?.getReader();
171
- if (!reader) throw new Error("No reader available");
172
- const decoder = new TextDecoder();
173
- let buffer = "";
174
- while (true) {
175
- const { done, value } = await reader.read();
176
- if (done) break;
177
- buffer += decoder.decode(value, { stream: true });
178
- const lines = buffer.split("\n");
179
- buffer = lines.pop() ?? "";
180
- for (const line of lines) if (line.startsWith("data: ")) try {
181
- const data = JSON.parse(line.slice(6));
182
- if (data.chunk) onMessage?.(data.chunk);
183
- if (data.done && data.response) onDone?.(data.response);
184
- } catch (e) {
185
- console.error("Failed to parse SSE data:", e);
186
- }
187
- }
179
+ await require_getIntlayerAPI_readServerSentEvents.readServerSentEvents(response, (data) => {
180
+ if (data.reasoning) onReasoning?.(data.reasoning);
181
+ if (data.chunk) onMessage?.(data.chunk);
182
+ if (data.done && data.response) onDone?.(data.response);
183
+ });
188
184
  } catch (error) {
189
185
  console.error("Error in askDocQuestion:", error);
190
186
  throw error;
@@ -224,25 +220,11 @@ const getAiAPI = (authAPIOptions = {}, intlayerConfig) => {
224
220
  }
225
221
  throw new Error(errorMessage);
226
222
  }
227
- const reader = response.body?.getReader();
228
- if (!reader) throw new Error("No reader available");
229
- const decoder = new TextDecoder();
230
- let buffer = "";
231
- while (true) {
232
- const { done, value } = await reader.read();
233
- if (done) break;
234
- buffer += decoder.decode(value, { stream: true });
235
- const lines = buffer.split("\n");
236
- buffer = lines.pop() ?? "";
237
- for (const line of lines) if (line.startsWith("data: ")) try {
238
- const data = JSON.parse(line.slice(6));
239
- if (data.chunk) onMessage?.(data.chunk);
240
- if (data.action) onAction?.(data.action);
241
- if (data.done && data.response) onDone?.(data.response);
242
- } catch (e) {
243
- console.error("Failed to parse SSE data:", e);
244
- }
245
- }
223
+ await require_getIntlayerAPI_readServerSentEvents.readServerSentEvents(response, (data) => {
224
+ if (data.chunk) onMessage?.(data.chunk);
225
+ if (data.action) onAction?.(data.action);
226
+ if (data.done && data.response) onDone?.(data.response);
227
+ });
246
228
  } catch (error) {
247
229
  console.error("Error in chat:", error);
248
230
  throw error;
@@ -264,6 +246,18 @@ const getAiAPI = (authAPIOptions = {}, intlayerConfig) => {
264
246
  * project.
265
247
  */
266
248
  const getAIStats = async (otherOptions = {}) => await require_fetcher.fetcher((0, _intlayer_backend_contract_defineRoute.buildRouteURL)(backendURL, aiGroup, aiEndpoints.getAIStats), authAPIOptions, otherOptions, { method: aiEndpoints.getAIStats.method });
249
+ /**
250
+ * Retrieves the AI credit balance of the selected organization for the
251
+ * current monthly period.
252
+ */
253
+ const getAICredits = async (otherOptions = {}) => await require_fetcher.fetcher((0, _intlayer_backend_contract_defineRoute.buildRouteURL)(backendURL, aiGroup, aiEndpoints.getAICredits), authAPIOptions, otherOptions, { method: aiEndpoints.getAICredits.method });
254
+ /**
255
+ * Retrieves the day-by-day AI credit usage of the selected organization.
256
+ */
257
+ const getAICreditUsage = async (params, otherOptions = {}) => await require_fetcher.fetcher((0, _intlayer_backend_contract_defineRoute.buildRouteURL)(backendURL, aiGroup, aiEndpoints.getAICreditUsage), authAPIOptions, otherOptions, {
258
+ method: aiEndpoints.getAICreditUsage.method,
259
+ params
260
+ });
267
261
  return {
268
262
  customQuery,
269
263
  translateJSON,
@@ -275,7 +269,9 @@ const getAiAPI = (authAPIOptions = {}, intlayerConfig) => {
275
269
  chat,
276
270
  autocomplete,
277
271
  getDiscussions,
278
- getAIStats
272
+ getAIStats,
273
+ getAICredits,
274
+ getAICreditUsage
279
275
  };
280
276
  };
281
277
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"ai.cjs","names":["editor","BACKEND_URL","fetcher","buildRouteURL","createEndpoint"],"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
+ {"version":3,"file":"ai.cjs","names":["editor","BACKEND_URL","fetcher","buildRouteURL","readServerSentEvents","createEndpoint"],"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 GetAICreditsResult,\n GetAICreditUsageParams,\n GetAICreditUsageResult,\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';\nimport { readServerSentEvents } from './readServerSentEvents';\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 /** Receives the summarized reasoning of the model as it streams. */\n onReasoning?: (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\n/** `data:` payload streamed by the `ask` endpoint. */\ntype AskDocQuestionStreamData = {\n chunk?: string;\n reasoning?: string;\n done?: boolean;\n response?: AskDocQuestionResult;\n};\n\n/** `data:` payload streamed by the `chat` endpoint. */\ntype ChatStreamData = {\n chunk?: string;\n action?: ClientAction;\n done?: boolean;\n response?: ChatResult;\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 getAICredits: { method: 'GET', path: '/credits' },\n getAICreditUsage: { method: 'GET', path: '/credits/usage' },\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, onReasoning, 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 await readServerSentEvents<AskDocQuestionStreamData>(response, (data) => {\n if (data.reasoning) {\n onReasoning?.(data.reasoning);\n }\n if (data.chunk) {\n onMessage?.(data.chunk);\n }\n if (data.done && data.response) {\n onDone?.(data.response);\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 await readServerSentEvents<ChatStreamData>(response, (data) => {\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 });\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 /**\n * Retrieves the AI credit balance of the selected organization for the\n * current monthly period.\n */\n const getAICredits = async (otherOptions: FetcherOptions = {}) =>\n await fetcher<GetAICreditsResult>(\n buildRouteURL(backendURL, aiGroup, aiEndpoints.getAICredits),\n authAPIOptions,\n otherOptions,\n {\n method: aiEndpoints.getAICredits.method,\n }\n );\n\n /**\n * Retrieves the day-by-day AI credit usage of the selected organization.\n */\n const getAICreditUsage = async (\n params?: GetAICreditUsageParams,\n otherOptions: FetcherOptions = {}\n ) =>\n await fetcher<GetAICreditUsageResult>(\n buildRouteURL(backendURL, aiGroup, aiEndpoints.getAICreditUsage),\n authAPIOptions,\n otherOptions,\n {\n method: aiEndpoints.getAICreditUsage.method,\n params,\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 getAICredits,\n getAICreditUsage,\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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"}
@@ -25,6 +25,14 @@ const analyticsEndpoints = {
25
25
  method: "GET",
26
26
  path: "/audience"
27
27
  },
28
+ getPageFlow: {
29
+ method: "GET",
30
+ path: "/page-flow"
31
+ },
32
+ getLiveVisitorFlow: {
33
+ method: "GET",
34
+ path: "/audience/live/visitors/:visitorId"
35
+ },
28
36
  getContentStats: {
29
37
  method: "GET",
30
38
  path: "/content-stats"
@@ -78,6 +86,25 @@ const getAnalyticsAPI = (authAPIOptions = {}, intlayerConfig) => {
78
86
  */
79
87
  const getExperimentResults = async (experimentKey, otherOptions = {}) => await require_fetcher.fetcher((0, _intlayer_backend_contract_defineRoute.buildRouteURL)(backendURL, analyticsGroup, analyticsEndpoints.getExperimentResults, { experimentKey }), authAPIOptions, otherOptions, { method: analyticsEndpoints.getExperimentResults.method });
80
88
  /**
89
+ * Averaged page-to-page navigation flow from a starting page.
90
+ * @param range - Rolling window of the report.
91
+ * @param startUrl - Starting page pathname (default `/`).
92
+ * @returns The flow steps and the links between them.
93
+ */
94
+ const getPageFlow = async (range, startUrl, otherOptions = {}) => await require_fetcher.fetcher((0, _intlayer_backend_contract_defineRoute.buildRouteURL)(backendURL, analyticsGroup, analyticsEndpoints.getPageFlow), authAPIOptions, otherOptions, {
95
+ method: analyticsEndpoints.getPageFlow.method,
96
+ params: {
97
+ range,
98
+ startUrl
99
+ }
100
+ });
101
+ /**
102
+ * Page journey of a visitor active in the last 30 minutes.
103
+ * @param visitorId - The visitor id from the `live` audience report.
104
+ * @returns The visitor and its steps (`visitor: null` once it went quiet).
105
+ */
106
+ const getLiveVisitorFlow = async (visitorId, otherOptions = {}) => await require_fetcher.fetcher((0, _intlayer_backend_contract_defineRoute.buildRouteURL)(backendURL, analyticsGroup, analyticsEndpoints.getLiveVisitorFlow, { visitorId }), authAPIOptions, otherOptions, { method: analyticsEndpoints.getLiveVisitorFlow.method });
107
+ /**
81
108
  * Page metadata (title and meta description) for a given url.
82
109
  * @param url - The page url to inspect.
83
110
  * @returns Title and description of the page.
@@ -90,6 +117,8 @@ const getAnalyticsAPI = (authAPIOptions = {}, intlayerConfig) => {
90
117
  sendEvents,
91
118
  getOverview,
92
119
  getAudience,
120
+ getLiveVisitorFlow,
121
+ getPageFlow,
93
122
  getContentStats,
94
123
  getExperimentResults,
95
124
  getPageMetadata
@@ -1 +1 @@
1
- {"version":3,"file":"analytics.cjs","names":["editor","BACKEND_URL","fetcher","buildRouteURL","createEndpoint"],"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,cAAcA,8BAAO,cAAcC;;;;;;;CAQ7D,MAAM,aAAa,OACjB,MACA,eAA+B,CAAC,MAEhC,MAAMC,4BACJC,sDACE,YACA,gBACA,mBAAmB,qBACrB,GACA,gBACA,cACA;EACE,QAAQ,mBAAmB,sBAAsB;EACjD;CACF,CACF;;;;;CAMF,MAAM,cAAc,OAAO,eAA+B,CAAC,MACzD,MAAMD,4BACJC,sDACE,YACA,gBACA,mBAAmB,oBACrB,GACA,gBACA,cACA,EAAE,QAAQ,mBAAmB,qBAAqB,OAAO,CAC3D;;;;;;;;CASF,MAAM,cAAc,OAClB,QAAgC,IAChC,eAA+B,CAAC,MAEhC,MAAMD,4BACJC,sDACE,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,MAAMD,4BACJC,sDACE,YACA,gBACA,mBAAmB,eACrB,GACA,gBACA,cACA,EAAE,QAAQ,mBAAmB,gBAAgB,OAAO,CACtD;;;;;;CAOF,MAAM,uBAAuB,OAC3B,eACA,eAA+B,CAAC,MAEhC,MAAMD,4BACJC,sDACE,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,MAAMD,4BACJC,sDACE,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,oBAAoBC,6CAAe,eAAe"}
1
+ {"version":3,"file":"analytics.cjs","names":["editor","BACKEND_URL","fetcher","buildRouteURL","createEndpoint"],"sources":["../../../src/getIntlayerAPI/analytics.ts"],"sourcesContent":["import type {\n AnalyticsRoutes,\n AudienceRange,\n analyticsContract,\n GetAnalyticsOverviewResult,\n GetAudienceResult,\n GetContentStatsResult,\n GetExperimentResultsResult,\n GetLiveVisitorFlowResult,\n GetPageFlowResult,\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 getPageFlow: { method: 'GET', path: '/page-flow' },\n getLiveVisitorFlow: {\n method: 'GET',\n path: '/audience/live/visitors/:visitorId',\n },\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 * Averaged page-to-page navigation flow from a starting page.\n * @param range - Rolling window of the report.\n * @param startUrl - Starting page pathname (default `/`).\n * @returns The flow steps and the links between them.\n */\n const getPageFlow = async (\n range: AudienceRange,\n startUrl: string,\n otherOptions: FetcherOptions = {}\n ) =>\n await fetcher<GetPageFlowResult>(\n buildRouteURL(backendURL, analyticsGroup, analyticsEndpoints.getPageFlow),\n authAPIOptions,\n otherOptions,\n {\n method: analyticsEndpoints.getPageFlow.method,\n params: { range, startUrl },\n }\n );\n\n /**\n * Page journey of a visitor active in the last 30 minutes.\n * @param visitorId - The visitor id from the `live` audience report.\n * @returns The visitor and its steps (`visitor: null` once it went quiet).\n */\n const getLiveVisitorFlow = async (\n visitorId: string,\n otherOptions: FetcherOptions = {}\n ) =>\n await fetcher<GetLiveVisitorFlowResult>(\n buildRouteURL(\n backendURL,\n analyticsGroup,\n analyticsEndpoints.getLiveVisitorFlow,\n { visitorId }\n ),\n authAPIOptions,\n otherOptions,\n { method: analyticsEndpoints.getLiveVisitorFlow.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 getLiveVisitorFlow,\n getPageFlow,\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":";;;;;;;;;AAuBA,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,aAAa;EAAE,QAAQ;EAAO,MAAM;CAAa;CACjD,oBAAoB;EAClB,QAAQ;EACR,MAAM;CACR;CACA,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,cAAcA,8BAAO,cAAcC;;;;;;;CAQ7D,MAAM,aAAa,OACjB,MACA,eAA+B,CAAC,MAEhC,MAAMC,4BACJC,sDACE,YACA,gBACA,mBAAmB,qBACrB,GACA,gBACA,cACA;EACE,QAAQ,mBAAmB,sBAAsB;EACjD;CACF,CACF;;;;;CAMF,MAAM,cAAc,OAAO,eAA+B,CAAC,MACzD,MAAMD,4BACJC,sDACE,YACA,gBACA,mBAAmB,oBACrB,GACA,gBACA,cACA,EAAE,QAAQ,mBAAmB,qBAAqB,OAAO,CAC3D;;;;;;;;CASF,MAAM,cAAc,OAClB,QAAgC,IAChC,eAA+B,CAAC,MAEhC,MAAMD,4BACJC,sDACE,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,MAAMD,4BACJC,sDACE,YACA,gBACA,mBAAmB,eACrB,GACA,gBACA,cACA,EAAE,QAAQ,mBAAmB,gBAAgB,OAAO,CACtD;;;;;;CAOF,MAAM,uBAAuB,OAC3B,eACA,eAA+B,CAAC,MAEhC,MAAMD,4BACJC,sDACE,YACA,gBACA,mBAAmB,sBACnB,EAAE,cAAc,CAClB,GACA,gBACA,cACA,EAAE,QAAQ,mBAAmB,qBAAqB,OAAO,CAC3D;;;;;;;CAQF,MAAM,cAAc,OAClB,OACA,UACA,eAA+B,CAAC,MAEhC,MAAMD,4BACJC,sDAAc,YAAY,gBAAgB,mBAAmB,WAAW,GACxE,gBACA,cACA;EACE,QAAQ,mBAAmB,YAAY;EACvC,QAAQ;GAAE;GAAO;EAAS;CAC5B,CACF;;;;;;CAOF,MAAM,qBAAqB,OACzB,WACA,eAA+B,CAAC,MAEhC,MAAMD,4BACJC,sDACE,YACA,gBACA,mBAAmB,oBACnB,EAAE,UAAU,CACd,GACA,gBACA,cACA,EAAE,QAAQ,mBAAmB,mBAAmB,OAAO,CACzD;;;;;;CAOF,MAAM,kBAAkB,OACtB,KACA,eAA+B,CAAC,MAEhC,MAAMD,4BACJC,sDACE,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;EACA;EACA;CACF;AACF;;;;;;;AAQA,MAAa,oBAAoBC,6CAAe,eAAe"}
@@ -0,0 +1,70 @@
1
+ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
+ // src/getIntlayerAPI/readServerSentEvents.ts
3
+ /**
4
+ * Error raised when the server emits an `event: error` frame mid-stream.
5
+ * `message` is the serialized payload, matching the `fetcher` convention so
6
+ * callers can match backend error codes with `error.message.includes(code)`.
7
+ */
8
+ var ServerSentEventError = class extends Error {
9
+ payload;
10
+ constructor(payload) {
11
+ super(JSON.stringify(payload));
12
+ this.name = "ServerSentEventError";
13
+ this.payload = payload;
14
+ }
15
+ };
16
+ /**
17
+ * Reads a `text/event-stream` response and calls `onData` with each parsed
18
+ * `data:` payload of the default event type.
19
+ *
20
+ * Throws a {@link ServerSentEventError} as soon as an `event: error` frame is
21
+ * received, so stream failures reject the caller instead of resolving silently.
22
+ */
23
+ const readServerSentEvents = async (response, onData) => {
24
+ const reader = response.body?.getReader();
25
+ if (!reader) throw new Error("No reader available");
26
+ const decoder = new TextDecoder();
27
+ let buffer = "";
28
+ let currentEventName = "message";
29
+ const handleLine = (line) => {
30
+ if (line === "") {
31
+ currentEventName = "message";
32
+ return;
33
+ }
34
+ if (line.startsWith("event:")) {
35
+ currentEventName = line.slice(6).trim();
36
+ return;
37
+ }
38
+ if (!line.startsWith("data:")) return;
39
+ const rawData = line.slice(5).trimStart();
40
+ let parsedData;
41
+ try {
42
+ parsedData = JSON.parse(rawData);
43
+ } catch {
44
+ if (currentEventName === "error") throw new ServerSentEventError({ message: rawData });
45
+ console.error("Failed to parse SSE data:", rawData);
46
+ return;
47
+ }
48
+ if (currentEventName === "error") throw new ServerSentEventError(parsedData);
49
+ onData(parsedData);
50
+ };
51
+ try {
52
+ while (true) {
53
+ const { done, value } = await reader.read();
54
+ if (done) break;
55
+ buffer += decoder.decode(value, { stream: true });
56
+ const lines = buffer.split("\n");
57
+ buffer = lines.pop() ?? "";
58
+ for (const line of lines) handleLine(line.replace(/\r$/, ""));
59
+ }
60
+ buffer += decoder.decode();
61
+ if (buffer !== "") handleLine(buffer.replace(/\r$/, ""));
62
+ } catch (error) {
63
+ await reader.cancel().catch(() => void 0);
64
+ throw error;
65
+ }
66
+ };
67
+
68
+ exports.ServerSentEventError = ServerSentEventError;
69
+ exports.readServerSentEvents = readServerSentEvents;
70
+ //# sourceMappingURL=readServerSentEvents.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"readServerSentEvents.cjs","names":[],"sources":["../../../src/getIntlayerAPI/readServerSentEvents.ts"],"sourcesContent":["/**\n * Error raised when the server emits an `event: error` frame mid-stream.\n * `message` is the serialized payload, matching the `fetcher` convention so\n * callers can match backend error codes with `error.message.includes(code)`.\n */\nexport class ServerSentEventError<\n Payload = Record<string, unknown>,\n> extends Error {\n readonly payload: Payload;\n\n constructor(payload: Payload) {\n super(JSON.stringify(payload));\n this.name = 'ServerSentEventError';\n this.payload = payload;\n }\n}\n\n/**\n * Reads a `text/event-stream` response and calls `onData` with each parsed\n * `data:` payload of the default event type.\n *\n * Throws a {@link ServerSentEventError} as soon as an `event: error` frame is\n * received, so stream failures reject the caller instead of resolving silently.\n */\nexport const readServerSentEvents = async <Data>(\n response: Response,\n onData: (data: Data) => void\n): Promise<void> => {\n const reader = response.body?.getReader();\n\n if (!reader) {\n throw new Error('No reader available');\n }\n\n const decoder = new TextDecoder();\n let buffer = '';\n let currentEventName = 'message';\n\n const handleLine = (line: string): void => {\n // A blank line terminates the current event: reset its type\n if (line === '') {\n currentEventName = 'message';\n return;\n }\n\n if (line.startsWith('event:')) {\n currentEventName = line.slice('event:'.length).trim();\n return;\n }\n\n if (!line.startsWith('data:')) return;\n\n const rawData = line.slice('data:'.length).trimStart();\n\n let parsedData: unknown;\n\n try {\n parsedData = JSON.parse(rawData);\n } catch {\n if (currentEventName === 'error') {\n throw new ServerSentEventError({ message: rawData });\n }\n\n console.error('Failed to parse SSE data:', rawData);\n return;\n }\n\n if (currentEventName === 'error') {\n throw new ServerSentEventError(parsedData);\n }\n\n onData(parsedData as Data);\n };\n\n try {\n while (true) {\n const { done, value } = await reader.read();\n\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 handleLine(line.replace(/\\r$/, ''));\n }\n }\n\n buffer += decoder.decode();\n\n if (buffer !== '') {\n handleLine(buffer.replace(/\\r$/, ''));\n }\n } catch (error) {\n await reader.cancel().catch(() => undefined);\n throw error;\n }\n};\n"],"mappings":";;;;;;;AAKA,IAAa,uBAAb,cAEU,MAAM;CACd,AAAS;CAET,YAAY,SAAkB;EAC5B,MAAM,KAAK,UAAU,OAAO,CAAC;EAC7B,KAAK,OAAO;EACZ,KAAK,UAAU;CACjB;AACF;;;;;;;;AASA,MAAa,uBAAuB,OAClC,UACA,WACkB;CAClB,MAAM,SAAS,SAAS,MAAM,UAAU;CAExC,IAAI,CAAC,QACH,MAAM,IAAI,MAAM,qBAAqB;CAGvC,MAAM,UAAU,IAAI,YAAY;CAChC,IAAI,SAAS;CACb,IAAI,mBAAmB;CAEvB,MAAM,cAAc,SAAuB;EAEzC,IAAI,SAAS,IAAI;GACf,mBAAmB;GACnB;EACF;EAEA,IAAI,KAAK,WAAW,QAAQ,GAAG;GAC7B,mBAAmB,KAAK,MAAM,CAAe,CAAC,CAAC,KAAK;GACpD;EACF;EAEA,IAAI,CAAC,KAAK,WAAW,OAAO,GAAG;EAE/B,MAAM,UAAU,KAAK,MAAM,CAAc,CAAC,CAAC,UAAU;EAErD,IAAI;EAEJ,IAAI;GACF,aAAa,KAAK,MAAM,OAAO;EACjC,QAAQ;GACN,IAAI,qBAAqB,SACvB,MAAM,IAAI,qBAAqB,EAAE,SAAS,QAAQ,CAAC;GAGrD,QAAQ,MAAM,6BAA6B,OAAO;GAClD;EACF;EAEA,IAAI,qBAAqB,SACvB,MAAM,IAAI,qBAAqB,UAAU;EAG3C,OAAO,UAAkB;CAC3B;CAEA,IAAI;EACF,OAAO,MAAM;GACX,MAAM,EAAE,MAAM,UAAU,MAAM,OAAO,KAAK;GAE1C,IAAI,MAAM;GAEV,UAAU,QAAQ,OAAO,OAAO,EAAE,QAAQ,KAAK,CAAC;GAChD,MAAM,QAAQ,OAAO,MAAM,IAAI;GAC/B,SAAS,MAAM,IAAI,KAAK;GAExB,KAAK,MAAM,QAAQ,OACjB,WAAW,KAAK,QAAQ,OAAO,EAAE,CAAC;EAEtC;EAEA,UAAU,QAAQ,OAAO;EAEzB,IAAI,WAAW,IACb,WAAW,OAAO,QAAQ,OAAO,EAAE,CAAC;CAExC,SAAS,OAAO;EACd,MAAM,OAAO,OAAO,CAAC,CAAC,YAAY,MAAS;EAC3C,MAAM;CACR;AACF"}
@@ -1,5 +1,6 @@
1
1
  import { createEndpoint } from "../cms/createIntlayerCMS.mjs";
2
2
  import { fetcher } from "../fetcher.mjs";
3
+ import { readServerSentEvents } from "./readServerSentEvents.mjs";
3
4
  import { editor } from "@intlayer/config/built";
4
5
  import { buildRouteURL } from "@intlayer/backend-contract/defineRoute";
5
6
  import { BACKEND_URL } from "@intlayer/config/defaultValues";
@@ -55,6 +56,14 @@ const aiEndpoints = {
55
56
  getAIStats: {
56
57
  method: "GET",
57
58
  path: "/stats"
59
+ },
60
+ getAICredits: {
61
+ method: "GET",
62
+ path: "/credits"
63
+ },
64
+ getAICreditUsage: {
65
+ method: "GET",
66
+ path: "/credits/usage"
58
67
  }
59
68
  };
60
69
  const getAiAPI = (authAPIOptions = {}, intlayerConfig) => {
@@ -134,7 +143,7 @@ const getAiAPI = (authAPIOptions = {}, intlayerConfig) => {
134
143
  */
135
144
  const askDocQuestion = async (body, otherOptions = {}) => {
136
145
  if (!body) return;
137
- const { onMessage, onDone, ...rest } = body;
146
+ const { onMessage, onReasoning, onDone, ...rest } = body;
138
147
  const abortController = new AbortController();
139
148
  try {
140
149
  const response = await fetch(buildRouteURL(backendURL, aiGroup, aiEndpoints.ask), {
@@ -166,24 +175,11 @@ const getAiAPI = (authAPIOptions = {}, intlayerConfig) => {
166
175
  }
167
176
  throw new Error(errorMessage);
168
177
  }
169
- const reader = response.body?.getReader();
170
- if (!reader) throw new Error("No reader available");
171
- const decoder = new TextDecoder();
172
- let buffer = "";
173
- while (true) {
174
- const { done, value } = await reader.read();
175
- if (done) break;
176
- buffer += decoder.decode(value, { stream: true });
177
- const lines = buffer.split("\n");
178
- buffer = lines.pop() ?? "";
179
- for (const line of lines) if (line.startsWith("data: ")) try {
180
- const data = JSON.parse(line.slice(6));
181
- if (data.chunk) onMessage?.(data.chunk);
182
- if (data.done && data.response) onDone?.(data.response);
183
- } catch (e) {
184
- console.error("Failed to parse SSE data:", e);
185
- }
186
- }
178
+ await readServerSentEvents(response, (data) => {
179
+ if (data.reasoning) onReasoning?.(data.reasoning);
180
+ if (data.chunk) onMessage?.(data.chunk);
181
+ if (data.done && data.response) onDone?.(data.response);
182
+ });
187
183
  } catch (error) {
188
184
  console.error("Error in askDocQuestion:", error);
189
185
  throw error;
@@ -223,25 +219,11 @@ const getAiAPI = (authAPIOptions = {}, intlayerConfig) => {
223
219
  }
224
220
  throw new Error(errorMessage);
225
221
  }
226
- const reader = response.body?.getReader();
227
- if (!reader) throw new Error("No reader available");
228
- const decoder = new TextDecoder();
229
- let buffer = "";
230
- while (true) {
231
- const { done, value } = await reader.read();
232
- if (done) break;
233
- buffer += decoder.decode(value, { stream: true });
234
- const lines = buffer.split("\n");
235
- buffer = lines.pop() ?? "";
236
- for (const line of lines) if (line.startsWith("data: ")) try {
237
- const data = JSON.parse(line.slice(6));
238
- if (data.chunk) onMessage?.(data.chunk);
239
- if (data.action) onAction?.(data.action);
240
- if (data.done && data.response) onDone?.(data.response);
241
- } catch (e) {
242
- console.error("Failed to parse SSE data:", e);
243
- }
244
- }
222
+ await readServerSentEvents(response, (data) => {
223
+ if (data.chunk) onMessage?.(data.chunk);
224
+ if (data.action) onAction?.(data.action);
225
+ if (data.done && data.response) onDone?.(data.response);
226
+ });
245
227
  } catch (error) {
246
228
  console.error("Error in chat:", error);
247
229
  throw error;
@@ -263,6 +245,18 @@ const getAiAPI = (authAPIOptions = {}, intlayerConfig) => {
263
245
  * project.
264
246
  */
265
247
  const getAIStats = async (otherOptions = {}) => await fetcher(buildRouteURL(backendURL, aiGroup, aiEndpoints.getAIStats), authAPIOptions, otherOptions, { method: aiEndpoints.getAIStats.method });
248
+ /**
249
+ * Retrieves the AI credit balance of the selected organization for the
250
+ * current monthly period.
251
+ */
252
+ const getAICredits = async (otherOptions = {}) => await fetcher(buildRouteURL(backendURL, aiGroup, aiEndpoints.getAICredits), authAPIOptions, otherOptions, { method: aiEndpoints.getAICredits.method });
253
+ /**
254
+ * Retrieves the day-by-day AI credit usage of the selected organization.
255
+ */
256
+ const getAICreditUsage = async (params, otherOptions = {}) => await fetcher(buildRouteURL(backendURL, aiGroup, aiEndpoints.getAICreditUsage), authAPIOptions, otherOptions, {
257
+ method: aiEndpoints.getAICreditUsage.method,
258
+ params
259
+ });
266
260
  return {
267
261
  customQuery,
268
262
  translateJSON,
@@ -274,7 +268,9 @@ const getAiAPI = (authAPIOptions = {}, intlayerConfig) => {
274
268
  chat,
275
269
  autocomplete,
276
270
  getDiscussions,
277
- getAIStats
271
+ getAIStats,
272
+ getAICredits,
273
+ getAICreditUsage
278
274
  };
279
275
  };
280
276
  /**
@@ -1 +1 @@
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
+ {"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 GetAICreditsResult,\n GetAICreditUsageParams,\n GetAICreditUsageResult,\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';\nimport { readServerSentEvents } from './readServerSentEvents';\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 /** Receives the summarized reasoning of the model as it streams. */\n onReasoning?: (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\n/** `data:` payload streamed by the `ask` endpoint. */\ntype AskDocQuestionStreamData = {\n chunk?: string;\n reasoning?: string;\n done?: boolean;\n response?: AskDocQuestionResult;\n};\n\n/** `data:` payload streamed by the `chat` endpoint. */\ntype ChatStreamData = {\n chunk?: string;\n action?: ClientAction;\n done?: boolean;\n response?: ChatResult;\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 getAICredits: { method: 'GET', path: '/credits' },\n getAICreditUsage: { method: 'GET', path: '/credits/usage' },\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, onReasoning, 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 await readServerSentEvents<AskDocQuestionStreamData>(response, (data) => {\n if (data.reasoning) {\n onReasoning?.(data.reasoning);\n }\n if (data.chunk) {\n onMessage?.(data.chunk);\n }\n if (data.done && data.response) {\n onDone?.(data.response);\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 await readServerSentEvents<ChatStreamData>(response, (data) => {\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 });\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 /**\n * Retrieves the AI credit balance of the selected organization for the\n * current monthly period.\n */\n const getAICredits = async (otherOptions: FetcherOptions = {}) =>\n await fetcher<GetAICreditsResult>(\n buildRouteURL(backendURL, aiGroup, aiEndpoints.getAICredits),\n authAPIOptions,\n otherOptions,\n {\n method: aiEndpoints.getAICredits.method,\n }\n );\n\n /**\n * Retrieves the day-by-day AI credit usage of the selected organization.\n */\n const getAICreditUsage = async (\n params?: GetAICreditUsageParams,\n otherOptions: FetcherOptions = {}\n ) =>\n await fetcher<GetAICreditUsageResult>(\n buildRouteURL(backendURL, aiGroup, aiEndpoints.getAICreditUsage),\n authAPIOptions,\n otherOptions,\n {\n method: aiEndpoints.getAICreditUsage.method,\n params,\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 getAICredits,\n getAICreditUsage,\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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"}
@@ -24,6 +24,14 @@ const analyticsEndpoints = {
24
24
  method: "GET",
25
25
  path: "/audience"
26
26
  },
27
+ getPageFlow: {
28
+ method: "GET",
29
+ path: "/page-flow"
30
+ },
31
+ getLiveVisitorFlow: {
32
+ method: "GET",
33
+ path: "/audience/live/visitors/:visitorId"
34
+ },
27
35
  getContentStats: {
28
36
  method: "GET",
29
37
  path: "/content-stats"
@@ -77,6 +85,25 @@ const getAnalyticsAPI = (authAPIOptions = {}, intlayerConfig) => {
77
85
  */
78
86
  const getExperimentResults = async (experimentKey, otherOptions = {}) => await fetcher(buildRouteURL(backendURL, analyticsGroup, analyticsEndpoints.getExperimentResults, { experimentKey }), authAPIOptions, otherOptions, { method: analyticsEndpoints.getExperimentResults.method });
79
87
  /**
88
+ * Averaged page-to-page navigation flow from a starting page.
89
+ * @param range - Rolling window of the report.
90
+ * @param startUrl - Starting page pathname (default `/`).
91
+ * @returns The flow steps and the links between them.
92
+ */
93
+ const getPageFlow = async (range, startUrl, otherOptions = {}) => await fetcher(buildRouteURL(backendURL, analyticsGroup, analyticsEndpoints.getPageFlow), authAPIOptions, otherOptions, {
94
+ method: analyticsEndpoints.getPageFlow.method,
95
+ params: {
96
+ range,
97
+ startUrl
98
+ }
99
+ });
100
+ /**
101
+ * Page journey of a visitor active in the last 30 minutes.
102
+ * @param visitorId - The visitor id from the `live` audience report.
103
+ * @returns The visitor and its steps (`visitor: null` once it went quiet).
104
+ */
105
+ const getLiveVisitorFlow = async (visitorId, otherOptions = {}) => await fetcher(buildRouteURL(backendURL, analyticsGroup, analyticsEndpoints.getLiveVisitorFlow, { visitorId }), authAPIOptions, otherOptions, { method: analyticsEndpoints.getLiveVisitorFlow.method });
106
+ /**
80
107
  * Page metadata (title and meta description) for a given url.
81
108
  * @param url - The page url to inspect.
82
109
  * @returns Title and description of the page.
@@ -89,6 +116,8 @@ const getAnalyticsAPI = (authAPIOptions = {}, intlayerConfig) => {
89
116
  sendEvents,
90
117
  getOverview,
91
118
  getAudience,
119
+ getLiveVisitorFlow,
120
+ getPageFlow,
92
121
  getContentStats,
93
122
  getExperimentResults,
94
123
  getPageMetadata
@@ -1 +1 @@
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
+ {"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 GetLiveVisitorFlowResult,\n GetPageFlowResult,\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 getPageFlow: { method: 'GET', path: '/page-flow' },\n getLiveVisitorFlow: {\n method: 'GET',\n path: '/audience/live/visitors/:visitorId',\n },\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 * Averaged page-to-page navigation flow from a starting page.\n * @param range - Rolling window of the report.\n * @param startUrl - Starting page pathname (default `/`).\n * @returns The flow steps and the links between them.\n */\n const getPageFlow = async (\n range: AudienceRange,\n startUrl: string,\n otherOptions: FetcherOptions = {}\n ) =>\n await fetcher<GetPageFlowResult>(\n buildRouteURL(backendURL, analyticsGroup, analyticsEndpoints.getPageFlow),\n authAPIOptions,\n otherOptions,\n {\n method: analyticsEndpoints.getPageFlow.method,\n params: { range, startUrl },\n }\n );\n\n /**\n * Page journey of a visitor active in the last 30 minutes.\n * @param visitorId - The visitor id from the `live` audience report.\n * @returns The visitor and its steps (`visitor: null` once it went quiet).\n */\n const getLiveVisitorFlow = async (\n visitorId: string,\n otherOptions: FetcherOptions = {}\n ) =>\n await fetcher<GetLiveVisitorFlowResult>(\n buildRouteURL(\n backendURL,\n analyticsGroup,\n analyticsEndpoints.getLiveVisitorFlow,\n { visitorId }\n ),\n authAPIOptions,\n otherOptions,\n { method: analyticsEndpoints.getLiveVisitorFlow.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 getLiveVisitorFlow,\n getPageFlow,\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":";;;;;;;;AAuBA,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,aAAa;EAAE,QAAQ;EAAO,MAAM;CAAa;CACjD,oBAAoB;EAClB,QAAQ;EACR,MAAM;CACR;CACA,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;;;;;;;CAQF,MAAM,cAAc,OAClB,OACA,UACA,eAA+B,CAAC,MAEhC,MAAM,QACJ,cAAc,YAAY,gBAAgB,mBAAmB,WAAW,GACxE,gBACA,cACA;EACE,QAAQ,mBAAmB,YAAY;EACvC,QAAQ;GAAE;GAAO;EAAS;CAC5B,CACF;;;;;;CAOF,MAAM,qBAAqB,OACzB,WACA,eAA+B,CAAC,MAEhC,MAAM,QACJ,cACE,YACA,gBACA,mBAAmB,oBACnB,EAAE,UAAU,CACd,GACA,gBACA,cACA,EAAE,QAAQ,mBAAmB,mBAAmB,OAAO,CACzD;;;;;;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;EACA;EACA;CACF;AACF;;;;;;;AAQA,MAAa,oBAAoB,eAAe,eAAe"}
@@ -0,0 +1,68 @@
1
+ // src/getIntlayerAPI/readServerSentEvents.ts
2
+ /**
3
+ * Error raised when the server emits an `event: error` frame mid-stream.
4
+ * `message` is the serialized payload, matching the `fetcher` convention so
5
+ * callers can match backend error codes with `error.message.includes(code)`.
6
+ */
7
+ var ServerSentEventError = class extends Error {
8
+ payload;
9
+ constructor(payload) {
10
+ super(JSON.stringify(payload));
11
+ this.name = "ServerSentEventError";
12
+ this.payload = payload;
13
+ }
14
+ };
15
+ /**
16
+ * Reads a `text/event-stream` response and calls `onData` with each parsed
17
+ * `data:` payload of the default event type.
18
+ *
19
+ * Throws a {@link ServerSentEventError} as soon as an `event: error` frame is
20
+ * received, so stream failures reject the caller instead of resolving silently.
21
+ */
22
+ const readServerSentEvents = async (response, onData) => {
23
+ const reader = response.body?.getReader();
24
+ if (!reader) throw new Error("No reader available");
25
+ const decoder = new TextDecoder();
26
+ let buffer = "";
27
+ let currentEventName = "message";
28
+ const handleLine = (line) => {
29
+ if (line === "") {
30
+ currentEventName = "message";
31
+ return;
32
+ }
33
+ if (line.startsWith("event:")) {
34
+ currentEventName = line.slice(6).trim();
35
+ return;
36
+ }
37
+ if (!line.startsWith("data:")) return;
38
+ const rawData = line.slice(5).trimStart();
39
+ let parsedData;
40
+ try {
41
+ parsedData = JSON.parse(rawData);
42
+ } catch {
43
+ if (currentEventName === "error") throw new ServerSentEventError({ message: rawData });
44
+ console.error("Failed to parse SSE data:", rawData);
45
+ return;
46
+ }
47
+ if (currentEventName === "error") throw new ServerSentEventError(parsedData);
48
+ onData(parsedData);
49
+ };
50
+ try {
51
+ while (true) {
52
+ const { done, value } = await reader.read();
53
+ if (done) break;
54
+ buffer += decoder.decode(value, { stream: true });
55
+ const lines = buffer.split("\n");
56
+ buffer = lines.pop() ?? "";
57
+ for (const line of lines) handleLine(line.replace(/\r$/, ""));
58
+ }
59
+ buffer += decoder.decode();
60
+ if (buffer !== "") handleLine(buffer.replace(/\r$/, ""));
61
+ } catch (error) {
62
+ await reader.cancel().catch(() => void 0);
63
+ throw error;
64
+ }
65
+ };
66
+
67
+ export { ServerSentEventError, readServerSentEvents };
68
+ //# sourceMappingURL=readServerSentEvents.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"readServerSentEvents.mjs","names":[],"sources":["../../../src/getIntlayerAPI/readServerSentEvents.ts"],"sourcesContent":["/**\n * Error raised when the server emits an `event: error` frame mid-stream.\n * `message` is the serialized payload, matching the `fetcher` convention so\n * callers can match backend error codes with `error.message.includes(code)`.\n */\nexport class ServerSentEventError<\n Payload = Record<string, unknown>,\n> extends Error {\n readonly payload: Payload;\n\n constructor(payload: Payload) {\n super(JSON.stringify(payload));\n this.name = 'ServerSentEventError';\n this.payload = payload;\n }\n}\n\n/**\n * Reads a `text/event-stream` response and calls `onData` with each parsed\n * `data:` payload of the default event type.\n *\n * Throws a {@link ServerSentEventError} as soon as an `event: error` frame is\n * received, so stream failures reject the caller instead of resolving silently.\n */\nexport const readServerSentEvents = async <Data>(\n response: Response,\n onData: (data: Data) => void\n): Promise<void> => {\n const reader = response.body?.getReader();\n\n if (!reader) {\n throw new Error('No reader available');\n }\n\n const decoder = new TextDecoder();\n let buffer = '';\n let currentEventName = 'message';\n\n const handleLine = (line: string): void => {\n // A blank line terminates the current event: reset its type\n if (line === '') {\n currentEventName = 'message';\n return;\n }\n\n if (line.startsWith('event:')) {\n currentEventName = line.slice('event:'.length).trim();\n return;\n }\n\n if (!line.startsWith('data:')) return;\n\n const rawData = line.slice('data:'.length).trimStart();\n\n let parsedData: unknown;\n\n try {\n parsedData = JSON.parse(rawData);\n } catch {\n if (currentEventName === 'error') {\n throw new ServerSentEventError({ message: rawData });\n }\n\n console.error('Failed to parse SSE data:', rawData);\n return;\n }\n\n if (currentEventName === 'error') {\n throw new ServerSentEventError(parsedData);\n }\n\n onData(parsedData as Data);\n };\n\n try {\n while (true) {\n const { done, value } = await reader.read();\n\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 handleLine(line.replace(/\\r$/, ''));\n }\n }\n\n buffer += decoder.decode();\n\n if (buffer !== '') {\n handleLine(buffer.replace(/\\r$/, ''));\n }\n } catch (error) {\n await reader.cancel().catch(() => undefined);\n throw error;\n }\n};\n"],"mappings":";;;;;;AAKA,IAAa,uBAAb,cAEU,MAAM;CACd,AAAS;CAET,YAAY,SAAkB;EAC5B,MAAM,KAAK,UAAU,OAAO,CAAC;EAC7B,KAAK,OAAO;EACZ,KAAK,UAAU;CACjB;AACF;;;;;;;;AASA,MAAa,uBAAuB,OAClC,UACA,WACkB;CAClB,MAAM,SAAS,SAAS,MAAM,UAAU;CAExC,IAAI,CAAC,QACH,MAAM,IAAI,MAAM,qBAAqB;CAGvC,MAAM,UAAU,IAAI,YAAY;CAChC,IAAI,SAAS;CACb,IAAI,mBAAmB;CAEvB,MAAM,cAAc,SAAuB;EAEzC,IAAI,SAAS,IAAI;GACf,mBAAmB;GACnB;EACF;EAEA,IAAI,KAAK,WAAW,QAAQ,GAAG;GAC7B,mBAAmB,KAAK,MAAM,CAAe,CAAC,CAAC,KAAK;GACpD;EACF;EAEA,IAAI,CAAC,KAAK,WAAW,OAAO,GAAG;EAE/B,MAAM,UAAU,KAAK,MAAM,CAAc,CAAC,CAAC,UAAU;EAErD,IAAI;EAEJ,IAAI;GACF,aAAa,KAAK,MAAM,OAAO;EACjC,QAAQ;GACN,IAAI,qBAAqB,SACvB,MAAM,IAAI,qBAAqB,EAAE,SAAS,QAAQ,CAAC;GAGrD,QAAQ,MAAM,6BAA6B,OAAO;GAClD;EACF;EAEA,IAAI,qBAAqB,SACvB,MAAM,IAAI,qBAAqB,UAAU;EAG3C,OAAO,UAAkB;CAC3B;CAEA,IAAI;EACF,OAAO,MAAM;GACX,MAAM,EAAE,MAAM,UAAU,MAAM,OAAO,KAAK;GAE1C,IAAI,MAAM;GAEV,UAAU,QAAQ,OAAO,OAAO,EAAE,QAAQ,KAAK,CAAC;GAChD,MAAM,QAAQ,OAAO,MAAM,IAAI;GAC/B,SAAS,MAAM,IAAI,KAAK;GAExB,KAAK,MAAM,QAAQ,OACjB,WAAW,KAAK,QAAQ,OAAO,EAAE,CAAC;EAEtC;EAEA,UAAU,QAAQ,OAAO;EAEzB,IAAI,WAAW,IACb,WAAW,OAAO,QAAQ,OAAO,EAAE,CAAC;CAExC,SAAS,OAAO;EACd,MAAM,OAAO,OAAO,CAAC,CAAC,YAAY,MAAS;EAC3C,MAAM;CACR;AACF"}
@@ -1,5 +1,5 @@
1
- import { IntlayerConfig } from "@intlayer/types/config";
2
1
  import { DictionaryAPI } from "@intlayer/backend-contract/dictionary";
2
+ import { IntlayerConfig } from "@intlayer/types/config";
3
3
  /**
4
4
  * Fetch distant dictionary
5
5
  */
@@ -1,5 +1,5 @@
1
- import { IntlayerConfig } from "@intlayer/types/config";
2
1
  import { DictionaryAPI } from "@intlayer/backend-contract/dictionary";
2
+ import { IntlayerConfig } from "@intlayer/types/config";
3
3
  /**
4
4
  * Fetch distant dictionary
5
5
  */
@@ -1,8 +1,8 @@
1
1
  import "../index.js";
2
2
  import { CMSEndpoint } from "../cms/createIntlayerCMS.js";
3
3
  import { FetcherOptions } from "../fetcher.js";
4
+ import { AIOptions, AskDocQuestionResult, AuditContentDeclarationBody, AuditContentDeclarationFieldBody, AuditContentDeclarationFieldResult, AuditContentDeclarationMetadataBody, AuditContentDeclarationMetadataResult, AuditContentDeclarationResult, AuditTagBody, AuditTagResult, AutocompleteResponse, ChatCompletionRequestMessage, ChatResult, CustomQueryBody, CustomQueryResult, GetAICreditUsageParams, GetAICreditUsageResult, GetAICreditsResult, GetAIStatsResult, GetDiscussionsParams, GetDiscussionsResult, TranslateJSONBody, TranslateJSONResult } from "@intlayer/backend-contract/ai";
4
5
  import { IntlayerConfig } from "@intlayer/types/config";
5
- import { AIOptions, AskDocQuestionResult, AuditContentDeclarationBody, AuditContentDeclarationFieldBody, AuditContentDeclarationFieldResult, AuditContentDeclarationMetadataBody, AuditContentDeclarationMetadataResult, AuditContentDeclarationResult, AuditTagBody, AuditTagResult, AutocompleteResponse, ChatCompletionRequestMessage, ChatResult, CustomQueryBody, CustomQueryResult, GetAIStatsResult, GetDiscussionsParams, GetDiscussionsResult, TranslateJSONBody, TranslateJSONResult } from "@intlayer/backend-contract/ai";
6
6
  export type AutocompleteBody = {
7
7
  text: string;
8
8
  aiOptions?: AIOptions;
@@ -14,6 +14,8 @@ export type AskDocQuestionBody = {
14
14
  messages: ChatCompletionRequestMessage[];
15
15
  discussionId: string;
16
16
  onMessage?: (chunk: string) => void;
17
+ /** Receives the summarized reasoning of the model as it streams. */
18
+ onReasoning?: (chunk: string) => void;
17
19
  onDone?: (response: AskDocQuestionResult) => void;
18
20
  };
19
21
  export type ClientAction = {
@@ -41,6 +43,8 @@ export declare const getAiAPI: (authAPIOptions?: FetcherOptions, intlayerConfig?
41
43
  autocomplete: (body?: AutocompleteBody, otherOptions?: FetcherOptions) => Promise<AutocompleteResponse>;
42
44
  getDiscussions: (params?: GetDiscussionsParams, otherOptions?: FetcherOptions) => Promise<GetDiscussionsResult>;
43
45
  getAIStats: (otherOptions?: FetcherOptions) => Promise<GetAIStatsResult>;
46
+ getAICredits: (otherOptions?: FetcherOptions) => Promise<GetAICreditsResult>;
47
+ getAICreditUsage: (params?: GetAICreditUsageParams, otherOptions?: FetcherOptions) => Promise<GetAICreditUsageResult>;
44
48
  };
45
49
  /**
46
50
  * Authenticated `ai` endpoint bound to an Intlayer CMS authenticator.
@@ -60,6 +64,8 @@ export declare const aiEndpoint: CMSEndpoint<{
60
64
  autocomplete: (body?: AutocompleteBody, otherOptions?: FetcherOptions) => Promise<AutocompleteResponse>;
61
65
  getDiscussions: (params?: GetDiscussionsParams, otherOptions?: FetcherOptions) => Promise<GetDiscussionsResult>;
62
66
  getAIStats: (otherOptions?: FetcherOptions) => Promise<GetAIStatsResult>;
67
+ getAICredits: (otherOptions?: FetcherOptions) => Promise<GetAICreditsResult>;
68
+ getAICreditUsage: (params?: GetAICreditUsageParams, otherOptions?: FetcherOptions) => Promise<GetAICreditUsageResult>;
63
69
  }>;
64
70
  export type { AskDocQuestionResult, ChatResult };
65
71
  //# sourceMappingURL=ai.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ai.d.ts","names":["_$__0.CMSEndpoint"],"sources":["../../../src/getIntlayerAPI/ai.ts"],"mappings":";;;;;YAgCY;EACV;EACA,YAAY;EACZ;EACA;EACA;;YAGU;EACV,UAAU;EACV;EACA,aAAa;EACb,UAAU,UAAU;;YAGV;EACN;EAAkB;;EAClB;;YAEM;EACV,UAAU;EACV;EACA,aAAa;EACb,UAAU,UAAU;EACpB,YAAY,QAAQ;;qBAkCT,WAAQ,iBACH,gBAAc,iBACb;EAWR,cAAA,OAAA,iBAAe,eACR,mBAAc,QAAA;EAkBrB,gBAAA,OAAA,mBAAiB,eACV,mBAAc,QAAA;EAkBrB,0BAAA,OAAA,6BAA2B,eACpB,mBAAc,QAAA;EAkBrB,+BAAA,OAAA,kCAAgC,eACzB,mBAAc,QAAA;EAsBrB,kCAAA,OAAA,qCAAmC,eAC5B,mBAAc,QAAA;EAsBrB,WAAA,OAAA,cAAY,eACL,mBAAc,QAAA;EAgCrB,iBAAA,OAAA,oBAAkB,eACX,mBAAc;EA0FH,OAAA,OAAA,UAAQ,eAAgB,mBAAc;EAyFxD,eAAA,OAAA,kBAAgB,eACT,mBAAc,QAAA;EAgBnB,iBAAA,SAAA,sBAAoB,eACf,mBAAc,QAAA;EAiBU,aAAA,eAAA,mBAAc,QAAA;;;;;;;;qBA+B3C,YA/B2CA;EA/V7C,cAAA,OAAA,iBAAe,eACR,mBAAc,QAAA;EAkBrB,gBAAA,OAAA,mBAAiB,eACV,mBAAc,QAAA;EAkBrB,0BAAA,OAAA,6BAA2B,eACpB,mBAAc,QAAA;EAkBrB,+BAAA,OAAA,kCAAgC,eACzB,mBAAc,QAAA;EAsBrB,kCAAA,OAAA,qCAAmC,eAC5B,mBAAc,QAAA;EAsBrB,WAAA,OAAA,cAAY,eACL,mBAAc,QAAA;EAgCrB,iBAAA,OAAA,oBAAkB,eACX,mBAAc;EA0FH,OAAA,OAAA,UAAQ,eAAgB,mBAAc;EAyFxD,eAAA,OAAA,kBAAgB,eACT,mBAAc,QAAA;EAgBnB,iBAAA,SAAA,sBAAoB,eACf,mBAAc,QAAA;EAiBU,aAAA,eAAA,mBAAc,QAAA"}
1
+ {"version":3,"file":"ai.d.ts","names":["_$__0.CMSEndpoint"],"sources":["../../../src/getIntlayerAPI/ai.ts"],"mappings":";;;;;YAoCY;EACV;EACA,YAAY;EACZ;EACA;EACA;;YAGU;EACV,UAAU;EACV;EACA,aAAa;;EAEb,eAAe;EACf,UAAU,UAAU;;YAGV;EACN;EAAkB;;EAClB;;YAEM;EACV,UAAU;EACV;EACA,aAAa;EACb,UAAU,UAAU;EACpB,YAAY,QAAQ;;qBAoDT,WAAQ,iBACH,gBAAc,iBACb;EAWR,cAAA,OAAA,iBAAe,eACR,mBAAc,QAAA;EAkBrB,gBAAA,OAAA,mBAAiB,eACV,mBAAc,QAAA;EAkBrB,0BAAA,OAAA,6BAA2B,eACpB,mBAAc,QAAA;EAkBrB,+BAAA,OAAA,kCAAgC,eACzB,mBAAc,QAAA;EAsBrB,kCAAA,OAAA,qCAAmC,eAC5B,mBAAc,QAAA;EAsBrB,WAAA,OAAA,cAAY,eACL,mBAAc,QAAA;EAgCrB,iBAAA,OAAA,oBAAkB,eACX,mBAAc;EAqEH,OAAA,OAAA,UAAQ,eAAgB,mBAAc;EAiExD,eAAA,OAAA,kBAAgB,eACT,mBAAc,QAAA;EAgBnB,iBAAA,SAAA,sBAAoB,eACf,mBAAc,QAAA;EAiBU,aAAA,eAAA,mBAAc,QAAA;EAcZ,eAAA,eAAA,mBAAc,QAAA;EAc7C,mBAAA,SAAA,wBAAsB,eACjB,mBAAc,QAAA;;;;;;;;qBAmCnB,YAnCmBA;EA/UrB,cAAA,OAAA,iBAAe,eACR,mBAAc,QAAA;EAkBrB,gBAAA,OAAA,mBAAiB,eACV,mBAAc,QAAA;EAkBrB,0BAAA,OAAA,6BAA2B,eACpB,mBAAc,QAAA;EAkBrB,+BAAA,OAAA,kCAAgC,eACzB,mBAAc,QAAA;EAsBrB,kCAAA,OAAA,qCAAmC,eAC5B,mBAAc,QAAA;EAsBrB,WAAA,OAAA,cAAY,eACL,mBAAc,QAAA;EAgCrB,iBAAA,OAAA,oBAAkB,eACX,mBAAc;EAqEH,OAAA,OAAA,UAAQ,eAAgB,mBAAc;EAiExD,eAAA,OAAA,kBAAgB,eACT,mBAAc,QAAA;EAgBnB,iBAAA,SAAA,sBAAoB,eACf,mBAAc,QAAA;EAiBU,aAAA,eAAA,mBAAc,QAAA;EAcZ,eAAA,eAAA,mBAAc,QAAA;EAc7C,mBAAA,SAAA,wBAAsB,eACjB,mBAAc,QAAA"}
@@ -2,11 +2,13 @@ import "../index.js";
2
2
  import { CMSEndpoint } from "../cms/createIntlayerCMS.js";
3
3
  import { FetcherOptions } from "../fetcher.js";
4
4
  import { IntlayerConfig } from "@intlayer/types/config";
5
- import { AudienceRange, GetAnalyticsOverviewResult, GetAudienceResult, GetContentStatsResult, GetExperimentResultsResult, GetPageMetadataResult, IngestAnalyticsBody, IngestAnalyticsResult } from "@intlayer/backend-contract/analytics";
5
+ import { AudienceRange, GetAnalyticsOverviewResult, GetAudienceResult, GetContentStatsResult, GetExperimentResultsResult, GetLiveVisitorFlowResult, GetPageFlowResult, GetPageMetadataResult, IngestAnalyticsBody, IngestAnalyticsResult } from "@intlayer/backend-contract/analytics";
6
6
  export declare const getAnalyticsAPI: (authAPIOptions?: FetcherOptions, intlayerConfig?: IntlayerConfig) => {
7
7
  sendEvents: (body: IngestAnalyticsBody, otherOptions?: FetcherOptions) => Promise<IngestAnalyticsResult>;
8
8
  getOverview: (otherOptions?: FetcherOptions) => Promise<GetAnalyticsOverviewResult>;
9
9
  getAudience: (range?: AudienceRange | number, otherOptions?: FetcherOptions) => Promise<GetAudienceResult>;
10
+ getLiveVisitorFlow: (visitorId: string, otherOptions?: FetcherOptions) => Promise<GetLiveVisitorFlowResult>;
11
+ getPageFlow: (range: AudienceRange, startUrl: string, otherOptions?: FetcherOptions) => Promise<GetPageFlowResult>;
10
12
  getContentStats: (otherOptions?: FetcherOptions) => Promise<GetContentStatsResult>;
11
13
  getExperimentResults: (experimentKey: string, otherOptions?: FetcherOptions) => Promise<GetExperimentResultsResult>;
12
14
  getPageMetadata: (url: string, otherOptions?: FetcherOptions) => Promise<GetPageMetadataResult>;
@@ -21,6 +23,8 @@ export declare const analyticsEndpoint: CMSEndpoint<{
21
23
  sendEvents: (body: IngestAnalyticsBody, otherOptions?: FetcherOptions) => Promise<IngestAnalyticsResult>;
22
24
  getOverview: (otherOptions?: FetcherOptions) => Promise<GetAnalyticsOverviewResult>;
23
25
  getAudience: (range?: AudienceRange | number, otherOptions?: FetcherOptions) => Promise<GetAudienceResult>;
26
+ getLiveVisitorFlow: (visitorId: string, otherOptions?: FetcherOptions) => Promise<GetLiveVisitorFlowResult>;
27
+ getPageFlow: (range: AudienceRange, startUrl: string, otherOptions?: FetcherOptions) => Promise<GetPageFlowResult>;
24
28
  getContentStats: (otherOptions?: FetcherOptions) => Promise<GetContentStatsResult>;
25
29
  getExperimentResults: (experimentKey: string, otherOptions?: FetcherOptions) => Promise<GetExperimentResultsResult>;
26
30
  getPageMetadata: (url: string, otherOptions?: FetcherOptions) => Promise<GetPageMetadataResult>;
@@ -1 +1 @@
1
- {"version":3,"file":"analytics.d.ts","names":["_$__0.CMSEndpoint"],"sources":["../../../src/getIntlayerAPI/analytics.ts"],"mappings":";;;;;qBAsCa,kBAAe,iBACV,gBAAc,iBACb;EAYT,aAAA,MAAA,qBAAmB,eACX,mBAAc,QAAA;EAoBW,cAAA,eAAA,mBAAc,QAAA;EAoB9C,cAAA,QAAA,wBAAsB,eACf,mBAAc,QAAA;EAoBe,kBAAA,eAAA,mBAAc,QAAA;EAkB1C,uBAAA,uBAAM,eACP,mBAAc,QAAA;EAoBvB,kBAAA,aAAM,eACG,mBAAc,QAAA;;;;;;;;qBAgCnB,mBAhCmBA;EAtGtB,aAAA,MAAA,qBAAmB,eACX,mBAAc,QAAA;EAoBW,cAAA,eAAA,mBAAc,QAAA;EAoB9C,cAAA,QAAA,wBAAsB,eACf,mBAAc,QAAA;EAoBe,kBAAA,eAAA,mBAAc,QAAA;EAkB1C,uBAAA,uBAAM,eACP,mBAAc,QAAA;EAoBvB,kBAAA,aAAM,eACG,mBAAc,QAAA"}
1
+ {"version":3,"file":"analytics.d.ts","names":["_$__0.CMSEndpoint"],"sources":["../../../src/getIntlayerAPI/analytics.ts"],"mappings":";;;;;qBA6Ca,kBAAe,iBACV,gBAAc,iBACb;EAYT,aAAA,MAAA,qBAAmB,eACX,mBAAc,QAAA;EAoBW,cAAA,eAAA,mBAAc,QAAA;EAoB9C,cAAA,QAAA,wBAAsB,eACf,mBAAc,QAAA;EAgFjB,qBAAA,mBAAM,eACH,mBAAc,QAAA;EArBrB,cAAA,OAAA,eAAa,kBACJ,eACF,mBAAc,QAAA;EA1Ce,kBAAA,eAAA,mBAAc,QAAA;EAkB1C,uBAAA,uBAAM,eACP,mBAAc,QAAA;EA8DvB,kBAAA,aAAM,eACG,mBAAc,QAAA;;;;;;;;qBAkCnB,mBAlCmBA;EAhJtB,aAAA,MAAA,qBAAmB,eACX,mBAAc,QAAA;EAoBW,cAAA,eAAA,mBAAc,QAAA;EAoB9C,cAAA,QAAA,wBAAsB,eACf,mBAAc,QAAA;EAgFjB,qBAAA,mBAAM,eACH,mBAAc,QAAA;EArBrB,cAAA,OAAA,eAAa,kBACJ,eACF,mBAAc,QAAA;EA1Ce,kBAAA,eAAA,mBAAc,QAAA;EAkB1C,uBAAA,uBAAM,eACP,mBAAc,QAAA;EA8DvB,kBAAA,aAAM,eACG,mBAAc,QAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"codeberg.d.ts","names":["_$__0.FetcherOptions","_$__0.CMSEndpoint"],"sources":["../../../src/getIntlayerAPI/codeberg.ts"],"mappings":";;;;qBAUa,iBAAc,iBAAdA,gBAAc,kDAAA;E,wDAAAA,mB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;qBAQd,kB;E,wDAAAA,mB"}
1
+ {"version":3,"file":"codeberg.d.ts","names":["_$__0.FetcherOptions"],"sources":["../../../src/getIntlayerAPI/codeberg.ts"],"mappings":";;;;qBAUa,iBAAc,iBAAdA,gBAAc,kDAAA;E,wDAAAA,mB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;qBAQd,kB;E,wDAAAA,mB"}
@@ -1,8 +1,8 @@
1
1
  import "../index.js";
2
2
  import { CMSEndpoint } from "../cms/createIntlayerCMS.js";
3
3
  import { FetcherOptions } from "../fetcher.js";
4
- import { IntlayerConfig } from "@intlayer/types/config";
5
4
  import { AddDictionaryBody, AddDictionaryResult, DeleteDictionaryParam, DeleteDictionaryResult, GetDictionariesByKeysResult, GetDictionariesKeysResult, GetDictionariesParams, GetDictionariesResult, GetDictionariesUpdateTimestampResult, GetDictionaryParams, GetDictionaryQuery, GetDictionaryResult, PushDictionariesBody, PushDictionariesResult, UpdateDictionaryBody, UpdateDictionaryResult } from "@intlayer/backend-contract/dictionary";
5
+ import { IntlayerConfig } from "@intlayer/types/config";
6
6
  export declare const getDictionaryAPI: (authAPIOptions?: FetcherOptions, intlayerConfig?: IntlayerConfig) => {
7
7
  getDictionaries: (filters?: GetDictionariesParams, otherOptions?: FetcherOptions) => Promise<GetDictionariesResult>;
8
8
  getDictionariesKeys: (otherOptions?: FetcherOptions) => Promise<GetDictionariesKeysResult>;
@@ -1 +1 @@
1
- {"version":3,"file":"gitee.d.ts","names":["_$__0.FetcherOptions","_$__0.CMSEndpoint"],"sources":["../../../src/getIntlayerAPI/gitee.ts"],"mappings":";;;;qBAUa,cAAW,iBAAXA,gBAAW,kDAAA;E,wDAAAA,mB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;qBAQX,e;E,wDAAAA,mB"}
1
+ {"version":3,"file":"gitee.d.ts","names":["_$__0.FetcherOptions"],"sources":["../../../src/getIntlayerAPI/gitee.ts"],"mappings":";;;;qBAUa,cAAW,iBAAXA,gBAAW,kDAAA;E,wDAAAA,mB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;qBAQX,e;E,wDAAAA,mB"}
@@ -1,8 +1,8 @@
1
1
  import "../index.js";
2
2
  import { CMSEndpoint } from "../cms/createIntlayerCMS.js";
3
3
  import { FetcherOptions } from "../fetcher.js";
4
- import { IntlayerConfig } from "@intlayer/types/config";
5
4
  import { AddNewAccessKeyBody, AddNewAccessKeyResponse, AddProjectBody, AddProjectResult, DeleteAccessKeyBody, DeleteAccessKeyResponse, DeleteProjectResult, GetProjectInsightsResult, GetProjectsParams, GetProjectsResult, PushProjectConfigurationBody, PushProjectConfigurationResult, RefreshAccessKeyBody, RefreshAccessKeyResponse, SelectProjectParam, SelectProjectResult, TriggerBuildResult, TriggerWebhookBody, TriggerWebhookResult, UnselectProjectResult, UpdateMemberAccessBody, UpdateMemberAccessResult, UpdateProjectBody, UpdateProjectMembersBody, UpdateProjectMembersResult, UpdateProjectResult } from "@intlayer/backend-contract/project";
5
+ import { IntlayerConfig } from "@intlayer/types/config";
6
6
  import { ResponseData } from "@intlayer/backend-contract/responseData";
7
7
  export declare const getProjectAPI: (authAPIOptions?: FetcherOptions, intlayerConfig?: IntlayerConfig) => {
8
8
  getProjects: (filters?: GetProjectsParams, otherOptions?: FetcherOptions) => Promise<GetProjectsResult>;
@@ -0,0 +1,18 @@
1
+ /**
2
+ * Error raised when the server emits an `event: error` frame mid-stream.
3
+ * `message` is the serialized payload, matching the `fetcher` convention so
4
+ * callers can match backend error codes with `error.message.includes(code)`.
5
+ */
6
+ export declare class ServerSentEventError<Payload = Record<string, unknown>> extends Error {
7
+ readonly payload: Payload;
8
+ constructor(payload: Payload);
9
+ }
10
+ /**
11
+ * Reads a `text/event-stream` response and calls `onData` with each parsed
12
+ * `data:` payload of the default event type.
13
+ *
14
+ * Throws a {@link ServerSentEventError} as soon as an `event: error` frame is
15
+ * received, so stream failures reject the caller instead of resolving silently.
16
+ */
17
+ export declare const readServerSentEvents: <Data>(response: Response, onData: (data: Data) => void) => Promise<void>;
18
+ //# sourceMappingURL=readServerSentEvents.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"readServerSentEvents.d.ts","names":[],"sources":["../../../src/getIntlayerAPI/readServerSentEvents.ts"],"mappings":";;;;;qBAKa,qBACX,UAAU,iCACF;WACC,SAAS;EAElB,YAAY,SAAS;;;;;;;;;qBAcV,uBAA8B,MAAI,UACnC,UAAQ,SACT,MAAM,kBACd"}
@@ -1,11 +1,11 @@
1
1
  import "./cms/index.js";
2
+ import "./distantDictionary/index.js";
3
+ import { FetcherError, FetcherOptions, fetcher, fetcherOptions } from "./fetcher.js";
2
4
  import { AuthManager, AuthManagerOptions, BindSectionOptions, clearAccessTokenCache, createAuthManager } from "./cms/createAuthManager.js";
3
5
  import { CMSEndpoint, IntlayerCMS, IntlayerCMSOptions, createEndpoint, createIntlayerCMS } from "./cms/createIntlayerCMS.js";
4
- import "./distantDictionary/index.js";
6
+ import { IntlayerAPI, getIntlayerAPI } from "./getIntlayerAPI/index.js";
5
7
  import { fetchDistantDictionaries } from "./distantDictionary/fetchDistantDictionaries.js";
6
8
  import { fetchDistantDictionary } from "./distantDictionary/fetchDistantDictionary.js";
7
- import { FetcherError, FetcherOptions, fetcher, fetcherOptions } from "./fetcher.js";
8
- import { IntlayerAPI, getIntlayerAPI } from "./getIntlayerAPI/index.js";
9
9
  import { AskDocQuestionBody, AskDocQuestionResult, AutocompleteBody, ChatBody, ChatResult, ClientAction, aiEndpoint, getAiAPI } from "./getIntlayerAPI/ai.js";
10
10
  import { analyticsEndpoint, getAnalyticsAPI } from "./getIntlayerAPI/analytics.js";
11
11
  import { assetEndpoint, getAssetAPI } from "./getIntlayerAPI/asset.js";
@@ -1,5 +1,5 @@
1
- import { IntlayerConfig } from "@intlayer/types/config";
2
1
  import { DictionaryAPI } from "@intlayer/backend-contract/dictionary";
2
+ import { IntlayerConfig } from "@intlayer/types/config";
3
3
  /** Options accepted by {@link createPublicClient}. */
4
4
  export type PublicClientOptions = {
5
5
  /** Overrides the build-time `editor` configuration. */
@@ -1,5 +1,5 @@
1
- import { DictionaryAPI } from "@intlayer/backend-contract/dictionary";
2
- import { EnvironmentAPI, ProjectAPI } from "@intlayer/backend-contract/project";
3
1
  import { AIOptions } from "@intlayer/backend-contract/ai";
2
+ import { DictionaryAPI } from "@intlayer/backend-contract/dictionary";
4
3
  import { MessageEventData } from "@intlayer/backend-contract/eventListener";
4
+ import { EnvironmentAPI, ProjectAPI } from "@intlayer/backend-contract/project";
5
5
  export type { AIOptions, DictionaryAPI, EnvironmentAPI, MessageEventData, ProjectAPI };
package/package.json CHANGED
@@ -1,24 +1,20 @@
1
1
  {
2
2
  "name": "@intlayer/api",
3
- "version": "9.7.1",
3
+ "version": "9.7.2",
4
4
  "private": false,
5
5
  "description": "SDK for interacting with the Intlayer API, enabling content auditing, and managing organizations, projects, and users.",
6
6
  "keywords": [
7
- "intlayer",
8
- "application",
9
7
  "api",
8
+ "application",
10
9
  "backend",
11
10
  "i18n",
12
- "internationalization"
11
+ "internationalization",
12
+ "intlayer"
13
13
  ],
14
14
  "homepage": "https://intlayer.org",
15
15
  "bugs": {
16
16
  "url": "https://github.com/aymericzip/intlayer/issues"
17
17
  },
18
- "repository": {
19
- "type": "git",
20
- "url": "git+https://github.com/aymericzip/intlayer.git"
21
- },
22
18
  "license": "Apache-2.0",
23
19
  "author": {
24
20
  "name": "Aymeric PINEAU",
@@ -31,7 +27,103 @@
31
27
  "url": "https://github.com/aymericzip"
32
28
  }
33
29
  ],
30
+ "repository": {
31
+ "type": "git",
32
+ "url": "git+https://github.com/aymericzip/intlayer.git"
33
+ },
34
+ "files": [
35
+ "./dist",
36
+ "./package.json"
37
+ ],
34
38
  "sideEffects": false,
39
+ "main": "dist/cjs/index.cjs",
40
+ "module": "dist/esm/index.mjs",
41
+ "types": "dist/types/index.d.ts",
42
+ "typesVersions": {
43
+ "*": {
44
+ "ai": [
45
+ "./dist/types/getIntlayerAPI/ai.d.ts"
46
+ ],
47
+ "analytics": [
48
+ "./dist/types/getIntlayerAPI/analytics.d.ts"
49
+ ],
50
+ "public": [
51
+ "./dist/types/public/index.d.ts"
52
+ ],
53
+ "audit": [
54
+ "./dist/types/getIntlayerAPI/audit.d.ts"
55
+ ],
56
+ "bitbucket": [
57
+ "./dist/types/getIntlayerAPI/bitbucket.d.ts"
58
+ ],
59
+ "gitee": [
60
+ "./dist/types/getIntlayerAPI/gitee.d.ts"
61
+ ],
62
+ "codeberg": [
63
+ "./dist/types/getIntlayerAPI/codeberg.d.ts"
64
+ ],
65
+ "asset": [
66
+ "./dist/types/getIntlayerAPI/asset.d.ts"
67
+ ],
68
+ "cms": [
69
+ "./dist/types/cms/index.d.ts"
70
+ ],
71
+ "dictionary": [
72
+ "./dist/types/getIntlayerAPI/dictionary.d.ts"
73
+ ],
74
+ "editor": [
75
+ "./dist/types/getIntlayerAPI/editor.d.ts"
76
+ ],
77
+ "github": [
78
+ "./dist/types/getIntlayerAPI/github.d.ts"
79
+ ],
80
+ "gitlab": [
81
+ "./dist/types/getIntlayerAPI/gitlab.d.ts"
82
+ ],
83
+ "newsletter": [
84
+ "./dist/types/getIntlayerAPI/newsletter.d.ts"
85
+ ],
86
+ "oAuth": [
87
+ "./dist/types/getIntlayerAPI/oAuth.d.ts"
88
+ ],
89
+ "environment": [
90
+ "./dist/types/getIntlayerAPI/environment.d.ts"
91
+ ],
92
+ "organization": [
93
+ "./dist/types/getIntlayerAPI/organization.d.ts"
94
+ ],
95
+ "project": [
96
+ "./dist/types/getIntlayerAPI/project.d.ts"
97
+ ],
98
+ "search": [
99
+ "./dist/types/getIntlayerAPI/search.d.ts"
100
+ ],
101
+ "showcaseProject": [
102
+ "./dist/types/getIntlayerAPI/showcaseProject.d.ts"
103
+ ],
104
+ "status": [
105
+ "./dist/types/getIntlayerAPI/status.d.ts"
106
+ ],
107
+ "stripe": [
108
+ "./dist/types/getIntlayerAPI/stripe.d.ts"
109
+ ],
110
+ "tag": [
111
+ "./dist/types/getIntlayerAPI/tag.d.ts"
112
+ ],
113
+ "translate": [
114
+ "./dist/types/getIntlayerAPI/translate.d.ts"
115
+ ],
116
+ "reviewer": [
117
+ "./dist/types/getIntlayerAPI/reviewer.d.ts"
118
+ ],
119
+ "user": [
120
+ "./dist/types/getIntlayerAPI/user.d.ts"
121
+ ],
122
+ "package.json": [
123
+ "./package.json"
124
+ ]
125
+ }
126
+ },
35
127
  "exports": {
36
128
  ".": {
37
129
  "types": "./dist/types/index.d.ts",
@@ -170,107 +262,15 @@
170
262
  },
171
263
  "./package.json": "./package.json"
172
264
  },
173
- "main": "dist/cjs/index.cjs",
174
- "module": "dist/esm/index.mjs",
175
- "types": "dist/types/index.d.ts",
176
- "typesVersions": {
177
- "*": {
178
- "ai": [
179
- "./dist/types/getIntlayerAPI/ai.d.ts"
180
- ],
181
- "analytics": [
182
- "./dist/types/getIntlayerAPI/analytics.d.ts"
183
- ],
184
- "public": [
185
- "./dist/types/public/index.d.ts"
186
- ],
187
- "audit": [
188
- "./dist/types/getIntlayerAPI/audit.d.ts"
189
- ],
190
- "bitbucket": [
191
- "./dist/types/getIntlayerAPI/bitbucket.d.ts"
192
- ],
193
- "gitee": [
194
- "./dist/types/getIntlayerAPI/gitee.d.ts"
195
- ],
196
- "codeberg": [
197
- "./dist/types/getIntlayerAPI/codeberg.d.ts"
198
- ],
199
- "asset": [
200
- "./dist/types/getIntlayerAPI/asset.d.ts"
201
- ],
202
- "cms": [
203
- "./dist/types/cms/index.d.ts"
204
- ],
205
- "dictionary": [
206
- "./dist/types/getIntlayerAPI/dictionary.d.ts"
207
- ],
208
- "editor": [
209
- "./dist/types/getIntlayerAPI/editor.d.ts"
210
- ],
211
- "github": [
212
- "./dist/types/getIntlayerAPI/github.d.ts"
213
- ],
214
- "gitlab": [
215
- "./dist/types/getIntlayerAPI/gitlab.d.ts"
216
- ],
217
- "newsletter": [
218
- "./dist/types/getIntlayerAPI/newsletter.d.ts"
219
- ],
220
- "oAuth": [
221
- "./dist/types/getIntlayerAPI/oAuth.d.ts"
222
- ],
223
- "environment": [
224
- "./dist/types/getIntlayerAPI/environment.d.ts"
225
- ],
226
- "organization": [
227
- "./dist/types/getIntlayerAPI/organization.d.ts"
228
- ],
229
- "project": [
230
- "./dist/types/getIntlayerAPI/project.d.ts"
231
- ],
232
- "search": [
233
- "./dist/types/getIntlayerAPI/search.d.ts"
234
- ],
235
- "showcaseProject": [
236
- "./dist/types/getIntlayerAPI/showcaseProject.d.ts"
237
- ],
238
- "status": [
239
- "./dist/types/getIntlayerAPI/status.d.ts"
240
- ],
241
- "stripe": [
242
- "./dist/types/getIntlayerAPI/stripe.d.ts"
243
- ],
244
- "tag": [
245
- "./dist/types/getIntlayerAPI/tag.d.ts"
246
- ],
247
- "translate": [
248
- "./dist/types/getIntlayerAPI/translate.d.ts"
249
- ],
250
- "reviewer": [
251
- "./dist/types/getIntlayerAPI/reviewer.d.ts"
252
- ],
253
- "user": [
254
- "./dist/types/getIntlayerAPI/user.d.ts"
255
- ],
256
- "package.json": [
257
- "./package.json"
258
- ]
259
- }
260
- },
261
- "files": [
262
- "./dist",
263
- "./package.json"
264
- ],
265
265
  "scripts": {
266
266
  "build": "bun --bun tsdown --config tsdown.config.ts",
267
267
  "build:ci": "bun --bun tsdown --config tsdown.config.ts",
268
268
  "clean": "bun --bun rimraf ./dist .turbo",
269
269
  "dev": "bun --bun tsdown --config tsdown.config.ts --watch",
270
- "format": "bun --bun biome format . --check",
271
- "format:fix": "bun --bun biome format --write .",
272
- "lint": "bun --bun biome lint .",
273
- "lint:fix": "bun --bun biome lint --write .",
270
+ "format": "oxfmt --check .",
271
+ "format:fix": "oxfmt .",
272
+ "lint": "oxlint .",
273
+ "lint:fix": "oxlint --fix .",
274
274
  "prepublish": "cp -f ../../../README.md ./README.md",
275
275
  "publish": "bun publish || true",
276
276
  "publish:canary": "bun publish --access public --tag canary || true",
@@ -281,9 +281,9 @@
281
281
  "typecheck": "tsc --noEmit --project tsconfig.types.json"
282
282
  },
283
283
  "dependencies": {
284
- "@intlayer/backend-contract": "9.7.1",
285
- "@intlayer/config": "9.7.1",
286
- "@intlayer/types": "9.7.1",
284
+ "@intlayer/backend-contract": "9.7.2",
285
+ "@intlayer/config": "9.7.2",
286
+ "@intlayer/types": "9.7.2",
287
287
  "defu": "6.1.7"
288
288
  },
289
289
  "devDependencies": {
@@ -291,8 +291,8 @@
291
291
  "@utils/ts-config": "1.0.4",
292
292
  "@utils/ts-config-types": "1.0.4",
293
293
  "@utils/tsdown-config": "1.0.4",
294
- "rimraf": "6.1.3",
295
- "tsdown": "0.23.4",
294
+ "rimraf": "6.1.4",
295
+ "tsdown": "0.23.7",
296
296
  "typescript": "7.0.2",
297
297
  "vitest": "5.1.0"
298
298
  },