{
  "version": 3,
  "sources": ["../../../../src/workers/ratelimit/ratelimit.worker.ts"],
  "sourcesContent": ["// Emulated Ratelimit Binding\n\n// ENV configuration\ninterface RatelimitConfig {\n\tnamespaceId: number;\n\tlimit: number;\n\tperiod: number;\n}\n\n// options for Ratelimit\n//   (should be kept in sync with https://bitbucket.cfdata.org/projects/EW/repos/edgeworker/browse/src/edgeworker/internal-api/ratelimit.capnp)\nconst RatelimitOptionKeys = [\"key\", \"limit\", \"period\"];\nconst RatelimitPeriodValues = [10, 60];\n\n// result from Ratelimit call\n//   (should be kept in sync with https://bitbucket.cfdata.org/projects/EW/repos/edgeworker/browse/src/edgeworker/internal-api/ratelimit.capnp)\ninterface RatelimitResult {\n\tsuccess: boolean;\n}\n\nfunction validate(test: boolean, message: string): asserts test {\n\tif (!test) {\n\t\tthrow new Error(message);\n\t}\n}\n\nclass Ratelimit {\n\tnamespaceId: number;\n\tlimitVal: number;\n\tperiod: number;\n\tbuckets: Map<string, number>;\n\tepoch: number;\n\n\tconstructor(config: RatelimitConfig) {\n\t\tthis.namespaceId = config.namespaceId;\n\t\tthis.limitVal = config.limit;\n\t\tthis.period = config.period;\n\n\t\tthis.buckets = new Map<string, number>();\n\t\tthis.epoch = 0;\n\t}\n\n\t// method that counts and checks against the limit in in-memory buckets\n\tasync limit(options: unknown): Promise<RatelimitResult> {\n\t\t// validate options input\n\t\tvalidate(\n\t\t\ttypeof options === \"object\" && options !== null,\n\t\t\t\"invalid rate limit options\"\n\t\t);\n\t\tconst invalidProps = Object.keys(options ?? {}).filter(\n\t\t\t(key) => !RatelimitOptionKeys.includes(key)\n\t\t);\n\t\tvalidate(\n\t\t\tinvalidProps.length == 0,\n\t\t\t`bad rate limit options: [${invalidProps.join(\",\")}]`\n\t\t);\n\t\tconst {\n\t\t\tkey = \"\",\n\t\t\tlimit = this.limitVal,\n\t\t\tperiod = this.period,\n\t\t} = options as Record<string, unknown>;\n\t\tvalidate(typeof key === \"string\", `invalid key: ${key}`);\n\t\tvalidate(typeof limit === \"number\", `limit must be a number: ${limit}`);\n\t\tvalidate(typeof period === \"number\", `period must be a number: ${period}`);\n\t\tvalidate(\n\t\t\tRatelimitPeriodValues.includes(period),\n\t\t\t`unsupported period: ${period}`\n\t\t);\n\n\t\tconst epoch = Math.floor(Date.now() / (period * 1000));\n\t\tif (epoch != this.epoch) {\n\t\t\t// clear counters\n\t\t\tthis.epoch = epoch;\n\t\t\tthis.buckets.clear();\n\t\t}\n\t\tconst val = this.buckets.get(key) || 0;\n\t\tif (val >= limit) {\n\t\t\treturn {\n\t\t\t\tsuccess: false,\n\t\t\t};\n\t\t}\n\t\tthis.buckets.set(key, val + 1);\n\t\treturn {\n\t\t\tsuccess: true,\n\t\t};\n\t}\n}\n\n// create a new Ratelimit\nexport default function (env: RatelimitConfig) {\n\treturn new Ratelimit(env);\n}\n"],
  "mappings": ";AAWA,IAAM,sBAAsB,CAAC,OAAO,SAAS,QAAQ,GAC/C,wBAAwB,CAAC,IAAI,EAAE;AAQrC,SAAS,SAAS,MAAe,SAA+B;AAC/D,MAAI,CAAC;AACJ,UAAM,IAAI,MAAM,OAAO;AAEzB;AAEA,IAAM,YAAN,MAAgB;AAAA,EACf;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EAEA,YAAY,QAAyB;AACpC,SAAK,cAAc,OAAO,aAC1B,KAAK,WAAW,OAAO,OACvB,KAAK,SAAS,OAAO,QAErB,KAAK,UAAU,oBAAI,IAAoB,GACvC,KAAK,QAAQ;AAAA,EACd;AAAA;AAAA,EAGA,MAAM,MAAM,SAA4C;AAEvD;AAAA,MACC,OAAO,WAAY,YAAY,YAAY;AAAA,MAC3C;AAAA,IACD;AACA,QAAM,eAAe,OAAO,KAAK,WAAW,CAAC,CAAC,EAAE;AAAA,MAC/C,CAACA,SAAQ,CAAC,oBAAoB,SAASA,IAAG;AAAA,IAC3C;AACA;AAAA,MACC,aAAa,UAAU;AAAA,MACvB,4BAA4B,aAAa,KAAK,GAAG,CAAC;AAAA,IACnD;AACA,QAAM;AAAA,MACL,MAAM;AAAA,MACN,QAAQ,KAAK;AAAA,MACb,SAAS,KAAK;AAAA,IACf,IAAI;AACJ,aAAS,OAAO,OAAQ,UAAU,gBAAgB,GAAG,EAAE,GACvD,SAAS,OAAO,SAAU,UAAU,2BAA2B,KAAK,EAAE,GACtE,SAAS,OAAO,UAAW,UAAU,4BAA4B,MAAM,EAAE,GACzE;AAAA,MACC,sBAAsB,SAAS,MAAM;AAAA,MACrC,uBAAuB,MAAM;AAAA,IAC9B;AAEA,QAAM,QAAQ,KAAK,MAAM,KAAK,IAAI,KAAK,SAAS,IAAK;AACrD,IAAI,SAAS,KAAK,UAEjB,KAAK,QAAQ,OACb,KAAK,QAAQ,MAAM;AAEpB,QAAM,MAAM,KAAK,QAAQ,IAAI,GAAG,KAAK;AACrC,WAAI,OAAO,QACH;AAAA,MACN,SAAS;AAAA,IACV,KAED,KAAK,QAAQ,IAAI,KAAK,MAAM,CAAC,GACtB;AAAA,MACN,SAAS;AAAA,IACV;AAAA,EACD;AACD;AAGe,SAAR,yBAAkB,KAAsB;AAC9C,SAAO,IAAI,UAAU,GAAG;AACzB;",
  "names": ["key"]
}
