{"version":3,"file":"channel-activation-config.cjs","names":[],"sources":["../../../../src/v2/runtime/core/channel-activation-config.ts"],"sourcesContent":["import type { CopilotKitIntelligence } from \"../intelligence-platform\";\n// Type-only: @copilotkit/channels is pure-ESM, so a value import would break this\n// package's CJS output (see `runtime.ts` for the same constraint).\nimport type { Channel } from \"@copilotkit/channels\";\n\n/**\n * Error thrown when a Channel activation config cannot be derived — either the\n * Intelligence API key does not carry a project id in the expected\n * `cpk-{projectId}_...` format, or the {@link Channel} is missing a `name`.\n */\nexport class ChannelConfigError extends Error {\n  constructor(message: string) {\n    super(message);\n    this.name = \"ChannelConfigError\";\n  }\n}\n\n/**\n * Resolved configuration needed to activate a single Channel against a\n * running Intelligence runtime instance.\n */\nexport interface ChannelActivationConfig {\n  /** Intelligence runner websocket URL the Channel connects to. */\n  wsUrl: string;\n  /** Intelligence API key used to authenticate the runner connection. */\n  apiKey: string;\n  /** Intelligence app-api HTTP base URL (`intelligence.ɵgetApiUrl()`), forwarded\n   * to the transport so the managed realtime path enables file/history parity\n   * (those are HTTP-only). Without it, Channels started by the normal runtime\n   * handler run with no history and no file support (OSS-476). */\n  apiUrl: string;\n  /** Project id parsed from {@link apiKey}. */\n  projectId: number;\n  /** The Channel's declared name (`createChannel({ name })`). */\n  channelName: string;\n  /**\n   * The managed provider this Channel declares to the Intelligence gateway on\n   * join, resolved from the Channel's per-Channel `provider` (e.g. `\"slack\"` or\n   * `\"teams\"`), defaulting to `\"slack\"`. Named `adapter` because that is the\n   * field the gateway's join payload expects; the gateway resolves the actual\n   * connection for the declared provider.\n   */\n  adapter: string;\n  /** Identifier for the runtime instance activating this Channel. */\n  runtimeInstanceId: string;\n}\n\n/** Matches the `cpk-{projectId}_...` Intelligence API key format. */\nconst API_KEY_PROJECT_ID_PATTERN = /^cpk-(\\d+)_/;\n\n/**\n * Parse the project id embedded in an Intelligence API key.\n *\n * Intelligence API keys are formatted `cpk-{projectId}_{rest}` — this\n * extracts and numerically parses the `{projectId}` segment.\n *\n * @param apiKey - The Intelligence API key to parse.\n * @returns The parsed, strictly-positive, safe-integer project id.\n * @throws {ChannelConfigError} If `apiKey` does not match the expected\n *   `cpk-{projectId}_...` format — a wrong/missing prefix or an absent project\n *   id segment all fail the same match — or if the parsed project id is not a\n *   strictly-positive safe integer.\n */\nexport function parseProjectIdFromApiKey(apiKey: string): number {\n  const match = API_KEY_PROJECT_ID_PATTERN.exec(apiKey);\n  if (!match) {\n    // The whole API key is a `cpk-…` secret — everything after the fixed `cpk-`\n    // namespace is sensitive, so a fixed-width slice (e.g. `apiKey.slice(0, 8)`)\n    // would echo secret bytes for a `cpk-_short_long`-shaped key. This message is\n    // logged and surfaced through `ready()`'s AggregateError, so echo NONE of the\n    // key value; name only the expected format to aid diagnosis.\n    throw new ChannelConfigError(\n      `Could not parse a project id from the Intelligence API key — expected the ` +\n        `\"cpk-{projectId}_...\" format (the key value is omitted here to avoid ` +\n        `leaking secret material).`,\n    );\n  }\n  const projectId = Number(match[1]);\n  // Validate the parser's OWN output: `cpk-0_...` matches the pattern but a\n  // non-positive project id would otherwise fail deep inside the launcher's\n  // `assertValidChannelRealtimeScope` (which requires a positive projectId).\n  // A very long digit run also matches `\\d+` but loses precision (or overflows\n  // to Infinity) once coerced to `Number`, so it must be rejected too even\n  // though it is `> 0` — `Number.isSafeInteger` catches both. This is the\n  // parser guarding its own contract, not a channel-name replica, so it\n  // belongs here. Reuse the same redaction: never echo the key value.\n  if (!Number.isSafeInteger(projectId) || projectId <= 0) {\n    throw new ChannelConfigError(\n      `Parsed an invalid project id (${projectId}) from the Intelligence API ` +\n        `key — the project id in \"cpk-{projectId}_...\" must be a positive safe ` +\n        `integer (the key value is omitted here to avoid leaking secret material).`,\n    );\n  }\n  return projectId;\n}\n\n/**\n * Derive the {@link ChannelActivationConfig} needed to activate `channel`\n * against the given Intelligence runtime configuration.\n *\n * @param args.intelligence - The Intelligence runtime client to pull the\n *   runner websocket URL and auth token from.\n * @param args.channel - The Channel being activated. Must have a `name`; its\n *   per-Channel `provider` selects the managed adapter declared to the gateway.\n * @param args.runtimeInstanceId - Identifier for the activating runtime\n *   instance, passed through unchanged.\n * @returns The resolved {@link ChannelActivationConfig}.\n * @throws {ChannelConfigError} If the Intelligence API key does not carry a\n *   parseable, strictly-positive project id, or if `channel.name` is\n *   missing/empty.\n *\n * The managed provider is a PER-CHANNEL choice read from `channel.provider`, so\n * one runtime can activate a Slack-backed Channel and a Teams-backed Channel\n * side by side. When `channel.provider` is unset the config adapter defaults to\n * `\"slack\"` — an explicit, documented default, not a silent global. The SDK\n * only DECLARES this provider to the Intelligence gateway on join; the gateway\n * resolves the actual connection and is the authority on which providers it\n * accepts (it accepts only `\"slack\"` today — Teams gateway support is tracked\n * in OSS-450).\n *\n * The Channel-name FORMAT rules (lowercase kebab-case, 3–64 chars) and the\n * reserved-name rule are NOT re-checked here. Their single source of truth is\n * the `@copilotkit/channels-intelligence` launcher\n * (`assertValidChannelRealtimeScope` + `assertValidChannelNames`), which\n * validates them at activation; a malformed name surfaces as a logged `error`\n * status via {@link ChannelManager.ready} rather than an up-front throw. An\n * empty/missing name is still rejected here because that is this config's own\n * precondition (it has no name to forward at all), not a downstream replica.\n */\nexport function deriveChannelActivationConfig(args: {\n  intelligence: CopilotKitIntelligence;\n  channel: Channel;\n  runtimeInstanceId: string;\n}): ChannelActivationConfig {\n  const { intelligence, channel, runtimeInstanceId } = args;\n\n  if (!channel.name) {\n    throw new ChannelConfigError(\n      \"Channel is missing a `name` — pass createChannel({ name }) to activate it.\",\n    );\n  }\n\n  const channelName = channel.name;\n\n  const wsUrl = intelligence.ɵgetRunnerWsUrl();\n  const apiUrl = intelligence.ɵgetApiUrl();\n  const apiKey = intelligence.ɵgetRunnerAuthToken();\n  const projectId = parseProjectIdFromApiKey(apiKey);\n\n  // Resolve the managed adapter declared to the gateway from the Channel's OWN\n  // `provider` — a per-Channel choice, not a manager-wide default. When\n  // `provider` is unset the adapter is the documented default `\"slack\"`; set\n  // `createChannel({ provider: \"teams\" })` to declare Teams instead. The value\n  // is trimmed so a padded runtime value (one that bypassed the typed union)\n  // resolves to its bare provider rather than being forwarded with whitespace,\n  // and a blank/whitespace-only provider falls back to `\"slack\"` (`??` alone\n  // would keep `\"\"`).\n  const trimmedProvider = channel.provider?.trim();\n\n  return {\n    wsUrl,\n    apiUrl,\n    apiKey,\n    projectId,\n    channelName,\n    adapter: trimmedProvider ? trimmedProvider : \"slack\",\n    runtimeInstanceId,\n  };\n}\n"],"mappings":";;;;;;;;AAUA,IAAa,qBAAb,cAAwC,MAAM;CAC5C,YAAY,SAAiB;AAC3B,QAAM,QAAQ;AACd,OAAK,OAAO;;;;AAmChB,MAAM,6BAA6B;;;;;;;;;;;;;;AAenC,SAAgB,yBAAyB,QAAwB;CAC/D,MAAM,QAAQ,2BAA2B,KAAK,OAAO;AACrD,KAAI,CAAC,MAMH,OAAM,IAAI,mBACR,6KAGD;CAEH,MAAM,YAAY,OAAO,MAAM,GAAG;AASlC,KAAI,CAAC,OAAO,cAAc,UAAU,IAAI,aAAa,EACnD,OAAM,IAAI,mBACR,iCAAiC,UAAU,6KAG5C;AAEH,QAAO;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAoCT,SAAgB,8BAA8B,MAIlB;CAC1B,MAAM,EAAE,cAAc,SAAS,sBAAsB;AAErD,KAAI,CAAC,QAAQ,KACX,OAAM,IAAI,mBACR,6EACD;CAGH,MAAM,cAAc,QAAQ;CAE5B,MAAM,QAAQ,aAAa,iBAAiB;CAC5C,MAAM,SAAS,aAAa,YAAY;CACxC,MAAM,SAAS,aAAa,qBAAqB;CACjD,MAAM,YAAY,yBAAyB,OAAO;CAUlD,MAAM,kBAAkB,QAAQ,UAAU,MAAM;AAEhD,QAAO;EACL;EACA;EACA;EACA;EACA;EACA,SAAS,kBAAkB,kBAAkB;EAC7C;EACD"}