{"version":3,"file":"createMessageChannel.cjs","names":["_messageGuards","require","createMessageChannel","channelName","messageDomain","payloadGuards","protocolVersion","typePrefix","isMessage","message","isRecord","type","startsWith","Object","hasOwn","slice","length","payload","messageCreators","fromEntries","keys","map","eventName","exports"],"sources":["../../../src/message-bus/createMessageChannel.ts"],"sourcesContent":["/*!\n * Copyright (c) 2026-present, Okta, Inc. and/or its affiliates. All rights reserved.\n * The Okta software accompanied by this notice is provided pursuant to the Apache License, Version 2.0 (the \"License.\")\n *\n * You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0.\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n *\n * See the License for the specific language governing permissions and limitations under the License.\n */\n\nimport { isRecord } from \"./messageGuards.js\";\n\n/**\n * Checks that a received payload has the shape one message type expects.\n */\nexport type PayloadGuard<Payload> = (payload: unknown) => payload is Payload;\n\nexport type PayloadGuards = Record<string, PayloadGuard<unknown>>;\n\nexport type PayloadOf<Guard> =\n  Guard extends PayloadGuard<infer Payload> ? Payload : never;\n\n/**\n * Every message a channel defines, as a union of `{ type, payload }` objects. `type` is `\"<messageDomain>/<eventName>\"`, the same shape Redux uses for action types.\n */\nexport type ChannelMessage<\n  MessageDomain extends string,\n  ChannelPayloadGuards extends PayloadGuards,\n> = {\n  [EventName in keyof ChannelPayloadGuards & string]: {\n    payload: PayloadOf<ChannelPayloadGuards[EventName]>;\n    type: `${MessageDomain}/${EventName}`;\n  };\n}[keyof ChannelPayloadGuards & string];\n\n/**\n * One function per message type. Each takes the payload and returns the whole message, so a sender can't misspell a `type` or send a payload of the wrong shape.\n */\nexport type MessageCreators<\n  MessageDomain extends string,\n  ChannelPayloadGuards extends PayloadGuards,\n> = {\n  [EventName in keyof ChannelPayloadGuards & string]: (\n    payload: PayloadOf<ChannelPayloadGuards[EventName]>,\n  ) => {\n    payload: PayloadOf<ChannelPayloadGuards[EventName]>;\n    type: `${MessageDomain}/${EventName}`;\n  };\n};\n\n/**\n * What a message bus needs to know about a channel to send and receive on it.\n */\nexport type MessageChannel<Message> = {\n  /**\n   * Name shared by every publisher and subscriber of the channel. Other code on the page also sends `message` events, so this is how a subscriber knows a message was meant for it.\n   */\n  channelName: string;\n  /**\n   * Checks that a received message is one this channel defines. Any script on the same origin can post a message, so a received one is never trusted without checking it.\n   */\n  isMessage: (message: unknown) => message is Message;\n  /**\n   * Which version of the channel's messages a sender speaks. A receiver drops messages from any other version.\n   */\n  protocolVersion: number;\n};\n\n/**\n * The union of every message a channel carries.\n */\nexport type MessageOf<Channel> =\n  Channel extends MessageChannel<infer Message> ? Message : never;\n\nexport type DefinedMessageChannel<\n  MessageDomain extends string,\n  ChannelPayloadGuards extends PayloadGuards,\n> = {\n  messageCreators: MessageCreators<MessageDomain, ChannelPayloadGuards>;\n} & MessageChannel<ChannelMessage<MessageDomain, ChannelPayloadGuards>>;\n\nexport type CreateMessageChannelArgs<\n  MessageDomain extends string,\n  ChannelPayloadGuards extends PayloadGuards,\n> = {\n  channelName: string;\n  /**\n   * The first half of every message `type` on this channel, such as `\"fullscreen\"` in `\"fullscreen/enterRequested\"`.\n   */\n  messageDomain: MessageDomain;\n  /**\n   * One check per message type, keyed by the second half of its `type`. The message types and their payload types all come from these checks, so the TypeScript types and the runtime check can't disagree.\n   */\n  payloadGuards: ChannelPayloadGuards;\n  /**\n   * Starts at `1`. Raise it only for a breaking change: a message type or field renamed, removed, or given a new meaning. Adding a message type or an optional field isn't breaking, because receivers ignore what they don't know.\n   */\n  protocolVersion: number;\n};\n\n/**\n * Define the messages a channel carries, once, and get both the TypeScript types and the runtime check from that one definition.\n *\n * Each app and Unified UI Shell can bundle a different version of Odyssey, and an auto-updater moves each repository to a new version on its own schedule. Compile-time types only help code built against the same version, so every received message is also checked at runtime.\n */\nexport const createMessageChannel = <\n  MessageDomain extends string,\n  ChannelPayloadGuards extends PayloadGuards,\n>({\n  channelName,\n  messageDomain,\n  payloadGuards,\n  protocolVersion,\n}: CreateMessageChannelArgs<\n  MessageDomain,\n  ChannelPayloadGuards\n>): DefinedMessageChannel<MessageDomain, ChannelPayloadGuards> => {\n  const typePrefix = `${messageDomain}/`;\n\n  const isMessage = (\n    message: unknown,\n  ): message is ChannelMessage<MessageDomain, ChannelPayloadGuards> =>\n    isRecord(message) &&\n    typeof message.type === \"string\" &&\n    message.type.startsWith(typePrefix) &&\n    Object.hasOwn(payloadGuards, message.type.slice(typePrefix.length)) &&\n    payloadGuards[message.type.slice(typePrefix.length)](message.payload);\n\n  // `Object.fromEntries` can't carry a separate type per key, so the mapped type is restored here. Every key and payload type still comes from `payloadGuards`.\n  const messageCreators = Object.fromEntries(\n    Object.keys(payloadGuards).map((eventName) => [\n      eventName,\n      (payload: unknown) => ({ payload, type: `${typePrefix}${eventName}` }),\n    ]),\n  ) as MessageCreators<MessageDomain, ChannelPayloadGuards>;\n\n  return {\n    channelName,\n    isMessage,\n    messageCreators,\n    protocolVersion,\n  };\n};\n"],"mappings":";;;;;;AAYA,IAAAA,cAAA,GAAAC,OAAA;AAZA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,GAiGO,MAAMC,oBAAoB,GAAGA,CAGlC;EACAC,WAAW;EACXC,aAAa;EACbC,aAAa;EACbC;AAIF,CAAC,KAAiE;EAChE,MAAMC,UAAU,GAAG,GAAGH,aAAa,GAAG;EAEtC,MAAMI,SAAS,GACbC,OAAgB,IAEhB,IAAAC,uBAAQ,EAACD,OAAO,CAAC,IACjB,OAAOA,OAAO,CAACE,IAAI,KAAK,QAAQ,IAChCF,OAAO,CAACE,IAAI,CAACC,UAAU,CAACL,UAAU,CAAC,IACnCM,MAAM,CAACC,MAAM,CAACT,aAAa,EAAEI,OAAO,CAACE,IAAI,CAACI,KAAK,CAACR,UAAU,CAACS,MAAM,CAAC,CAAC,IACnEX,aAAa,CAACI,OAAO,CAACE,IAAI,CAACI,KAAK,CAACR,UAAU,CAACS,MAAM,CAAC,CAAC,CAACP,OAAO,CAACQ,OAAO,CAAC;EAGvE,MAAMC,eAAe,GAAGL,MAAM,CAACM,WAAW,CACxCN,MAAM,CAACO,IAAI,CAACf,aAAa,CAAC,CAACgB,GAAG,CAAEC,SAAS,IAAK,CAC5CA,SAAS,EACRL,OAAgB,KAAM;IAAEA,OAAO;IAAEN,IAAI,EAAE,GAAGJ,UAAU,GAAGe,SAAS;EAAG,CAAC,CAAC,CACvE,CACH,CAAyD;EAEzD,OAAO;IACLnB,WAAW;IACXK,SAAS;IACTU,eAAe;IACfZ;EACF,CAAC;AACH,CAAC;AAACiB,OAAA,CAAArB,oBAAA,GAAAA,oBAAA","ignoreList":[]}