{"version":3,"sources":["../lib/state-storage.ts","../lib/state-storage-fake.ts"],"sourcesContent":["import { SSMClient, GetParameterCommand, PutParameterCommand } from \"@aws-sdk/client-ssm\";\nimport { Logger } from \"@sailplane/logger\";\n\nconst logger = new Logger(\"state-storage\");\n\ninterface StateStorageOptions {\n  /** If true, do not log values. */\n  quiet?: boolean;\n  /**\n   * If true, store as encrypted or decrypt on get. Uses account default KMS key.\n   * Implies quiet as well.\n   */\n  secure?: boolean;\n  /**\n   * If set, set and get the value as is, not JSON. (Only works for string values.)\n   */\n  isRaw?: boolean;\n}\n\n/**\n * Service for storing state of other services.\n * Saved state can be fetched by any other execution of code in the AWS account, region,\n * and environment (dev/prod).\n *\n * Suggested use with Injector:\n *   Injector.register(StateStorage, () => new StateStorage(process.env.STATE_STORAGE_PREFIX));\n */\nexport class StateStorage {\n  /**\n   * Construct\n   *\n   * @param namePrefix prefix string to start all parameter names with.\n   *                   Should at least include the environment (dev/prod).\n   * @param ssm the SSMClient to use\n   */\n  constructor(\n    private readonly namePrefix: string,\n    /* istanbul ignore next - default never used when unit testing */\n    private readonly ssm = new SSMClient({}),\n  ) {\n    if (!this.namePrefix.endsWith(\"/\")) this.namePrefix = this.namePrefix + \"/\";\n  }\n\n  /**\n   * Save state for a later run.\n   *\n   * @param {string} service name of the service (class name?) that owns the state\n   * @param {string} name name of the state variable to save\n   * @param value content to save\n   * @param optionsOrQuiet a StateStorageOptions, or if true sets quiet option. (For backward compatibility.)\n   * @returns {Promise<void>} completes upon success - rejects if lacking ssm:PutParameter permission\n   */\n  set(\n    service: string,\n    name: string,\n    value: any,\n    optionsOrQuiet: boolean | StateStorageOptions = {},\n  ): Promise<void> {\n    const options =\n      optionsOrQuiet === true ? { quiet: true } : (optionsOrQuiet as StateStorageOptions);\n    const key = this.generateName(service, name);\n    const content = options.isRaw === true ? value : JSON.stringify(value);\n\n    if (options.quiet || options.secure) {\n      logger.info(`Saving state ${key}`);\n    } else {\n      logger.info(`Saving state ${key}=${content}`);\n    }\n\n    const command = new PutParameterCommand({\n      Name: key,\n      Type: options.secure ? \"SecureString\" : \"String\",\n      Value: content,\n      Overwrite: true,\n    });\n    return this.ssm.send(command).then(() => undefined);\n  }\n\n  /**\n   * Fetch last state saved.\n   *\n   * @param {string} service name of the service (class name?) that owns the state\n   * @param {string} name name of the state variable to fetch\n   * @param optionsOrQuiet a StateStorageOptions, or if true sets quiet option. (For backward compatibility.)\n   * @returns {Promise<any>} completes with the saved value, or reject if not found or lacking ssm:GetParameter permission\n   */\n  get(\n    service: string,\n    name: string,\n    optionsOrQuiet: boolean | StateStorageOptions = {},\n  ): Promise<any> {\n    const options =\n      optionsOrQuiet === true ? { quiet: true } : (optionsOrQuiet as StateStorageOptions);\n    const key = this.generateName(service, name);\n    const command = new GetParameterCommand({\n      Name: key,\n      WithDecryption: options.secure,\n    });\n\n    return this.ssm.send(command).then((result) => {\n      const content = result && result.Parameter ? result.Parameter.Value : undefined;\n\n      if (options.quiet || options.secure) {\n        logger.info(`Loaded state ${key}`);\n      } else {\n        logger.info(`Loaded state ${key}=${content}`);\n      }\n\n      return options.isRaw ? content : content ? JSON.parse(content) : undefined;\n    });\n  }\n\n  protected generateName(service: string, name: string): string {\n    return this.namePrefix + service + \"/\" + name;\n  }\n}\n","import { StateStorage } from \"./state-storage\";\n\n/**\n * Version of StateStorage to use in unit testing.\n * This fake will store data in instance memory, instead of the AWS Parameter Store.\n */\nexport class StateStorageFake extends StateStorage {\n  storage: Record<string, string> = {};\n\n  constructor(namePrefix: string) {\n    super(namePrefix);\n  }\n\n  set(service: string, name: string, value: any, _options: any): Promise<void> {\n    const key = this.generateName(service, name);\n    this.storage[key] = JSON.stringify(value);\n    return Promise.resolve();\n  }\n\n  get(service: string, name: string, _options: any): Promise<any> {\n    const key = this.generateName(service, name);\n\n    const content = this.storage[key];\n    if (content) return Promise.resolve(JSON.parse(content));\n    else return Promise.reject(new Error(\"mock StateStorage.get not found: \" + key));\n  }\n}\n"],"mappings":";AAAA,SAAS,WAAW,qBAAqB,2BAA2B;AACpE,SAAS,cAAc;AAEvB,IAAM,SAAS,IAAI,OAAO,eAAe;AAwBlC,IAAM,eAAN,MAAmB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQxB,YACmB,YAEA,MAAM,IAAI,UAAU,CAAC,CAAC,GACvC;AAHiB;AAEA;AAEjB,QAAI,CAAC,KAAK,WAAW,SAAS,GAAG,EAAG,MAAK,aAAa,KAAK,aAAa;AAAA,EAC1E;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,IACE,SACA,MACA,OACA,iBAAgD,CAAC,GAClC;AACf,UAAM,UACJ,mBAAmB,OAAO,EAAE,OAAO,KAAK,IAAK;AAC/C,UAAM,MAAM,KAAK,aAAa,SAAS,IAAI;AAC3C,UAAM,UAAU,QAAQ,UAAU,OAAO,QAAQ,KAAK,UAAU,KAAK;AAErE,QAAI,QAAQ,SAAS,QAAQ,QAAQ;AACnC,aAAO,KAAK,gBAAgB,GAAG,EAAE;AAAA,IACnC,OAAO;AACL,aAAO,KAAK,gBAAgB,GAAG,IAAI,OAAO,EAAE;AAAA,IAC9C;AAEA,UAAM,UAAU,IAAI,oBAAoB;AAAA,MACtC,MAAM;AAAA,MACN,MAAM,QAAQ,SAAS,iBAAiB;AAAA,MACxC,OAAO;AAAA,MACP,WAAW;AAAA,IACb,CAAC;AACD,WAAO,KAAK,IAAI,KAAK,OAAO,EAAE,KAAK,MAAM,MAAS;AAAA,EACpD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,IACE,SACA,MACA,iBAAgD,CAAC,GACnC;AACd,UAAM,UACJ,mBAAmB,OAAO,EAAE,OAAO,KAAK,IAAK;AAC/C,UAAM,MAAM,KAAK,aAAa,SAAS,IAAI;AAC3C,UAAM,UAAU,IAAI,oBAAoB;AAAA,MACtC,MAAM;AAAA,MACN,gBAAgB,QAAQ;AAAA,IAC1B,CAAC;AAED,WAAO,KAAK,IAAI,KAAK,OAAO,EAAE,KAAK,CAAC,WAAW;AAC7C,YAAM,UAAU,UAAU,OAAO,YAAY,OAAO,UAAU,QAAQ;AAEtE,UAAI,QAAQ,SAAS,QAAQ,QAAQ;AACnC,eAAO,KAAK,gBAAgB,GAAG,EAAE;AAAA,MACnC,OAAO;AACL,eAAO,KAAK,gBAAgB,GAAG,IAAI,OAAO,EAAE;AAAA,MAC9C;AAEA,aAAO,QAAQ,QAAQ,UAAU,UAAU,KAAK,MAAM,OAAO,IAAI;AAAA,IACnE,CAAC;AAAA,EACH;AAAA,EAEU,aAAa,SAAiB,MAAsB;AAC5D,WAAO,KAAK,aAAa,UAAU,MAAM;AAAA,EAC3C;AACF;;;AC7GO,IAAM,mBAAN,cAA+B,aAAa;AAAA,EAGjD,YAAY,YAAoB;AAC9B,UAAM,UAAU;AAHlB,mBAAkC,CAAC;AAAA,EAInC;AAAA,EAEA,IAAI,SAAiB,MAAc,OAAY,UAA8B;AAC3E,UAAM,MAAM,KAAK,aAAa,SAAS,IAAI;AAC3C,SAAK,QAAQ,GAAG,IAAI,KAAK,UAAU,KAAK;AACxC,WAAO,QAAQ,QAAQ;AAAA,EACzB;AAAA,EAEA,IAAI,SAAiB,MAAc,UAA6B;AAC9D,UAAM,MAAM,KAAK,aAAa,SAAS,IAAI;AAE3C,UAAM,UAAU,KAAK,QAAQ,GAAG;AAChC,QAAI,QAAS,QAAO,QAAQ,QAAQ,KAAK,MAAM,OAAO,CAAC;AAAA,QAClD,QAAO,QAAQ,OAAO,IAAI,MAAM,sCAAsC,GAAG,CAAC;AAAA,EACjF;AACF;","names":[]}