{"version":3,"sources":["../../../src/shared/pubsub/pubsub.ts"],"names":["initializedClient","pubsubClient","PubSub","topicMap","Map","retrySettings","retryCodes","backoffSettings","initialRetryDelayMillis","retryDelayMultiplier","maxRetryDelayMillis","initialRpcTimeoutMillis","rpcTimeoutMultiplier","maxRpcTimeoutMillis","totalTimeoutMillis","addTopicToMap","topic","topicWithOpts","setPublishOptions","batching","maxMessages","maxMilliseconds","maxBytes","gaxOpts","retry","set","get","getTopic","topicPublisher","has","prepareTopics","topics","forEach","TIMEOUT_ERROR","publish","data","logger","Buffer","from","JSON","stringify","err","mesId","message","includes","delete","error","subscriptionNamesByTopic","createTopicAndSubscription","fullName","options","shortName","replace","genName","String","process","env","USER","lastName","autoCreateTopic","subscriptionName","autoCreateSubscription","subscriptionOptions","subOpts","undefined","topicExists","exists","create","subscription","subscribe","optLogger","pipe","name","Observable","subscriber","log","EOL","add","close","then","catch"],"mappings":"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","sourcesContent":["import * as PubSub from '@google-cloud/pubsub';\nimport { fromEvent, defer, from, merge, Observable } from 'rxjs';\nimport { switchMap, map, ignoreElements } from 'rxjs/operators';\nimport { appName } from '../app';\nimport { EOL } from 'os';\nimport { isDevBuild } from '../isTest';\nimport { registerError } from '../registerError';\nimport { BasicLogger, defaultBasicLogger } from '../logging';\nimport { uuid } from '../uuid';\n\nlet initializedClient: PubSub.PubSub | null = null;\n\nexport const pubsubClient = () => {\n  return initializedClient || (initializedClient = new PubSub.PubSub());\n};\n\nconst topicMap = new Map<string, PubSub.Topic>();\n\nconst retrySettings = {\n  retryCodes: [\n    10, // 'ABORTED'\n    1, // 'CANCELLED',\n    4, // 'DEADLINE_EXCEEDED'\n    13, // 'INTERNAL'\n    8, // 'RESOURCE_EXHAUSTED'\n    14, // 'UNAVAILABLE'\n    2, // 'UNKNOWN'\n  ],\n  backoffSettings: {\n    initialRetryDelayMillis: 5,\n    retryDelayMultiplier: 2,\n    maxRetryDelayMillis: 60000,\n    initialRpcTimeoutMillis: 10000,\n    rpcTimeoutMultiplier: 1.0,\n    maxRpcTimeoutMillis: 10000,\n    totalTimeoutMillis: 10000,\n  },\n};\n\nconst addTopicToMap = (topic: string) => {\n  const topicWithOpts = pubsubClient().topic(topic);\n\n  topicWithOpts.setPublishOptions({\n    batching: {\n      maxMessages: 1,\n      maxMilliseconds: 1,\n      maxBytes: 1,\n    },\n    gaxOpts: {\n      retry: retrySettings,\n    },\n  });\n\n  topicMap.set(topic, topicWithOpts);\n\n  return topicMap.get(topic) as PubSub.Topic;\n};\n\nexport const getTopic = (topic: string): PubSub.Topic => {\n  const topicPublisher = topicMap.has(topic)\n    ? topicMap.get(topic)\n    : addTopicToMap(topic);\n\n  if (!topicPublisher) {\n    return addTopicToMap(topic);\n  }\n\n  return topicPublisher;\n};\n\nexport async function prepareTopics(topics: string[]) {\n  topics.forEach((topic) => {\n    addTopicToMap(topic);\n  });\n}\n\nconst TIMEOUT_ERROR = 'Retry total timeout exceeded before any response';\n\nexport async function publish<T>(\n  topic: string,\n  data: T,\n  logger: BasicLogger = defaultBasicLogger()\n) {\n  const topicPublisher = getTopic(topic);\n\n  topicPublisher.publish(\n    Buffer.from(JSON.stringify(data), 'utf8'),\n    (err: Error | null, mesId) => {\n      if (err) {\n        registerError(err);\n        if (err.message.includes(TIMEOUT_ERROR)) {\n          topicMap.delete(topic);\n        }\n        logger.error(\n          `💥  Error when publishing to topic ${topic} ${\n            mesId ? `with message ${mesId}` : ''\n          }`,\n          err\n        );\n      }\n    }\n  );\n}\n\nexport type Message = PubSub.Message;\n\ntype SubscribeOptions = PubSub.SubscriptionOptions & {\n  autoCreateTopic?: boolean;\n  subscriptionName?: string;\n  autoCreateSubscription?: boolean;\n  autoDeleteSubscription?: boolean;\n  subscriptionOptions?: PubSub.CreateSubscriptionOptions;\n};\n\nconst subscriptionNamesByTopic = new Map<string, string>();\n\nasync function createTopicAndSubscription(\n  topic: string,\n  fullName: string,\n  options?: SubscribeOptions\n) {\n  const shortName = fullName.replace('@aimee-blue/', '');\n\n  const genName = isDevBuild()\n    ? `${shortName}-${String(process.env.USER)}`\n    : `${shortName}-${uuid()}`;\n\n  const lastName = subscriptionNamesByTopic.get(topic);\n\n  const {\n    autoCreateTopic,\n    subscriptionName,\n    autoCreateSubscription,\n    subscriptionOptions,\n    ...subOpts\n  } = {\n    autoCreateTopic: true,\n    subscriptionName: lastName || genName,\n    autoCreateSubscription: true,\n    subscriptionOptions: undefined,\n    ...options,\n  };\n\n  const topicPublisher = getTopic(topic);\n\n  if (autoCreateTopic && !lastName) {\n    const [topicExists] = await topicPublisher.exists();\n    if (!topicExists) {\n      await topicPublisher.create();\n    }\n  }\n\n  const subscription = topicPublisher.subscription(subscriptionName, subOpts);\n\n  if (autoCreateSubscription && !lastName) {\n    const [exists] = await subscription.exists();\n    if (!exists) {\n      await subscription.create(subscriptionOptions);\n    }\n  }\n\n  // if success, then remember:\n  if (!subscriptionNamesByTopic.get(topic)) {\n    subscriptionNamesByTopic.set(topic, subscriptionName);\n  }\n\n  return subscription;\n}\n\nexport function subscribe(\n  topic: string,\n  options?: SubscribeOptions,\n  optLogger?: BasicLogger\n) {\n  return defer(() => from(appName())).pipe(\n    switchMap((name) => createTopicAndSubscription(topic, name, options)),\n    switchMap(\n      (subscription) =>\n        new Observable<Message>((subscriber) => {\n          const name = subscription.name;\n\n          const logger = optLogger || defaultBasicLogger();\n\n          logger.log(\n            `${EOL}🎬  Subscribing to topic \"${topic}\" with subscription \"${name}\"`,\n            EOL\n          );\n\n          subscriber.add(\n            merge(\n              fromEvent<PubSub.Message>(subscription, 'message'),\n              fromEvent<Error>(subscription, 'error').pipe(\n                map((err) => {\n                  throw err;\n                }),\n                ignoreElements()\n              )\n            ).subscribe(subscriber)\n          );\n          subscriber.add(() => {\n            subscription\n              .close()\n              .then(() => {\n                logger.log(\n                  `${EOL}🏁  Unsubscribed from \"${subscription.name}\"`,\n                  EOL\n                );\n              })\n              .catch((err: Error) => {\n                registerError(err);\n                logger.error(\n                  `${EOL}💥  Error when unsubscribing from \"${subscription.name}\"`,\n                  err,\n                  EOL\n                );\n              });\n          });\n        })\n    )\n  );\n}\n"],"file":"pubsub.js"}