@sailplane/state-storage
Version:
Serverless state and configuration storage
1 lines • 6.97 kB
Source Map (JSON)
{"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":[]}