@intlayer/api 9.6.0 → 9.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (206) hide show
  1. package/dist/cjs/cms/createAuthManager.cjs +2 -3
  2. package/dist/cjs/cms/createIntlayerCMS.cjs +2 -3
  3. package/dist/cjs/cms/index.cjs +2 -2
  4. package/dist/cjs/distantDictionary/fetchDistantDictionaries.cjs +3 -4
  5. package/dist/cjs/distantDictionary/fetchDistantDictionaries.cjs.map +1 -1
  6. package/dist/cjs/distantDictionary/fetchDistantDictionary.cjs +3 -4
  7. package/dist/cjs/distantDictionary/fetchDistantDictionary.cjs.map +1 -1
  8. package/dist/cjs/distantDictionary/index.cjs +2 -2
  9. package/dist/cjs/fetcher.cjs +2 -3
  10. package/dist/cjs/fetcher.cjs.map +1 -1
  11. package/dist/cjs/getIntlayerAPI/ai.cjs +79 -26
  12. package/dist/cjs/getIntlayerAPI/ai.cjs.map +1 -1
  13. package/dist/cjs/getIntlayerAPI/analytics.cjs +47 -14
  14. package/dist/cjs/getIntlayerAPI/analytics.cjs.map +1 -1
  15. package/dist/cjs/getIntlayerAPI/asset.cjs +41 -12
  16. package/dist/cjs/getIntlayerAPI/asset.cjs.map +1 -1
  17. package/dist/cjs/getIntlayerAPI/audit.cjs +73 -20
  18. package/dist/cjs/getIntlayerAPI/audit.cjs.map +1 -1
  19. package/dist/cjs/getIntlayerAPI/bitbucket.cjs +42 -13
  20. package/dist/cjs/getIntlayerAPI/bitbucket.cjs.map +1 -1
  21. package/dist/cjs/getIntlayerAPI/codeberg.cjs +20 -0
  22. package/dist/cjs/getIntlayerAPI/codeberg.cjs.map +1 -0
  23. package/dist/cjs/getIntlayerAPI/dictionary.cjs +62 -17
  24. package/dist/cjs/getIntlayerAPI/dictionary.cjs.map +1 -1
  25. package/dist/cjs/getIntlayerAPI/editor.cjs +3 -4
  26. package/dist/cjs/getIntlayerAPI/editor.cjs.map +1 -1
  27. package/dist/cjs/getIntlayerAPI/environment.cjs +47 -14
  28. package/dist/cjs/getIntlayerAPI/environment.cjs.map +1 -1
  29. package/dist/cjs/getIntlayerAPI/forge.cjs +63 -0
  30. package/dist/cjs/getIntlayerAPI/forge.cjs.map +1 -0
  31. package/dist/cjs/getIntlayerAPI/gitee.cjs +20 -0
  32. package/dist/cjs/getIntlayerAPI/gitee.cjs.map +1 -0
  33. package/dist/cjs/getIntlayerAPI/github.cjs +47 -14
  34. package/dist/cjs/getIntlayerAPI/github.cjs.map +1 -1
  35. package/dist/cjs/getIntlayerAPI/gitlab.cjs +42 -13
  36. package/dist/cjs/getIntlayerAPI/gitlab.cjs.map +1 -1
  37. package/dist/cjs/getIntlayerAPI/index.cjs +27 -24
  38. package/dist/cjs/getIntlayerAPI/index.cjs.map +1 -1
  39. package/dist/cjs/getIntlayerAPI/newsletter.cjs +31 -10
  40. package/dist/cjs/getIntlayerAPI/newsletter.cjs.map +1 -1
  41. package/dist/cjs/getIntlayerAPI/oAuth.cjs +33 -8
  42. package/dist/cjs/getIntlayerAPI/oAuth.cjs.map +1 -1
  43. package/dist/cjs/getIntlayerAPI/organization.cjs +75 -24
  44. package/dist/cjs/getIntlayerAPI/organization.cjs.map +1 -1
  45. package/dist/cjs/getIntlayerAPI/project.cjs +115 -33
  46. package/dist/cjs/getIntlayerAPI/project.cjs.map +1 -1
  47. package/dist/cjs/getIntlayerAPI/reviewer.cjs +145 -35
  48. package/dist/cjs/getIntlayerAPI/reviewer.cjs.map +1 -1
  49. package/dist/cjs/getIntlayerAPI/search.cjs +18 -7
  50. package/dist/cjs/getIntlayerAPI/search.cjs.map +1 -1
  51. package/dist/cjs/getIntlayerAPI/showcaseProject.cjs +64 -19
  52. package/dist/cjs/getIntlayerAPI/showcaseProject.cjs.map +1 -1
  53. package/dist/cjs/getIntlayerAPI/status.cjs +19 -7
  54. package/dist/cjs/getIntlayerAPI/status.cjs.map +1 -1
  55. package/dist/cjs/getIntlayerAPI/stripe.cjs +144 -39
  56. package/dist/cjs/getIntlayerAPI/stripe.cjs.map +1 -1
  57. package/dist/cjs/getIntlayerAPI/tag.cjs +36 -11
  58. package/dist/cjs/getIntlayerAPI/tag.cjs.map +1 -1
  59. package/dist/cjs/getIntlayerAPI/translate.cjs +49 -12
  60. package/dist/cjs/getIntlayerAPI/translate.cjs.map +1 -1
  61. package/dist/cjs/getIntlayerAPI/user.cjs +61 -18
  62. package/dist/cjs/getIntlayerAPI/user.cjs.map +1 -1
  63. package/dist/cjs/index.cjs +38 -30
  64. package/dist/cjs/proxy.cjs +28 -25
  65. package/dist/cjs/proxy.cjs.map +1 -1
  66. package/dist/cjs/public/createPublicClient.cjs +26 -7
  67. package/dist/cjs/public/createPublicClient.cjs.map +1 -1
  68. package/dist/cjs/public/index.cjs +1 -1
  69. package/dist/cjs/resolveInternalBackendUrl.cjs +1 -2
  70. package/dist/esm/cms/createAuthManager.mjs +1 -2
  71. package/dist/esm/cms/createIntlayerCMS.mjs +1 -2
  72. package/dist/esm/distantDictionary/fetchDistantDictionaries.mjs +1 -2
  73. package/dist/esm/distantDictionary/fetchDistantDictionaries.mjs.map +1 -1
  74. package/dist/esm/distantDictionary/fetchDistantDictionary.mjs +1 -2
  75. package/dist/esm/distantDictionary/fetchDistantDictionary.mjs.map +1 -1
  76. package/dist/esm/fetcher.mjs +1 -2
  77. package/dist/esm/fetcher.mjs.map +1 -1
  78. package/dist/esm/getIntlayerAPI/ai.mjs +78 -25
  79. package/dist/esm/getIntlayerAPI/ai.mjs.map +1 -1
  80. package/dist/esm/getIntlayerAPI/analytics.mjs +46 -13
  81. package/dist/esm/getIntlayerAPI/analytics.mjs.map +1 -1
  82. package/dist/esm/getIntlayerAPI/asset.mjs +40 -11
  83. package/dist/esm/getIntlayerAPI/asset.mjs.map +1 -1
  84. package/dist/esm/getIntlayerAPI/audit.mjs +72 -19
  85. package/dist/esm/getIntlayerAPI/audit.mjs.map +1 -1
  86. package/dist/esm/getIntlayerAPI/bitbucket.mjs +41 -12
  87. package/dist/esm/getIntlayerAPI/bitbucket.mjs.map +1 -1
  88. package/dist/esm/getIntlayerAPI/codeberg.mjs +18 -0
  89. package/dist/esm/getIntlayerAPI/codeberg.mjs.map +1 -0
  90. package/dist/esm/getIntlayerAPI/dictionary.mjs +61 -16
  91. package/dist/esm/getIntlayerAPI/dictionary.mjs.map +1 -1
  92. package/dist/esm/getIntlayerAPI/editor.mjs +2 -3
  93. package/dist/esm/getIntlayerAPI/editor.mjs.map +1 -1
  94. package/dist/esm/getIntlayerAPI/environment.mjs +46 -13
  95. package/dist/esm/getIntlayerAPI/environment.mjs.map +1 -1
  96. package/dist/esm/getIntlayerAPI/forge.mjs +62 -0
  97. package/dist/esm/getIntlayerAPI/forge.mjs.map +1 -0
  98. package/dist/esm/getIntlayerAPI/gitee.mjs +18 -0
  99. package/dist/esm/getIntlayerAPI/gitee.mjs.map +1 -0
  100. package/dist/esm/getIntlayerAPI/github.mjs +46 -13
  101. package/dist/esm/getIntlayerAPI/github.mjs.map +1 -1
  102. package/dist/esm/getIntlayerAPI/gitlab.mjs +41 -12
  103. package/dist/esm/getIntlayerAPI/gitlab.mjs.map +1 -1
  104. package/dist/esm/getIntlayerAPI/index.mjs +6 -3
  105. package/dist/esm/getIntlayerAPI/index.mjs.map +1 -1
  106. package/dist/esm/getIntlayerAPI/newsletter.mjs +30 -9
  107. package/dist/esm/getIntlayerAPI/newsletter.mjs.map +1 -1
  108. package/dist/esm/getIntlayerAPI/oAuth.mjs +32 -7
  109. package/dist/esm/getIntlayerAPI/oAuth.mjs.map +1 -1
  110. package/dist/esm/getIntlayerAPI/organization.mjs +74 -23
  111. package/dist/esm/getIntlayerAPI/organization.mjs.map +1 -1
  112. package/dist/esm/getIntlayerAPI/project.mjs +114 -32
  113. package/dist/esm/getIntlayerAPI/project.mjs.map +1 -1
  114. package/dist/esm/getIntlayerAPI/reviewer.mjs +144 -34
  115. package/dist/esm/getIntlayerAPI/reviewer.mjs.map +1 -1
  116. package/dist/esm/getIntlayerAPI/search.mjs +17 -6
  117. package/dist/esm/getIntlayerAPI/search.mjs.map +1 -1
  118. package/dist/esm/getIntlayerAPI/showcaseProject.mjs +63 -18
  119. package/dist/esm/getIntlayerAPI/showcaseProject.mjs.map +1 -1
  120. package/dist/esm/getIntlayerAPI/status.mjs +18 -6
  121. package/dist/esm/getIntlayerAPI/status.mjs.map +1 -1
  122. package/dist/esm/getIntlayerAPI/stripe.mjs +143 -38
  123. package/dist/esm/getIntlayerAPI/stripe.mjs.map +1 -1
  124. package/dist/esm/getIntlayerAPI/tag.mjs +35 -10
  125. package/dist/esm/getIntlayerAPI/tag.mjs.map +1 -1
  126. package/dist/esm/getIntlayerAPI/translate.mjs +48 -11
  127. package/dist/esm/getIntlayerAPI/translate.mjs.map +1 -1
  128. package/dist/esm/getIntlayerAPI/user.mjs +60 -17
  129. package/dist/esm/getIntlayerAPI/user.mjs.map +1 -1
  130. package/dist/esm/index.mjs +10 -7
  131. package/dist/esm/proxy.mjs +6 -3
  132. package/dist/esm/proxy.mjs.map +1 -1
  133. package/dist/esm/public/createPublicClient.mjs +26 -7
  134. package/dist/esm/public/createPublicClient.mjs.map +1 -1
  135. package/dist/esm/resolveInternalBackendUrl.mjs +1 -2
  136. package/dist/types/cms/createAuthManager.d.ts +1 -2
  137. package/dist/types/cms/createAuthManager.d.ts.map +1 -1
  138. package/dist/types/cms/createIntlayerCMS.d.ts +0 -2
  139. package/dist/types/cms/createIntlayerCMS.d.ts.map +1 -1
  140. package/dist/types/distantDictionary/fetchDistantDictionaries.d.ts +1 -3
  141. package/dist/types/distantDictionary/fetchDistantDictionaries.d.ts.map +1 -1
  142. package/dist/types/distantDictionary/fetchDistantDictionary.d.ts +1 -3
  143. package/dist/types/distantDictionary/fetchDistantDictionary.d.ts.map +1 -1
  144. package/dist/types/fetcher.d.ts +1 -3
  145. package/dist/types/fetcher.d.ts.map +1 -1
  146. package/dist/types/getIntlayerAPI/ai.d.ts +3 -5
  147. package/dist/types/getIntlayerAPI/ai.d.ts.map +1 -1
  148. package/dist/types/getIntlayerAPI/analytics.d.ts +3 -5
  149. package/dist/types/getIntlayerAPI/analytics.d.ts.map +1 -1
  150. package/dist/types/getIntlayerAPI/asset.d.ts +3 -4
  151. package/dist/types/getIntlayerAPI/asset.d.ts.map +1 -1
  152. package/dist/types/getIntlayerAPI/audit.d.ts +49 -7
  153. package/dist/types/getIntlayerAPI/audit.d.ts.map +1 -1
  154. package/dist/types/getIntlayerAPI/bitbucket.d.ts +2 -4
  155. package/dist/types/getIntlayerAPI/bitbucket.d.ts.map +1 -1
  156. package/dist/types/getIntlayerAPI/codeberg.d.ts +59 -0
  157. package/dist/types/getIntlayerAPI/codeberg.d.ts.map +1 -0
  158. package/dist/types/getIntlayerAPI/dictionary.d.ts +3 -5
  159. package/dist/types/getIntlayerAPI/dictionary.d.ts.map +1 -1
  160. package/dist/types/getIntlayerAPI/editor.d.ts +4 -5
  161. package/dist/types/getIntlayerAPI/editor.d.ts.map +1 -1
  162. package/dist/types/getIntlayerAPI/environment.d.ts +3 -5
  163. package/dist/types/getIntlayerAPI/environment.d.ts.map +1 -1
  164. package/dist/types/getIntlayerAPI/forge.d.ts +34 -0
  165. package/dist/types/getIntlayerAPI/forge.d.ts.map +1 -0
  166. package/dist/types/getIntlayerAPI/gitee.d.ts +59 -0
  167. package/dist/types/getIntlayerAPI/gitee.d.ts.map +1 -0
  168. package/dist/types/getIntlayerAPI/github.d.ts +2 -4
  169. package/dist/types/getIntlayerAPI/github.d.ts.map +1 -1
  170. package/dist/types/getIntlayerAPI/gitlab.d.ts +2 -4
  171. package/dist/types/getIntlayerAPI/gitlab.d.ts.map +1 -1
  172. package/dist/types/getIntlayerAPI/index.d.ts +6 -3
  173. package/dist/types/getIntlayerAPI/index.d.ts.map +1 -1
  174. package/dist/types/getIntlayerAPI/newsletter.d.ts +3 -5
  175. package/dist/types/getIntlayerAPI/newsletter.d.ts.map +1 -1
  176. package/dist/types/getIntlayerAPI/oAuth.d.ts +2 -2
  177. package/dist/types/getIntlayerAPI/oAuth.d.ts.map +1 -1
  178. package/dist/types/getIntlayerAPI/organization.d.ts +3 -7
  179. package/dist/types/getIntlayerAPI/organization.d.ts.map +1 -1
  180. package/dist/types/getIntlayerAPI/project.d.ts +4 -5
  181. package/dist/types/getIntlayerAPI/project.d.ts.map +1 -1
  182. package/dist/types/getIntlayerAPI/reviewer.d.ts +682 -39
  183. package/dist/types/getIntlayerAPI/reviewer.d.ts.map +1 -1
  184. package/dist/types/getIntlayerAPI/search.d.ts +3 -5
  185. package/dist/types/getIntlayerAPI/search.d.ts.map +1 -1
  186. package/dist/types/getIntlayerAPI/showcaseProject.d.ts +3 -5
  187. package/dist/types/getIntlayerAPI/showcaseProject.d.ts.map +1 -1
  188. package/dist/types/getIntlayerAPI/status.d.ts +5 -8
  189. package/dist/types/getIntlayerAPI/status.d.ts.map +1 -1
  190. package/dist/types/getIntlayerAPI/stripe.d.ts +3 -5
  191. package/dist/types/getIntlayerAPI/stripe.d.ts.map +1 -1
  192. package/dist/types/getIntlayerAPI/tag.d.ts +3 -5
  193. package/dist/types/getIntlayerAPI/tag.d.ts.map +1 -1
  194. package/dist/types/getIntlayerAPI/translate.d.ts +3 -5
  195. package/dist/types/getIntlayerAPI/translate.d.ts.map +1 -1
  196. package/dist/types/getIntlayerAPI/user.d.ts +6 -8
  197. package/dist/types/getIntlayerAPI/user.d.ts.map +1 -1
  198. package/dist/types/index.d.ts +12 -9
  199. package/dist/types/proxy.d.ts +0 -2
  200. package/dist/types/proxy.d.ts.map +1 -1
  201. package/dist/types/public/createPublicClient.d.ts +1 -9
  202. package/dist/types/public/createPublicClient.d.ts.map +1 -1
  203. package/dist/types/resolveInternalBackendUrl.d.ts +0 -2
  204. package/dist/types/resolveInternalBackendUrl.d.ts.map +1 -1
  205. package/dist/types/types.d.ts +5 -2
  206. package/package.json +23 -6
@@ -1 +1 @@
1
- {"version":3,"file":"analytics.mjs","names":[],"sources":["../../../src/getIntlayerAPI/analytics.ts"],"sourcesContent":["import type {\n AudienceRange,\n GetAnalyticsOverviewResult,\n GetAudienceResult,\n GetContentStatsResult,\n GetExperimentResultsResult,\n GetPageMetadataResult,\n IngestAnalyticsBody,\n IngestAnalyticsResult,\n} from '@intlayer/backend';\nimport { editor } from '@intlayer/config/built';\nimport type { IntlayerConfig } from '@intlayer/types/config';\nimport { createEndpoint } from '../cms/createIntlayerCMS';\nimport { type FetcherOptions, fetcher } from '../fetcher';\n\nexport const getAnalyticsAPI = (\n authAPIOptions: FetcherOptions = {},\n intlayerConfig?: IntlayerConfig\n) => {\n const backendURL = intlayerConfig?.editor?.backendURL ?? editor.backendURL;\n\n const ANALYTICS_API_ROUTE = `${backendURL}/api/analytics`;\n\n /**\n * Ingest a batch of analytics events. Public — attribution is by the\n * project's `clientId` in the body.\n * @param body - Session id, sdk version, and the collected events.\n * @returns The number of accepted events.\n */\n const sendEvents = async (\n body: IngestAnalyticsBody,\n otherOptions: FetcherOptions = {}\n ) =>\n await fetcher<IngestAnalyticsResult>(\n `${ANALYTICS_API_ROUTE}/events`,\n authAPIOptions,\n otherOptions,\n {\n method: 'POST',\n body,\n }\n );\n\n /**\n * Page/locale totals for the authenticated project.\n * @returns Views grouped by url and locale.\n */\n const getOverview = async (otherOptions: FetcherOptions = {}) =>\n await fetcher<GetAnalyticsOverviewResult>(\n `${ANALYTICS_API_ROUTE}/overview`,\n authAPIOptions,\n otherOptions,\n { method: 'GET' }\n );\n\n /**\n * Audience report: distinct visitors (today / 7d / window), page views, the\n * evolution series, and locale + country breakdowns.\n * @param range - Rolling window, either a named range (`1h`, `24h`, `7d`,\n * `30d`, `90d`, `6mo`, `1y`, `3y`) or a number of days (default 30).\n * @returns The audience statistics.\n */\n const getAudience = async (\n range: AudienceRange | number = 30,\n otherOptions: FetcherOptions = {}\n ) =>\n await fetcher<GetAudienceResult>(\n `${ANALYTICS_API_ROUTE}/audience`,\n authAPIOptions,\n otherOptions,\n {\n method: 'GET',\n params: typeof range === 'number' ? { days: String(range) } : { range },\n }\n );\n\n /**\n * Per-content exposure totals — \"which content is actually shown\".\n * @returns Exposures grouped by dictionary key, key path, and locale.\n */\n const getContentStats = async (otherOptions: FetcherOptions = {}) =>\n await fetcher<GetContentStatsResult>(\n `${ANALYTICS_API_ROUTE}/content-stats`,\n authAPIOptions,\n otherOptions,\n { method: 'GET' }\n );\n\n /**\n * A/B experiment results with per-variant conversion rates and significance.\n * @param experimentKey - The experiment to evaluate.\n * @returns The experiment result set.\n */\n const getExperimentResults = async (\n experimentKey: string,\n otherOptions: FetcherOptions = {}\n ) =>\n await fetcher<GetExperimentResultsResult>(\n `${ANALYTICS_API_ROUTE}/experiments/${experimentKey}`,\n authAPIOptions,\n otherOptions,\n { method: 'GET' }\n );\n\n /**\n * Page metadata (title and meta description) for a given url.\n * @param url - The page url to inspect.\n * @returns Title and description of the page.\n */\n const getPageMetadata = async (\n url: string,\n otherOptions: FetcherOptions = {}\n ) =>\n await fetcher<GetPageMetadataResult>(\n `${ANALYTICS_API_ROUTE}/page-metadata`,\n authAPIOptions,\n otherOptions,\n {\n method: 'GET',\n params: { url },\n }\n );\n\n return {\n sendEvents,\n getOverview,\n getAudience,\n getContentStats,\n getExperimentResults,\n getPageMetadata,\n };\n};\n\n/**\n * Authenticated `analytics` endpoint bound to an Intlayer CMS authenticator.\n *\n * Pass an authenticator created with `createIntlayerCMS`, or omit it to use\n * the build-time configuration (`@intlayer/config/built`).\n */\nexport const analyticsEndpoint = createEndpoint(getAnalyticsAPI);\n"],"mappings":";;;;;AAeA,MAAa,mBACX,iBAAiC,CAAC,GAClC,mBACG;CAGH,MAAM,sBAAsB,GAFT,gBAAgB,QAAQ,cAAc,OAAO,WAEtB;;;;;;;CAQ1C,MAAM,aAAa,OACjB,MACA,eAA+B,CAAC,MAEhC,MAAM,QACJ,GAAG,oBAAoB,UACvB,gBACA,cACA;EACE,QAAQ;EACR;CACF,CACF;;;;;CAMF,MAAM,cAAc,OAAO,eAA+B,CAAC,MACzD,MAAM,QACJ,GAAG,oBAAoB,YACvB,gBACA,cACA,EAAE,QAAQ,MAAM,CAClB;;;;;;;;CASF,MAAM,cAAc,OAClB,QAAgC,IAChC,eAA+B,CAAC,MAEhC,MAAM,QACJ,GAAG,oBAAoB,YACvB,gBACA,cACA;EACE,QAAQ;EACR,QAAQ,OAAO,UAAU,WAAW,EAAE,MAAM,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM;CACxE,CACF;;;;;CAMF,MAAM,kBAAkB,OAAO,eAA+B,CAAC,MAC7D,MAAM,QACJ,GAAG,oBAAoB,iBACvB,gBACA,cACA,EAAE,QAAQ,MAAM,CAClB;;;;;;CAOF,MAAM,uBAAuB,OAC3B,eACA,eAA+B,CAAC,MAEhC,MAAM,QACJ,GAAG,oBAAoB,eAAe,iBACtC,gBACA,cACA,EAAE,QAAQ,MAAM,CAClB;;;;;;CAOF,MAAM,kBAAkB,OACtB,KACA,eAA+B,CAAC,MAEhC,MAAM,QACJ,GAAG,oBAAoB,iBACvB,gBACA,cACA;EACE,QAAQ;EACR,QAAQ,EAAE,IAAI;CAChB,CACF;CAEF,OAAO;EACL;EACA;EACA;EACA;EACA;EACA;CACF;AACF;;;;;;;AAQA,MAAa,oBAAoB,eAAe,eAAe"}
1
+ {"version":3,"file":"analytics.mjs","names":[],"sources":["../../../src/getIntlayerAPI/analytics.ts"],"sourcesContent":["import type {\n AnalyticsRoutes,\n AudienceRange,\n analyticsContract,\n GetAnalyticsOverviewResult,\n GetAudienceResult,\n GetContentStatsResult,\n GetExperimentResultsResult,\n GetPageMetadataResult,\n IngestAnalyticsBody,\n IngestAnalyticsResult,\n} from '@intlayer/backend-contract/analytics';\nimport type { RouteEndpoints } from '@intlayer/backend-contract/defineRoute';\nimport { buildRouteURL } from '@intlayer/backend-contract/defineRoute';\nimport { editor } from '@intlayer/config/built';\nimport { BACKEND_URL } from '@intlayer/config/defaultValues';\nimport type { IntlayerConfig } from '@intlayer/types/config';\nimport { createEndpoint } from '../cms/createIntlayerCMS';\nimport { type FetcherOptions, fetcher } from '../fetcher';\n\n/** Prefix of the routes, checked against the backend contract. */\nconst analyticsGroup = {\n prefix: '/api/analytics',\n} as const satisfies Pick<typeof analyticsContract, 'prefix'>;\n\n/**\n * Method and path of every route, checked against the backend contract at\n * compile time (the contract's zod schemas are never loaded).\n */\nconst analyticsEndpoints = {\n ingestAnalyticsEvents: { method: 'POST', path: '/events' },\n getAnalyticsOverview: { method: 'GET', path: '/overview' },\n getAnalyticsAudience: { method: 'GET', path: '/audience' },\n getContentStats: { method: 'GET', path: '/content-stats' },\n getExperimentResults: { method: 'GET', path: '/experiments/:experimentKey' },\n getPageMetadata: { method: 'GET', path: '/page-metadata' },\n} as const satisfies RouteEndpoints<AnalyticsRoutes>;\n\nexport const getAnalyticsAPI = (\n authAPIOptions: FetcherOptions = {},\n intlayerConfig?: IntlayerConfig\n) => {\n const backendURL =\n intlayerConfig?.editor?.backendURL ?? editor.backendURL ?? BACKEND_URL;\n\n /**\n * Ingest a batch of analytics events. Public — attribution is by the\n * project's `clientId` in the body.\n * @param body - Session id, sdk version, and the collected events.\n * @returns The number of accepted events.\n */\n const sendEvents = async (\n body: IngestAnalyticsBody,\n otherOptions: FetcherOptions = {}\n ) =>\n await fetcher<IngestAnalyticsResult>(\n buildRouteURL(\n backendURL,\n analyticsGroup,\n analyticsEndpoints.ingestAnalyticsEvents\n ),\n authAPIOptions,\n otherOptions,\n {\n method: analyticsEndpoints.ingestAnalyticsEvents.method,\n body,\n }\n );\n\n /**\n * Page/locale totals for the authenticated project.\n * @returns Views grouped by url and locale.\n */\n const getOverview = async (otherOptions: FetcherOptions = {}) =>\n await fetcher<GetAnalyticsOverviewResult>(\n buildRouteURL(\n backendURL,\n analyticsGroup,\n analyticsEndpoints.getAnalyticsOverview\n ),\n authAPIOptions,\n otherOptions,\n { method: analyticsEndpoints.getAnalyticsOverview.method }\n );\n\n /**\n * Audience report: distinct visitors (today / 7d / window), page views, the\n * evolution series, and locale + country breakdowns.\n * @param range - Rolling window, either a named range (`1h`, `24h`, `7d`,\n * `30d`, `90d`, `6mo`, `1y`, `3y`) or a number of days (default 30).\n * @returns The audience statistics.\n */\n const getAudience = async (\n range: AudienceRange | number = 30,\n otherOptions: FetcherOptions = {}\n ) =>\n await fetcher<GetAudienceResult>(\n buildRouteURL(\n backendURL,\n analyticsGroup,\n analyticsEndpoints.getAnalyticsAudience\n ),\n authAPIOptions,\n otherOptions,\n {\n method: analyticsEndpoints.getAnalyticsAudience.method,\n params: typeof range === 'number' ? { days: String(range) } : { range },\n }\n );\n\n /**\n * Per-content exposure totals — \"which content is actually shown\".\n * @returns Exposures grouped by dictionary key, key path, and locale.\n */\n const getContentStats = async (otherOptions: FetcherOptions = {}) =>\n await fetcher<GetContentStatsResult>(\n buildRouteURL(\n backendURL,\n analyticsGroup,\n analyticsEndpoints.getContentStats\n ),\n authAPIOptions,\n otherOptions,\n { method: analyticsEndpoints.getContentStats.method }\n );\n\n /**\n * A/B experiment results with per-variant conversion rates and significance.\n * @param experimentKey - The experiment to evaluate.\n * @returns The experiment result set.\n */\n const getExperimentResults = async (\n experimentKey: string,\n otherOptions: FetcherOptions = {}\n ) =>\n await fetcher<GetExperimentResultsResult>(\n buildRouteURL(\n backendURL,\n analyticsGroup,\n analyticsEndpoints.getExperimentResults,\n { experimentKey }\n ),\n authAPIOptions,\n otherOptions,\n { method: analyticsEndpoints.getExperimentResults.method }\n );\n\n /**\n * Page metadata (title and meta description) for a given url.\n * @param url - The page url to inspect.\n * @returns Title and description of the page.\n */\n const getPageMetadata = async (\n url: string,\n otherOptions: FetcherOptions = {}\n ) =>\n await fetcher<GetPageMetadataResult>(\n buildRouteURL(\n backendURL,\n analyticsGroup,\n analyticsEndpoints.getPageMetadata\n ),\n authAPIOptions,\n otherOptions,\n {\n method: analyticsEndpoints.getPageMetadata.method,\n params: { url },\n }\n );\n\n return {\n sendEvents,\n getOverview,\n getAudience,\n getContentStats,\n getExperimentResults,\n getPageMetadata,\n };\n};\n\n/**\n * Authenticated `analytics` endpoint bound to an Intlayer CMS authenticator.\n *\n * Pass an authenticator created with `createIntlayerCMS`, or omit it to use\n * the build-time configuration (`@intlayer/config/built`).\n */\nexport const analyticsEndpoint = createEndpoint(getAnalyticsAPI);\n"],"mappings":";;;;;;;;AAqBA,MAAM,iBAAiB,EACrB,QAAQ,iBACV;;;;;AAMA,MAAM,qBAAqB;CACzB,uBAAuB;EAAE,QAAQ;EAAQ,MAAM;CAAU;CACzD,sBAAsB;EAAE,QAAQ;EAAO,MAAM;CAAY;CACzD,sBAAsB;EAAE,QAAQ;EAAO,MAAM;CAAY;CACzD,iBAAiB;EAAE,QAAQ;EAAO,MAAM;CAAiB;CACzD,sBAAsB;EAAE,QAAQ;EAAO,MAAM;CAA8B;CAC3E,iBAAiB;EAAE,QAAQ;EAAO,MAAM;CAAiB;AAC3D;AAEA,MAAa,mBACX,iBAAiC,CAAC,GAClC,mBACG;CACH,MAAM,aACJ,gBAAgB,QAAQ,cAAc,OAAO,cAAc;;;;;;;CAQ7D,MAAM,aAAa,OACjB,MACA,eAA+B,CAAC,MAEhC,MAAM,QACJ,cACE,YACA,gBACA,mBAAmB,qBACrB,GACA,gBACA,cACA;EACE,QAAQ,mBAAmB,sBAAsB;EACjD;CACF,CACF;;;;;CAMF,MAAM,cAAc,OAAO,eAA+B,CAAC,MACzD,MAAM,QACJ,cACE,YACA,gBACA,mBAAmB,oBACrB,GACA,gBACA,cACA,EAAE,QAAQ,mBAAmB,qBAAqB,OAAO,CAC3D;;;;;;;;CASF,MAAM,cAAc,OAClB,QAAgC,IAChC,eAA+B,CAAC,MAEhC,MAAM,QACJ,cACE,YACA,gBACA,mBAAmB,oBACrB,GACA,gBACA,cACA;EACE,QAAQ,mBAAmB,qBAAqB;EAChD,QAAQ,OAAO,UAAU,WAAW,EAAE,MAAM,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM;CACxE,CACF;;;;;CAMF,MAAM,kBAAkB,OAAO,eAA+B,CAAC,MAC7D,MAAM,QACJ,cACE,YACA,gBACA,mBAAmB,eACrB,GACA,gBACA,cACA,EAAE,QAAQ,mBAAmB,gBAAgB,OAAO,CACtD;;;;;;CAOF,MAAM,uBAAuB,OAC3B,eACA,eAA+B,CAAC,MAEhC,MAAM,QACJ,cACE,YACA,gBACA,mBAAmB,sBACnB,EAAE,cAAc,CAClB,GACA,gBACA,cACA,EAAE,QAAQ,mBAAmB,qBAAqB,OAAO,CAC3D;;;;;;CAOF,MAAM,kBAAkB,OACtB,KACA,eAA+B,CAAC,MAEhC,MAAM,QACJ,cACE,YACA,gBACA,mBAAmB,eACrB,GACA,gBACA,cACA;EACE,QAAQ,mBAAmB,gBAAgB;EAC3C,QAAQ,EAAE,IAAI;CAChB,CACF;CAEF,OAAO;EACL;EACA;EACA;EACA;EACA;EACA;CACF;AACF;;;;;;;AAQA,MAAa,oBAAoB,eAAe,eAAe"}
@@ -1,17 +1,47 @@
1
- import { fetcher } from "../fetcher.mjs";
2
1
  import { createEndpoint } from "../cms/createIntlayerCMS.mjs";
2
+ import { fetcher } from "../fetcher.mjs";
3
3
  import { editor } from "@intlayer/config/built";
4
+ import { buildRouteURL } from "@intlayer/backend-contract/defineRoute";
5
+ import { BACKEND_URL } from "@intlayer/config/defaultValues";
4
6
 
5
- //#region src/getIntlayerAPI/asset.ts
7
+ // src/getIntlayerAPI/asset.ts
8
+ /** Prefix of the routes, checked against the backend contract. */
9
+ const assetGroup = { prefix: "/api/assets" };
10
+ /**
11
+ * Method and path of every route, checked against the backend contract at
12
+ * compile time (the contract's zod schemas are never loaded).
13
+ */
14
+ const assetEndpoints = {
15
+ getAssets: {
16
+ method: "GET",
17
+ path: "/"
18
+ },
19
+ getAssetById: {
20
+ method: "GET",
21
+ path: "/:assetId"
22
+ },
23
+ uploadAsset: {
24
+ method: "POST",
25
+ path: "/"
26
+ },
27
+ updateAsset: {
28
+ method: "PATCH",
29
+ path: "/:assetId"
30
+ },
31
+ deleteAsset: {
32
+ method: "DELETE",
33
+ path: "/:assetId"
34
+ }
35
+ };
6
36
  const getAssetAPI = (authAPIOptions = {}, intlayerConfig) => {
7
- const ASSET_API_ROUTE = `${intlayerConfig?.editor?.backendURL ?? editor.backendURL}/api/assets`;
37
+ const backendURL = intlayerConfig?.editor?.backendURL ?? editor.backendURL ?? BACKEND_URL;
8
38
  /**
9
39
  * Retrieves all assets for the current session project, paginated.
10
40
  * @param page - Page number (1-based).
11
41
  * @param pageSize - Number of items per page.
12
42
  * @returns Paginated list of assets.
13
43
  */
14
- const getAssets = async (page, pageSize, otherOptions = {}) => await fetcher(ASSET_API_ROUTE, authAPIOptions, otherOptions, {
44
+ const getAssets = async (page, pageSize, otherOptions = {}) => await fetcher(buildRouteURL(backendURL, assetGroup, assetEndpoints.getAssets), authAPIOptions, otherOptions, {
15
45
  cache: "no-store",
16
46
  params: {
17
47
  ...page !== void 0 && { page: String(page) },
@@ -23,7 +53,7 @@ const getAssetAPI = (authAPIOptions = {}, intlayerConfig) => {
23
53
  * @param assetId - The asset document ID.
24
54
  * @returns The asset.
25
55
  */
26
- const getAssetById = async (assetId, otherOptions = {}) => await fetcher(`${ASSET_API_ROUTE}/${assetId}`, authAPIOptions, otherOptions, { cache: "no-store" });
56
+ const getAssetById = async (assetId, otherOptions = {}) => await fetcher(buildRouteURL(backendURL, assetGroup, assetEndpoints.getAssetById, { assetId: String(assetId) }), authAPIOptions, otherOptions, { cache: "no-store" });
27
57
  /**
28
58
  * Uploads a new asset image.
29
59
  * @param file - The image File object.
@@ -40,8 +70,8 @@ const getAssetAPI = (authAPIOptions = {}, intlayerConfig) => {
40
70
  if (alt) headers["X-Alt-Text"] = alt;
41
71
  if (caption) headers["X-Caption"] = caption;
42
72
  const authHeaders = authAPIOptions.headers ?? {};
43
- const response = await fetch(ASSET_API_ROUTE, {
44
- method: "POST",
73
+ const response = await fetch(buildRouteURL(backendURL, assetGroup, assetEndpoints.uploadAsset), {
74
+ method: assetEndpoints.uploadAsset.method,
45
75
  credentials: "include",
46
76
  headers: {
47
77
  ...authHeaders,
@@ -62,8 +92,8 @@ const getAssetAPI = (authAPIOptions = {}, intlayerConfig) => {
62
92
  * @param data - Fields to update.
63
93
  * @returns The updated asset record.
64
94
  */
65
- const updateAsset = async (assetId, data, otherOptions = {}) => await fetcher(`${ASSET_API_ROUTE}/${assetId}`, authAPIOptions, otherOptions, {
66
- method: "PATCH",
95
+ const updateAsset = async (assetId, data, otherOptions = {}) => await fetcher(buildRouteURL(backendURL, assetGroup, assetEndpoints.updateAsset, { assetId: String(assetId) }), authAPIOptions, otherOptions, {
96
+ method: assetEndpoints.updateAsset.method,
67
97
  body: data
68
98
  });
69
99
  /**
@@ -71,7 +101,7 @@ const getAssetAPI = (authAPIOptions = {}, intlayerConfig) => {
71
101
  * @param assetId - The asset document ID.
72
102
  * @returns Confirmation response.
73
103
  */
74
- const deleteAsset = async (assetId, otherOptions = {}) => await fetcher(`${ASSET_API_ROUTE}/${assetId}`, authAPIOptions, otherOptions, { method: "DELETE" });
104
+ const deleteAsset = async (assetId, otherOptions = {}) => await fetcher(buildRouteURL(backendURL, assetGroup, assetEndpoints.deleteAsset, { assetId: String(assetId) }), authAPIOptions, otherOptions, { method: assetEndpoints.deleteAsset.method });
75
105
  return {
76
106
  getAssets,
77
107
  getAssetById,
@@ -88,6 +118,5 @@ const getAssetAPI = (authAPIOptions = {}, intlayerConfig) => {
88
118
  */
89
119
  const assetEndpoint = createEndpoint(getAssetAPI);
90
120
 
91
- //#endregion
92
121
  export { assetEndpoint, getAssetAPI };
93
122
  //# sourceMappingURL=asset.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"asset.mjs","names":[],"sources":["../../../src/getIntlayerAPI/asset.ts"],"sourcesContent":["import type {\n DeleteAssetResult,\n GetAssetByIdResult,\n GetAssetsResult,\n UpdateAssetResult,\n UploadAssetResult,\n} from '@intlayer/backend';\nimport { editor } from '@intlayer/config/built';\nimport type { IntlayerConfig } from '@intlayer/types/config';\nimport { createEndpoint } from '../cms/createIntlayerCMS';\nimport { type FetcherOptions, fetcher } from '../fetcher';\n\nexport const getAssetAPI = (\n authAPIOptions: FetcherOptions = {},\n intlayerConfig?: IntlayerConfig\n) => {\n const backendURL = intlayerConfig?.editor?.backendURL ?? editor.backendURL;\n\n const ASSET_API_ROUTE = `${backendURL}/api/assets`;\n\n /**\n * Retrieves all assets for the current session project, paginated.\n * @param page - Page number (1-based).\n * @param pageSize - Number of items per page.\n * @returns Paginated list of assets.\n */\n const getAssets = async (\n page?: number,\n pageSize?: number,\n otherOptions: FetcherOptions = {}\n ) =>\n await fetcher<GetAssetsResult>(\n ASSET_API_ROUTE,\n authAPIOptions,\n otherOptions,\n {\n cache: 'no-store',\n params: {\n ...(page !== undefined && { page: String(page) }),\n ...(pageSize !== undefined && { pageSize: String(pageSize) }),\n },\n }\n );\n\n /**\n * Retrieves a single asset by ID.\n * @param assetId - The asset document ID.\n * @returns The asset.\n */\n const getAssetById = async (\n assetId: string,\n otherOptions: FetcherOptions = {}\n ) =>\n await fetcher<GetAssetByIdResult>(\n `${ASSET_API_ROUTE}/${assetId}`,\n authAPIOptions,\n otherOptions,\n { cache: 'no-store' }\n );\n\n /**\n * Uploads a new asset image.\n * @param file - The image File object.\n * @param alt - Optional alt text.\n * @param caption - Optional caption.\n * @returns The created asset record with its public URL.\n */\n const uploadAsset = async (\n file: File,\n alt?: string,\n caption?: string,\n otherOptions: FetcherOptions = {}\n ) => {\n const buffer = await file.arrayBuffer();\n\n const headers: Record<string, string> = {\n 'Content-Type': file.type || 'image/jpeg',\n 'X-File-Name': file.name,\n };\n\n if (alt) headers['X-Alt-Text'] = alt;\n if (caption) headers['X-Caption'] = caption;\n\n const authHeaders =\n (authAPIOptions.headers as Record<string, string> | undefined) ?? {};\n\n const response = await fetch(ASSET_API_ROUTE, {\n method: 'POST',\n credentials: 'include',\n headers: { ...authHeaders, ...headers },\n body: buffer,\n signal: otherOptions.signal as AbortSignal | undefined,\n });\n\n if (!response.ok) {\n const result = await response.json();\n throw new Error(JSON.stringify(result.error) ?? 'Asset upload failed');\n }\n\n return (await response.json()) as UploadAssetResult;\n };\n\n /**\n * Updates mutable metadata (name, alt text, caption) of an asset.\n * @param assetId - The asset document ID.\n * @param data - Fields to update.\n * @returns The updated asset record.\n */\n const updateAsset = async (\n assetId: string,\n data: { originalName?: string; alt?: string; caption?: string },\n otherOptions: FetcherOptions = {}\n ) =>\n await fetcher<UpdateAssetResult>(\n `${ASSET_API_ROUTE}/${assetId}`,\n authAPIOptions,\n otherOptions,\n { method: 'PATCH', body: data as unknown as Record<string, unknown> }\n );\n\n /**\n * Deletes an asset by ID.\n * @param assetId - The asset document ID.\n * @returns Confirmation response.\n */\n const deleteAsset = async (\n assetId: string,\n otherOptions: FetcherOptions = {}\n ) =>\n await fetcher<DeleteAssetResult>(\n `${ASSET_API_ROUTE}/${assetId}`,\n authAPIOptions,\n otherOptions,\n { method: 'DELETE' }\n );\n\n return {\n getAssets,\n getAssetById,\n uploadAsset,\n updateAsset,\n deleteAsset,\n };\n};\n\n/**\n * Authenticated `asset` endpoint bound to an Intlayer CMS authenticator.\n *\n * Pass an authenticator created with `createIntlayerCMS`, or omit it to use\n * the build-time configuration (`@intlayer/config/built`).\n */\nexport const assetEndpoint = createEndpoint(getAssetAPI);\n"],"mappings":";;;;;AAYA,MAAa,eACX,iBAAiC,CAAC,GAClC,mBACG;CAGH,MAAM,kBAAkB,GAFL,gBAAgB,QAAQ,cAAc,OAAO,WAE1B;;;;;;;CAQtC,MAAM,YAAY,OAChB,MACA,UACA,eAA+B,CAAC,MAEhC,MAAM,QACJ,iBACA,gBACA,cACA;EACE,OAAO;EACP,QAAQ;GACN,GAAI,SAAS,UAAa,EAAE,MAAM,OAAO,IAAI,EAAE;GAC/C,GAAI,aAAa,UAAa,EAAE,UAAU,OAAO,QAAQ,EAAE;EAC7D;CACF,CACF;;;;;;CAOF,MAAM,eAAe,OACnB,SACA,eAA+B,CAAC,MAEhC,MAAM,QACJ,GAAG,gBAAgB,GAAG,WACtB,gBACA,cACA,EAAE,OAAO,WAAW,CACtB;;;;;;;;CASF,MAAM,cAAc,OAClB,MACA,KACA,SACA,eAA+B,CAAC,MAC7B;EACH,MAAM,SAAS,MAAM,KAAK,YAAY;EAEtC,MAAM,UAAkC;GACtC,gBAAgB,KAAK,QAAQ;GAC7B,eAAe,KAAK;EACtB;EAEA,IAAI,KAAK,QAAQ,gBAAgB;EACjC,IAAI,SAAS,QAAQ,eAAe;EAEpC,MAAM,cACH,eAAe,WAAkD,CAAC;EAErE,MAAM,WAAW,MAAM,MAAM,iBAAiB;GAC5C,QAAQ;GACR,aAAa;GACb,SAAS;IAAE,GAAG;IAAa,GAAG;GAAQ;GACtC,MAAM;GACN,QAAQ,aAAa;EACvB,CAAC;EAED,IAAI,CAAC,SAAS,IAAI;GAChB,MAAM,SAAS,MAAM,SAAS,KAAK;GACnC,MAAM,IAAI,MAAM,KAAK,UAAU,OAAO,KAAK,KAAK,qBAAqB;EACvE;EAEA,OAAQ,MAAM,SAAS,KAAK;CAC9B;;;;;;;CAQA,MAAM,cAAc,OAClB,SACA,MACA,eAA+B,CAAC,MAEhC,MAAM,QACJ,GAAG,gBAAgB,GAAG,WACtB,gBACA,cACA;EAAE,QAAQ;EAAS,MAAM;CAA2C,CACtE;;;;;;CAOF,MAAM,cAAc,OAClB,SACA,eAA+B,CAAC,MAEhC,MAAM,QACJ,GAAG,gBAAgB,GAAG,WACtB,gBACA,cACA,EAAE,QAAQ,SAAS,CACrB;CAEF,OAAO;EACL;EACA;EACA;EACA;EACA;CACF;AACF;;;;;;;AAQA,MAAa,gBAAgB,eAAe,WAAW"}
1
+ {"version":3,"file":"asset.mjs","names":[],"sources":["../../../src/getIntlayerAPI/asset.ts"],"sourcesContent":["import type {\n AssetRoutes,\n assetContract,\n DeleteAssetResult,\n GetAssetByIdResult,\n GetAssetsResult,\n UpdateAssetResult,\n UploadAssetResult,\n} from '@intlayer/backend-contract/asset';\nimport type { RouteEndpoints } from '@intlayer/backend-contract/defineRoute';\nimport { buildRouteURL } from '@intlayer/backend-contract/defineRoute';\nimport { editor } from '@intlayer/config/built';\nimport { BACKEND_URL } from '@intlayer/config/defaultValues';\nimport type { IntlayerConfig } from '@intlayer/types/config';\nimport { createEndpoint } from '../cms/createIntlayerCMS';\nimport { type FetcherOptions, fetcher } from '../fetcher';\n\n/** Prefix of the routes, checked against the backend contract. */\nconst assetGroup = {\n prefix: '/api/assets',\n} as const satisfies Pick<typeof assetContract, 'prefix'>;\n\n/**\n * Method and path of every route, checked against the backend contract at\n * compile time (the contract's zod schemas are never loaded).\n */\nconst assetEndpoints = {\n getAssets: { method: 'GET', path: '/' },\n getAssetById: { method: 'GET', path: '/:assetId' },\n uploadAsset: { method: 'POST', path: '/' },\n updateAsset: { method: 'PATCH', path: '/:assetId' },\n deleteAsset: { method: 'DELETE', path: '/:assetId' },\n} as const satisfies RouteEndpoints<AssetRoutes>;\n\nexport const getAssetAPI = (\n authAPIOptions: FetcherOptions = {},\n intlayerConfig?: IntlayerConfig\n) => {\n const backendURL =\n intlayerConfig?.editor?.backendURL ?? editor.backendURL ?? BACKEND_URL;\n\n /**\n * Retrieves all assets for the current session project, paginated.\n * @param page - Page number (1-based).\n * @param pageSize - Number of items per page.\n * @returns Paginated list of assets.\n */\n const getAssets = async (\n page?: number,\n pageSize?: number,\n otherOptions: FetcherOptions = {}\n ) =>\n await fetcher<GetAssetsResult>(\n buildRouteURL(backendURL, assetGroup, assetEndpoints.getAssets),\n authAPIOptions,\n otherOptions,\n {\n cache: 'no-store',\n params: {\n ...(page !== undefined && { page: String(page) }),\n ...(pageSize !== undefined && { pageSize: String(pageSize) }),\n },\n }\n );\n\n /**\n * Retrieves a single asset by ID.\n * @param assetId - The asset document ID.\n * @returns The asset.\n */\n const getAssetById = async (\n assetId: string,\n otherOptions: FetcherOptions = {}\n ) =>\n await fetcher<GetAssetByIdResult>(\n buildRouteURL(backendURL, assetGroup, assetEndpoints.getAssetById, {\n assetId: String(assetId),\n }),\n authAPIOptions,\n otherOptions,\n { cache: 'no-store' }\n );\n\n /**\n * Uploads a new asset image.\n * @param file - The image File object.\n * @param alt - Optional alt text.\n * @param caption - Optional caption.\n * @returns The created asset record with its public URL.\n */\n const uploadAsset = async (\n file: File,\n alt?: string,\n caption?: string,\n otherOptions: FetcherOptions = {}\n ) => {\n const buffer = await file.arrayBuffer();\n\n const headers: Record<string, string> = {\n 'Content-Type': file.type || 'image/jpeg',\n 'X-File-Name': file.name,\n };\n\n if (alt) headers['X-Alt-Text'] = alt;\n if (caption) headers['X-Caption'] = caption;\n\n const authHeaders =\n (authAPIOptions.headers as Record<string, string> | undefined) ?? {};\n\n const response = await fetch(\n buildRouteURL(backendURL, assetGroup, assetEndpoints.uploadAsset),\n {\n method: assetEndpoints.uploadAsset.method,\n credentials: 'include',\n headers: { ...authHeaders, ...headers },\n body: buffer,\n signal: otherOptions.signal as AbortSignal | undefined,\n }\n );\n\n if (!response.ok) {\n const result = await response.json();\n throw new Error(JSON.stringify(result.error) ?? 'Asset upload failed');\n }\n\n return (await response.json()) as UploadAssetResult;\n };\n\n /**\n * Updates mutable metadata (name, alt text, caption) of an asset.\n * @param assetId - The asset document ID.\n * @param data - Fields to update.\n * @returns The updated asset record.\n */\n const updateAsset = async (\n assetId: string,\n data: { originalName?: string; alt?: string; caption?: string },\n otherOptions: FetcherOptions = {}\n ) =>\n await fetcher<UpdateAssetResult>(\n buildRouteURL(backendURL, assetGroup, assetEndpoints.updateAsset, {\n assetId: String(assetId),\n }),\n authAPIOptions,\n otherOptions,\n {\n method: assetEndpoints.updateAsset.method,\n body: data as unknown as Record<string, unknown>,\n }\n );\n\n /**\n * Deletes an asset by ID.\n * @param assetId - The asset document ID.\n * @returns Confirmation response.\n */\n const deleteAsset = async (\n assetId: string,\n otherOptions: FetcherOptions = {}\n ) =>\n await fetcher<DeleteAssetResult>(\n buildRouteURL(backendURL, assetGroup, assetEndpoints.deleteAsset, {\n assetId: String(assetId),\n }),\n authAPIOptions,\n otherOptions,\n { method: assetEndpoints.deleteAsset.method }\n );\n\n return {\n getAssets,\n getAssetById,\n uploadAsset,\n updateAsset,\n deleteAsset,\n };\n};\n\n/**\n * Authenticated `asset` endpoint bound to an Intlayer CMS authenticator.\n *\n * Pass an authenticator created with `createIntlayerCMS`, or omit it to use\n * the build-time configuration (`@intlayer/config/built`).\n */\nexport const assetEndpoint = createEndpoint(getAssetAPI);\n"],"mappings":";;;;;;;;AAkBA,MAAM,aAAa,EACjB,QAAQ,cACV;;;;;AAMA,MAAM,iBAAiB;CACrB,WAAW;EAAE,QAAQ;EAAO,MAAM;CAAI;CACtC,cAAc;EAAE,QAAQ;EAAO,MAAM;CAAY;CACjD,aAAa;EAAE,QAAQ;EAAQ,MAAM;CAAI;CACzC,aAAa;EAAE,QAAQ;EAAS,MAAM;CAAY;CAClD,aAAa;EAAE,QAAQ;EAAU,MAAM;CAAY;AACrD;AAEA,MAAa,eACX,iBAAiC,CAAC,GAClC,mBACG;CACH,MAAM,aACJ,gBAAgB,QAAQ,cAAc,OAAO,cAAc;;;;;;;CAQ7D,MAAM,YAAY,OAChB,MACA,UACA,eAA+B,CAAC,MAEhC,MAAM,QACJ,cAAc,YAAY,YAAY,eAAe,SAAS,GAC9D,gBACA,cACA;EACE,OAAO;EACP,QAAQ;GACN,GAAI,SAAS,UAAa,EAAE,MAAM,OAAO,IAAI,EAAE;GAC/C,GAAI,aAAa,UAAa,EAAE,UAAU,OAAO,QAAQ,EAAE;EAC7D;CACF,CACF;;;;;;CAOF,MAAM,eAAe,OACnB,SACA,eAA+B,CAAC,MAEhC,MAAM,QACJ,cAAc,YAAY,YAAY,eAAe,cAAc,EACjE,SAAS,OAAO,OAAO,EACzB,CAAC,GACD,gBACA,cACA,EAAE,OAAO,WAAW,CACtB;;;;;;;;CASF,MAAM,cAAc,OAClB,MACA,KACA,SACA,eAA+B,CAAC,MAC7B;EACH,MAAM,SAAS,MAAM,KAAK,YAAY;EAEtC,MAAM,UAAkC;GACtC,gBAAgB,KAAK,QAAQ;GAC7B,eAAe,KAAK;EACtB;EAEA,IAAI,KAAK,QAAQ,gBAAgB;EACjC,IAAI,SAAS,QAAQ,eAAe;EAEpC,MAAM,cACH,eAAe,WAAkD,CAAC;EAErE,MAAM,WAAW,MAAM,MACrB,cAAc,YAAY,YAAY,eAAe,WAAW,GAChE;GACE,QAAQ,eAAe,YAAY;GACnC,aAAa;GACb,SAAS;IAAE,GAAG;IAAa,GAAG;GAAQ;GACtC,MAAM;GACN,QAAQ,aAAa;EACvB,CACF;EAEA,IAAI,CAAC,SAAS,IAAI;GAChB,MAAM,SAAS,MAAM,SAAS,KAAK;GACnC,MAAM,IAAI,MAAM,KAAK,UAAU,OAAO,KAAK,KAAK,qBAAqB;EACvE;EAEA,OAAQ,MAAM,SAAS,KAAK;CAC9B;;;;;;;CAQA,MAAM,cAAc,OAClB,SACA,MACA,eAA+B,CAAC,MAEhC,MAAM,QACJ,cAAc,YAAY,YAAY,eAAe,aAAa,EAChE,SAAS,OAAO,OAAO,EACzB,CAAC,GACD,gBACA,cACA;EACE,QAAQ,eAAe,YAAY;EACnC,MAAM;CACR,CACF;;;;;;CAOF,MAAM,cAAc,OAClB,SACA,eAA+B,CAAC,MAEhC,MAAM,QACJ,cAAc,YAAY,YAAY,eAAe,aAAa,EAChE,SAAS,OAAO,OAAO,EACzB,CAAC,GACD,gBACA,cACA,EAAE,QAAQ,eAAe,YAAY,OAAO,CAC9C;CAEF,OAAO;EACL;EACA;EACA;EACA;EACA;CACF;AACF;;;;;;;AAQA,MAAa,gBAAgB,eAAe,WAAW"}
@@ -1,10 +1,64 @@
1
- import { fetcher } from "../fetcher.mjs";
2
1
  import { createEndpoint } from "../cms/createIntlayerCMS.mjs";
2
+ import { fetcher } from "../fetcher.mjs";
3
3
  import { editor } from "@intlayer/config/built";
4
+ import { buildRouteURL } from "@intlayer/backend-contract/defineRoute";
5
+ import { BACKEND_URL } from "@intlayer/config/defaultValues";
4
6
 
5
- //#region src/getIntlayerAPI/audit.ts
7
+ // src/getIntlayerAPI/audit.ts
8
+ /** Prefix of the routes, checked against the backend contract. */
9
+ const scanGroup = { prefix: "/api/scan" };
10
+ /**
11
+ * Method and path of every route, checked against the backend contract at
12
+ * compile time (the contract's zod schemas are never loaded).
13
+ */
14
+ const scanEndpoints = {
15
+ scan: {
16
+ method: "GET",
17
+ path: "/"
18
+ },
19
+ getTechnologyUsage: {
20
+ method: "GET",
21
+ path: "/technologies"
22
+ },
23
+ getScannedHosts: {
24
+ method: "GET",
25
+ path: "/hosts"
26
+ },
27
+ getScannedHost: {
28
+ method: "GET",
29
+ path: "/hosts/:host"
30
+ },
31
+ reportHostDetection: {
32
+ method: "POST",
33
+ path: "/hosts/detections"
34
+ },
35
+ discoverUrls: {
36
+ method: "GET",
37
+ path: "/recursive/discover"
38
+ },
39
+ startRecursive: {
40
+ method: "POST",
41
+ path: "/recursive/start"
42
+ },
43
+ getRecursiveStatus: {
44
+ method: "GET",
45
+ path: "/recursive/:jobId"
46
+ },
47
+ cancelRecursive: {
48
+ method: "POST",
49
+ path: "/recursive/:jobId/cancel"
50
+ },
51
+ pauseRecursive: {
52
+ method: "POST",
53
+ path: "/recursive/:jobId/pause"
54
+ },
55
+ resumeRecursive: {
56
+ method: "POST",
57
+ path: "/recursive/:jobId/resume"
58
+ }
59
+ };
6
60
  const getAuditAPI = (authAPIOptions = {}, intlayerConfig) => {
7
- const AUDIT_API_ROUTE = `${intlayerConfig?.editor?.backendURL ?? editor.backendURL}/api/scan`;
61
+ const backendURL = intlayerConfig?.editor?.backendURL ?? editor.backendURL ?? BACKEND_URL;
8
62
  /**
9
63
  * Streams a single-page SEO audit as Server-Sent Events.
10
64
  *
@@ -17,8 +71,8 @@ const getAuditAPI = (authAPIOptions = {}, intlayerConfig) => {
17
71
  * });
18
72
  * ```
19
73
  */
20
- const discoverUrls = async (params, otherOptions = {}) => await fetcher(`${AUDIT_API_ROUTE}/recursive/discover`, authAPIOptions, otherOptions, {
21
- method: "GET",
74
+ const discoverUrls = async (params, otherOptions = {}) => await fetcher(buildRouteURL(backendURL, scanGroup, scanEndpoints.discoverUrls), authAPIOptions, otherOptions, {
75
+ method: scanEndpoints.discoverUrls.method,
22
76
  params
23
77
  });
24
78
  const scanUrl = async (body, otherOptions = {}) => {
@@ -26,9 +80,9 @@ const getAuditAPI = (authAPIOptions = {}, intlayerConfig) => {
26
80
  const { url, refresh, onMessage, onDone } = body;
27
81
  const params = new URLSearchParams({ url });
28
82
  if (refresh) params.set("refresh", "true");
29
- const endpoint = `${AUDIT_API_ROUTE}?${params.toString()}`;
83
+ const endpoint = `${buildRouteURL(backendURL, scanGroup, scanEndpoints.scan)}?${params.toString()}`;
30
84
  const response = await fetch(endpoint, {
31
- method: "GET",
85
+ method: scanEndpoints.scan.method,
32
86
  headers: {
33
87
  Accept: "text/event-stream",
34
88
  ...authAPIOptions.headers,
@@ -70,37 +124,37 @@ const getAuditAPI = (authAPIOptions = {}, intlayerConfig) => {
70
124
  /**
71
125
  * Starts a recursive audit job for the given URL.
72
126
  */
73
- const startRecursiveAudit = async (body, otherOptions = {}) => await fetcher(`${AUDIT_API_ROUTE}/recursive/start`, authAPIOptions, otherOptions, {
74
- method: "POST",
127
+ const startRecursiveAudit = async (body, otherOptions = {}) => await fetcher(buildRouteURL(backendURL, scanGroup, scanEndpoints.startRecursive), authAPIOptions, otherOptions, {
128
+ method: scanEndpoints.startRecursive.method,
75
129
  params: body?.url ? { url: body.url } : void 0,
76
130
  body: body?.urls !== void 0 ? { urls: body.urls } : void 0
77
131
  });
78
132
  /**
79
133
  * Gets the status of a recursive audit job.
80
134
  */
81
- const getRecursiveAuditStatus = async (params, otherOptions = {}) => await fetcher(`${AUDIT_API_ROUTE}/recursive/${params?.jobId}`, authAPIOptions, otherOptions, { method: "GET" });
82
- const cancelRecursiveAudit = async (params, otherOptions = {}) => await fetcher(`${AUDIT_API_ROUTE}/recursive/${params?.jobId}/cancel`, authAPIOptions, otherOptions, { method: "POST" });
83
- const pauseRecursiveAudit = async (params, otherOptions = {}) => await fetcher(`${AUDIT_API_ROUTE}/recursive/${params?.jobId}/pause`, authAPIOptions, otherOptions, { method: "POST" });
84
- const resumeRecursiveAudit = async (params, otherOptions = {}) => await fetcher(`${AUDIT_API_ROUTE}/recursive/${params?.jobId}/resume`, authAPIOptions, otherOptions, { method: "POST" });
135
+ const getRecursiveAuditStatus = async (params, otherOptions = {}) => await fetcher(buildRouteURL(backendURL, scanGroup, scanEndpoints.getRecursiveStatus, { jobId: String(params?.jobId) }), authAPIOptions, otherOptions, { method: scanEndpoints.getRecursiveStatus.method });
136
+ const cancelRecursiveAudit = async (params, otherOptions = {}) => await fetcher(buildRouteURL(backendURL, scanGroup, scanEndpoints.cancelRecursive, { jobId: String(params?.jobId) }), authAPIOptions, otherOptions, { method: scanEndpoints.cancelRecursive.method });
137
+ const pauseRecursiveAudit = async (params, otherOptions = {}) => await fetcher(buildRouteURL(backendURL, scanGroup, scanEndpoints.pauseRecursive, { jobId: String(params?.jobId) }), authAPIOptions, otherOptions, { method: scanEndpoints.pauseRecursive.method });
138
+ const resumeRecursiveAudit = async (params, otherOptions = {}) => await fetcher(buildRouteURL(backendURL, scanGroup, scanEndpoints.resumeRecursive, { jobId: String(params?.jobId) }), authAPIOptions, otherOptions, { method: scanEndpoints.resumeRecursive.method });
85
139
  /**
86
140
  * Admin — number of scanned domains using each technology.
87
141
  */
88
- const getTechnologyUsage = async (params, otherOptions = {}) => await fetcher(`${AUDIT_API_ROUTE}/technologies`, authAPIOptions, otherOptions, {
89
- method: "GET",
142
+ const getTechnologyUsage = async (params, otherOptions = {}) => await fetcher(buildRouteURL(backendURL, scanGroup, scanEndpoints.getTechnologyUsage), authAPIOptions, otherOptions, {
143
+ method: scanEndpoints.getTechnologyUsage.method,
90
144
  params
91
145
  });
92
146
  /**
93
147
  * Admin — scanned hosts, most recently scanned first, filterable by
94
148
  * technology.
95
149
  */
96
- const getScannedHosts = async (params, otherOptions = {}) => await fetcher(`${AUDIT_API_ROUTE}/hosts`, authAPIOptions, otherOptions, {
97
- method: "GET",
150
+ const getScannedHosts = async (params, otherOptions = {}) => await fetcher(buildRouteURL(backendURL, scanGroup, scanEndpoints.getScannedHosts), authAPIOptions, otherOptions, {
151
+ method: scanEndpoints.getScannedHosts.method,
98
152
  params
99
153
  });
100
154
  /**
101
155
  * Admin — a scanned host with its stored scans, newest first.
102
156
  */
103
- const getScannedHost = async (params, otherOptions = {}) => await fetcher(`${AUDIT_API_ROUTE}/hosts/${encodeURIComponent(params?.host ?? "")}`, authAPIOptions, otherOptions, { method: "GET" });
157
+ const getScannedHost = async (params, otherOptions = {}) => await fetcher(buildRouteURL(backendURL, scanGroup, scanEndpoints.getScannedHost, { host: params?.host ?? "" }), authAPIOptions, otherOptions, { method: scanEndpoints.getScannedHost.method });
104
158
  return {
105
159
  getTechnologyUsage,
106
160
  getScannedHosts,
@@ -122,6 +176,5 @@ const getAuditAPI = (authAPIOptions = {}, intlayerConfig) => {
122
176
  */
123
177
  const auditEndpoint = createEndpoint(getAuditAPI);
124
178
 
125
- //#endregion
126
179
  export { auditEndpoint, getAuditAPI };
127
180
  //# sourceMappingURL=audit.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"audit.mjs","names":[],"sources":["../../../src/getIntlayerAPI/audit.ts"],"sourcesContent":["import type {\n AuditEvent,\n GetRecursiveAuditStatusResult,\n GetScannedHostParams,\n GetScannedHostResult,\n GetScannedHostsQuery,\n GetScannedHostsResult,\n GetTechnologyUsageQuery,\n GetTechnologyUsageResult,\n StartRecursiveAuditResult,\n} from '@intlayer/backend';\nimport { editor } from '@intlayer/config/built';\nimport type { IntlayerConfig } from '@intlayer/types/config';\nimport { createEndpoint } from '../cms/createIntlayerCMS';\nimport { type FetcherOptions, fetcher } from '../fetcher';\n\nexport type {\n AuditEvent,\n GetRecursiveAuditStatusResult,\n GetScannedHostParams,\n GetScannedHostResult,\n GetScannedHostsQuery,\n GetScannedHostsResult,\n GetTechnologyUsageQuery,\n GetTechnologyUsageResult,\n StartRecursiveAuditResult,\n};\n\nexport type ScanUrlBody = {\n url: string;\n /**\n * Force a new audit. Without it, a URL audited less than an hour ago is\n * replayed from cache (its first event carries `cachedAt`).\n */\n refresh?: boolean;\n onMessage?: (event: AuditEvent) => void;\n onDone?: () => void;\n};\n\nexport type DiscoverUrlsParams = {\n url: string;\n};\n\nexport type DiscoverUrlsResult = {\n urls: string[];\n};\n\nexport type StartRecursiveAuditBody = {\n url: string;\n urls?: string[];\n};\n\nexport type GetRecursiveAuditStatusParams = {\n jobId: string;\n};\n\nexport type RecursiveAuditJobParams = {\n jobId: string;\n};\n\nexport const getAuditAPI = (\n authAPIOptions: FetcherOptions = {},\n intlayerConfig?: IntlayerConfig\n) => {\n const backendURL = intlayerConfig?.editor?.backendURL ?? editor.backendURL;\n\n const AUDIT_API_ROUTE = `${backendURL}/api/scan`;\n\n /**\n * Streams a single-page SEO audit as Server-Sent Events.\n *\n * Usage:\n * ```ts\n * await audit.scanUrl({\n * url: 'https://example.com',\n * onMessage: (event) => console.log(event),\n * onDone: () => console.log('done'),\n * });\n * ```\n */\n const discoverUrls = async (\n params?: DiscoverUrlsParams,\n otherOptions: FetcherOptions = {}\n ) =>\n await fetcher<DiscoverUrlsResult>(\n `${AUDIT_API_ROUTE}/recursive/discover`,\n authAPIOptions,\n otherOptions,\n {\n method: 'GET',\n params,\n }\n );\n\n const scanUrl = async (\n body?: ScanUrlBody,\n otherOptions: FetcherOptions = {}\n ) => {\n if (!body?.url) return;\n\n const { url, refresh, onMessage, onDone } = body;\n\n const params = new URLSearchParams({ url });\n if (refresh) params.set('refresh', 'true');\n const endpoint = `${AUDIT_API_ROUTE}?${params.toString()}`;\n\n const response = await fetch(endpoint, {\n method: 'GET',\n headers: {\n Accept: 'text/event-stream',\n ...authAPIOptions.headers,\n ...otherOptions.headers,\n },\n credentials: 'include',\n signal: otherOptions.signal,\n });\n\n if (!response.ok) {\n let errorMessage = 'An error occurred';\n try {\n const errorData = await response.json();\n errorMessage = JSON.stringify(errorData.error) ?? errorMessage;\n } catch {\n try {\n const errorText = await response.text();\n if (errorText) errorMessage = errorText;\n } catch {\n // ignore\n }\n }\n throw new Error(errorMessage);\n }\n\n const reader = response.body?.getReader();\n if (!reader) throw new Error('No reader available');\n\n const decoder = new TextDecoder();\n let buffer = '';\n\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 if (line.startsWith('data: ')) {\n try {\n const event = JSON.parse(line.slice(6)) as AuditEvent;\n onMessage?.(event);\n } catch {\n // ignore malformed lines\n }\n }\n }\n }\n\n onDone?.();\n };\n\n /**\n * Starts a recursive audit job for the given URL.\n */\n const startRecursiveAudit = async (\n body?: StartRecursiveAuditBody,\n otherOptions: FetcherOptions = {}\n ) =>\n await fetcher<StartRecursiveAuditResult>(\n `${AUDIT_API_ROUTE}/recursive/start`,\n authAPIOptions,\n otherOptions,\n {\n method: 'POST',\n params: body?.url ? { url: body.url } : undefined,\n body: body?.urls !== undefined ? { urls: body.urls as any } : undefined,\n }\n );\n\n /**\n * Gets the status of a recursive audit job.\n */\n const getRecursiveAuditStatus = async (\n params?: GetRecursiveAuditStatusParams,\n otherOptions: FetcherOptions = {}\n ) =>\n await fetcher<GetRecursiveAuditStatusResult>(\n `${AUDIT_API_ROUTE}/recursive/${params?.jobId}`,\n authAPIOptions,\n otherOptions,\n {\n method: 'GET',\n }\n );\n\n const cancelRecursiveAudit = async (\n params?: RecursiveAuditJobParams,\n otherOptions: FetcherOptions = {}\n ) =>\n await fetcher<{ success: boolean }>(\n `${AUDIT_API_ROUTE}/recursive/${params?.jobId}/cancel`,\n authAPIOptions,\n otherOptions,\n { method: 'POST' }\n );\n\n const pauseRecursiveAudit = async (\n params?: RecursiveAuditJobParams,\n otherOptions: FetcherOptions = {}\n ) =>\n await fetcher<{ success: boolean }>(\n `${AUDIT_API_ROUTE}/recursive/${params?.jobId}/pause`,\n authAPIOptions,\n otherOptions,\n { method: 'POST' }\n );\n\n const resumeRecursiveAudit = async (\n params?: RecursiveAuditJobParams,\n otherOptions: FetcherOptions = {}\n ) =>\n await fetcher<{ success: boolean }>(\n `${AUDIT_API_ROUTE}/recursive/${params?.jobId}/resume`,\n authAPIOptions,\n otherOptions,\n { method: 'POST' }\n );\n\n /**\n * Admin — number of scanned domains using each technology.\n */\n const getTechnologyUsage = async (\n params?: GetTechnologyUsageQuery,\n otherOptions: FetcherOptions = {}\n ) =>\n await fetcher<GetTechnologyUsageResult>(\n `${AUDIT_API_ROUTE}/technologies`,\n authAPIOptions,\n otherOptions,\n { method: 'GET', params }\n );\n\n /**\n * Admin — scanned hosts, most recently scanned first, filterable by\n * technology.\n */\n const getScannedHosts = async (\n params?: GetScannedHostsQuery,\n otherOptions: FetcherOptions = {}\n ) =>\n await fetcher<GetScannedHostsResult>(\n `${AUDIT_API_ROUTE}/hosts`,\n authAPIOptions,\n otherOptions,\n { method: 'GET', params }\n );\n\n /**\n * Admin — a scanned host with its stored scans, newest first.\n */\n const getScannedHost = async (\n params?: GetScannedHostParams,\n otherOptions: FetcherOptions = {}\n ) =>\n await fetcher<GetScannedHostResult>(\n `${AUDIT_API_ROUTE}/hosts/${encodeURIComponent(params?.host ?? '')}`,\n authAPIOptions,\n otherOptions,\n { method: 'GET' }\n );\n\n return {\n getTechnologyUsage,\n getScannedHosts,\n getScannedHost,\n discoverUrls,\n scanUrl,\n startRecursiveAudit,\n getRecursiveAuditStatus,\n cancelRecursiveAudit,\n pauseRecursiveAudit,\n resumeRecursiveAudit,\n };\n};\n\n/**\n * Authenticated `audit` 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 auditEndpoint = createEndpoint(getAuditAPI);\n"],"mappings":";;;;;AA4DA,MAAa,eACX,iBAAiC,CAAC,GAClC,mBACG;CAGH,MAAM,kBAAkB,GAFL,gBAAgB,QAAQ,cAAc,OAAO,WAE1B;;;;;;;;;;;;;CActC,MAAM,eAAe,OACnB,QACA,eAA+B,CAAC,MAEhC,MAAM,QACJ,GAAG,gBAAgB,sBACnB,gBACA,cACA;EACE,QAAQ;EACR;CACF,CACF;CAEF,MAAM,UAAU,OACd,MACA,eAA+B,CAAC,MAC7B;EACH,IAAI,CAAC,MAAM,KAAK;EAEhB,MAAM,EAAE,KAAK,SAAS,WAAW,WAAW;EAE5C,MAAM,SAAS,IAAI,gBAAgB,EAAE,IAAI,CAAC;EAC1C,IAAI,SAAS,OAAO,IAAI,WAAW,MAAM;EACzC,MAAM,WAAW,GAAG,gBAAgB,GAAG,OAAO,SAAS;EAEvD,MAAM,WAAW,MAAM,MAAM,UAAU;GACrC,QAAQ;GACR,SAAS;IACP,QAAQ;IACR,GAAG,eAAe;IAClB,GAAG,aAAa;GAClB;GACA,aAAa;GACb,QAAQ,aAAa;EACvB,CAAC;EAED,IAAI,CAAC,SAAS,IAAI;GAChB,IAAI,eAAe;GACnB,IAAI;IACF,MAAM,YAAY,MAAM,SAAS,KAAK;IACtC,eAAe,KAAK,UAAU,UAAU,KAAK,KAAK;GACpD,QAAQ;IACN,IAAI;KACF,MAAM,YAAY,MAAM,SAAS,KAAK;KACtC,IAAI,WAAW,eAAe;IAChC,QAAQ,CAER;GACF;GACA,MAAM,IAAI,MAAM,YAAY;EAC9B;EAEA,MAAM,SAAS,SAAS,MAAM,UAAU;EACxC,IAAI,CAAC,QAAQ,MAAM,IAAI,MAAM,qBAAqB;EAElD,MAAM,UAAU,IAAI,YAAY;EAChC,IAAI,SAAS;EAEb,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,IAAI,KAAK,WAAW,QAAQ,GAC1B,IAAI;IACF,MAAM,QAAQ,KAAK,MAAM,KAAK,MAAM,CAAC,CAAC;IACtC,YAAY,KAAK;GACnB,QAAQ,CAER;EAGN;EAEA,SAAS;CACX;;;;CAKA,MAAM,sBAAsB,OAC1B,MACA,eAA+B,CAAC,MAEhC,MAAM,QACJ,GAAG,gBAAgB,mBACnB,gBACA,cACA;EACE,QAAQ;EACR,QAAQ,MAAM,MAAM,EAAE,KAAK,KAAK,IAAI,IAAI;EACxC,MAAM,MAAM,SAAS,SAAY,EAAE,MAAM,KAAK,KAAY,IAAI;CAChE,CACF;;;;CAKF,MAAM,0BAA0B,OAC9B,QACA,eAA+B,CAAC,MAEhC,MAAM,QACJ,GAAG,gBAAgB,aAAa,QAAQ,SACxC,gBACA,cACA,EACE,QAAQ,MACV,CACF;CAEF,MAAM,uBAAuB,OAC3B,QACA,eAA+B,CAAC,MAEhC,MAAM,QACJ,GAAG,gBAAgB,aAAa,QAAQ,MAAM,UAC9C,gBACA,cACA,EAAE,QAAQ,OAAO,CACnB;CAEF,MAAM,sBAAsB,OAC1B,QACA,eAA+B,CAAC,MAEhC,MAAM,QACJ,GAAG,gBAAgB,aAAa,QAAQ,MAAM,SAC9C,gBACA,cACA,EAAE,QAAQ,OAAO,CACnB;CAEF,MAAM,uBAAuB,OAC3B,QACA,eAA+B,CAAC,MAEhC,MAAM,QACJ,GAAG,gBAAgB,aAAa,QAAQ,MAAM,UAC9C,gBACA,cACA,EAAE,QAAQ,OAAO,CACnB;;;;CAKF,MAAM,qBAAqB,OACzB,QACA,eAA+B,CAAC,MAEhC,MAAM,QACJ,GAAG,gBAAgB,gBACnB,gBACA,cACA;EAAE,QAAQ;EAAO;CAAO,CAC1B;;;;;CAMF,MAAM,kBAAkB,OACtB,QACA,eAA+B,CAAC,MAEhC,MAAM,QACJ,GAAG,gBAAgB,SACnB,gBACA,cACA;EAAE,QAAQ;EAAO;CAAO,CAC1B;;;;CAKF,MAAM,iBAAiB,OACrB,QACA,eAA+B,CAAC,MAEhC,MAAM,QACJ,GAAG,gBAAgB,SAAS,mBAAmB,QAAQ,QAAQ,EAAE,KACjE,gBACA,cACA,EAAE,QAAQ,MAAM,CAClB;CAEF,OAAO;EACL;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;EACA;CACF;AACF;;;;;;;AAQA,MAAa,gBAAgB,eAAe,WAAW"}
1
+ {"version":3,"file":"audit.mjs","names":[],"sources":["../../../src/getIntlayerAPI/audit.ts"],"sourcesContent":["import type { RouteEndpoints } from '@intlayer/backend-contract/defineRoute';\nimport { buildRouteURL } from '@intlayer/backend-contract/defineRoute';\nimport type {\n AuditEvent,\n GetRecursiveAuditStatusResult,\n GetScannedHostParams,\n GetScannedHostResult,\n GetScannedHostsQuery,\n GetScannedHostsResult,\n GetTechnologyUsageQuery,\n GetTechnologyUsageResult,\n ScanRoutes,\n StartRecursiveAuditResult,\n scanContract,\n} from '@intlayer/backend-contract/scan';\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 {\n AuditEvent,\n GetRecursiveAuditStatusResult,\n GetScannedHostParams,\n GetScannedHostResult,\n GetScannedHostsQuery,\n GetScannedHostsResult,\n GetTechnologyUsageQuery,\n GetTechnologyUsageResult,\n StartRecursiveAuditResult,\n};\n\nexport type ScanUrlBody = {\n url: string;\n /**\n * Force a new audit. Without it, a URL audited less than an hour ago is\n * replayed from cache (its first event carries `cachedAt`).\n */\n refresh?: boolean;\n onMessage?: (event: AuditEvent) => void;\n onDone?: () => void;\n};\n\nexport type DiscoverUrlsParams = {\n url: string;\n};\n\nexport type DiscoverUrlsResult = {\n urls: string[];\n};\n\nexport type StartRecursiveAuditBody = {\n url: string;\n urls?: string[];\n};\n\nexport type GetRecursiveAuditStatusParams = {\n jobId: string;\n};\n\nexport type RecursiveAuditJobParams = {\n jobId: string;\n};\n\n/** Prefix of the routes, checked against the backend contract. */\nconst scanGroup = {\n prefix: '/api/scan',\n} as const satisfies Pick<typeof scanContract, '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 scanEndpoints = {\n scan: { method: 'GET', path: '/' },\n getTechnologyUsage: { method: 'GET', path: '/technologies' },\n getScannedHosts: { method: 'GET', path: '/hosts' },\n getScannedHost: { method: 'GET', path: '/hosts/:host' },\n reportHostDetection: { method: 'POST', path: '/hosts/detections' },\n discoverUrls: { method: 'GET', path: '/recursive/discover' },\n startRecursive: { method: 'POST', path: '/recursive/start' },\n getRecursiveStatus: { method: 'GET', path: '/recursive/:jobId' },\n cancelRecursive: { method: 'POST', path: '/recursive/:jobId/cancel' },\n pauseRecursive: { method: 'POST', path: '/recursive/:jobId/pause' },\n resumeRecursive: { method: 'POST', path: '/recursive/:jobId/resume' },\n} as const satisfies RouteEndpoints<ScanRoutes>;\n\nexport const getAuditAPI = (\n authAPIOptions: FetcherOptions = {},\n intlayerConfig?: IntlayerConfig\n) => {\n const backendURL =\n intlayerConfig?.editor?.backendURL ?? editor.backendURL ?? BACKEND_URL;\n\n /**\n * Streams a single-page SEO audit as Server-Sent Events.\n *\n * Usage:\n * ```ts\n * await audit.scanUrl({\n * url: 'https://example.com',\n * onMessage: (event) => console.log(event),\n * onDone: () => console.log('done'),\n * });\n * ```\n */\n const discoverUrls = async (\n params?: DiscoverUrlsParams,\n otherOptions: FetcherOptions = {}\n ) =>\n await fetcher<DiscoverUrlsResult>(\n buildRouteURL(backendURL, scanGroup, scanEndpoints.discoverUrls),\n authAPIOptions,\n otherOptions,\n {\n method: scanEndpoints.discoverUrls.method,\n params,\n }\n );\n\n const scanUrl = async (\n body?: ScanUrlBody,\n otherOptions: FetcherOptions = {}\n ) => {\n if (!body?.url) return;\n\n const { url, refresh, onMessage, onDone } = body;\n\n const params = new URLSearchParams({ url });\n if (refresh) params.set('refresh', 'true');\n const endpoint = `${buildRouteURL(backendURL, scanGroup, scanEndpoints.scan)}?${params.toString()}`;\n\n const response = await fetch(endpoint, {\n method: scanEndpoints.scan.method,\n headers: {\n Accept: 'text/event-stream',\n ...authAPIOptions.headers,\n ...otherOptions.headers,\n },\n credentials: 'include',\n signal: otherOptions.signal,\n });\n\n if (!response.ok) {\n let errorMessage = 'An error occurred';\n try {\n const errorData = await response.json();\n errorMessage = JSON.stringify(errorData.error) ?? errorMessage;\n } catch {\n try {\n const errorText = await response.text();\n if (errorText) errorMessage = errorText;\n } catch {\n // ignore\n }\n }\n throw new Error(errorMessage);\n }\n\n const reader = response.body?.getReader();\n if (!reader) throw new Error('No reader available');\n\n const decoder = new TextDecoder();\n let buffer = '';\n\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 if (line.startsWith('data: ')) {\n try {\n const event = JSON.parse(line.slice(6)) as AuditEvent;\n onMessage?.(event);\n } catch {\n // ignore malformed lines\n }\n }\n }\n }\n\n onDone?.();\n };\n\n /**\n * Starts a recursive audit job for the given URL.\n */\n const startRecursiveAudit = async (\n body?: StartRecursiveAuditBody,\n otherOptions: FetcherOptions = {}\n ) =>\n await fetcher<StartRecursiveAuditResult>(\n buildRouteURL(backendURL, scanGroup, scanEndpoints.startRecursive),\n authAPIOptions,\n otherOptions,\n {\n method: scanEndpoints.startRecursive.method,\n params: body?.url ? { url: body.url } : undefined,\n body: body?.urls !== undefined ? { urls: body.urls as any } : undefined,\n }\n );\n\n /**\n * Gets the status of a recursive audit job.\n */\n const getRecursiveAuditStatus = async (\n params?: GetRecursiveAuditStatusParams,\n otherOptions: FetcherOptions = {}\n ) =>\n await fetcher<GetRecursiveAuditStatusResult>(\n buildRouteURL(backendURL, scanGroup, scanEndpoints.getRecursiveStatus, {\n jobId: String(params?.jobId),\n }),\n authAPIOptions,\n otherOptions,\n {\n method: scanEndpoints.getRecursiveStatus.method,\n }\n );\n\n const cancelRecursiveAudit = async (\n params?: RecursiveAuditJobParams,\n otherOptions: FetcherOptions = {}\n ) =>\n await fetcher<{ success: boolean }>(\n buildRouteURL(backendURL, scanGroup, scanEndpoints.cancelRecursive, {\n jobId: String(params?.jobId),\n }),\n authAPIOptions,\n otherOptions,\n { method: scanEndpoints.cancelRecursive.method }\n );\n\n const pauseRecursiveAudit = async (\n params?: RecursiveAuditJobParams,\n otherOptions: FetcherOptions = {}\n ) =>\n await fetcher<{ success: boolean }>(\n buildRouteURL(backendURL, scanGroup, scanEndpoints.pauseRecursive, {\n jobId: String(params?.jobId),\n }),\n authAPIOptions,\n otherOptions,\n { method: scanEndpoints.pauseRecursive.method }\n );\n\n const resumeRecursiveAudit = async (\n params?: RecursiveAuditJobParams,\n otherOptions: FetcherOptions = {}\n ) =>\n await fetcher<{ success: boolean }>(\n buildRouteURL(backendURL, scanGroup, scanEndpoints.resumeRecursive, {\n jobId: String(params?.jobId),\n }),\n authAPIOptions,\n otherOptions,\n { method: scanEndpoints.resumeRecursive.method }\n );\n\n /**\n * Admin — number of scanned domains using each technology.\n */\n const getTechnologyUsage = async (\n params?: GetTechnologyUsageQuery,\n otherOptions: FetcherOptions = {}\n ) =>\n await fetcher<GetTechnologyUsageResult>(\n buildRouteURL(backendURL, scanGroup, scanEndpoints.getTechnologyUsage),\n authAPIOptions,\n otherOptions,\n { method: scanEndpoints.getTechnologyUsage.method, params }\n );\n\n /**\n * Admin — scanned hosts, most recently scanned first, filterable by\n * technology.\n */\n const getScannedHosts = async (\n params?: GetScannedHostsQuery,\n otherOptions: FetcherOptions = {}\n ) =>\n await fetcher<GetScannedHostsResult>(\n buildRouteURL(backendURL, scanGroup, scanEndpoints.getScannedHosts),\n authAPIOptions,\n otherOptions,\n { method: scanEndpoints.getScannedHosts.method, params }\n );\n\n /**\n * Admin — a scanned host with its stored scans, newest first.\n */\n const getScannedHost = async (\n params?: GetScannedHostParams,\n otherOptions: FetcherOptions = {}\n ) =>\n await fetcher<GetScannedHostResult>(\n buildRouteURL(backendURL, scanGroup, scanEndpoints.getScannedHost, {\n host: params?.host ?? '',\n }),\n authAPIOptions,\n otherOptions,\n { method: scanEndpoints.getScannedHost.method }\n );\n\n return {\n getTechnologyUsage,\n getScannedHosts,\n getScannedHost,\n discoverUrls,\n scanUrl,\n startRecursiveAudit,\n getRecursiveAuditStatus,\n cancelRecursiveAudit,\n pauseRecursiveAudit,\n resumeRecursiveAudit,\n };\n};\n\n/**\n * Authenticated `audit` 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 auditEndpoint = createEndpoint(getAuditAPI);\n"],"mappings":"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"}
@@ -1,28 +1,58 @@
1
- import { fetcher } from "../fetcher.mjs";
2
1
  import { createEndpoint } from "../cms/createIntlayerCMS.mjs";
2
+ import { fetcher } from "../fetcher.mjs";
3
3
  import { editor } from "@intlayer/config/built";
4
+ import { buildRouteURL } from "@intlayer/backend-contract/defineRoute";
5
+ import { BACKEND_URL } from "@intlayer/config/defaultValues";
4
6
 
5
- //#region src/getIntlayerAPI/bitbucket.ts
7
+ // src/getIntlayerAPI/bitbucket.ts
8
+ /** Prefix of the routes, checked against the backend contract. */
9
+ const bitbucketGroup = { prefix: "/api/bitbucket" };
10
+ /**
11
+ * Method and path of every route, checked against the backend contract at
12
+ * compile time (the contract's zod schemas are never loaded).
13
+ */
14
+ const bitbucketEndpoints = {
15
+ getAuthUrl: {
16
+ method: "GET",
17
+ path: "/auth-url"
18
+ },
19
+ authCallback: {
20
+ method: "POST",
21
+ path: "/auth"
22
+ },
23
+ listRepos: {
24
+ method: "GET",
25
+ path: "/repos"
26
+ },
27
+ checkConfig: {
28
+ method: "POST",
29
+ path: "/check-config"
30
+ },
31
+ getConfigFile: {
32
+ method: "POST",
33
+ path: "/get-config-file"
34
+ }
35
+ };
6
36
  const getBitbucketAPI = (authAPIOptions = {}, intlayerConfig) => {
7
- const BITBUCKET_API_ROUTE = `${intlayerConfig?.editor?.backendURL ?? editor.backendURL}/api/bitbucket`;
37
+ const backendURL = intlayerConfig?.editor?.backendURL ?? editor.backendURL ?? BACKEND_URL;
8
38
  /**
9
39
  * Get Bitbucket OAuth authorization URL
10
40
  * @param redirectUri - Redirect URI after OAuth authorization
11
41
  */
12
- const getAuthUrl = async (redirectUri, otherOptions = {}) => await fetcher(`${BITBUCKET_API_ROUTE}/auth-url`, authAPIOptions, otherOptions, { params: { redirectUri } });
42
+ const getAuthUrl = async (redirectUri, otherOptions = {}) => await fetcher(buildRouteURL(backendURL, bitbucketGroup, bitbucketEndpoints.getAuthUrl), authAPIOptions, otherOptions, { params: { redirectUri } });
13
43
  /**
14
44
  * Exchange Bitbucket authorization code for access token
15
45
  * @param code - Bitbucket authorization code
16
46
  */
17
- const authenticate = async (code, otherOptions = {}) => await fetcher(`${BITBUCKET_API_ROUTE}/auth`, authAPIOptions, otherOptions, {
18
- method: "POST",
47
+ const authenticate = async (code, otherOptions = {}) => await fetcher(buildRouteURL(backendURL, bitbucketGroup, bitbucketEndpoints.authCallback), authAPIOptions, otherOptions, {
48
+ method: bitbucketEndpoints.authCallback.method,
19
49
  body: { code }
20
50
  });
21
51
  /**
22
52
  * Get user's Bitbucket repositories
23
53
  * @param token - Optional Bitbucket access token. If not provided, backend will use session.
24
54
  */
25
- const getRepositories = async (token, otherOptions = {}) => await fetcher(`${BITBUCKET_API_ROUTE}/repos`, authAPIOptions, otherOptions, { params: token ? { token } : void 0 });
55
+ const getRepositories = async (token, otherOptions = {}) => await fetcher(buildRouteURL(backendURL, bitbucketGroup, bitbucketEndpoints.listRepos), authAPIOptions, otherOptions, { params: token ? { token } : void 0 });
26
56
  /**
27
57
  * Check if intlayer.config.ts exists in a Bitbucket repository
28
58
  * @param token - Optional Bitbucket access token. If not provided, backend will use session.
@@ -30,8 +60,8 @@ const getBitbucketAPI = (authAPIOptions = {}, intlayerConfig) => {
30
60
  * @param repoSlug - Repository slug
31
61
  * @param branch - Branch name (default: 'main')
32
62
  */
33
- const checkIntlayerConfig = async (token, workspace, repoSlug, branch = "main", otherOptions = {}) => await fetcher(`${BITBUCKET_API_ROUTE}/check-config`, authAPIOptions, otherOptions, {
34
- method: "POST",
63
+ const checkIntlayerConfig = async (token, workspace, repoSlug, branch = "main", otherOptions = {}) => await fetcher(buildRouteURL(backendURL, bitbucketGroup, bitbucketEndpoints.checkConfig), authAPIOptions, otherOptions, {
64
+ method: bitbucketEndpoints.checkConfig.method,
35
65
  body: {
36
66
  token: token ?? void 0,
37
67
  workspace,
@@ -47,8 +77,8 @@ const getBitbucketAPI = (authAPIOptions = {}, intlayerConfig) => {
47
77
  * @param branch - Branch name (default: 'main')
48
78
  * @param path - File path (default: 'intlayer.config.ts')
49
79
  */
50
- const getConfigFile = async (token, workspace, repoSlug, branch = "main", path = "intlayer.config.ts", otherOptions = {}) => await fetcher(`${BITBUCKET_API_ROUTE}/get-config-file`, authAPIOptions, otherOptions, {
51
- method: "POST",
80
+ const getConfigFile = async (token, workspace, repoSlug, branch = "main", path = "intlayer.config.ts", otherOptions = {}) => await fetcher(buildRouteURL(backendURL, bitbucketGroup, bitbucketEndpoints.getConfigFile), authAPIOptions, otherOptions, {
81
+ method: bitbucketEndpoints.getConfigFile.method,
52
82
  body: {
53
83
  token: token ?? void 0,
54
84
  workspace,
@@ -73,6 +103,5 @@ const getBitbucketAPI = (authAPIOptions = {}, intlayerConfig) => {
73
103
  */
74
104
  const bitbucketEndpoint = createEndpoint(getBitbucketAPI);
75
105
 
76
- //#endregion
77
106
  export { bitbucketEndpoint, getBitbucketAPI };
78
107
  //# sourceMappingURL=bitbucket.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"bitbucket.mjs","names":[],"sources":["../../../src/getIntlayerAPI/bitbucket.ts"],"sourcesContent":["import { editor } from '@intlayer/config/built';\nimport type { IntlayerConfig } from '@intlayer/types/config';\nimport { createEndpoint } from '../cms/createIntlayerCMS';\nimport { type FetcherOptions, fetcher } from '../fetcher';\n\nexport type BitbucketRepository = {\n uuid: string;\n name: string;\n full_name: string;\n slug: string;\n mainbranch?: {\n name: string;\n type: string;\n };\n links: {\n html: {\n href: string;\n };\n };\n workspace: {\n slug: string;\n name: string;\n uuid: string;\n };\n owner: {\n display_name: string;\n username?: string;\n uuid: string;\n };\n updated_on: string;\n is_private: boolean;\n};\n\nexport type BitbucketAuthCallbackBody = {\n code: string;\n};\n\nexport type BitbucketAuthCallbackResult = {\n data: {\n token: string;\n };\n};\n\nexport type BitbucketListReposResult = {\n data: BitbucketRepository[];\n};\n\nexport type BitbucketCheckConfigBody = {\n token?: string;\n workspace: string;\n repoSlug: string;\n branch?: string;\n};\n\nexport type BitbucketCheckConfigResult = {\n data: {\n hasConfig: boolean;\n configPaths: string[];\n };\n};\n\nexport type BitbucketGetConfigFileBody = {\n token?: string;\n workspace: string;\n repoSlug: string;\n branch?: string;\n path?: string;\n};\n\nexport type BitbucketGetConfigFileResult = {\n data: {\n content: string;\n };\n};\n\nexport type BitbucketGetAuthUrlResult = {\n data: {\n authUrl: string;\n };\n};\n\nexport const getBitbucketAPI = (\n authAPIOptions: FetcherOptions = {},\n intlayerConfig?: IntlayerConfig\n) => {\n const backendURL = intlayerConfig?.editor?.backendURL ?? editor.backendURL;\n\n const BITBUCKET_API_ROUTE = `${backendURL}/api/bitbucket`;\n\n /**\n * Get Bitbucket OAuth authorization URL\n * @param redirectUri - Redirect URI after OAuth authorization\n */\n const getAuthUrl = async (\n redirectUri: string,\n otherOptions: FetcherOptions = {}\n ) =>\n await fetcher<BitbucketGetAuthUrlResult>(\n `${BITBUCKET_API_ROUTE}/auth-url`,\n authAPIOptions,\n otherOptions,\n {\n params: { redirectUri },\n }\n );\n\n /**\n * Exchange Bitbucket authorization code for access token\n * @param code - Bitbucket authorization code\n */\n const authenticate = async (\n code: string,\n otherOptions: FetcherOptions = {}\n ) =>\n await fetcher<BitbucketAuthCallbackResult>(\n `${BITBUCKET_API_ROUTE}/auth`,\n authAPIOptions,\n otherOptions,\n {\n method: 'POST',\n body: { code },\n }\n );\n\n /**\n * Get user's Bitbucket repositories\n * @param token - Optional Bitbucket access token. If not provided, backend will use session.\n */\n const getRepositories = async (\n token?: string | null,\n otherOptions: FetcherOptions = {}\n ) =>\n await fetcher<BitbucketListReposResult>(\n `${BITBUCKET_API_ROUTE}/repos`,\n authAPIOptions,\n otherOptions,\n {\n params: token ? { token } : undefined,\n }\n );\n\n /**\n * Check if intlayer.config.ts exists in a Bitbucket repository\n * @param token - Optional Bitbucket access token. If not provided, backend will use session.\n * @param workspace - Bitbucket workspace slug\n * @param repoSlug - Repository slug\n * @param branch - Branch name (default: 'main')\n */\n const checkIntlayerConfig = async (\n token: string | null | undefined,\n workspace: string,\n repoSlug: string,\n branch: string = 'main',\n otherOptions: FetcherOptions = {}\n ) =>\n await fetcher<BitbucketCheckConfigResult>(\n `${BITBUCKET_API_ROUTE}/check-config`,\n authAPIOptions,\n otherOptions,\n {\n method: 'POST',\n body: { token: token ?? undefined, workspace, repoSlug, branch },\n }\n );\n\n /**\n * Get intlayer.config.ts file contents from a Bitbucket repository\n * @param token - Optional Bitbucket access token. If not provided, backend will use session.\n * @param workspace - Bitbucket workspace slug\n * @param repoSlug - Repository slug\n * @param branch - Branch name (default: 'main')\n * @param path - File path (default: 'intlayer.config.ts')\n */\n const getConfigFile = async (\n token: string | null | undefined,\n workspace: string,\n repoSlug: string,\n branch: string = 'main',\n path: string = 'intlayer.config.ts',\n otherOptions: FetcherOptions = {}\n ) =>\n await fetcher<BitbucketGetConfigFileResult>(\n `${BITBUCKET_API_ROUTE}/get-config-file`,\n authAPIOptions,\n otherOptions,\n {\n method: 'POST',\n body: {\n token: token ?? undefined,\n workspace,\n repoSlug,\n branch,\n path,\n },\n }\n );\n\n return {\n getAuthUrl,\n authenticate,\n getRepositories,\n checkIntlayerConfig,\n getConfigFile,\n };\n};\n\n/**\n * Authenticated `bitbucket` 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 bitbucketEndpoint = createEndpoint(getBitbucketAPI);\n"],"mappings":";;;;;AAiFA,MAAa,mBACX,iBAAiC,CAAC,GAClC,mBACG;CAGH,MAAM,sBAAsB,GAFT,gBAAgB,QAAQ,cAAc,OAAO,WAEtB;;;;;CAM1C,MAAM,aAAa,OACjB,aACA,eAA+B,CAAC,MAEhC,MAAM,QACJ,GAAG,oBAAoB,YACvB,gBACA,cACA,EACE,QAAQ,EAAE,YAAY,EACxB,CACF;;;;;CAMF,MAAM,eAAe,OACnB,MACA,eAA+B,CAAC,MAEhC,MAAM,QACJ,GAAG,oBAAoB,QACvB,gBACA,cACA;EACE,QAAQ;EACR,MAAM,EAAE,KAAK;CACf,CACF;;;;;CAMF,MAAM,kBAAkB,OACtB,OACA,eAA+B,CAAC,MAEhC,MAAM,QACJ,GAAG,oBAAoB,SACvB,gBACA,cACA,EACE,QAAQ,QAAQ,EAAE,MAAM,IAAI,OAC9B,CACF;;;;;;;;CASF,MAAM,sBAAsB,OAC1B,OACA,WACA,UACA,SAAiB,QACjB,eAA+B,CAAC,MAEhC,MAAM,QACJ,GAAG,oBAAoB,gBACvB,gBACA,cACA;EACE,QAAQ;EACR,MAAM;GAAE,OAAO,SAAS;GAAW;GAAW;GAAU;EAAO;CACjE,CACF;;;;;;;;;CAUF,MAAM,gBAAgB,OACpB,OACA,WACA,UACA,SAAiB,QACjB,OAAe,sBACf,eAA+B,CAAC,MAEhC,MAAM,QACJ,GAAG,oBAAoB,mBACvB,gBACA,cACA;EACE,QAAQ;EACR,MAAM;GACJ,OAAO,SAAS;GAChB;GACA;GACA;GACA;EACF;CACF,CACF;CAEF,OAAO;EACL;EACA;EACA;EACA;EACA;CACF;AACF;;;;;;;AAQA,MAAa,oBAAoB,eAAe,eAAe"}
1
+ {"version":3,"file":"bitbucket.mjs","names":[],"sources":["../../../src/getIntlayerAPI/bitbucket.ts"],"sourcesContent":["import type { RouteEndpoints } from '@intlayer/backend-contract/defineRoute';\nimport { buildRouteURL } from '@intlayer/backend-contract/defineRoute';\nimport type {\n BitbucketRoutes,\n bitbucketContract,\n} from '@intlayer/backend-contract/gitProviders';\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 BitbucketRepository = {\n uuid: string;\n name: string;\n full_name: string;\n slug: string;\n mainbranch?: {\n name: string;\n type: string;\n };\n links: {\n html: {\n href: string;\n };\n };\n workspace: {\n slug: string;\n name: string;\n uuid: string;\n };\n owner: {\n display_name: string;\n username?: string;\n uuid: string;\n };\n updated_on: string;\n is_private: boolean;\n};\n\nexport type BitbucketAuthCallbackBody = {\n code: string;\n};\n\nexport type BitbucketAuthCallbackResult = {\n data: {\n token: string;\n };\n};\n\nexport type BitbucketListReposResult = {\n data: BitbucketRepository[];\n};\n\nexport type BitbucketCheckConfigBody = {\n token?: string;\n workspace: string;\n repoSlug: string;\n branch?: string;\n};\n\nexport type BitbucketCheckConfigResult = {\n data: {\n hasConfig: boolean;\n configPaths: string[];\n };\n};\n\nexport type BitbucketGetConfigFileBody = {\n token?: string;\n workspace: string;\n repoSlug: string;\n branch?: string;\n path?: string;\n};\n\nexport type BitbucketGetConfigFileResult = {\n data: {\n content: string;\n };\n};\n\nexport type BitbucketGetAuthUrlResult = {\n data: {\n authUrl: string;\n };\n};\n\n/** Prefix of the routes, checked against the backend contract. */\nconst bitbucketGroup = {\n prefix: '/api/bitbucket',\n} as const satisfies Pick<typeof bitbucketContract, '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 bitbucketEndpoints = {\n getAuthUrl: { method: 'GET', path: '/auth-url' },\n authCallback: { method: 'POST', path: '/auth' },\n listRepos: { method: 'GET', path: '/repos' },\n checkConfig: { method: 'POST', path: '/check-config' },\n getConfigFile: { method: 'POST', path: '/get-config-file' },\n} as const satisfies RouteEndpoints<BitbucketRoutes>;\n\nexport const getBitbucketAPI = (\n authAPIOptions: FetcherOptions = {},\n intlayerConfig?: IntlayerConfig\n) => {\n const backendURL =\n intlayerConfig?.editor?.backendURL ?? editor.backendURL ?? BACKEND_URL;\n\n /**\n * Get Bitbucket OAuth authorization URL\n * @param redirectUri - Redirect URI after OAuth authorization\n */\n const getAuthUrl = async (\n redirectUri: string,\n otherOptions: FetcherOptions = {}\n ) =>\n await fetcher<BitbucketGetAuthUrlResult>(\n buildRouteURL(backendURL, bitbucketGroup, bitbucketEndpoints.getAuthUrl),\n authAPIOptions,\n otherOptions,\n {\n params: { redirectUri },\n }\n );\n\n /**\n * Exchange Bitbucket authorization code for access token\n * @param code - Bitbucket authorization code\n */\n const authenticate = async (\n code: string,\n otherOptions: FetcherOptions = {}\n ) =>\n await fetcher<BitbucketAuthCallbackResult>(\n buildRouteURL(\n backendURL,\n bitbucketGroup,\n bitbucketEndpoints.authCallback\n ),\n authAPIOptions,\n otherOptions,\n {\n method: bitbucketEndpoints.authCallback.method,\n body: { code },\n }\n );\n\n /**\n * Get user's Bitbucket repositories\n * @param token - Optional Bitbucket access token. If not provided, backend will use session.\n */\n const getRepositories = async (\n token?: string | null,\n otherOptions: FetcherOptions = {}\n ) =>\n await fetcher<BitbucketListReposResult>(\n buildRouteURL(backendURL, bitbucketGroup, bitbucketEndpoints.listRepos),\n authAPIOptions,\n otherOptions,\n {\n params: token ? { token } : undefined,\n }\n );\n\n /**\n * Check if intlayer.config.ts exists in a Bitbucket repository\n * @param token - Optional Bitbucket access token. If not provided, backend will use session.\n * @param workspace - Bitbucket workspace slug\n * @param repoSlug - Repository slug\n * @param branch - Branch name (default: 'main')\n */\n const checkIntlayerConfig = async (\n token: string | null | undefined,\n workspace: string,\n repoSlug: string,\n branch: string = 'main',\n otherOptions: FetcherOptions = {}\n ) =>\n await fetcher<BitbucketCheckConfigResult>(\n buildRouteURL(backendURL, bitbucketGroup, bitbucketEndpoints.checkConfig),\n authAPIOptions,\n otherOptions,\n {\n method: bitbucketEndpoints.checkConfig.method,\n body: { token: token ?? undefined, workspace, repoSlug, branch },\n }\n );\n\n /**\n * Get intlayer.config.ts file contents from a Bitbucket repository\n * @param token - Optional Bitbucket access token. If not provided, backend will use session.\n * @param workspace - Bitbucket workspace slug\n * @param repoSlug - Repository slug\n * @param branch - Branch name (default: 'main')\n * @param path - File path (default: 'intlayer.config.ts')\n */\n const getConfigFile = async (\n token: string | null | undefined,\n workspace: string,\n repoSlug: string,\n branch: string = 'main',\n path: string = 'intlayer.config.ts',\n otherOptions: FetcherOptions = {}\n ) =>\n await fetcher<BitbucketGetConfigFileResult>(\n buildRouteURL(\n backendURL,\n bitbucketGroup,\n bitbucketEndpoints.getConfigFile\n ),\n authAPIOptions,\n otherOptions,\n {\n method: bitbucketEndpoints.getConfigFile.method,\n body: {\n token: token ?? undefined,\n workspace,\n repoSlug,\n branch,\n path,\n },\n }\n );\n\n return {\n getAuthUrl,\n authenticate,\n getRepositories,\n checkIntlayerConfig,\n getConfigFile,\n };\n};\n\n/**\n * Authenticated `bitbucket` 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 bitbucketEndpoint = createEndpoint(getBitbucketAPI);\n"],"mappings":";;;;;;;;AAyFA,MAAM,iBAAiB,EACrB,QAAQ,iBACV;;;;;AAMA,MAAM,qBAAqB;CACzB,YAAY;EAAE,QAAQ;EAAO,MAAM;CAAY;CAC/C,cAAc;EAAE,QAAQ;EAAQ,MAAM;CAAQ;CAC9C,WAAW;EAAE,QAAQ;EAAO,MAAM;CAAS;CAC3C,aAAa;EAAE,QAAQ;EAAQ,MAAM;CAAgB;CACrD,eAAe;EAAE,QAAQ;EAAQ,MAAM;CAAmB;AAC5D;AAEA,MAAa,mBACX,iBAAiC,CAAC,GAClC,mBACG;CACH,MAAM,aACJ,gBAAgB,QAAQ,cAAc,OAAO,cAAc;;;;;CAM7D,MAAM,aAAa,OACjB,aACA,eAA+B,CAAC,MAEhC,MAAM,QACJ,cAAc,YAAY,gBAAgB,mBAAmB,UAAU,GACvE,gBACA,cACA,EACE,QAAQ,EAAE,YAAY,EACxB,CACF;;;;;CAMF,MAAM,eAAe,OACnB,MACA,eAA+B,CAAC,MAEhC,MAAM,QACJ,cACE,YACA,gBACA,mBAAmB,YACrB,GACA,gBACA,cACA;EACE,QAAQ,mBAAmB,aAAa;EACxC,MAAM,EAAE,KAAK;CACf,CACF;;;;;CAMF,MAAM,kBAAkB,OACtB,OACA,eAA+B,CAAC,MAEhC,MAAM,QACJ,cAAc,YAAY,gBAAgB,mBAAmB,SAAS,GACtE,gBACA,cACA,EACE,QAAQ,QAAQ,EAAE,MAAM,IAAI,OAC9B,CACF;;;;;;;;CASF,MAAM,sBAAsB,OAC1B,OACA,WACA,UACA,SAAiB,QACjB,eAA+B,CAAC,MAEhC,MAAM,QACJ,cAAc,YAAY,gBAAgB,mBAAmB,WAAW,GACxE,gBACA,cACA;EACE,QAAQ,mBAAmB,YAAY;EACvC,MAAM;GAAE,OAAO,SAAS;GAAW;GAAW;GAAU;EAAO;CACjE,CACF;;;;;;;;;CAUF,MAAM,gBAAgB,OACpB,OACA,WACA,UACA,SAAiB,QACjB,OAAe,sBACf,eAA+B,CAAC,MAEhC,MAAM,QACJ,cACE,YACA,gBACA,mBAAmB,aACrB,GACA,gBACA,cACA;EACE,QAAQ,mBAAmB,cAAc;EACzC,MAAM;GACJ,OAAO,SAAS;GAChB;GACA;GACA;GACA;EACF;CACF,CACF;CAEF,OAAO;EACL;EACA;EACA;EACA;EACA;CACF;AACF;;;;;;;AAQA,MAAa,oBAAoB,eAAe,eAAe"}
@@ -0,0 +1,18 @@
1
+ import { createEndpoint } from "../cms/createIntlayerCMS.mjs";
2
+ import { createForgeAPI } from "./forge.mjs";
3
+
4
+ // src/getIntlayerAPI/codeberg.ts
5
+ /** Prefix of the routes, checked against the backend contract. */
6
+ const codebergGroup = { prefix: "/api/codeberg" };
7
+ /** Codeberg (Forgejo) repositories of the linked account. */
8
+ const getCodebergAPI = createForgeAPI(codebergGroup);
9
+ /**
10
+ * Authenticated `codeberg` endpoint bound to an Intlayer CMS authenticator.
11
+ *
12
+ * Pass an authenticator created with `createIntlayerCMS`, or omit it to use
13
+ * the build-time configuration (`@intlayer/config/built`).
14
+ */
15
+ const codebergEndpoint = createEndpoint(getCodebergAPI);
16
+
17
+ export { codebergEndpoint, getCodebergAPI };
18
+ //# sourceMappingURL=codeberg.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"codeberg.mjs","names":[],"sources":["../../../src/getIntlayerAPI/codeberg.ts"],"sourcesContent":["import type { codebergContract } from '@intlayer/backend-contract/gitProviders';\nimport { createEndpoint } from '../cms/createIntlayerCMS';\nimport { createForgeAPI } from './forge';\n\n/** Prefix of the routes, checked against the backend contract. */\nconst codebergGroup = {\n prefix: '/api/codeberg',\n} as const satisfies Pick<typeof codebergContract, 'prefix'>;\n\n/** Codeberg (Forgejo) repositories of the linked account. */\nexport const getCodebergAPI = createForgeAPI(codebergGroup);\n\n/**\n * Authenticated `codeberg` 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 codebergEndpoint = createEndpoint(getCodebergAPI);\n"],"mappings":";;;;;AAKA,MAAM,gBAAgB,EACpB,QAAQ,gBACV;;AAGA,MAAa,iBAAiB,eAAe,aAAa;;;;;;;AAQ1D,MAAa,mBAAmB,eAAe,cAAc"}