@camunda/ccma-api 3.1.0 → 5.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 (56) hide show
  1. package/dist/index.d.ts +12 -8
  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 +212 -0
  5. package/dist/services/accounts/approvals.m2m.service.js +330 -0
  6. package/dist/services/accounts/approvals.m2m.service.js.map +2 -2
  7. package/dist/services/accounts/early-access-features.service.d.ts +4 -0
  8. package/dist/services/accounts/early-access-features.service.js.map +2 -2
  9. package/dist/services/accounts/hdp.service.d.ts +16 -3
  10. package/dist/services/accounts/hdp.service.js +45 -2
  11. package/dist/services/accounts/hdp.service.js.map +2 -2
  12. package/dist/services/accounts/orgs.service.d.ts +5 -0
  13. package/dist/services/accounts/orgs.service.js.map +2 -2
  14. package/dist/services/console/console.approvals.m2m.service.d.ts +95 -1
  15. package/dist/services/console/console.approvals.m2m.service.js +142 -0
  16. package/dist/services/console/console.approvals.m2m.service.js.map +2 -2
  17. package/dist/services/console/console.cluster-parameters.service.d.ts +6 -0
  18. package/dist/services/console/console.cluster-parameters.service.js.map +2 -2
  19. package/dist/services/console/console.cluster.service.d.ts +2 -0
  20. package/dist/services/console/console.cluster.service.js.map +2 -2
  21. package/dist/services/console/generation.service.d.ts +17 -1
  22. package/dist/services/console/generation.service.js +52 -1
  23. package/dist/services/console/generation.service.js.map +2 -2
  24. package/dist/services/control/control.approvals.service.d.ts +421 -0
  25. package/dist/services/control/control.approvals.service.js +209 -1
  26. package/dist/services/control/control.approvals.service.js.map +2 -2
  27. package/dist/services/control/control.approvals.service.spec.d.ts +1 -0
  28. package/dist/services/control/control.dashboards.service.d.ts +76 -0
  29. package/dist/services/control/control.dashboards.service.js +180 -0
  30. package/dist/services/control/control.dashboards.service.js.map +7 -0
  31. package/dist/services/control/control.dashboards.service.spec.d.ts +1 -0
  32. package/dist/services/control/control.feature-flags.service.d.ts +53 -0
  33. package/dist/services/control/control.feature-flags.service.js +123 -0
  34. package/dist/services/control/control.feature-flags.service.js.map +7 -0
  35. package/dist/services/control/control.feature-flags.service.spec.d.ts +1 -0
  36. package/dist/services/control/control.platform.service.d.ts +14 -0
  37. package/dist/services/control/control.platform.service.js +27 -0
  38. package/dist/services/control/control.platform.service.js.map +2 -2
  39. package/dist/services/control/control.platform.service.spec.d.ts +1 -0
  40. package/dist/services/external/external.accounts.service.d.ts +2 -2
  41. package/dist/services/external/external.accounts.service.js.map +2 -2
  42. package/dist/services/github/github.service.d.ts +20 -0
  43. package/dist/services/github/github.service.js +50 -1
  44. package/dist/services/github/github.service.js.map +2 -2
  45. package/dist/services/openrouter/openrouter.service.d.ts +35 -0
  46. package/dist/services/openrouter/openrouter.service.js +45 -0
  47. package/dist/services/openrouter/openrouter.service.js.map +2 -2
  48. package/dist/services/slack/slack-blockkit.service.d.ts +7 -0
  49. package/dist/services/slack/slack-blockkit.service.js +1 -0
  50. package/dist/services/slack/slack-blockkit.service.js.map +2 -2
  51. package/dist/utils/environments.js +3 -4
  52. package/dist/utils/environments.js.map +2 -2
  53. package/dist/utils/sse.d.ts +1 -0
  54. package/dist/utils/sse.js +7 -0
  55. package/dist/utils/sse.js.map +2 -2
  56. package/package.json +2 -2
@@ -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();
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/utils/sse.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\n/**\n * Dependency-free Server-Sent Events client built on `fetch` + `ReadableStream`.\n *\n * Why not the native `EventSource`? It cannot send an `Authorization` header,\n * which every Camunda stream requires. This helper reuses the same\n * `config.auth.getToken()` contract as `request()`, so it always sends a fresh\n * bearer token \u2014 including on every reconnect, which is how token rotation is\n * handled (no separate refresh timer needed on the consumer side).\n *\n * It is isomorphic (browser + Node 22+), auto-reconnects with exponential\n * backoff + full jitter, honours `Last-Event-ID`, and aborts+reconnects when\n * the stream goes silent past `heartbeatTimeoutMs` (comment/keep-alive frames\n * count as activity, so a well-behaved server keeps the connection pinned).\n */\n\nexport type SseConnectionState =\n | 'connecting'\n | 'open'\n | 'reconnecting'\n | 'closed'\n\nexport interface SseMessage {\n /** Concatenated `data:` lines (newline-joined), excluding the trailing newline. */\n data: string\n /** The `event:` field, if the server set one. */\n event?: string\n /** The `id:` field, if the server set one. Echoed back as `Last-Event-ID`. */\n id?: string\n}\n\nexport interface SseConnectionOptions {\n /** Absolute URL of the event stream. */\n url: string\n /** Reuses `auth.getToken` (called per (re)connect) and `logger`. */\n config: RequestBaseParamsConfig\n /** Called for each complete, non-empty SSE event (comment-only frames excluded). */\n onMessage: (message: SseMessage) => void\n /** Observability hook for connection lifecycle transitions. */\n onStateChange?: (state: SseConnectionState) => void\n /**\n * Abort + reconnect when no bytes (including comments / keep-alives) arrive\n * for this long. Default 120_000 ms.\n */\n heartbeatTimeoutMs?: number\n /** Backoff tuning. Defaults: base 1_000 ms, max 30_000 ms, full jitter. */\n reconnect?: {\n baseDelayMs?: number\n maxDelayMs?: number\n }\n}\n\nexport interface SseConnection {\n /** Idempotent. Aborts any in-flight fetch, cancels timers, emits no further events. */\n close: () => void\n /** Current lifecycle state. */\n readonly state: SseConnectionState\n}\n\nconst DEFAULT_HEARTBEAT_TIMEOUT_MS = 120_000\nconst DEFAULT_BASE_DELAY_MS = 1_000\nconst DEFAULT_MAX_DELAY_MS = 30_000\n\n/**\n * Incrementally parses a `text/event-stream` byte stream into complete events.\n * Events are separated by a blank line; `data:` lines accumulate; `event:`/`id:`\n * set the corresponding fields; lines starting with `:` are comments (ignored,\n * but still count as stream activity for the heartbeat).\n */\nclass SseParser {\n private buffer = ''\n private dataLines: string[] = []\n private eventName: string | undefined\n private lastEventId: string | undefined\n\n constructor(\n private readonly onMessage: (message: SseMessage) => void,\n /** Seed used to resume: exposed back so the connection can send Last-Event-ID. */\n lastEventId: string | undefined,\n ) {\n this.lastEventId = lastEventId\n }\n\n getLastEventId(): string | undefined {\n return this.lastEventId\n }\n\n /** Feed a decoded text chunk. Returns nothing; dispatches via `onMessage`. */\n push(chunk: string): void {\n this.buffer += chunk\n // Normalize CRLF / CR to LF so line splitting is uniform.\n this.buffer = this.buffer.replace(/\\r\\n?/g, '\\n')\n\n let newlineIndex = this.buffer.indexOf('\\n')\n while (newlineIndex !== -1) {\n const line = this.buffer.slice(0, newlineIndex)\n this.buffer = this.buffer.slice(newlineIndex + 1)\n this.handleLine(line)\n newlineIndex = this.buffer.indexOf('\\n')\n }\n }\n\n private handleLine(line: string): void {\n // Blank line: dispatch the accumulated event.\n if (line === '') {\n this.dispatch()\n return\n }\n\n // Comment line (keep-alive) \u2014 ignored.\n if (line.startsWith(':')) {\n return\n }\n\n const colonIndex = line.indexOf(':')\n const field = colonIndex === -1 ? line : line.slice(0, colonIndex)\n let value = colonIndex === -1 ? '' : line.slice(colonIndex + 1)\n // A single leading space after the colon is stripped, per the spec.\n if (value.startsWith(' ')) {\n value = value.slice(1)\n }\n\n switch (field) {\n case 'data':\n this.dataLines.push(value)\n break\n case 'event':\n this.eventName = value\n break\n case 'id':\n // Per spec, an id containing NUL is ignored; otherwise it updates the\n // last-event-id used on reconnect.\n if (!value.includes('\\u0000')) {\n this.lastEventId = value\n }\n break\n // `retry:` and unknown fields are intentionally ignored.\n default:\n break\n }\n }\n\n private dispatch(): void {\n if (this.dataLines.length === 0 && this.eventName === undefined) {\n // Nothing to dispatch (e.g. stray blank line).\n this.reset()\n return\n }\n\n this.onMessage({\n data: this.dataLines.join('\\n'),\n event: this.eventName,\n id: this.lastEventId,\n })\n this.reset()\n }\n\n private reset(): void {\n this.dataLines = []\n this.eventName = undefined\n }\n}\n\nfunction computeBackoff(\n attempt: number,\n baseDelayMs: number,\n maxDelayMs: number,\n): number {\n const exponential = Math.min(maxDelayMs, baseDelayMs * 2 ** attempt)\n // Full jitter: pick uniformly in [0, exponential].\n return Math.floor(Math.random() * exponential)\n}\n\nexport function connectSse(options: SseConnectionOptions): SseConnection {\n const heartbeatTimeoutMs =\n options.heartbeatTimeoutMs ?? DEFAULT_HEARTBEAT_TIMEOUT_MS\n const baseDelayMs = options.reconnect?.baseDelayMs ?? DEFAULT_BASE_DELAY_MS\n const maxDelayMs = options.reconnect?.maxDelayMs ?? DEFAULT_MAX_DELAY_MS\n const logger = options.config.logger\n\n let state: SseConnectionState = 'connecting'\n let closed = false\n let attempt = 0\n let lastEventId: string | undefined\n let controller: AbortController | undefined\n let heartbeatTimer: ReturnType<typeof setTimeout> | undefined\n let reconnectTimer: ReturnType<typeof setTimeout> | undefined\n // Once we've seen a 401/403 we allow exactly one immediate fresh-token retry\n // before falling back to normal backoff, so a transient auth blip self-heals\n // without hammering the token endpoint.\n let authRetryUsed = false\n\n const setState = (next: SseConnectionState): void => {\n if (state === next || closed) {\n return\n }\n state = next\n try {\n options.onStateChange?.(next)\n } catch (error) {\n logger?.debug('connectSse onStateChange callback threw', { error })\n }\n }\n\n const clearHeartbeat = (): void => {\n if (heartbeatTimer !== undefined) {\n clearTimeout(heartbeatTimer)\n heartbeatTimer = undefined\n }\n }\n\n const armHeartbeat = (): void => {\n clearHeartbeat()\n heartbeatTimer = setTimeout(() => {\n logger?.debug('connectSse heartbeat timeout, reconnecting', {\n url: options.url,\n })\n // Abort the current fetch; the read loop's catch schedules the reconnect.\n controller?.abort()\n }, heartbeatTimeoutMs)\n }\n\n const scheduleReconnect = (): void => {\n if (closed) {\n return\n }\n // Guard against stacking timers: multiple error paths (heartbeat abort +\n // stream end, etc.) can each call scheduleReconnect before the pending\n // timer fires. Without this, overlapping timers spawn concurrent run()\n // loops (and concurrent fetches).\n if (reconnectTimer !== undefined) {\n return\n }\n setState('reconnecting')\n const delay = computeBackoff(attempt, baseDelayMs, maxDelayMs)\n attempt += 1\n reconnectTimer = setTimeout(() => {\n reconnectTimer = undefined\n void run()\n }, delay)\n }\n\n const run = async (): Promise<void> => {\n if (closed) {\n return\n }\n\n controller = new AbortController()\n\n let token: string | undefined\n try {\n token = options.config.auth\n ? await options.config.auth.getToken()\n : undefined\n } catch (error) {\n logger?.debug('connectSse failed to get token', { error })\n scheduleReconnect()\n return\n }\n\n if (closed) {\n return\n }\n\n const headers: Record<string, string> = {\n accept: 'text/event-stream',\n }\n // Correlation headers (traceparent, x-cc-session-id) so the SSE connection\n // is traceable and grouped into the session, mirroring request(). A\n // throwing getDynamicHeaders is swallowed \u2014 the stream still connects.\n if (options.config.getDynamicHeaders) {\n try {\n Object.assign(headers, options.config.getDynamicHeaders())\n } catch (error) {\n logger?.debug('connectSse getDynamicHeaders threw', { error })\n }\n }\n if (token) {\n headers.authorization = `Bearer ${token}`\n }\n if (lastEventId !== undefined) {\n headers['last-event-id'] = lastEventId\n }\n\n const parser = new SseParser(options.onMessage, lastEventId)\n\n try {\n const response = await fetch(options.url, {\n method: 'GET',\n headers,\n signal: controller.signal,\n ...(options.config.proxyAgent ?? {}),\n })\n\n if (!response.ok) {\n // Auth blip: retry once immediately with a freshly minted token before\n // falling back to backoff.\n if (\n (response.status === 401 || response.status === 403) &&\n !authRetryUsed\n ) {\n authRetryUsed = true\n logger?.debug(\n 'connectSse auth error, retrying once with fresh token',\n {\n status: response.status,\n },\n )\n setState('reconnecting')\n void run()\n return\n }\n logger?.debug('connectSse non-ok response', { status: response.status })\n scheduleReconnect()\n return\n }\n\n if (!response.body) {\n logger?.debug('connectSse response has no body')\n scheduleReconnect()\n return\n }\n\n // Connected successfully: reset backoff + auth-retry budget.\n attempt = 0\n authRetryUsed = false\n setState('open')\n armHeartbeat()\n\n const reader = response.body.getReader()\n const decoder = new TextDecoder()\n\n while (!closed) {\n const { done, value } = await reader.read()\n if (done) {\n break\n }\n // Any bytes (incl. comments) count as liveness.\n armHeartbeat()\n parser.push(decoder.decode(value, { stream: true }))\n lastEventId = parser.getLastEventId()\n }\n\n // Stream ended cleanly (server closed): reconnect unless we're closing.\n if (!closed) {\n scheduleReconnect()\n }\n } catch (error) {\n if (closed) {\n return\n }\n // AbortError from close() is handled by the `closed` guard above; an\n // AbortError from the heartbeat means we intentionally dropped a silent\n // connection and should reconnect.\n logger?.debug('connectSse stream error, reconnecting', { error })\n scheduleReconnect()\n } finally {\n clearHeartbeat()\n }\n }\n\n const close = (): void => {\n if (closed) {\n return\n }\n closed = true\n clearHeartbeat()\n if (reconnectTimer !== undefined) {\n clearTimeout(reconnectTimer)\n reconnectTimer = undefined\n }\n controller?.abort()\n setStateClosed()\n }\n\n // `setState` short-circuits once `closed` is true, so set the terminal state\n // through a dedicated path.\n function setStateClosed(): void {\n state = 'closed'\n try {\n options.onStateChange?.('closed')\n } catch (error) {\n logger?.debug('connectSse onStateChange callback threw', { error })\n }\n }\n\n void run()\n\n return {\n close,\n get state() {\n return state\n },\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\n/**\n * Dependency-free Server-Sent Events client built on `fetch` + `ReadableStream`.\n *\n * Why not the native `EventSource`? It cannot send an `Authorization` header,\n * which every Camunda stream requires. This helper reuses the same\n * `config.auth.getToken()` contract as `request()`, so it always sends a fresh\n * bearer token \u2014 including on every reconnect, which is how token rotation is\n * handled (no separate refresh timer needed on the consumer side).\n *\n * It is isomorphic (browser + Node 22+), auto-reconnects with exponential\n * backoff + full jitter, honours `Last-Event-ID`, and aborts+reconnects when\n * the stream goes silent past `heartbeatTimeoutMs` (comment/keep-alive frames\n * count as activity, so a well-behaved server keeps the connection pinned).\n * A `204` answer ends the connection for good, as the SSE standard asks.\n */\n\nexport type SseConnectionState =\n | 'connecting'\n | 'open'\n | 'reconnecting'\n | 'closed'\n\nexport interface SseMessage {\n /** Concatenated `data:` lines (newline-joined), excluding the trailing newline. */\n data: string\n /** The `event:` field, if the server set one. */\n event?: string\n /** The `id:` field, if the server set one. Echoed back as `Last-Event-ID`. */\n id?: string\n}\n\nexport interface SseConnectionOptions {\n /** Absolute URL of the event stream. */\n url: string\n /** Reuses `auth.getToken` (called per (re)connect) and `logger`. */\n config: RequestBaseParamsConfig\n /** Called for each complete, non-empty SSE event (comment-only frames excluded). */\n onMessage: (message: SseMessage) => void\n /** Observability hook for connection lifecycle transitions. */\n onStateChange?: (state: SseConnectionState) => void\n /**\n * Abort + reconnect when no bytes (including comments / keep-alives) arrive\n * for this long. Default 120_000 ms.\n */\n heartbeatTimeoutMs?: number\n /** Backoff tuning. Defaults: base 1_000 ms, max 30_000 ms, full jitter. */\n reconnect?: {\n baseDelayMs?: number\n maxDelayMs?: number\n }\n}\n\nexport interface SseConnection {\n /** Idempotent. Aborts any in-flight fetch, cancels timers, emits no further events. */\n close: () => void\n /** Current lifecycle state. */\n readonly state: SseConnectionState\n}\n\nconst DEFAULT_HEARTBEAT_TIMEOUT_MS = 120_000\nconst DEFAULT_BASE_DELAY_MS = 1_000\nconst DEFAULT_MAX_DELAY_MS = 30_000\n\n/**\n * Incrementally parses a `text/event-stream` byte stream into complete events.\n * Events are separated by a blank line; `data:` lines accumulate; `event:`/`id:`\n * set the corresponding fields; lines starting with `:` are comments (ignored,\n * but still count as stream activity for the heartbeat).\n */\nclass SseParser {\n private buffer = ''\n private dataLines: string[] = []\n private eventName: string | undefined\n private lastEventId: string | undefined\n\n constructor(\n private readonly onMessage: (message: SseMessage) => void,\n /** Seed used to resume: exposed back so the connection can send Last-Event-ID. */\n lastEventId: string | undefined,\n ) {\n this.lastEventId = lastEventId\n }\n\n getLastEventId(): string | undefined {\n return this.lastEventId\n }\n\n /** Feed a decoded text chunk. Returns nothing; dispatches via `onMessage`. */\n push(chunk: string): void {\n this.buffer += chunk\n // Normalize CRLF / CR to LF so line splitting is uniform.\n this.buffer = this.buffer.replace(/\\r\\n?/g, '\\n')\n\n let newlineIndex = this.buffer.indexOf('\\n')\n while (newlineIndex !== -1) {\n const line = this.buffer.slice(0, newlineIndex)\n this.buffer = this.buffer.slice(newlineIndex + 1)\n this.handleLine(line)\n newlineIndex = this.buffer.indexOf('\\n')\n }\n }\n\n private handleLine(line: string): void {\n // Blank line: dispatch the accumulated event.\n if (line === '') {\n this.dispatch()\n return\n }\n\n // Comment line (keep-alive) \u2014 ignored.\n if (line.startsWith(':')) {\n return\n }\n\n const colonIndex = line.indexOf(':')\n const field = colonIndex === -1 ? line : line.slice(0, colonIndex)\n let value = colonIndex === -1 ? '' : line.slice(colonIndex + 1)\n // A single leading space after the colon is stripped, per the spec.\n if (value.startsWith(' ')) {\n value = value.slice(1)\n }\n\n switch (field) {\n case 'data':\n this.dataLines.push(value)\n break\n case 'event':\n this.eventName = value\n break\n case 'id':\n // Per spec, an id containing NUL is ignored; otherwise it updates the\n // last-event-id used on reconnect.\n if (!value.includes('\\u0000')) {\n this.lastEventId = value\n }\n break\n // `retry:` and unknown fields are intentionally ignored.\n default:\n break\n }\n }\n\n private dispatch(): void {\n if (this.dataLines.length === 0 && this.eventName === undefined) {\n // Nothing to dispatch (e.g. stray blank line).\n this.reset()\n return\n }\n\n this.onMessage({\n data: this.dataLines.join('\\n'),\n event: this.eventName,\n id: this.lastEventId,\n })\n this.reset()\n }\n\n private reset(): void {\n this.dataLines = []\n this.eventName = undefined\n }\n}\n\nfunction computeBackoff(\n attempt: number,\n baseDelayMs: number,\n maxDelayMs: number,\n): number {\n const exponential = Math.min(maxDelayMs, baseDelayMs * 2 ** attempt)\n // Full jitter: pick uniformly in [0, exponential].\n return Math.floor(Math.random() * exponential)\n}\n\nexport function connectSse(options: SseConnectionOptions): SseConnection {\n const heartbeatTimeoutMs =\n options.heartbeatTimeoutMs ?? DEFAULT_HEARTBEAT_TIMEOUT_MS\n const baseDelayMs = options.reconnect?.baseDelayMs ?? DEFAULT_BASE_DELAY_MS\n const maxDelayMs = options.reconnect?.maxDelayMs ?? DEFAULT_MAX_DELAY_MS\n const logger = options.config.logger\n\n let state: SseConnectionState = 'connecting'\n let closed = false\n let attempt = 0\n let lastEventId: string | undefined\n let controller: AbortController | undefined\n let heartbeatTimer: ReturnType<typeof setTimeout> | undefined\n let reconnectTimer: ReturnType<typeof setTimeout> | undefined\n // Once we've seen a 401/403 we allow exactly one immediate fresh-token retry\n // before falling back to normal backoff, so a transient auth blip self-heals\n // without hammering the token endpoint.\n let authRetryUsed = false\n\n const setState = (next: SseConnectionState): void => {\n if (state === next || closed) {\n return\n }\n state = next\n try {\n options.onStateChange?.(next)\n } catch (error) {\n logger?.debug('connectSse onStateChange callback threw', { error })\n }\n }\n\n const clearHeartbeat = (): void => {\n if (heartbeatTimer !== undefined) {\n clearTimeout(heartbeatTimer)\n heartbeatTimer = undefined\n }\n }\n\n const armHeartbeat = (): void => {\n clearHeartbeat()\n heartbeatTimer = setTimeout(() => {\n logger?.debug('connectSse heartbeat timeout, reconnecting', {\n url: options.url,\n })\n // Abort the current fetch; the read loop's catch schedules the reconnect.\n controller?.abort()\n }, heartbeatTimeoutMs)\n }\n\n const scheduleReconnect = (): void => {\n if (closed) {\n return\n }\n // Guard against stacking timers: multiple error paths (heartbeat abort +\n // stream end, etc.) can each call scheduleReconnect before the pending\n // timer fires. Without this, overlapping timers spawn concurrent run()\n // loops (and concurrent fetches).\n if (reconnectTimer !== undefined) {\n return\n }\n setState('reconnecting')\n const delay = computeBackoff(attempt, baseDelayMs, maxDelayMs)\n attempt += 1\n reconnectTimer = setTimeout(() => {\n reconnectTimer = undefined\n void run()\n }, delay)\n }\n\n const run = async (): Promise<void> => {\n if (closed) {\n return\n }\n\n controller = new AbortController()\n\n let token: string | undefined\n try {\n token = options.config.auth\n ? await options.config.auth.getToken()\n : undefined\n } catch (error) {\n logger?.debug('connectSse failed to get token', { error })\n scheduleReconnect()\n return\n }\n\n if (closed) {\n return\n }\n\n const headers: Record<string, string> = {\n accept: 'text/event-stream',\n }\n // Correlation headers (traceparent, x-cc-session-id) so the SSE connection\n // is traceable and grouped into the session, mirroring request(). A\n // throwing getDynamicHeaders is swallowed \u2014 the stream still connects.\n if (options.config.getDynamicHeaders) {\n try {\n Object.assign(headers, options.config.getDynamicHeaders())\n } catch (error) {\n logger?.debug('connectSse getDynamicHeaders threw', { error })\n }\n }\n if (token) {\n headers.authorization = `Bearer ${token}`\n }\n if (lastEventId !== undefined) {\n headers['last-event-id'] = lastEventId\n }\n\n const parser = new SseParser(options.onMessage, lastEventId)\n\n try {\n const response = await fetch(options.url, {\n method: 'GET',\n headers,\n signal: controller.signal,\n ...(options.config.proxyAgent ?? {}),\n })\n\n if (!response.ok) {\n // Auth blip: retry once immediately with a freshly minted token before\n // falling back to backoff.\n if (\n (response.status === 401 || response.status === 403) &&\n !authRetryUsed\n ) {\n authRetryUsed = true\n logger?.debug(\n 'connectSse auth error, retrying once with fresh token',\n {\n status: response.status,\n },\n )\n setState('reconnecting')\n void run()\n return\n }\n logger?.debug('connectSse non-ok response', { status: response.status })\n scheduleReconnect()\n return\n }\n\n // Per the SSE standard, a 204 means the server wants no stream for this\n // client. Reconnecting would only repeat the request.\n if (response.status === 204) {\n logger?.debug('connectSse got 204, the server wants no stream', {\n url: options.url,\n })\n close()\n return\n }\n\n if (!response.body) {\n logger?.debug('connectSse response has no body')\n scheduleReconnect()\n return\n }\n\n // Connected successfully: reset backoff + auth-retry budget.\n attempt = 0\n authRetryUsed = false\n setState('open')\n armHeartbeat()\n\n const reader = response.body.getReader()\n const decoder = new TextDecoder()\n\n while (!closed) {\n const { done, value } = await reader.read()\n if (done) {\n break\n }\n // Any bytes (incl. comments) count as liveness.\n armHeartbeat()\n parser.push(decoder.decode(value, { stream: true }))\n lastEventId = parser.getLastEventId()\n }\n\n // Stream ended cleanly (server closed): reconnect unless we're closing.\n if (!closed) {\n scheduleReconnect()\n }\n } catch (error) {\n if (closed) {\n return\n }\n // AbortError from close() is handled by the `closed` guard above; an\n // AbortError from the heartbeat means we intentionally dropped a silent\n // connection and should reconnect.\n logger?.debug('connectSse stream error, reconnecting', { error })\n scheduleReconnect()\n } finally {\n clearHeartbeat()\n }\n }\n\n const close = (): void => {\n if (closed) {\n return\n }\n closed = true\n clearHeartbeat()\n if (reconnectTimer !== undefined) {\n clearTimeout(reconnectTimer)\n reconnectTimer = undefined\n }\n controller?.abort()\n setStateClosed()\n }\n\n // `setState` short-circuits once `closed` is true, so set the terminal state\n // through a dedicated path.\n function setStateClosed(): void {\n state = 'closed'\n try {\n options.onStateChange?.('closed')\n } catch (error) {\n logger?.debug('connectSse onStateChange callback threw', { error })\n }\n }\n\n void run()\n\n return {\n close,\n get state() {\n return state\n },\n }\n}\n"],
5
+ "mappings": "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",
6
6
  "names": []
7
7
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@camunda/ccma-api",
3
- "version": "3.1.0",
3
+ "version": "5.0.0",
4
4
  "description": "Centralized API service layer for Camunda Cloud Management Apps",
5
5
  "bugs": {
6
6
  "url": "https://github.com/camunda/camunda-cloud-management-apps/issues"
@@ -41,7 +41,7 @@
41
41
  }
42
42
  },
43
43
  "dependencies": {
44
- "@camunda/ccma-shared-types": "5.0.0"
44
+ "@camunda/ccma-shared-types": "7.0.0"
45
45
  },
46
46
  "scripts": {
47
47
  "build": "node esbuild.mjs && tsc --emitDeclarationOnly --outDir dist",