@camunda/ccma-api 3.1.0 → 4.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (44) hide show
  1. package/dist/index.d.ts +11 -7
  2. package/dist/index.js +4 -0
  3. package/dist/index.js.map +2 -2
  4. package/dist/services/accounts/approvals.m2m.service.d.ts +157 -0
  5. package/dist/services/accounts/approvals.m2m.service.js +226 -0
  6. package/dist/services/accounts/approvals.m2m.service.js.map +2 -2
  7. package/dist/services/accounts/hdp.service.d.ts +16 -3
  8. package/dist/services/accounts/hdp.service.js +45 -2
  9. package/dist/services/accounts/hdp.service.js.map +2 -2
  10. package/dist/services/console/console.approvals.m2m.service.d.ts +12 -1
  11. package/dist/services/console/console.approvals.m2m.service.js +31 -0
  12. package/dist/services/console/console.approvals.m2m.service.js.map +2 -2
  13. package/dist/services/control/control.approvals.service.d.ts +276 -0
  14. package/dist/services/control/control.approvals.service.js +155 -0
  15. package/dist/services/control/control.approvals.service.js.map +2 -2
  16. package/dist/services/control/control.dashboards.service.d.ts +76 -0
  17. package/dist/services/control/control.dashboards.service.js +180 -0
  18. package/dist/services/control/control.dashboards.service.js.map +7 -0
  19. package/dist/services/control/control.dashboards.service.spec.d.ts +1 -0
  20. package/dist/services/control/control.feature-flags.service.d.ts +53 -0
  21. package/dist/services/control/control.feature-flags.service.js +123 -0
  22. package/dist/services/control/control.feature-flags.service.js.map +7 -0
  23. package/dist/services/control/control.feature-flags.service.spec.d.ts +1 -0
  24. package/dist/services/control/control.platform.service.d.ts +14 -0
  25. package/dist/services/control/control.platform.service.js +27 -0
  26. package/dist/services/control/control.platform.service.js.map +2 -2
  27. package/dist/services/control/control.platform.service.spec.d.ts +1 -0
  28. package/dist/services/external/external.accounts.service.d.ts +2 -2
  29. package/dist/services/external/external.accounts.service.js.map +2 -2
  30. package/dist/services/github/github.service.d.ts +20 -0
  31. package/dist/services/github/github.service.js +50 -1
  32. package/dist/services/github/github.service.js.map +2 -2
  33. package/dist/services/openrouter/openrouter.service.d.ts +35 -0
  34. package/dist/services/openrouter/openrouter.service.js +45 -0
  35. package/dist/services/openrouter/openrouter.service.js.map +2 -2
  36. package/dist/services/slack/slack-blockkit.service.d.ts +7 -0
  37. package/dist/services/slack/slack-blockkit.service.js +1 -0
  38. package/dist/services/slack/slack-blockkit.service.js.map +2 -2
  39. package/dist/utils/environments.js +3 -4
  40. package/dist/utils/environments.js.map +2 -2
  41. package/dist/utils/sse.d.ts +1 -0
  42. package/dist/utils/sse.js +7 -0
  43. package/dist/utils/sse.js.map +2 -2
  44. package/package.json +2 -2
@@ -169,7 +169,10 @@ class GithubService {
169
169
  tag_name: release.tag_name,
170
170
  body: release.body,
171
171
  created_at: release.created_at,
172
- prerelease: release.prerelease
172
+ prerelease: release.prerelease,
173
+ html_url: release.html_url,
174
+ published_at: release.published_at ?? void 0,
175
+ draft: release.draft
173
176
  };
174
177
  });
175
178
  }
@@ -275,6 +278,52 @@ class GithubService {
275
278
  }
276
279
  return response.body ?? "";
277
280
  }
281
+ static async compareCommits(params) {
282
+ const encodeRef = (ref) => encodeURIComponent(ref).replace(/%2F/gu, "/");
283
+ const base = encodeRef(params.options.base);
284
+ const head = encodeRef(params.options.head);
285
+ const serviceContext = {
286
+ method: {
287
+ name: `GithubService.compareCommits`,
288
+ // per_page=1: callers read the counts, not the commit list.
289
+ url: `https://api.github.com/repos/${params.options.owner}/${params.options.repo}/compare/${base}...${head}?per_page=1`,
290
+ normalizedUrl: `https://api.github.com/repos/:owner/:repo/compare/:basehead`,
291
+ type: "get"
292
+ },
293
+ source: params.config.metrics?.source || "unset",
294
+ target: {
295
+ name: "github",
296
+ type: "external"
297
+ }
298
+ };
299
+ const response = await request({
300
+ config: params.config,
301
+ url: serviceContext.method.url,
302
+ method: serviceContext.method.type,
303
+ metricsDetails: serviceContext,
304
+ type: "json",
305
+ headers: {
306
+ Accept: "application/vnd.github+json",
307
+ Authorization: `Bearer ${params.options.apiToken}`
308
+ }
309
+ });
310
+ if (!response.ok) {
311
+ throw new HttpError(
312
+ `${serviceContext.method.name}: ${response.status} ${response.statusText}`,
313
+ response.status,
314
+ response.statusText
315
+ );
316
+ }
317
+ const aheadBy = response.body?.ahead_by;
318
+ if (typeof aheadBy !== "number") {
319
+ throw new HttpError(
320
+ `${serviceContext.method.name}: no ahead_by in the answer`,
321
+ response.status,
322
+ response.statusText
323
+ );
324
+ }
325
+ return { aheadBy, htmlUrl: response.body?.html_url ?? "" };
326
+ }
278
327
  }
279
328
  export {
280
329
  GithubService
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/services/github/github.service.ts"],
4
- "sourcesContent": ["/*\n * Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH\n * under one or more contributor license agreements. Licensed under a commercial license.\n * You may not use this file except in compliance with the commercial license.\n */\n\nimport { HOUR } from '@camunda/ccma-shared-types'\nimport type {\n RequestBaseParams,\n RequestBaseServiceContext,\n} from '../../types/general.types.js'\nimport { request } from '../../utils/api.js'\nimport { Cache } from '../../utils/cache.js'\nimport { HttpError } from '../../utils/errors.js'\n\nconst releaseCache = new Cache<string, GithubRelease[]>(HOUR)\n\n/**\n * How many release pages are fetched at once.\n *\n * GitHub's *secondary* rate limit is about concurrency, not a request budget:\n * firing every iteration in one `Promise.all` is what answered\n * `GET /api/releases/release-train/:trainName` with \"You have exceeded a\n * secondary rate limit\". Batching keeps the walk parallel enough to stay fast\n * while bounding how much of it is in flight.\n */\nconst PAGE_BATCH_SIZE = 5\n\nexport interface GithubListMajorMinorReleasesRequest extends RequestBaseParams {\n options: {\n owner: string\n repo: string\n apiToken: string\n iterations?: number\n onlyLatest?: boolean\n includeAlphas?: boolean\n onlyPrerelease?: boolean\n replaceBugfixSuffix?: boolean\n }\n}\n\nexport interface GithubListReleasesRequest extends RequestBaseParams {\n options: {\n owner: string\n repo: string\n apiToken: string\n pageSize?: number\n currentPage?: number\n }\n}\n\nexport interface GithubGetNextBugfixReleaseVersionRequest\n extends RequestBaseParams {\n options: {\n owner: string\n repo: string\n apiToken: string\n iterations?: number\n onlyLatest?: boolean\n majorMinor: string\n }\n}\n\nexport interface GithubRelease {\n url: string\n tag_name: string\n body: string\n created_at: string\n prerelease: boolean\n}\n\nexport interface GithubListDirectoryContentRequest extends RequestBaseParams {\n options: {\n owner: string\n repo: string\n apiToken: string\n path: string\n ref?: string\n }\n}\n\nexport interface GithubGetRawFileRequest extends RequestBaseParams {\n options: {\n owner: string\n repo: string\n apiToken: string\n path: string\n ref?: string\n }\n}\n\nexport interface GithubContentItem {\n name: string\n path: string\n sha: string\n size: number\n url: string\n download_url: string | undefined\n type: string\n}\n\nexport class GithubService {\n public static async getNextBugfixReleaseVersion(\n params: GithubGetNextBugfixReleaseVersionRequest,\n ): Promise<string> {\n const releases = await GithubService.listMajorMinorReleases({\n config: params.config,\n options: {\n owner: params.options.owner,\n repo: params.options.repo,\n apiToken: params.options.apiToken,\n onlyLatest: true,\n iterations: params.options.iterations,\n },\n })\n if (releases.length === 0) {\n throw new Error(\n `No releases found for ${params.options.owner}/${params.options.repo}`,\n )\n }\n const latestRelease = releases[0]\n if (latestRelease.tag_name.startsWith(params.options.majorMinor)) {\n throw new Error(\n `Not allowed to create a new bugfix release for ${latestRelease.tag_name}`,\n )\n }\n for (const release of releases) {\n if (release.tag_name.startsWith(params.options.majorMinor)) {\n const versionSplitted = release.tag_name.split('.')\n if (versionSplitted.length !== 3) {\n throw new Error(`Invalid version format: ${release.tag_name}`)\n }\n const majorVersion = Number(versionSplitted[0])\n const minorVersion = Number(versionSplitted[1])\n const patchVersion = Number(versionSplitted[2]) + 1\n return `${majorVersion}.${minorVersion}.${patchVersion}`\n }\n }\n throw new Error(`No bugfix release found for ${params.options.majorMinor}`)\n }\n\n public static async listMajorMinorReleases(\n params: GithubListMajorMinorReleasesRequest,\n ): Promise<GithubRelease[]> {\n // `replaceBugfixSuffix` rewrites the tags in the result, so it has to be\n // part of the key: without it `getNextBugfixReleaseVersion` (which does not\n // set it) and the release-train lookup (which does) shared one entry and\n // whichever loaded first decided what the other saw.\n const cacheKey = `major-minor-${params.options.owner}-${\n params.options.repo\n }-${params.options.onlyLatest ?? false}-${\n params.options.includeAlphas ?? false\n }-${params.options.onlyPrerelease ?? false}-${\n params.options.replaceBugfixSuffix ?? false\n }`\n // Single-flight: several trains are looked up at once and they all land on\n // this key, so without coalescing each concurrent miss ran its own page\n // walk against GitHub.\n return releaseCache.getOrLoad(\n cacheKey,\n () => GithubService.fetchMajorMinorReleases(params),\n { ignoreCache: params.cacheControl?.ignoreCache === true },\n )\n }\n\n private static async fetchMajorMinorReleases(\n params: GithubListMajorMinorReleasesRequest,\n ): Promise<GithubRelease[]> {\n const pageSize = 100\n const ITERATIONS = params.options.iterations || 15\n\n // Walk the pages in bounded-concurrency batches and stop as soon as a page\n // comes back short \u2014 GitHub only returns fewer than `per_page` items on the\n // last page, so every iteration after that was an empty response whose only\n // effect was upstream load.\n const allPageResults: GithubRelease[][] = []\n for (\n let firstPage = 1;\n firstPage <= ITERATIONS;\n firstPage += PAGE_BATCH_SIZE\n ) {\n const batchSize = Math.min(PAGE_BATCH_SIZE, ITERATIONS - firstPage + 1)\n // eslint-disable-next-line no-await-in-loop\n const batch = await Promise.all(\n Array.from({ length: batchSize }, (_, index) =>\n GithubService.getReleases({\n config: params.config,\n options: {\n owner: params.options.owner,\n repo: params.options.repo,\n apiToken: params.options.apiToken,\n pageSize,\n currentPage: firstPage + index,\n },\n }),\n ),\n )\n allPageResults.push(...batch)\n if (batch.some((releases) => releases.length < pageSize)) {\n break\n }\n }\n\n const stableReleases: GithubRelease[] = []\n for (const releases of allPageResults) {\n // replace bugfix suffix\n if (params.options.replaceBugfixSuffix === true) {\n releases.forEach((release) => {\n if (release.tag_name.endsWith('_bugfix')) {\n release.tag_name = release.tag_name.replace(/_bugfix.*/u, '')\n }\n })\n }\n\n const filtered = releases.filter((release) => {\n let includeRelease = !release.prerelease\n if (params.options.onlyPrerelease) {\n includeRelease = release.prerelease\n }\n if (includeRelease && params.options.includeAlphas) {\n includeRelease =\n release.tag_name.includes('-alpha') &&\n !release.tag_name.includes('-alphatest')\n }\n return includeRelease\n })\n stableReleases.push(...filtered)\n }\n\n let releasesToRespond: GithubRelease[] = []\n\n stableReleases.sort((a, b) => {\n return new Date(b.created_at).getTime() - new Date(a.created_at).getTime()\n })\n\n if (params.options.onlyLatest) {\n const onlyLatest: Record<string, number> = {}\n for (const release of stableReleases) {\n const splitted = release.tag_name.split('.')\n const majorMinor = `${splitted[0]}.${splitted[1]}`\n const patchVersion = Number(splitted[2])\n if (!onlyLatest[majorMinor]) {\n onlyLatest[majorMinor] = patchVersion\n } else if (patchVersion > onlyLatest[majorMinor]) {\n onlyLatest[majorMinor] = patchVersion\n }\n }\n const releaseStrings = Object.keys(onlyLatest).map((key) => {\n return `${key}.${onlyLatest[key]}`\n })\n const foundReleases = stableReleases.filter((release) => {\n return releaseStrings.includes(release.tag_name)\n })\n releasesToRespond = foundReleases\n } else {\n releasesToRespond = stableReleases\n }\n // Storing is `getOrLoad`'s job \u2014 it only caches a load that resolved.\n return releasesToRespond\n }\n\n public static async getReleases(\n params: GithubListReleasesRequest,\n ): Promise<GithubRelease[]> {\n const pageSize = params.options.pageSize || 100\n const currentPage = params.options.currentPage || 1\n const queryParams = new URLSearchParams()\n queryParams.append('per_page', pageSize.toString())\n queryParams.append('page', currentPage.toString())\n const serviceContext: RequestBaseServiceContext = {\n method: {\n name: `GithubService.getReleases`,\n url: `https://api.github.com/repos/${params.options.owner}/${\n params.options.repo\n }/releases?${queryParams.toString()}`,\n normalizedUrl: `https://api.github.com/repos/:owner/:repo`,\n type: 'get',\n },\n source: params.config.metrics?.source || 'unset',\n target: {\n name: 'github',\n type: 'external',\n },\n }\n\n const response = await request<GithubRelease[]>({\n config: params.config,\n url: serviceContext.method.url,\n method: serviceContext.method.type,\n metricsDetails: serviceContext,\n type: 'json',\n headers: {\n Accept: 'application/vnd.github+json',\n Authorization: `Bearer ${params.options.apiToken}`,\n },\n })\n if (!response.ok) {\n throw new HttpError(\n `${serviceContext.method.name}: ${response.status} ${response.statusText}`,\n response.status,\n response.statusText,\n )\n }\n\n let releases: GithubRelease[] = []\n if (response.body) {\n releases = response.body.map((release) => {\n return {\n url: release.url,\n tag_name: release.tag_name,\n body: release.body,\n created_at: release.created_at,\n prerelease: release.prerelease,\n }\n })\n }\n return releases\n }\n\n public static async listDirectoryContent(\n params: GithubListDirectoryContentRequest,\n ): Promise<GithubContentItem[]> {\n const queryParams = new URLSearchParams()\n if (params.options.ref) {\n queryParams.append('ref', params.options.ref)\n }\n const encodedPath = encodeURIComponent(params.options.path).replace(\n /%2F/gu,\n '/',\n )\n const serviceContext: RequestBaseServiceContext = {\n method: {\n name: `GithubService.listDirectoryContent`,\n url: `https://api.github.com/repos/${params.options.owner}/${\n params.options.repo\n }/contents/${encodedPath}${queryParams.size ? `?${queryParams.toString()}` : ''}`,\n normalizedUrl: `https://api.github.com/repos/:owner/:repo/contents/:path`,\n type: 'get',\n },\n source: params.config.metrics?.source || 'unset',\n target: {\n name: 'github',\n type: 'external',\n },\n }\n\n const response = await request<any[]>({\n config: params.config,\n url: serviceContext.method.url,\n method: serviceContext.method.type,\n metricsDetails: serviceContext,\n type: 'json',\n headers: {\n Accept: 'application/vnd.github+json',\n Authorization: `Bearer ${params.options.apiToken}`,\n },\n })\n if (!response.ok) {\n throw new HttpError(\n `${serviceContext.method.name}: ${response.status} ${response.statusText}`,\n response.status,\n response.statusText,\n )\n }\n\n let items: GithubContentItem[] = []\n if (Array.isArray(response.body)) {\n items = response.body.map((item: any) => {\n return {\n name: item.name,\n path: item.path,\n sha: item.sha,\n size: item.size,\n url: item.url,\n download_url: item.download_url,\n type: item.type,\n } as GithubContentItem\n })\n }\n return items\n }\n\n public static async getRawFile(\n params: GithubGetRawFileRequest,\n ): Promise<string> {\n const queryParams = new URLSearchParams()\n if (params.options.ref) {\n queryParams.append('ref', params.options.ref)\n }\n const encodedPath = encodeURIComponent(params.options.path).replace(\n /%2F/gu,\n '/',\n )\n const serviceContext: RequestBaseServiceContext = {\n method: {\n name: `GithubService.getRawFile`,\n url: `https://api.github.com/repos/${params.options.owner}/${\n params.options.repo\n }/contents/${encodedPath}${queryParams.size ? `?${queryParams.toString()}` : ''}`,\n normalizedUrl: `https://api.github.com/repos/:owner/:repo/contents/:path`,\n type: 'get',\n },\n source: params.config.metrics?.source || 'unset',\n target: {\n name: 'github',\n type: 'external',\n },\n }\n\n const response = await request<string>({\n config: params.config,\n url: serviceContext.method.url,\n method: serviceContext.method.type,\n metricsDetails: serviceContext,\n // do not set a Content-Type for GET, but expect text back\n type: 'none',\n responseType: 'text',\n headers: {\n Accept: 'application/vnd.github.raw',\n Authorization: `Bearer ${params.options.apiToken}`,\n },\n })\n if (!response.ok) {\n throw new HttpError(\n `${serviceContext.method.name}: ${response.status} ${response.statusText}`,\n response.status,\n response.statusText,\n )\n }\n return response.body ?? ''\n }\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["/*\n * Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH\n * under one or more contributor license agreements. Licensed under a commercial license.\n * You may not use this file except in compliance with the commercial license.\n */\n\nimport { HOUR } from '@camunda/ccma-shared-types'\nimport type {\n RequestBaseParams,\n RequestBaseServiceContext,\n} from '../../types/general.types.js'\nimport { request } from '../../utils/api.js'\nimport { Cache } from '../../utils/cache.js'\nimport { HttpError } from '../../utils/errors.js'\n\nconst releaseCache = new Cache<string, GithubRelease[]>(HOUR)\n\n/**\n * How many release pages are fetched at once.\n *\n * GitHub's *secondary* rate limit is about concurrency, not a request budget:\n * firing every iteration in one `Promise.all` is what answered\n * `GET /api/releases/release-train/:trainName` with \"You have exceeded a\n * secondary rate limit\". Batching keeps the walk parallel enough to stay fast\n * while bounding how much of it is in flight.\n */\nconst PAGE_BATCH_SIZE = 5\n\nexport interface GithubListMajorMinorReleasesRequest extends RequestBaseParams {\n options: {\n owner: string\n repo: string\n apiToken: string\n iterations?: number\n onlyLatest?: boolean\n includeAlphas?: boolean\n onlyPrerelease?: boolean\n replaceBugfixSuffix?: boolean\n }\n}\n\nexport interface GithubListReleasesRequest extends RequestBaseParams {\n options: {\n owner: string\n repo: string\n apiToken: string\n pageSize?: number\n currentPage?: number\n }\n}\n\nexport interface GithubGetNextBugfixReleaseVersionRequest\n extends RequestBaseParams {\n options: {\n owner: string\n repo: string\n apiToken: string\n iterations?: number\n onlyLatest?: boolean\n majorMinor: string\n }\n}\n\nexport interface GithubRelease {\n url: string\n tag_name: string\n body: string\n /** The date of the tagged commit, not of the release. */\n created_at: string\n prerelease: boolean\n html_url?: string\n /** When the release was made. A draft has none. */\n published_at?: string | undefined\n draft?: boolean\n}\n\nexport interface GithubListDirectoryContentRequest extends RequestBaseParams {\n options: {\n owner: string\n repo: string\n apiToken: string\n path: string\n ref?: string\n }\n}\n\nexport interface GithubGetRawFileRequest extends RequestBaseParams {\n options: {\n owner: string\n repo: string\n apiToken: string\n path: string\n ref?: string\n }\n}\n\nexport interface GithubContentItem {\n name: string\n path: string\n sha: string\n size: number\n url: string\n download_url: string | undefined\n type: string\n}\n\nexport interface GithubCompareCommitsRequest extends RequestBaseParams {\n options: {\n owner: string\n repo: string\n apiToken: string\n base: string\n head: string\n }\n}\n\nexport interface GithubCommitComparison {\n /** Commits that `head` has and `base` does not have. */\n aheadBy: number\n htmlUrl: string\n}\n\nexport class GithubService {\n public static async getNextBugfixReleaseVersion(\n params: GithubGetNextBugfixReleaseVersionRequest,\n ): Promise<string> {\n const releases = await GithubService.listMajorMinorReleases({\n config: params.config,\n options: {\n owner: params.options.owner,\n repo: params.options.repo,\n apiToken: params.options.apiToken,\n onlyLatest: true,\n iterations: params.options.iterations,\n },\n })\n if (releases.length === 0) {\n throw new Error(\n `No releases found for ${params.options.owner}/${params.options.repo}`,\n )\n }\n const latestRelease = releases[0]\n if (latestRelease.tag_name.startsWith(params.options.majorMinor)) {\n throw new Error(\n `Not allowed to create a new bugfix release for ${latestRelease.tag_name}`,\n )\n }\n for (const release of releases) {\n if (release.tag_name.startsWith(params.options.majorMinor)) {\n const versionSplitted = release.tag_name.split('.')\n if (versionSplitted.length !== 3) {\n throw new Error(`Invalid version format: ${release.tag_name}`)\n }\n const majorVersion = Number(versionSplitted[0])\n const minorVersion = Number(versionSplitted[1])\n const patchVersion = Number(versionSplitted[2]) + 1\n return `${majorVersion}.${minorVersion}.${patchVersion}`\n }\n }\n throw new Error(`No bugfix release found for ${params.options.majorMinor}`)\n }\n\n public static async listMajorMinorReleases(\n params: GithubListMajorMinorReleasesRequest,\n ): Promise<GithubRelease[]> {\n // `replaceBugfixSuffix` rewrites the tags in the result, so it has to be\n // part of the key: without it `getNextBugfixReleaseVersion` (which does not\n // set it) and the release-train lookup (which does) shared one entry and\n // whichever loaded first decided what the other saw.\n const cacheKey = `major-minor-${params.options.owner}-${\n params.options.repo\n }-${params.options.onlyLatest ?? false}-${\n params.options.includeAlphas ?? false\n }-${params.options.onlyPrerelease ?? false}-${\n params.options.replaceBugfixSuffix ?? false\n }`\n // Single-flight: several trains are looked up at once and they all land on\n // this key, so without coalescing each concurrent miss ran its own page\n // walk against GitHub.\n return releaseCache.getOrLoad(\n cacheKey,\n () => GithubService.fetchMajorMinorReleases(params),\n { ignoreCache: params.cacheControl?.ignoreCache === true },\n )\n }\n\n private static async fetchMajorMinorReleases(\n params: GithubListMajorMinorReleasesRequest,\n ): Promise<GithubRelease[]> {\n const pageSize = 100\n const ITERATIONS = params.options.iterations || 15\n\n // Walk the pages in bounded-concurrency batches and stop as soon as a page\n // comes back short \u2014 GitHub only returns fewer than `per_page` items on the\n // last page, so every iteration after that was an empty response whose only\n // effect was upstream load.\n const allPageResults: GithubRelease[][] = []\n for (\n let firstPage = 1;\n firstPage <= ITERATIONS;\n firstPage += PAGE_BATCH_SIZE\n ) {\n const batchSize = Math.min(PAGE_BATCH_SIZE, ITERATIONS - firstPage + 1)\n // eslint-disable-next-line no-await-in-loop\n const batch = await Promise.all(\n Array.from({ length: batchSize }, (_, index) =>\n GithubService.getReleases({\n config: params.config,\n options: {\n owner: params.options.owner,\n repo: params.options.repo,\n apiToken: params.options.apiToken,\n pageSize,\n currentPage: firstPage + index,\n },\n }),\n ),\n )\n allPageResults.push(...batch)\n if (batch.some((releases) => releases.length < pageSize)) {\n break\n }\n }\n\n const stableReleases: GithubRelease[] = []\n for (const releases of allPageResults) {\n // replace bugfix suffix\n if (params.options.replaceBugfixSuffix === true) {\n releases.forEach((release) => {\n if (release.tag_name.endsWith('_bugfix')) {\n release.tag_name = release.tag_name.replace(/_bugfix.*/u, '')\n }\n })\n }\n\n const filtered = releases.filter((release) => {\n let includeRelease = !release.prerelease\n if (params.options.onlyPrerelease) {\n includeRelease = release.prerelease\n }\n if (includeRelease && params.options.includeAlphas) {\n includeRelease =\n release.tag_name.includes('-alpha') &&\n !release.tag_name.includes('-alphatest')\n }\n return includeRelease\n })\n stableReleases.push(...filtered)\n }\n\n let releasesToRespond: GithubRelease[] = []\n\n stableReleases.sort((a, b) => {\n return new Date(b.created_at).getTime() - new Date(a.created_at).getTime()\n })\n\n if (params.options.onlyLatest) {\n const onlyLatest: Record<string, number> = {}\n for (const release of stableReleases) {\n const splitted = release.tag_name.split('.')\n const majorMinor = `${splitted[0]}.${splitted[1]}`\n const patchVersion = Number(splitted[2])\n if (!onlyLatest[majorMinor]) {\n onlyLatest[majorMinor] = patchVersion\n } else if (patchVersion > onlyLatest[majorMinor]) {\n onlyLatest[majorMinor] = patchVersion\n }\n }\n const releaseStrings = Object.keys(onlyLatest).map((key) => {\n return `${key}.${onlyLatest[key]}`\n })\n const foundReleases = stableReleases.filter((release) => {\n return releaseStrings.includes(release.tag_name)\n })\n releasesToRespond = foundReleases\n } else {\n releasesToRespond = stableReleases\n }\n // Storing is `getOrLoad`'s job \u2014 it only caches a load that resolved.\n return releasesToRespond\n }\n\n public static async getReleases(\n params: GithubListReleasesRequest,\n ): Promise<GithubRelease[]> {\n const pageSize = params.options.pageSize || 100\n const currentPage = params.options.currentPage || 1\n const queryParams = new URLSearchParams()\n queryParams.append('per_page', pageSize.toString())\n queryParams.append('page', currentPage.toString())\n const serviceContext: RequestBaseServiceContext = {\n method: {\n name: `GithubService.getReleases`,\n url: `https://api.github.com/repos/${params.options.owner}/${\n params.options.repo\n }/releases?${queryParams.toString()}`,\n normalizedUrl: `https://api.github.com/repos/:owner/:repo`,\n type: 'get',\n },\n source: params.config.metrics?.source || 'unset',\n target: {\n name: 'github',\n type: 'external',\n },\n }\n\n const response = await request<\n (Omit<GithubRelease, 'published_at'> & { published_at: string | null })[]\n >({\n config: params.config,\n url: serviceContext.method.url,\n method: serviceContext.method.type,\n metricsDetails: serviceContext,\n type: 'json',\n headers: {\n Accept: 'application/vnd.github+json',\n Authorization: `Bearer ${params.options.apiToken}`,\n },\n })\n if (!response.ok) {\n throw new HttpError(\n `${serviceContext.method.name}: ${response.status} ${response.statusText}`,\n response.status,\n response.statusText,\n )\n }\n\n let releases: GithubRelease[] = []\n if (response.body) {\n releases = response.body.map((release) => {\n return {\n url: release.url,\n tag_name: release.tag_name,\n body: release.body,\n created_at: release.created_at,\n prerelease: release.prerelease,\n html_url: release.html_url,\n published_at: release.published_at ?? undefined,\n draft: release.draft,\n }\n })\n }\n return releases\n }\n\n public static async listDirectoryContent(\n params: GithubListDirectoryContentRequest,\n ): Promise<GithubContentItem[]> {\n const queryParams = new URLSearchParams()\n if (params.options.ref) {\n queryParams.append('ref', params.options.ref)\n }\n const encodedPath = encodeURIComponent(params.options.path).replace(\n /%2F/gu,\n '/',\n )\n const serviceContext: RequestBaseServiceContext = {\n method: {\n name: `GithubService.listDirectoryContent`,\n url: `https://api.github.com/repos/${params.options.owner}/${\n params.options.repo\n }/contents/${encodedPath}${queryParams.size ? `?${queryParams.toString()}` : ''}`,\n normalizedUrl: `https://api.github.com/repos/:owner/:repo/contents/:path`,\n type: 'get',\n },\n source: params.config.metrics?.source || 'unset',\n target: {\n name: 'github',\n type: 'external',\n },\n }\n\n const response = await request<any[]>({\n config: params.config,\n url: serviceContext.method.url,\n method: serviceContext.method.type,\n metricsDetails: serviceContext,\n type: 'json',\n headers: {\n Accept: 'application/vnd.github+json',\n Authorization: `Bearer ${params.options.apiToken}`,\n },\n })\n if (!response.ok) {\n throw new HttpError(\n `${serviceContext.method.name}: ${response.status} ${response.statusText}`,\n response.status,\n response.statusText,\n )\n }\n\n let items: GithubContentItem[] = []\n if (Array.isArray(response.body)) {\n items = response.body.map((item: any) => {\n return {\n name: item.name,\n path: item.path,\n sha: item.sha,\n size: item.size,\n url: item.url,\n download_url: item.download_url,\n type: item.type,\n } as GithubContentItem\n })\n }\n return items\n }\n\n public static async getRawFile(\n params: GithubGetRawFileRequest,\n ): Promise<string> {\n const queryParams = new URLSearchParams()\n if (params.options.ref) {\n queryParams.append('ref', params.options.ref)\n }\n const encodedPath = encodeURIComponent(params.options.path).replace(\n /%2F/gu,\n '/',\n )\n const serviceContext: RequestBaseServiceContext = {\n method: {\n name: `GithubService.getRawFile`,\n url: `https://api.github.com/repos/${params.options.owner}/${\n params.options.repo\n }/contents/${encodedPath}${queryParams.size ? `?${queryParams.toString()}` : ''}`,\n normalizedUrl: `https://api.github.com/repos/:owner/:repo/contents/:path`,\n type: 'get',\n },\n source: params.config.metrics?.source || 'unset',\n target: {\n name: 'github',\n type: 'external',\n },\n }\n\n const response = await request<string>({\n config: params.config,\n url: serviceContext.method.url,\n method: serviceContext.method.type,\n metricsDetails: serviceContext,\n // do not set a Content-Type for GET, but expect text back\n type: 'none',\n responseType: 'text',\n headers: {\n Accept: 'application/vnd.github.raw',\n Authorization: `Bearer ${params.options.apiToken}`,\n },\n })\n if (!response.ok) {\n throw new HttpError(\n `${serviceContext.method.name}: ${response.status} ${response.statusText}`,\n response.status,\n response.statusText,\n )\n }\n return response.body ?? ''\n }\n\n public static async compareCommits(\n params: GithubCompareCommitsRequest,\n ): Promise<GithubCommitComparison> {\n const encodeRef = (ref: string) =>\n encodeURIComponent(ref).replace(/%2F/gu, '/')\n const base = encodeRef(params.options.base)\n const head = encodeRef(params.options.head)\n const serviceContext: RequestBaseServiceContext = {\n method: {\n name: `GithubService.compareCommits`,\n // per_page=1: callers read the counts, not the commit list.\n url: `https://api.github.com/repos/${params.options.owner}/${\n params.options.repo\n }/compare/${base}...${head}?per_page=1`,\n normalizedUrl: `https://api.github.com/repos/:owner/:repo/compare/:basehead`,\n type: 'get',\n },\n source: params.config.metrics?.source || 'unset',\n target: {\n name: 'github',\n type: 'external',\n },\n }\n\n const response = await request<{ ahead_by?: number; html_url?: string }>({\n config: params.config,\n url: serviceContext.method.url,\n method: serviceContext.method.type,\n metricsDetails: serviceContext,\n type: 'json',\n headers: {\n Accept: 'application/vnd.github+json',\n Authorization: `Bearer ${params.options.apiToken}`,\n },\n })\n if (!response.ok) {\n throw new HttpError(\n `${serviceContext.method.name}: ${response.status} ${response.statusText}`,\n response.status,\n response.statusText,\n )\n }\n // `request` gives `{}` for a body that is not JSON. A missing count must\n // not read as \"no new commits\".\n const aheadBy = response.body?.ahead_by\n if (typeof aheadBy !== 'number') {\n throw new HttpError(\n `${serviceContext.method.name}: no ahead_by in the answer`,\n response.status,\n response.statusText,\n )\n }\n\n return { aheadBy, htmlUrl: response.body?.html_url ?? '' }\n }\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -64,6 +64,11 @@ export interface CreateOpenRouterKeyRequest extends RequestBaseParams {
64
64
  limit?: number;
65
65
  /** When false, credits of a customer-owned provider key do not count. */
66
66
  include_byok_in_limit?: boolean;
67
+ /**
68
+ * UUID of the workspace that owns the key. When absent, OpenRouter puts the
69
+ * key in the default workspace of the account.
70
+ */
71
+ workspace_id?: string;
67
72
  };
68
73
  }
69
74
  /**
@@ -143,6 +148,11 @@ export interface ListOpenRouterKeysRequest extends RequestBaseParams {
143
148
  offset?: number;
144
149
  /** When true, disabled keys are part of the result. */
145
150
  includeDisabled?: boolean;
151
+ /**
152
+ * UUID of the workspace to list. When absent, OpenRouter lists the default
153
+ * workspace only, so a key in another workspace is not in the result.
154
+ */
155
+ workspace_id?: string;
146
156
  };
147
157
  }
148
158
  /**
@@ -151,6 +161,23 @@ export interface ListOpenRouterKeysRequest extends RequestBaseParams {
151
161
  export interface ListOpenRouterKeysResponse {
152
162
  data: OpenRouterKeyData[];
153
163
  }
164
+ /**
165
+ * Request to read one workspace
166
+ * GET /workspaces/{id}
167
+ */
168
+ export interface GetOpenRouterWorkspaceRequest extends RequestBaseParams {
169
+ options: OpenRouterRequestOptions & {
170
+ /** UUID of the workspace to read. */
171
+ workspaceId: string;
172
+ };
173
+ }
174
+ /**
175
+ * Response from reading one workspace. The caller needs the status code only,
176
+ * so the body stays open.
177
+ */
178
+ export interface GetOpenRouterWorkspaceResponse {
179
+ [key: string]: unknown;
180
+ }
154
181
  /**
155
182
  * Service for the key management API of OpenRouter.
156
183
  *
@@ -196,5 +223,13 @@ export declare class OpenRouterService {
196
223
  * GET /keys
197
224
  */
198
225
  static listKeys(params: ListOpenRouterKeysRequest): Promise<ListOpenRouterKeysResponse>;
226
+ /**
227
+ * Read one workspace.
228
+ *
229
+ * A 404 means that the workspace does not exist. A caller uses this to check
230
+ * a workspace id before it creates keys in that workspace.
231
+ * GET /workspaces/{id}
232
+ */
233
+ static getWorkspace(params: GetOpenRouterWorkspaceRequest): Promise<GetOpenRouterWorkspaceResponse>;
199
234
  }
200
235
  export {};
@@ -27,6 +27,9 @@ class OpenRouterService {
27
27
  },
28
28
  ...params.options.include_byok_in_limit !== void 0 && {
29
29
  include_byok_in_limit: params.options.include_byok_in_limit
30
+ },
31
+ ...params.options.workspace_id && {
32
+ workspace_id: params.options.workspace_id
30
33
  }
31
34
  };
32
35
  const response = await request({
@@ -187,6 +190,9 @@ class OpenRouterService {
187
190
  if (params.options.includeDisabled) {
188
191
  query.set("include_disabled", "true");
189
192
  }
193
+ if (params.options.workspace_id) {
194
+ query.set("workspace_id", params.options.workspace_id);
195
+ }
190
196
  const queryString = query.toString();
191
197
  const serviceContext = {
192
198
  method: {
@@ -219,6 +225,45 @@ class OpenRouterService {
219
225
  }
220
226
  return response.body;
221
227
  }
228
+ /**
229
+ * Read one workspace.
230
+ *
231
+ * A 404 means that the workspace does not exist. A caller uses this to check
232
+ * a workspace id before it creates keys in that workspace.
233
+ * GET /workspaces/{id}
234
+ */
235
+ static async getWorkspace(params) {
236
+ const serviceContext = {
237
+ method: {
238
+ name: "OpenRouterService.getWorkspace",
239
+ url: `${params.options.openRouterApiBaseUrl}/workspaces/${encodeURIComponent(params.options.workspaceId)}`,
240
+ normalizedUrl: "/workspaces/:id",
241
+ type: "get"
242
+ },
243
+ source: params.config.metrics?.source || "unset",
244
+ target: {
245
+ name: "openrouter",
246
+ type: "external"
247
+ }
248
+ };
249
+ const response = await request({
250
+ config: params.config,
251
+ url: serviceContext.method.url,
252
+ method: serviceContext.method.type,
253
+ metricsDetails: serviceContext,
254
+ headers: {
255
+ Authorization: `Bearer ${params.options.apiToken}`
256
+ }
257
+ });
258
+ if (!response.ok) {
259
+ throw new HttpError(
260
+ `${serviceContext.method.name}: ${response.status} ${response.statusText}`,
261
+ response.status,
262
+ response.statusText
263
+ );
264
+ }
265
+ return response.body ?? {};
266
+ }
222
267
  }
223
268
  export {
224
269
  OPENROUTER_KEY_PAGE_SIZE,
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/services/openrouter/openrouter.service.ts"],
4
- "sourcesContent": ["/*\n * Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH\n * under one or more contributor license agreements. Licensed under a commercial license.\n * You may not use this file except in compliance with the commercial license.\n */\n\nimport type {\n RequestBaseParams,\n RequestBaseServiceContext,\n} from '../../types/general.types.js'\nimport { request } from '../../utils/api.js'\nimport { HttpError } from '../../utils/errors.js'\n\n/**\n * Fields that every key management route of OpenRouter returns for a key.\n *\n * OpenRouter addresses a key by its `hash`, never by the key itself. The key\n * comes back exactly once, from the create route. Thus the caller must persist\n * the hash together with the key. Without the hash, the key cannot be read,\n * disabled or deleted.\n *\n * `usage` and `limit` hold USD credits. They are the OpenRouter names for the\n * `spend` and `max_budget` of LiteLLM.\n */\n/**\n * Number of keys that `GET /keys` gives back in one page.\n *\n * A caller that scans for a key must step `offset` by this number. The\n * integration writes one key per org, so a real account holds more keys than\n * one page.\n */\nexport const OPENROUTER_KEY_PAGE_SIZE = 100\n\nexport interface OpenRouterKeyData {\n /** Identifier of the key for every management route. */\n hash: string\n /** Name of the key. This service writes `org-<orgId>` into it. */\n name?: string\n /** Label of the key, which OpenRouter derives from the name. */\n label?: string\n /** Credit limit in USD. `null` means no limit. */\n limit?: number | null\n /** Credits spent in USD. */\n usage?: number\n /** True when the key is disabled and rejects inference requests. */\n disabled?: boolean\n created_at?: string\n updated_at?: string\n /**\n * Fields that OpenRouter sends and this service does not model, such as\n * `limit_remaining` and the `usage_daily` family. `unknown` keeps them\n * readable and makes a caller narrow the type first.\n */\n [key: string]: unknown\n}\n\n/**\n * Common options of every key management request.\n *\n * The token is a Provisioning API key. An inference key cannot read or write\n * other keys.\n */\ninterface OpenRouterRequestOptions {\n /** Base URL of the OpenRouter API, including the `/api/v1` prefix. */\n openRouterApiBaseUrl: string\n /** Provisioning API key for authentication. */\n apiToken: string\n}\n\n/**\n * Request to create a key\n * POST /keys\n */\nexport interface CreateOpenRouterKeyRequest extends RequestBaseParams {\n options: OpenRouterRequestOptions & {\n /** Name of the key. Used to find the key again if the hash is lost. */\n name: string\n /** Credit limit in USD. */\n limit?: number\n /** When false, credits of a customer-owned provider key do not count. */\n include_byok_in_limit?: boolean\n }\n}\n\n/**\n * Response from creating a key.\n *\n * `key` holds the inference credential and OpenRouter returns it only here.\n * `data.hash` is the handle for every later request about this key.\n */\nexport interface CreateOpenRouterKeyResponse {\n key: string\n data: OpenRouterKeyData\n}\n\n/**\n * Request to read one key\n * GET /keys/{hash}\n */\nexport interface GetOpenRouterKeyRequest extends RequestBaseParams {\n options: OpenRouterRequestOptions & {\n /** Hash of the key to read. */\n hash: string\n }\n}\n\n/**\n * Response from reading one key\n */\nexport interface GetOpenRouterKeyResponse {\n data: OpenRouterKeyData\n}\n\n/**\n * Request to update a key\n * PATCH /keys/{hash}\n */\nexport interface UpdateOpenRouterKeyRequest extends RequestBaseParams {\n options: OpenRouterRequestOptions & {\n /** Hash of the key to update. */\n hash: string\n /** New name of the key. */\n name?: string\n /** True disables the key. False enables it again. */\n disabled?: boolean\n /** New credit limit in USD. */\n limit?: number\n }\n}\n\n/**\n * Response from updating a key\n */\nexport interface UpdateOpenRouterKeyResponse {\n data: OpenRouterKeyData\n}\n\n/**\n * Request to delete a key\n * DELETE /keys/{hash}\n */\nexport interface DeleteOpenRouterKeyRequest extends RequestBaseParams {\n options: OpenRouterRequestOptions & {\n /** Hash of the key to delete. */\n hash: string\n }\n}\n\n/**\n * Response from deleting a key\n */\nexport interface DeleteOpenRouterKeyResponse {\n /** True when OpenRouter removed the key. */\n deleted?: boolean\n /** Fields that OpenRouter sends and this service does not model. */\n [key: string]: unknown\n}\n\n/**\n * Request to list keys\n * GET /keys\n */\nexport interface ListOpenRouterKeysRequest extends RequestBaseParams {\n options: OpenRouterRequestOptions & {\n /** Number of keys to skip. OpenRouter returns 100 keys per page. */\n offset?: number\n /** When true, disabled keys are part of the result. */\n includeDisabled?: boolean\n }\n}\n\n/**\n * Response from listing keys\n */\nexport interface ListOpenRouterKeysResponse {\n data: OpenRouterKeyData[]\n}\n\n/**\n * Service for the key management API of OpenRouter.\n *\n * API documentation: https://openrouter.ai/docs/features/provisioning-api-keys\n *\n * This is the OpenRouter counterpart of `LiteLLMService`. Two differences\n * shape every method:\n *\n * - OpenRouter has no teams. One key per org carries the whole budget, and\n * the name of the key holds the org id.\n * - OpenRouter addresses a key by hash. LiteLLM addressed a key by its value.\n */\nexport class OpenRouterService {\n /**\n * Create a key\n * POST /keys\n */\n public static async createKey(\n params: CreateOpenRouterKeyRequest,\n ): Promise<CreateOpenRouterKeyResponse> {\n const serviceContext: RequestBaseServiceContext = {\n method: {\n name: 'OpenRouterService.createKey',\n url: `${params.options.openRouterApiBaseUrl}/keys`,\n normalizedUrl: '/keys',\n type: 'post',\n },\n source: params.config.metrics?.source || 'unset',\n target: {\n name: 'openrouter',\n type: 'external',\n },\n }\n\n const body = {\n name: params.options.name,\n ...(params.options.limit !== undefined && {\n limit: params.options.limit,\n }),\n ...(params.options.include_byok_in_limit !== undefined && {\n include_byok_in_limit: params.options.include_byok_in_limit,\n }),\n }\n\n const response = await request<CreateOpenRouterKeyResponse>({\n config: params.config,\n url: serviceContext.method.url,\n method: serviceContext.method.type,\n metricsDetails: serviceContext,\n type: 'json',\n headers: {\n Authorization: `Bearer ${params.options.apiToken}`,\n },\n body,\n })\n\n if (!response.ok) {\n throw new HttpError(\n `${serviceContext.method.name}: ${response.status} ${response.statusText}`,\n response.status,\n response.statusText,\n )\n }\n\n return response.body!\n }\n\n /**\n * Read one key, with its credit usage and limit\n * GET /keys/{hash}\n */\n public static async getKey(\n params: GetOpenRouterKeyRequest,\n ): Promise<GetOpenRouterKeyResponse> {\n const serviceContext: RequestBaseServiceContext = {\n method: {\n name: 'OpenRouterService.getKey',\n url: `${params.options.openRouterApiBaseUrl}/keys/${encodeURIComponent(params.options.hash)}`,\n normalizedUrl: '/keys/:hash',\n type: 'get',\n },\n source: params.config.metrics?.source || 'unset',\n target: {\n name: 'openrouter',\n type: 'external',\n },\n }\n\n const response = await request<GetOpenRouterKeyResponse>({\n config: params.config,\n url: serviceContext.method.url,\n method: serviceContext.method.type,\n metricsDetails: serviceContext,\n headers: {\n Authorization: `Bearer ${params.options.apiToken}`,\n },\n })\n\n if (!response.ok) {\n throw new HttpError(\n `${serviceContext.method.name}: ${response.status} ${response.statusText}`,\n response.status,\n response.statusText,\n )\n }\n\n return response.body!\n }\n\n /**\n * Update the name, the disabled state or the credit limit of a key.\n *\n * OpenRouter has no separate block, unblock or budget route. All three are\n * this one PATCH with a different field.\n * PATCH /keys/{hash}\n */\n public static async updateKey(\n params: UpdateOpenRouterKeyRequest,\n ): Promise<UpdateOpenRouterKeyResponse> {\n const serviceContext: RequestBaseServiceContext = {\n method: {\n name: 'OpenRouterService.updateKey',\n url: `${params.options.openRouterApiBaseUrl}/keys/${encodeURIComponent(params.options.hash)}`,\n normalizedUrl: '/keys/:hash',\n type: 'patch',\n },\n source: params.config.metrics?.source || 'unset',\n target: {\n name: 'openrouter',\n type: 'external',\n },\n }\n\n const body = {\n ...(params.options.name !== undefined && { name: params.options.name }),\n ...(params.options.disabled !== undefined && {\n disabled: params.options.disabled,\n }),\n ...(params.options.limit !== undefined && {\n limit: params.options.limit,\n }),\n }\n\n const response = await request<UpdateOpenRouterKeyResponse>({\n config: params.config,\n url: serviceContext.method.url,\n method: serviceContext.method.type,\n metricsDetails: serviceContext,\n type: 'json',\n headers: {\n Authorization: `Bearer ${params.options.apiToken}`,\n },\n body,\n })\n\n if (!response.ok) {\n throw new HttpError(\n `${serviceContext.method.name}: ${response.status} ${response.statusText}`,\n response.status,\n response.statusText,\n )\n }\n\n return response.body!\n }\n\n /**\n * Delete a key\n * DELETE /keys/{hash}\n */\n public static async deleteKey(\n params: DeleteOpenRouterKeyRequest,\n ): Promise<DeleteOpenRouterKeyResponse> {\n const serviceContext: RequestBaseServiceContext = {\n method: {\n name: 'OpenRouterService.deleteKey',\n url: `${params.options.openRouterApiBaseUrl}/keys/${encodeURIComponent(params.options.hash)}`,\n normalizedUrl: '/keys/:hash',\n type: 'delete',\n },\n source: params.config.metrics?.source || 'unset',\n target: {\n name: 'openrouter',\n type: 'external',\n },\n }\n\n const response = await request<DeleteOpenRouterKeyResponse>({\n config: params.config,\n url: serviceContext.method.url,\n method: serviceContext.method.type,\n metricsDetails: serviceContext,\n headers: {\n Authorization: `Bearer ${params.options.apiToken}`,\n },\n })\n\n if (!response.ok) {\n throw new HttpError(\n `${serviceContext.method.name}: ${response.status} ${response.statusText}`,\n response.status,\n response.statusText,\n )\n }\n\n return response.body ?? {}\n }\n\n /**\n * List keys, newest first.\n *\n * This is the recovery path for a key whose hash is not in the metadata of\n * the org. The name of the key holds the org id, so a caller can match on\n * it. OpenRouter returns 100 keys per page. Use `offset` for the next page.\n * GET /keys\n */\n public static async listKeys(\n params: ListOpenRouterKeysRequest,\n ): Promise<ListOpenRouterKeysResponse> {\n const query = new URLSearchParams()\n if (params.options.offset !== undefined) {\n query.set('offset', String(params.options.offset))\n }\n if (params.options.includeDisabled) {\n query.set('include_disabled', 'true')\n }\n const queryString = query.toString()\n\n const serviceContext: RequestBaseServiceContext = {\n method: {\n name: 'OpenRouterService.listKeys',\n url: `${params.options.openRouterApiBaseUrl}/keys${queryString ? `?${queryString}` : ''}`,\n normalizedUrl: '/keys',\n type: 'get',\n },\n source: params.config.metrics?.source || 'unset',\n target: {\n name: 'openrouter',\n type: 'external',\n },\n }\n\n const response = await request<ListOpenRouterKeysResponse>({\n config: params.config,\n url: serviceContext.method.url,\n method: serviceContext.method.type,\n metricsDetails: serviceContext,\n headers: {\n Authorization: `Bearer ${params.options.apiToken}`,\n },\n })\n\n if (!response.ok) {\n throw new HttpError(\n `${serviceContext.method.name}: ${response.status} ${response.statusText}`,\n response.status,\n response.statusText,\n )\n }\n\n return response.body!\n }\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["/*\n * Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH\n * under one or more contributor license agreements. Licensed under a commercial license.\n * You may not use this file except in compliance with the commercial license.\n */\n\nimport type {\n RequestBaseParams,\n RequestBaseServiceContext,\n} from '../../types/general.types.js'\nimport { request } from '../../utils/api.js'\nimport { HttpError } from '../../utils/errors.js'\n\n/**\n * Fields that every key management route of OpenRouter returns for a key.\n *\n * OpenRouter addresses a key by its `hash`, never by the key itself. The key\n * comes back exactly once, from the create route. Thus the caller must persist\n * the hash together with the key. Without the hash, the key cannot be read,\n * disabled or deleted.\n *\n * `usage` and `limit` hold USD credits. They are the OpenRouter names for the\n * `spend` and `max_budget` of LiteLLM.\n */\n/**\n * Number of keys that `GET /keys` gives back in one page.\n *\n * A caller that scans for a key must step `offset` by this number. The\n * integration writes one key per org, so a real account holds more keys than\n * one page.\n */\nexport const OPENROUTER_KEY_PAGE_SIZE = 100\n\nexport interface OpenRouterKeyData {\n /** Identifier of the key for every management route. */\n hash: string\n /** Name of the key. This service writes `org-<orgId>` into it. */\n name?: string\n /** Label of the key, which OpenRouter derives from the name. */\n label?: string\n /** Credit limit in USD. `null` means no limit. */\n limit?: number | null\n /** Credits spent in USD. */\n usage?: number\n /** True when the key is disabled and rejects inference requests. */\n disabled?: boolean\n created_at?: string\n updated_at?: string\n /**\n * Fields that OpenRouter sends and this service does not model, such as\n * `limit_remaining` and the `usage_daily` family. `unknown` keeps them\n * readable and makes a caller narrow the type first.\n */\n [key: string]: unknown\n}\n\n/**\n * Common options of every key management request.\n *\n * The token is a Provisioning API key. An inference key cannot read or write\n * other keys.\n */\ninterface OpenRouterRequestOptions {\n /** Base URL of the OpenRouter API, including the `/api/v1` prefix. */\n openRouterApiBaseUrl: string\n /** Provisioning API key for authentication. */\n apiToken: string\n}\n\n/**\n * Request to create a key\n * POST /keys\n */\nexport interface CreateOpenRouterKeyRequest extends RequestBaseParams {\n options: OpenRouterRequestOptions & {\n /** Name of the key. Used to find the key again if the hash is lost. */\n name: string\n /** Credit limit in USD. */\n limit?: number\n /** When false, credits of a customer-owned provider key do not count. */\n include_byok_in_limit?: boolean\n /**\n * UUID of the workspace that owns the key. When absent, OpenRouter puts the\n * key in the default workspace of the account.\n */\n workspace_id?: string\n }\n}\n\n/**\n * Response from creating a key.\n *\n * `key` holds the inference credential and OpenRouter returns it only here.\n * `data.hash` is the handle for every later request about this key.\n */\nexport interface CreateOpenRouterKeyResponse {\n key: string\n data: OpenRouterKeyData\n}\n\n/**\n * Request to read one key\n * GET /keys/{hash}\n */\nexport interface GetOpenRouterKeyRequest extends RequestBaseParams {\n options: OpenRouterRequestOptions & {\n /** Hash of the key to read. */\n hash: string\n }\n}\n\n/**\n * Response from reading one key\n */\nexport interface GetOpenRouterKeyResponse {\n data: OpenRouterKeyData\n}\n\n/**\n * Request to update a key\n * PATCH /keys/{hash}\n */\nexport interface UpdateOpenRouterKeyRequest extends RequestBaseParams {\n options: OpenRouterRequestOptions & {\n /** Hash of the key to update. */\n hash: string\n /** New name of the key. */\n name?: string\n /** True disables the key. False enables it again. */\n disabled?: boolean\n /** New credit limit in USD. */\n limit?: number\n }\n}\n\n/**\n * Response from updating a key\n */\nexport interface UpdateOpenRouterKeyResponse {\n data: OpenRouterKeyData\n}\n\n/**\n * Request to delete a key\n * DELETE /keys/{hash}\n */\nexport interface DeleteOpenRouterKeyRequest extends RequestBaseParams {\n options: OpenRouterRequestOptions & {\n /** Hash of the key to delete. */\n hash: string\n }\n}\n\n/**\n * Response from deleting a key\n */\nexport interface DeleteOpenRouterKeyResponse {\n /** True when OpenRouter removed the key. */\n deleted?: boolean\n /** Fields that OpenRouter sends and this service does not model. */\n [key: string]: unknown\n}\n\n/**\n * Request to list keys\n * GET /keys\n */\nexport interface ListOpenRouterKeysRequest extends RequestBaseParams {\n options: OpenRouterRequestOptions & {\n /** Number of keys to skip. OpenRouter returns 100 keys per page. */\n offset?: number\n /** When true, disabled keys are part of the result. */\n includeDisabled?: boolean\n /**\n * UUID of the workspace to list. When absent, OpenRouter lists the default\n * workspace only, so a key in another workspace is not in the result.\n */\n workspace_id?: string\n }\n}\n\n/**\n * Response from listing keys\n */\nexport interface ListOpenRouterKeysResponse {\n data: OpenRouterKeyData[]\n}\n\n/**\n * Request to read one workspace\n * GET /workspaces/{id}\n */\nexport interface GetOpenRouterWorkspaceRequest extends RequestBaseParams {\n options: OpenRouterRequestOptions & {\n /** UUID of the workspace to read. */\n workspaceId: string\n }\n}\n\n/**\n * Response from reading one workspace. The caller needs the status code only,\n * so the body stays open.\n */\nexport interface GetOpenRouterWorkspaceResponse {\n [key: string]: unknown\n}\n\n/**\n * Service for the key management API of OpenRouter.\n *\n * API documentation: https://openrouter.ai/docs/features/provisioning-api-keys\n *\n * This is the OpenRouter counterpart of `LiteLLMService`. Two differences\n * shape every method:\n *\n * - OpenRouter has no teams. One key per org carries the whole budget, and\n * the name of the key holds the org id.\n * - OpenRouter addresses a key by hash. LiteLLM addressed a key by its value.\n */\nexport class OpenRouterService {\n /**\n * Create a key\n * POST /keys\n */\n public static async createKey(\n params: CreateOpenRouterKeyRequest,\n ): Promise<CreateOpenRouterKeyResponse> {\n const serviceContext: RequestBaseServiceContext = {\n method: {\n name: 'OpenRouterService.createKey',\n url: `${params.options.openRouterApiBaseUrl}/keys`,\n normalizedUrl: '/keys',\n type: 'post',\n },\n source: params.config.metrics?.source || 'unset',\n target: {\n name: 'openrouter',\n type: 'external',\n },\n }\n\n const body = {\n name: params.options.name,\n ...(params.options.limit !== undefined && {\n limit: params.options.limit,\n }),\n ...(params.options.include_byok_in_limit !== undefined && {\n include_byok_in_limit: params.options.include_byok_in_limit,\n }),\n ...(params.options.workspace_id && {\n workspace_id: params.options.workspace_id,\n }),\n }\n\n const response = await request<CreateOpenRouterKeyResponse>({\n config: params.config,\n url: serviceContext.method.url,\n method: serviceContext.method.type,\n metricsDetails: serviceContext,\n type: 'json',\n headers: {\n Authorization: `Bearer ${params.options.apiToken}`,\n },\n body,\n })\n\n if (!response.ok) {\n throw new HttpError(\n `${serviceContext.method.name}: ${response.status} ${response.statusText}`,\n response.status,\n response.statusText,\n )\n }\n\n return response.body!\n }\n\n /**\n * Read one key, with its credit usage and limit\n * GET /keys/{hash}\n */\n public static async getKey(\n params: GetOpenRouterKeyRequest,\n ): Promise<GetOpenRouterKeyResponse> {\n const serviceContext: RequestBaseServiceContext = {\n method: {\n name: 'OpenRouterService.getKey',\n url: `${params.options.openRouterApiBaseUrl}/keys/${encodeURIComponent(params.options.hash)}`,\n normalizedUrl: '/keys/:hash',\n type: 'get',\n },\n source: params.config.metrics?.source || 'unset',\n target: {\n name: 'openrouter',\n type: 'external',\n },\n }\n\n const response = await request<GetOpenRouterKeyResponse>({\n config: params.config,\n url: serviceContext.method.url,\n method: serviceContext.method.type,\n metricsDetails: serviceContext,\n headers: {\n Authorization: `Bearer ${params.options.apiToken}`,\n },\n })\n\n if (!response.ok) {\n throw new HttpError(\n `${serviceContext.method.name}: ${response.status} ${response.statusText}`,\n response.status,\n response.statusText,\n )\n }\n\n return response.body!\n }\n\n /**\n * Update the name, the disabled state or the credit limit of a key.\n *\n * OpenRouter has no separate block, unblock or budget route. All three are\n * this one PATCH with a different field.\n * PATCH /keys/{hash}\n */\n public static async updateKey(\n params: UpdateOpenRouterKeyRequest,\n ): Promise<UpdateOpenRouterKeyResponse> {\n const serviceContext: RequestBaseServiceContext = {\n method: {\n name: 'OpenRouterService.updateKey',\n url: `${params.options.openRouterApiBaseUrl}/keys/${encodeURIComponent(params.options.hash)}`,\n normalizedUrl: '/keys/:hash',\n type: 'patch',\n },\n source: params.config.metrics?.source || 'unset',\n target: {\n name: 'openrouter',\n type: 'external',\n },\n }\n\n const body = {\n ...(params.options.name !== undefined && { name: params.options.name }),\n ...(params.options.disabled !== undefined && {\n disabled: params.options.disabled,\n }),\n ...(params.options.limit !== undefined && {\n limit: params.options.limit,\n }),\n }\n\n const response = await request<UpdateOpenRouterKeyResponse>({\n config: params.config,\n url: serviceContext.method.url,\n method: serviceContext.method.type,\n metricsDetails: serviceContext,\n type: 'json',\n headers: {\n Authorization: `Bearer ${params.options.apiToken}`,\n },\n body,\n })\n\n if (!response.ok) {\n throw new HttpError(\n `${serviceContext.method.name}: ${response.status} ${response.statusText}`,\n response.status,\n response.statusText,\n )\n }\n\n return response.body!\n }\n\n /**\n * Delete a key\n * DELETE /keys/{hash}\n */\n public static async deleteKey(\n params: DeleteOpenRouterKeyRequest,\n ): Promise<DeleteOpenRouterKeyResponse> {\n const serviceContext: RequestBaseServiceContext = {\n method: {\n name: 'OpenRouterService.deleteKey',\n url: `${params.options.openRouterApiBaseUrl}/keys/${encodeURIComponent(params.options.hash)}`,\n normalizedUrl: '/keys/:hash',\n type: 'delete',\n },\n source: params.config.metrics?.source || 'unset',\n target: {\n name: 'openrouter',\n type: 'external',\n },\n }\n\n const response = await request<DeleteOpenRouterKeyResponse>({\n config: params.config,\n url: serviceContext.method.url,\n method: serviceContext.method.type,\n metricsDetails: serviceContext,\n headers: {\n Authorization: `Bearer ${params.options.apiToken}`,\n },\n })\n\n if (!response.ok) {\n throw new HttpError(\n `${serviceContext.method.name}: ${response.status} ${response.statusText}`,\n response.status,\n response.statusText,\n )\n }\n\n return response.body ?? {}\n }\n\n /**\n * List keys, newest first.\n *\n * This is the recovery path for a key whose hash is not in the metadata of\n * the org. The name of the key holds the org id, so a caller can match on\n * it. OpenRouter returns 100 keys per page. Use `offset` for the next page.\n * GET /keys\n */\n public static async listKeys(\n params: ListOpenRouterKeysRequest,\n ): Promise<ListOpenRouterKeysResponse> {\n const query = new URLSearchParams()\n if (params.options.offset !== undefined) {\n query.set('offset', String(params.options.offset))\n }\n if (params.options.includeDisabled) {\n query.set('include_disabled', 'true')\n }\n if (params.options.workspace_id) {\n query.set('workspace_id', params.options.workspace_id)\n }\n const queryString = query.toString()\n\n const serviceContext: RequestBaseServiceContext = {\n method: {\n name: 'OpenRouterService.listKeys',\n url: `${params.options.openRouterApiBaseUrl}/keys${queryString ? `?${queryString}` : ''}`,\n normalizedUrl: '/keys',\n type: 'get',\n },\n source: params.config.metrics?.source || 'unset',\n target: {\n name: 'openrouter',\n type: 'external',\n },\n }\n\n const response = await request<ListOpenRouterKeysResponse>({\n config: params.config,\n url: serviceContext.method.url,\n method: serviceContext.method.type,\n metricsDetails: serviceContext,\n headers: {\n Authorization: `Bearer ${params.options.apiToken}`,\n },\n })\n\n if (!response.ok) {\n throw new HttpError(\n `${serviceContext.method.name}: ${response.status} ${response.statusText}`,\n response.status,\n response.statusText,\n )\n }\n\n return response.body!\n }\n\n /**\n * Read one workspace.\n *\n * A 404 means that the workspace does not exist. A caller uses this to check\n * a workspace id before it creates keys in that workspace.\n * GET /workspaces/{id}\n */\n public static async getWorkspace(\n params: GetOpenRouterWorkspaceRequest,\n ): Promise<GetOpenRouterWorkspaceResponse> {\n const serviceContext: RequestBaseServiceContext = {\n method: {\n name: 'OpenRouterService.getWorkspace',\n url: `${params.options.openRouterApiBaseUrl}/workspaces/${encodeURIComponent(params.options.workspaceId)}`,\n normalizedUrl: '/workspaces/:id',\n type: 'get',\n },\n source: params.config.metrics?.source || 'unset',\n target: {\n name: 'openrouter',\n type: 'external',\n },\n }\n\n const response = await request<GetOpenRouterWorkspaceResponse>({\n config: params.config,\n url: serviceContext.method.url,\n method: serviceContext.method.type,\n metricsDetails: serviceContext,\n headers: {\n Authorization: `Bearer ${params.options.apiToken}`,\n },\n })\n\n if (!response.ok) {\n throw new HttpError(\n `${serviceContext.method.name}: ${response.status} ${response.statusText}`,\n response.status,\n response.statusText,\n )\n }\n\n return response.body ?? {}\n }\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -5,6 +5,13 @@ export interface SlackBlock {
5
5
  }
6
6
  export interface SendBlockKitMessageParams extends RequestBaseParams {
7
7
  webhookUrl: string;
8
+ /**
9
+ * Slack shows this text in the notification, and a screen reader reads it
10
+ * instead of the blocks. Without it, Slack builds a fallback from some
11
+ * block types only, which can leave out content, for example a table.
12
+ * Slack parses it as mrkdwn, thus escape `&`, `<` and `>` in user data.
13
+ */
14
+ text?: string;
8
15
  blocks: SlackBlock[];
9
16
  }
10
17
  export interface SendBlockKitMessageResponse {
@@ -21,6 +21,7 @@ class SlackBlockKitService {
21
21
  }
22
22
  };
23
23
  const body = {
24
+ ...params.text === void 0 ? {} : { text: params.text },
24
25
  blocks: params.blocks
25
26
  };
26
27
  const response = await request({
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../../src/services/slack/slack-blockkit.service.ts"],
4
- "sourcesContent": ["/*\n * Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH\n * under one or more contributor license agreements. Licensed under a commercial license.\n * You may not use this file except in compliance with the commercial license.\n */\n\nimport type {\n RequestBaseParams,\n RequestBaseServiceContext,\n} from '../../types/general.types.js'\nimport { request } from '../../utils/api.js'\n\n// Slack Block Kit block types\n// https://api.slack.com/reference/block-kit/blocks\nexport interface SlackBlock {\n type: string\n [key: string]: any\n}\n\nexport interface SendBlockKitMessageParams extends RequestBaseParams {\n webhookUrl: string\n blocks: SlackBlock[]\n}\n\nexport interface SendBlockKitMessageResponse {\n ok: boolean\n status: number\n statusText: string\n}\n\n/**\n * Service for sending Slack Block Kit messages with full block structure support.\n * Unlike SlackService which only supports simple sections, this service accepts\n * complete Block Kit JSON including buttons and other interactive elements.\n */\nexport class SlackBlockKitService {\n /**\n * Send a Block Kit message to a Slack webhook URL.\n *\n * @param params - Parameters including webhook URL, blocks array, and config\n * @returns Response object with ok, status, and statusText\n */\n public static async sendBlockKitMessage(\n params: SendBlockKitMessageParams,\n ): Promise<SendBlockKitMessageResponse> {\n const serviceContext: RequestBaseServiceContext = {\n method: {\n name: 'SlackBlockKitService.sendBlockKitMessage',\n url: params.webhookUrl,\n normalizedUrl: 'https://hooks.slack.com/services/:webhookId',\n type: 'post',\n },\n source: params.config.metrics?.source || 'unset',\n target: {\n name: 'slack',\n type: 'external',\n },\n }\n\n const body = {\n blocks: params.blocks,\n }\n\n const response = await request<void>({\n config: params.config,\n url: serviceContext.method.url,\n method: serviceContext.method.type,\n metricsDetails: serviceContext,\n body,\n type: 'json',\n responseType: 'none',\n })\n\n return {\n ok: response.ok,\n status: response.status,\n statusText: response.statusText || '',\n }\n }\n}\n"],
5
- "mappings": "AAUA,SAAS,eAAe;AAyBjB,MAAM,qBAAqB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOhC,aAAoB,oBAClB,QACsC;AACtC,UAAM,iBAA4C;AAAA,MAChD,QAAQ;AAAA,QACN,MAAM;AAAA,QACN,KAAK,OAAO;AAAA,QACZ,eAAe;AAAA,QACf,MAAM;AAAA,MACR;AAAA,MACA,QAAQ,OAAO,OAAO,SAAS,UAAU;AAAA,MACzC,QAAQ;AAAA,QACN,MAAM;AAAA,QACN,MAAM;AAAA,MACR;AAAA,IACF;AAEA,UAAM,OAAO;AAAA,MACX,QAAQ,OAAO;AAAA,IACjB;AAEA,UAAM,WAAW,MAAM,QAAc;AAAA,MACnC,QAAQ,OAAO;AAAA,MACf,KAAK,eAAe,OAAO;AAAA,MAC3B,QAAQ,eAAe,OAAO;AAAA,MAC9B,gBAAgB;AAAA,MAChB;AAAA,MACA,MAAM;AAAA,MACN,cAAc;AAAA,IAChB,CAAC;AAED,WAAO;AAAA,MACL,IAAI,SAAS;AAAA,MACb,QAAQ,SAAS;AAAA,MACjB,YAAY,SAAS,cAAc;AAAA,IACrC;AAAA,EACF;AACF;",
4
+ "sourcesContent": ["/*\n * Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH\n * under one or more contributor license agreements. Licensed under a commercial license.\n * You may not use this file except in compliance with the commercial license.\n */\n\nimport type {\n RequestBaseParams,\n RequestBaseServiceContext,\n} from '../../types/general.types.js'\nimport { request } from '../../utils/api.js'\n\n// Slack Block Kit block types\n// https://api.slack.com/reference/block-kit/blocks\nexport interface SlackBlock {\n type: string\n [key: string]: any\n}\n\nexport interface SendBlockKitMessageParams extends RequestBaseParams {\n webhookUrl: string\n /**\n * Slack shows this text in the notification, and a screen reader reads it\n * instead of the blocks. Without it, Slack builds a fallback from some\n * block types only, which can leave out content, for example a table.\n * Slack parses it as mrkdwn, thus escape `&`, `<` and `>` in user data.\n */\n text?: string\n blocks: SlackBlock[]\n}\n\nexport interface SendBlockKitMessageResponse {\n ok: boolean\n status: number\n statusText: string\n}\n\n/**\n * Service for sending Slack Block Kit messages with full block structure support.\n * Unlike SlackService which only supports simple sections, this service accepts\n * complete Block Kit JSON including buttons and other interactive elements.\n */\nexport class SlackBlockKitService {\n /**\n * Send a Block Kit message to a Slack webhook URL.\n *\n * @param params - Parameters including webhook URL, blocks array, and config\n * @returns Response object with ok, status, and statusText\n */\n public static async sendBlockKitMessage(\n params: SendBlockKitMessageParams,\n ): Promise<SendBlockKitMessageResponse> {\n const serviceContext: RequestBaseServiceContext = {\n method: {\n name: 'SlackBlockKitService.sendBlockKitMessage',\n url: params.webhookUrl,\n normalizedUrl: 'https://hooks.slack.com/services/:webhookId',\n type: 'post',\n },\n source: params.config.metrics?.source || 'unset',\n target: {\n name: 'slack',\n type: 'external',\n },\n }\n\n const body = {\n ...(params.text === undefined ? {} : { text: params.text }),\n blocks: params.blocks,\n }\n\n const response = await request<void>({\n config: params.config,\n url: serviceContext.method.url,\n method: serviceContext.method.type,\n metricsDetails: serviceContext,\n body,\n type: 'json',\n responseType: 'none',\n })\n\n return {\n ok: response.ok,\n status: response.status,\n statusText: response.statusText || '',\n }\n }\n}\n"],
5
+ "mappings": "AAUA,SAAS,eAAe;AAgCjB,MAAM,qBAAqB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOhC,aAAoB,oBAClB,QACsC;AACtC,UAAM,iBAA4C;AAAA,MAChD,QAAQ;AAAA,QACN,MAAM;AAAA,QACN,KAAK,OAAO;AAAA,QACZ,eAAe;AAAA,QACf,MAAM;AAAA,MACR;AAAA,MACA,QAAQ,OAAO,OAAO,SAAS,UAAU;AAAA,MACzC,QAAQ;AAAA,QACN,MAAM;AAAA,QACN,MAAM;AAAA,MACR;AAAA,IACF;AAEA,UAAM,OAAO;AAAA,MACX,GAAI,OAAO,SAAS,SAAY,CAAC,IAAI,EAAE,MAAM,OAAO,KAAK;AAAA,MACzD,QAAQ,OAAO;AAAA,IACjB;AAEA,UAAM,WAAW,MAAM,QAAc;AAAA,MACnC,QAAQ,OAAO;AAAA,MACf,KAAK,eAAe,OAAO;AAAA,MAC3B,QAAQ,eAAe,OAAO;AAAA,MAC9B,gBAAgB;AAAA,MAChB;AAAA,MACA,MAAM;AAAA,MACN,cAAc;AAAA,IAChB,CAAC;AAED,WAAO;AAAA,MACL,IAAI,SAAS;AAAA,MACb,QAAQ,SAAS;AAAA,MACjB,YAAY,SAAS,cAAc;AAAA,IACrC;AAAA,EACF;AACF;",
6
6
  "names": []
7
7
  }
@@ -21,10 +21,9 @@ const ENV_PARAMS = [
21
21
  prod: "https://accounts.cloud.camunda.io"
22
22
  },
23
23
  {
24
- // control-backend, the four-eyes approval service. It reaches dev today
25
- // and nothing else: `saas-argocd-apps` holds an ApplicationSet for dev
26
- // only. The int and prod names follow the pattern of every other service
27
- // of the fleet, so they are right on the day the ApplicationSet lands.
24
+ // control-backend, the four-eyes approval service. It deploys to dev, int
25
+ // and prod, and the names follow the pattern of every other service of
26
+ // the fleet.
28
27
  id: "control",
29
28
  dev: "https://control.cloud.dev.ultrawombat.com",
30
29
  devAws: "https://control.cloud.dev.ultrawombat.com",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/utils/environments.ts"],
4
- "sourcesContent": ["/*\n * Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH\n * under one or more contributor license agreements. Licensed under a commercial license.\n * You may not use this file except in compliance with the commercial license.\n */\n\nimport type { RequestBaseParamsConfig } from '../types/general.types.js'\n\nexport type ServiceName =\n | 'accounts'\n | 'console'\n | 'control'\n | 'audit-logger'\n | 'notifications'\n | 'login'\n | 'login-internal'\n | 'comm-bridge'\n | 'telemetry'\n | 'mixpanel'\n | 'alert-distributor'\n | 'analytic-bridge'\n | 'wordpress-helpcenter'\n\nexport type ServiceAudience =\n | 'camunda-cloud-audience'\n | 'comm-bridge-audience'\n | 'notification-audience'\n | 'analytics-audience'\n\nexport interface EnvironmentParam {\n id: ServiceName | ServiceAudience\n dev: string\n devAws: string\n int: string\n prod: string\n}\n\nconst ENV_PARAMS: EnvironmentParam[] = [\n {\n id: 'notifications',\n dev: 'https://notifications.cloud.dev.ultrawombat.com',\n devAws: 'https://notifications.cloud.dev.ultrawombat.com',\n int: 'https://notifications.cloud.ultrawombat.com',\n prod: 'https://notifications.cloud.camunda.io',\n },\n {\n id: 'console',\n dev: 'https://console.cloud.dev.ultrawombat.com',\n devAws: 'https://console-aws.cloud.dev.ultrawombat.com',\n int: 'https://console.cloud.ultrawombat.com',\n prod: 'https://console.cloud.camunda.io',\n },\n {\n id: 'accounts',\n dev: 'https://accounts.cloud.dev.ultrawombat.com',\n devAws: 'https://accounts-aws.cloud.dev.ultrawombat.com',\n int: 'https://accounts.cloud.ultrawombat.com',\n prod: 'https://accounts.cloud.camunda.io',\n },\n {\n // control-backend, the four-eyes approval service. It reaches dev today\n // and nothing else: `saas-argocd-apps` holds an ApplicationSet for dev\n // only. The int and prod names follow the pattern of every other service\n // of the fleet, so they are right on the day the ApplicationSet lands.\n id: 'control',\n dev: 'https://control.cloud.dev.ultrawombat.com',\n devAws: 'https://control.cloud.dev.ultrawombat.com',\n int: 'https://control.cloud.ultrawombat.com',\n prod: 'https://control.cloud.camunda.io',\n },\n {\n id: 'audit-logger',\n dev: 'https://audit.cloud.dev.ultrawombat.com',\n devAws: 'https://audit-logger.cloud.dev.ultrawombat.com',\n int: 'https://audit.cloud.ultrawombat.com',\n prod: 'https://audit.cloud.camunda.io',\n },\n {\n id: 'analytic-bridge',\n dev: 'https://analytics.cloud.dev.ultrawombat.com',\n devAws: 'https://analytics-bridge.cloud.dev.ultrawombat.com',\n int: 'https://analytics.cloud.ultrawombat.com',\n prod: 'https://analytics.cloud.camunda.io',\n },\n {\n id: 'login',\n dev: 'https://login.cloud.dev.ultrawombat.com',\n devAws: 'https://login.cloud.dev.ultrawombat.com',\n int: 'https://login.cloud.ultrawombat.com',\n prod: 'https://login.cloud.camunda.io',\n },\n {\n id: 'login-internal',\n dev: 'http://token-issuer.token-issuer.svc.cluster.local:8080',\n devAws: 'http://token-issuer.token-issuer.svc.cluster.local:8080',\n int: 'http://token-issuer.token-issuer.svc.cluster.local:8080',\n prod: 'http://token-issuer.token-issuer.svc.cluster.local:8080',\n },\n {\n id: 'comm-bridge',\n dev: 'https://comm.cloud.dev.ultrawombat.com',\n devAws: 'https://comm.cloud.dev.ultrawombat.com',\n int: 'https://comm.cloud.ultrawombat.com',\n prod: 'https://comm.cloud.camunda.io',\n },\n {\n id: 'telemetry',\n dev: 'https://telemetry.cloud.dev.ultrawombat.com',\n devAws: 'https://telemetry.cloud.dev.ultrawombat.com',\n int: 'https://telemetry.cloud.ultrawombat.com',\n prod: 'https://telemetry.cloud.camunda.io',\n },\n {\n id: 'mixpanel',\n dev: 'https://api.mixpanel.com',\n devAws: 'https://api.mixpanel.com',\n int: 'https://api.mixpanel.com',\n prod: 'https://api.mixpanel.com',\n },\n {\n id: 'alert-distributor',\n dev: 'https://alert-distributor.cloud.dev.ultrawombat.com',\n devAws: 'https://alert-distributor.cloud.dev.ultrawombat.com',\n int: 'https://alert-distributor.cloud.ultrawombat.com',\n prod: 'https://alert-distributor.cloud.camunda.io',\n },\n {\n id: 'wordpress-helpcenter',\n dev: 'https://camunda-help-stg.mystagingwebsite.com',\n devAws: 'https://camunda-help-stg.mystagingwebsite.com',\n int: 'https://camunda-help-stg.mystagingwebsite.com',\n prod: 'https://camunda-helpcenter.mystagingwebsite.com',\n },\n // AUDIENCES\n {\n id: 'camunda-cloud-audience',\n dev: 'cloud.dev.ultrawombat.com',\n devAws: 'cloud.dev.ultrawombat.com',\n int: 'cloud.ultrawombat.com',\n prod: 'cloud.camunda.io',\n },\n {\n id: 'comm-bridge-audience',\n dev: 'comm.dev.ultrawombat.com',\n devAws: 'comm.dev.ultrawombat.com',\n int: 'comm.ultrawombat.com',\n prod: 'comm.camunda.io',\n },\n {\n id: 'notification-audience',\n dev: 'notifications.dev.ultrawombat.com',\n devAws: 'notifications.dev.ultrawombat.com',\n int: 'notifications.ultrawombat.com',\n prod: 'notifications.camunda.io',\n },\n {\n id: 'analytics-audience',\n dev: 'analytics.dev.ultrawombat.com',\n devAws: 'analytics.dev.ultrawombat.com',\n int: 'analytics.ultrawombat.com',\n prod: 'analytics.camunda.io',\n },\n]\n\nexport function getEnvParam(\n id: ServiceName | ServiceAudience,\n config: RequestBaseParamsConfig,\n) {\n if (config.envOverride?.[id] && config.envOverride[id].length > 0) {\n return config.envOverride[id]\n }\n\n if (\n (id === 'console' && config.stage === 'localconsole') ||\n (id === 'accounts' && config.stage === 'localaccounts')\n ) {\n // special handling if running console/accounts frontend and backend locally\n return `http://localhost:8080`\n }\n\n const envParam = ENV_PARAMS.find(\n (environmentParam) => environmentParam.id === id,\n )\n if (!envParam) {\n throw new Error(`Unknown id: ${id}`)\n }\n switch (config.stage) {\n case 'local':\n case 'localconsole':\n case 'localaccounts':\n case 'dev':\n return envParam.dev\n case 'devAws':\n return envParam.devAws\n case 'int':\n return envParam.int\n case 'prod':\n return envParam.prod\n default:\n throw new Error(`Unknown stage: ${config.stage}`)\n }\n}\n"],
5
- "mappings": "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",
4
+ "sourcesContent": ["/*\n * Copyright Camunda Services GmbH and/or licensed to Camunda Services GmbH\n * under one or more contributor license agreements. Licensed under a commercial license.\n * You may not use this file except in compliance with the commercial license.\n */\n\nimport type { RequestBaseParamsConfig } from '../types/general.types.js'\n\nexport type ServiceName =\n | 'accounts'\n | 'console'\n | 'control'\n | 'audit-logger'\n | 'notifications'\n | 'login'\n | 'login-internal'\n | 'comm-bridge'\n | 'telemetry'\n | 'mixpanel'\n | 'alert-distributor'\n | 'analytic-bridge'\n | 'wordpress-helpcenter'\n\nexport type ServiceAudience =\n | 'camunda-cloud-audience'\n | 'comm-bridge-audience'\n | 'notification-audience'\n | 'analytics-audience'\n\nexport interface EnvironmentParam {\n id: ServiceName | ServiceAudience\n dev: string\n devAws: string\n int: string\n prod: string\n}\n\nconst ENV_PARAMS: EnvironmentParam[] = [\n {\n id: 'notifications',\n dev: 'https://notifications.cloud.dev.ultrawombat.com',\n devAws: 'https://notifications.cloud.dev.ultrawombat.com',\n int: 'https://notifications.cloud.ultrawombat.com',\n prod: 'https://notifications.cloud.camunda.io',\n },\n {\n id: 'console',\n dev: 'https://console.cloud.dev.ultrawombat.com',\n devAws: 'https://console-aws.cloud.dev.ultrawombat.com',\n int: 'https://console.cloud.ultrawombat.com',\n prod: 'https://console.cloud.camunda.io',\n },\n {\n id: 'accounts',\n dev: 'https://accounts.cloud.dev.ultrawombat.com',\n devAws: 'https://accounts-aws.cloud.dev.ultrawombat.com',\n int: 'https://accounts.cloud.ultrawombat.com',\n prod: 'https://accounts.cloud.camunda.io',\n },\n {\n // control-backend, the four-eyes approval service. It deploys to dev, int\n // and prod, and the names follow the pattern of every other service of\n // the fleet.\n id: 'control',\n dev: 'https://control.cloud.dev.ultrawombat.com',\n devAws: 'https://control.cloud.dev.ultrawombat.com',\n int: 'https://control.cloud.ultrawombat.com',\n prod: 'https://control.cloud.camunda.io',\n },\n {\n id: 'audit-logger',\n dev: 'https://audit.cloud.dev.ultrawombat.com',\n devAws: 'https://audit-logger.cloud.dev.ultrawombat.com',\n int: 'https://audit.cloud.ultrawombat.com',\n prod: 'https://audit.cloud.camunda.io',\n },\n {\n id: 'analytic-bridge',\n dev: 'https://analytics.cloud.dev.ultrawombat.com',\n devAws: 'https://analytics-bridge.cloud.dev.ultrawombat.com',\n int: 'https://analytics.cloud.ultrawombat.com',\n prod: 'https://analytics.cloud.camunda.io',\n },\n {\n id: 'login',\n dev: 'https://login.cloud.dev.ultrawombat.com',\n devAws: 'https://login.cloud.dev.ultrawombat.com',\n int: 'https://login.cloud.ultrawombat.com',\n prod: 'https://login.cloud.camunda.io',\n },\n {\n id: 'login-internal',\n dev: 'http://token-issuer.token-issuer.svc.cluster.local:8080',\n devAws: 'http://token-issuer.token-issuer.svc.cluster.local:8080',\n int: 'http://token-issuer.token-issuer.svc.cluster.local:8080',\n prod: 'http://token-issuer.token-issuer.svc.cluster.local:8080',\n },\n {\n id: 'comm-bridge',\n dev: 'https://comm.cloud.dev.ultrawombat.com',\n devAws: 'https://comm.cloud.dev.ultrawombat.com',\n int: 'https://comm.cloud.ultrawombat.com',\n prod: 'https://comm.cloud.camunda.io',\n },\n {\n id: 'telemetry',\n dev: 'https://telemetry.cloud.dev.ultrawombat.com',\n devAws: 'https://telemetry.cloud.dev.ultrawombat.com',\n int: 'https://telemetry.cloud.ultrawombat.com',\n prod: 'https://telemetry.cloud.camunda.io',\n },\n {\n id: 'mixpanel',\n dev: 'https://api.mixpanel.com',\n devAws: 'https://api.mixpanel.com',\n int: 'https://api.mixpanel.com',\n prod: 'https://api.mixpanel.com',\n },\n {\n id: 'alert-distributor',\n dev: 'https://alert-distributor.cloud.dev.ultrawombat.com',\n devAws: 'https://alert-distributor.cloud.dev.ultrawombat.com',\n int: 'https://alert-distributor.cloud.ultrawombat.com',\n prod: 'https://alert-distributor.cloud.camunda.io',\n },\n {\n id: 'wordpress-helpcenter',\n dev: 'https://camunda-help-stg.mystagingwebsite.com',\n devAws: 'https://camunda-help-stg.mystagingwebsite.com',\n int: 'https://camunda-help-stg.mystagingwebsite.com',\n prod: 'https://camunda-helpcenter.mystagingwebsite.com',\n },\n // AUDIENCES\n {\n id: 'camunda-cloud-audience',\n dev: 'cloud.dev.ultrawombat.com',\n devAws: 'cloud.dev.ultrawombat.com',\n int: 'cloud.ultrawombat.com',\n prod: 'cloud.camunda.io',\n },\n {\n id: 'comm-bridge-audience',\n dev: 'comm.dev.ultrawombat.com',\n devAws: 'comm.dev.ultrawombat.com',\n int: 'comm.ultrawombat.com',\n prod: 'comm.camunda.io',\n },\n {\n id: 'notification-audience',\n dev: 'notifications.dev.ultrawombat.com',\n devAws: 'notifications.dev.ultrawombat.com',\n int: 'notifications.ultrawombat.com',\n prod: 'notifications.camunda.io',\n },\n {\n id: 'analytics-audience',\n dev: 'analytics.dev.ultrawombat.com',\n devAws: 'analytics.dev.ultrawombat.com',\n int: 'analytics.ultrawombat.com',\n prod: 'analytics.camunda.io',\n },\n]\n\nexport function getEnvParam(\n id: ServiceName | ServiceAudience,\n config: RequestBaseParamsConfig,\n) {\n if (config.envOverride?.[id] && config.envOverride[id].length > 0) {\n return config.envOverride[id]\n }\n\n if (\n (id === 'console' && config.stage === 'localconsole') ||\n (id === 'accounts' && config.stage === 'localaccounts')\n ) {\n // special handling if running console/accounts frontend and backend locally\n return `http://localhost:8080`\n }\n\n const envParam = ENV_PARAMS.find(\n (environmentParam) => environmentParam.id === id,\n )\n if (!envParam) {\n throw new Error(`Unknown id: ${id}`)\n }\n switch (config.stage) {\n case 'local':\n case 'localconsole':\n case 'localaccounts':\n case 'dev':\n return envParam.dev\n case 'devAws':\n return envParam.devAws\n case 'int':\n return envParam.int\n case 'prod':\n return envParam.prod\n default:\n throw new Error(`Unknown stage: ${config.stage}`)\n }\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
@@ -12,6 +12,7 @@ import type { RequestBaseParamsConfig } from '../types/general.types.js';
12
12
  * backoff + full jitter, honours `Last-Event-ID`, and aborts+reconnects when
13
13
  * the stream goes silent past `heartbeatTimeoutMs` (comment/keep-alive frames
14
14
  * count as activity, so a well-behaved server keeps the connection pinned).
15
+ * A `204` answer ends the connection for good, as the SSE standard asks.
15
16
  */
16
17
  export type SseConnectionState = 'connecting' | 'open' | 'reconnecting' | 'closed';
17
18
  export interface SseMessage {
package/dist/utils/sse.js CHANGED
@@ -186,6 +186,13 @@ function connectSse(options) {
186
186
  scheduleReconnect();
187
187
  return;
188
188
  }
189
+ if (response.status === 204) {
190
+ logger?.debug("connectSse got 204, the server wants no stream", {
191
+ url: options.url
192
+ });
193
+ close();
194
+ return;
195
+ }
189
196
  if (!response.body) {
190
197
  logger?.debug("connectSse response has no body");
191
198
  scheduleReconnect();