@cartanova/qgrid-cli 2.7.7 → 2.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bundle/dist/application/qgrid/oauth.js +5 -2
- package/bundle/dist/application/qgrid/qgrid.frame.js +63 -28
- package/bundle/dist/application/qgrid/qgrid.types.js +6 -3
- package/bundle/dist/application/request-log/request-log.model.js +2 -2
- package/bundle/dist/sonamu.config.js +3 -1
- package/bundle/dist/utils/providers/anthropic/anthropic-dispatcher.js +12 -7
- package/bundle/dist/utils/providers/anthropic/anthropic-quota.js +7 -5
- package/bundle/dist/utils/providers/openai/openai-callback-relay.js +86 -0
- package/bundle/src/application/qgrid/oauth.test.ts +28 -0
- package/bundle/src/application/qgrid/oauth.ts +5 -0
- package/bundle/src/application/qgrid/qgrid-oauth-redirect.test.ts +71 -8
- package/bundle/src/application/qgrid/qgrid.frame.test.ts +43 -0
- package/bundle/src/application/qgrid/qgrid.frame.ts +72 -26
- package/bundle/src/application/qgrid/qgrid.types.ts +5 -2
- package/bundle/src/application/request-log/request-log.model.test.ts +25 -0
- package/bundle/src/application/request-log/request-log.model.ts +3 -1
- package/bundle/src/application/sonamu.generated.http +7 -3
- package/bundle/src/sonamu.config.ts +2 -0
- package/bundle/src/utils/providers/anthropic/anthropic-dispatcher.test.ts +36 -0
- package/bundle/src/utils/providers/anthropic/anthropic-dispatcher.ts +20 -7
- package/bundle/src/utils/providers/anthropic/anthropic-quota.test.ts +22 -0
- package/bundle/src/utils/providers/anthropic/anthropic-quota.ts +16 -2
- package/bundle/src/utils/providers/openai/openai-callback-relay.test.ts +109 -0
- package/bundle/src/utils/providers/openai/openai-callback-relay.ts +105 -0
- package/bundle/web-dist/client/assets/{index-CokxkK2G.js → index-D208L33c.js} +3 -3
- package/bundle/web-dist/client/assets/{logs-Ckqp98Y3.js → logs-noN5Aka6.js} +1 -1
- package/bundle/web-dist/client/assets/{monit-u0pMHbyf.js → monit-Ber13xcA.js} +1 -1
- package/bundle/web-dist/client/assets/{routes-DobxbCAV.js → routes-3_xetpSK.js} +2 -2
- package/bundle/web-dist/client/assets/{settings-C8rfyi9z.js → settings-C5sHCg8X.js} +1 -1
- package/bundle/web-dist/client/assets/{show-FbUQYs4L.js → show-BhTgGnkc.js} +1 -1
- package/bundle/web-dist/client/assets/tokens-R7obwdAV.js +1 -0
- package/bundle/web-dist/client/assets/use-oauth-login-flow-CRAqRZXX.js +1 -0
- package/bundle/web-dist/client/index.html +1 -1
- package/bundle/web-dist/server/assets/{routes-B9X0lvjQ.js → routes-Ct3I9263.js} +3 -2
- package/bundle/web-dist/server/assets/{tokens-CyItE-L-.js → tokens-PR42jF1J.js} +3 -2
- package/bundle/web-dist/server/assets/{use-oauth-login-flow-CItVKngs.js → use-oauth-login-flow-C-33Z5HA.js} +16 -10
- package/bundle/web-dist/server/entry-server.generated.js +3 -3
- package/dist/cli.js +10 -11
- package/package.json +1 -1
- package/skills/qgrid/SKILL.md +7 -2
- package/skills/qgrid/references/ai-sdk-provider-contract.md +7 -0
- package/skills/qgrid/references/anthropic-claude-code-runtime.md +5 -1
- package/skills/qgrid/references/cli-env-and-server-boot.md +1 -1
- package/skills/qgrid/references/decision-rationale.md +3 -1
- package/skills/qgrid/references/docs-workflow.md +3 -3
- package/skills/qgrid/references/openai-codex-runtime.md +12 -5
- package/skills/qgrid/references/request-log-run-lifecycle.md +2 -0
- package/skills/qgrid/references/sonamu-api-web-flow.md +4 -2
- package/skills/qgrid/references/token-auth-quota-lifecycle.md +7 -2
- package/skills/qgrid/references/verification-and-debugging.md +19 -16
- package/bundle/web-dist/client/assets/tokens-DFwEavFD.js +0 -1
- package/bundle/web-dist/client/assets/use-oauth-login-flow-D-9h3WUt.js +0 -1
|
@@ -2,6 +2,7 @@ import { getExpiresAt, getRefreshToken } from "../common/credentials.js";
|
|
|
2
2
|
import { serializeAndValidateDispatchSchema } from "../common/schema-validation.js";
|
|
3
3
|
import { QuotaThresholdExceededError } from "../../../application/qgrid/qgrid.types.js";
|
|
4
4
|
import { TokenModel } from "../../../application/token/token.model.js";
|
|
5
|
+
import { invalidateAnthropicQuotaUsage } from "../../../application/qgrid/oauth.js";
|
|
5
6
|
import { SmoothWeightedRoundRobin } from "../common/smooth-weighted-round-robin.js";
|
|
6
7
|
import { assertSupportedOneMillionSuffix, canonicalAnthropicModel } from "./anthropic-constants.js";
|
|
7
8
|
import { readAnthropicQuotaUsage } from "./anthropic-quota.js";
|
|
@@ -91,12 +92,12 @@ var AnthropicDispatcher = class {
|
|
|
91
92
|
this.tokenPool.delete(id);
|
|
92
93
|
this.weightedSelector.removeToken(id);
|
|
93
94
|
}
|
|
94
|
-
async selectToken(preferredTokenId) {
|
|
95
|
+
async selectToken(model, preferredTokenId) {
|
|
95
96
|
const preferred = preferredTokenId === void 0 ? void 0 : this.tokenPool.get(preferredTokenId);
|
|
96
97
|
if (preferredTokenId !== void 0 && !preferred) throw new Error(`Preferred anthropic token ${preferredTokenId} is not available`);
|
|
97
98
|
const rows = preferred ? [preferred] : [...this.tokenPool.values()];
|
|
98
99
|
if (rows.length === 0) return null;
|
|
99
|
-
const { eligible, overThresholdTokens } = await this.filterEligibleTokens(rows);
|
|
100
|
+
const { eligible, overThresholdTokens } = await this.filterEligibleTokens(rows, model);
|
|
100
101
|
if (eligible.length === 0) {
|
|
101
102
|
logger.warn("quota_threshold gate: all_exceeded", {
|
|
102
103
|
provider: "anthropic",
|
|
@@ -112,7 +113,7 @@ var AnthropicDispatcher = class {
|
|
|
112
113
|
if (selectedId === null) return null;
|
|
113
114
|
return this.tokenPool.get(selectedId) ?? null;
|
|
114
115
|
}
|
|
115
|
-
async filterEligibleTokens(rows) {
|
|
116
|
+
async filterEligibleTokens(rows, model) {
|
|
116
117
|
const thresholded = rows.filter((token) => this.hasQuotaThreshold(token));
|
|
117
118
|
if (thresholded.length === 0) return {
|
|
118
119
|
eligible: rows,
|
|
@@ -122,7 +123,7 @@ var AnthropicDispatcher = class {
|
|
|
122
123
|
const overThresholdTokens = [];
|
|
123
124
|
(await Promise.allSettled(thresholded.map(async (token) => ({
|
|
124
125
|
token,
|
|
125
|
-
result: await readAnthropicQuotaUsage(token.credentials.accessToken)
|
|
126
|
+
result: await readAnthropicQuotaUsage(token.credentials.accessToken, model)
|
|
126
127
|
})))).forEach((check, index) => {
|
|
127
128
|
if (check.status === "rejected") {
|
|
128
129
|
const token = thresholded[index];
|
|
@@ -202,7 +203,7 @@ var AnthropicDispatcher = class {
|
|
|
202
203
|
assertSupportedOneMillionSuffix(req.model);
|
|
203
204
|
const model = canonicalAnthropicModel(req.model);
|
|
204
205
|
const jsonSchema = serializeAndValidateDispatchSchema(req.outputSchema, "anthropic");
|
|
205
|
-
const token = await this.selectToken(req.preferredTokenId);
|
|
206
|
+
const token = await this.selectToken(model, req.preferredTokenId);
|
|
206
207
|
if (!token) throw new Error("No anthropic tokens available");
|
|
207
208
|
const exec = async () => {
|
|
208
209
|
let accessToken = token.credentials.accessToken;
|
|
@@ -232,7 +233,11 @@ var AnthropicDispatcher = class {
|
|
|
232
233
|
abortSignal: req.abortSignal,
|
|
233
234
|
includePartialMessages: opts?.includePartialMessages
|
|
234
235
|
}, onDelta);
|
|
235
|
-
if (session.quotaExhausted)
|
|
236
|
+
if (session.quotaExhausted) {
|
|
237
|
+
invalidateAnthropicQuotaUsage(token.credentials.accessToken);
|
|
238
|
+
if (accessToken !== token.credentials.accessToken) invalidateAnthropicQuotaUsage(accessToken);
|
|
239
|
+
throw new Error(`quota exhausted (${token.name})`);
|
|
240
|
+
}
|
|
236
241
|
if (session.isError) {
|
|
237
242
|
const reason = session.subtype ?? session.terminalReason ?? (session.isError ? "is_error" : "unknown");
|
|
238
243
|
const body = session.text ? session.text.length > 500 ? `${session.text.slice(0, 500)}…(${session.text.length} chars)` : session.text : `empty text, outputTokens=${session.usage.outputTokens}`;
|
|
@@ -262,4 +267,4 @@ var AnthropicDispatcher = class {
|
|
|
262
267
|
//#endregion
|
|
263
268
|
export { AnthropicDispatcher };
|
|
264
269
|
|
|
265
|
-
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYW50aHJvcGljLWRpc3BhdGNoZXIuanMiLCJuYW1lcyI6W10sInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vc3JjL3V0aWxzL3Byb3ZpZGVycy9hbnRocm9waWMvYW50aHJvcGljLWRpc3BhdGNoZXIudHMiXSwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBBbnRocm9waWNEaXNwYXRjaGVyXG4gKlxuICogT3BlbkFJRGlzcGF0Y2hlcuyZgCDri6zrpqwsIHdvcmtlciBwb29s7J2EIOuRkOuKlCDrjIDsi6Ag7JqU7LKt67OEIGZyZXNoIHNwYXduXG4gKiDthqDtgbDsnYAg7J2466mU66qo66asKE1BUCnsnLzroZwg6rSA66as7ZWY6rOgIHNtb290aCB3ZWlnaHRlZCByb3VuZC1yb2JpbiDsnLzroZwg6rOg66W464ukXG4gKlxuICogLSDrqqjrk6Ag7JqU7LKt7J2AIGZyZXNoIGAtLXNlc3Npb24taWRgIOuhnCDsi6TtlolcbiAqIC0g66mA7Yuw7YS0IOusuOunpeydgCDtgbTrnbzsnbTslrjtirjqsIAg66ekIO2YuOy2nCDrs7TrgrTripQgZnVsbCBoaXN0b3J5IOulvCDtj4ntg4TtmZTtlbQg7KCE64us7ZWc64ukLlxuICogLSDrsJzquIntlZwgc2Vzc2lvbi1pZCDrpbwgR2VuZXJhdGVSZXN1bHQudGhyZWFkQ29vcmQodGhyZWFkSWQ9c2Vzc2lvbi1pZCwgd29ya2VySWQ9dG9rZW5JZCxcbiAqICAgZXBvY2g9MCnroZwg7Jis66CkLCDsg4HsnIQoaXNzdWVDb252Q29udGV4dCnqsIAg7YG065287JeQIO2ajOyGoe2VoCDsooztkZzrpbwg66eM65Og64ukLiDri6TsnYwgdHVybiDsnbQg7KKM7ZGc66W8XG4gKiAgIO2ajOyGoe2VtOuPhCBBbnRocm9waWMg65287Jqw7YyF7JeQ64qUIOyTsOyngCDslYrripTri6QuXG4gKi9cblxuaW1wb3J0IHsgZ2V0TG9nZ2VyIH0gZnJvbSBcIkBsb2d0YXBlL2xvZ3RhcGVcIjtcblxuaW1wb3J0IHsgUXVvdGFUaHJlc2hvbGRFeGNlZWRlZEVycm9yIH0gZnJvbSBcIi4uLy4uLy4uL2FwcGxpY2F0aW9uL3FncmlkL3FncmlkLnR5cGVzXCI7XG5pbXBvcnQgeyBUb2tlbk1vZGVsIH0gZnJvbSBcIi4uLy4uLy4uL2FwcGxpY2F0aW9uL3Rva2VuL3Rva2VuLm1vZGVsXCI7XG5pbXBvcnQgeyB0eXBlIEFudGhyb3BpY0NyZWRlbnRpYWxzIH0gZnJvbSBcIi4uLy4uLy4uL2FwcGxpY2F0aW9uL3Rva2VuL3Rva2VuLnR5cGVzXCI7XG5pbXBvcnQgeyBnZXRFeHBpcmVzQXQsIGdldFJlZnJlc2hUb2tlbiB9IGZyb20gXCIuLi9jb21tb24vY3JlZGVudGlhbHNcIjtcbmltcG9ydCB7XG4gIHR5cGUgR2VuZXJhdGVSZXF1ZXN0LFxuICB0eXBlIEdlbmVyYXRlUmVzdWx0LFxuICB0eXBlIEdlbmVyYXRlU3RyZWFtQ2FsbGJhY2tzLFxuICB0eXBlIFByb3ZpZGVyRGlzcGF0Y2hlcixcbn0gZnJvbSBcIi4uL2NvbW1vbi9wcm92aWRlci1kaXNwYXRjaGVyXCI7XG5pbXBvcnQgeyBzZXJpYWxpemVBbmRWYWxpZGF0ZURpc3BhdGNoU2NoZW1hIH0gZnJvbSBcIi4uL2NvbW1vbi9zY2hlbWEtdmFsaWRhdGlvblwiO1xuaW1wb3J0IHsgU21vb3RoV2VpZ2h0ZWRSb3VuZFJvYmluIH0gZnJvbSBcIi4uL2NvbW1vbi9zbW9vdGgtd2VpZ2h0ZWQtcm91bmQtcm9iaW5cIjtcbmltcG9ydCB7IGFzc2VydFN1cHBvcnRlZE9uZU1pbGxpb25TdWZmaXgsIGNhbm9uaWNhbEFudGhyb3BpY01vZGVsIH0gZnJvbSBcIi4vYW50aHJvcGljLWNvbnN0YW50c1wiO1xuaW1wb3J0IHsgcmVhZEFudGhyb3BpY1F1b3RhVXNhZ2UsIHR5cGUgQW50aHJvcGljUXVvdGFVc2FnZVJlc3VsdCB9IGZyb20gXCIuL2FudGhyb3BpYy1xdW90YVwiO1xuaW1wb3J0IHsgbWFrZUFudGhyb3BpY1dvcmtlcklkLCBydW5DbGF1ZGVTZXNzaW9uIH0gZnJvbSBcIi4vY2xhdWRlLXNlc3Npb25cIjtcblxuY29uc3QgbG9nZ2VyID0gZ2V0TG9nZ2VyKFtcInFncmlkXCIsIFwiYW50aHJvcGljLWRpc3BhdGNoZXJcIl0pO1xuXG4vLyAxTSBjb250ZXh0IOygleyDgSDsg53shLHsnYAg7Iuk7Lih7IOBIDEwMHMr6rmM7KeAIOqwhOuLpC4gMjQwc+uKlCDsmYTstqkg7J6l7LmY7J28IOu/kCxcbi8vIOqxsOu2gCvqsbDrjIAgc3lzdGVtIOyerOyDneyEsSDsp4Dsl7DsnYQg7JmE7KCE7Z6IIO2VtOqysO2VmOuKlCDqsJLsnYAg7JWE64uI64ukLlxuY29uc3QgREVGQVVMVF9USU1FT1VUX01TID0gMjQwXzAwMDtcbi8vIGFjY2VzcyB0b2tlbiDrp4zro4wg7J6E67CVIOyehOqzhCDigJQg6riw7KG0IHN0YW5kYWxvbmUg6rK966GcKHFncmlkLmRpc3BhdGNoZXIudHMp7JmAIOuPmeydvCg2MHMpLlxuY29uc3QgUkVGUkVTSF9TQUZFVFlfTVMgPSA2MF8wMDA7XG5cbmludGVyZmFjZSBQb29sZWRUb2tlbiB7XG4gIGlkOiBudW1iZXI7XG4gIG5hbWU6IHN0cmluZztcbiAgY3JlZGVudGlhbHM6IEFudGhyb3BpY0NyZWRlbnRpYWxzO1xuICBxdW90YVRocmVzaG9sZD86IG51bWJlciB8IG51bGw7XG4gIHdlaWdodDogbnVtYmVyO1xufVxuXG5mdW5jdGlvbiBxdW90YVRocmVzaG9sZEV4Y2VlZGVkTWVzc2FnZShcbiAgcHJvdmlkZXI6IHN0cmluZyxcbiAgdG9rZW5zOiBBcnJheTx7IHRva2VuTmFtZTogc3RyaW5nOyB0aHJlc2hvbGQ6IG51bWJlciB9Pixcbik6IHN0cmluZyB7XG4gIGNvbnN0IGRldGFpbHMgPSB0b2tlbnNcbiAgICAubWFwKCh0b2tlbikgPT4gYCR7dG9rZW4udG9rZW5OYW1lfSAodGhyZXNob2xkICR7dG9rZW4udGhyZXNob2xkfSUpYClcbiAgICAuam9pbihcIiwgXCIpO1xuICByZXR1cm4gZGV0YWlscy5sZW5ndGggPiAwXG4gICAgPyBgQWxsICR7cHJvdmlkZXJ9IHRva2VucyBleGNlZWRlZCBxdW90YSB0aHJlc2hvbGQ6ICR7ZGV0YWlsc31gXG4gICAgOiBgQWxsICR7cHJvdmlkZXJ9IHRva2VucyBleGNlZWRlZCBxdW90YSB0aHJlc2hvbGRgO1xufVxuXG5leHBvcnQgY2xhc3MgQW50aHJvcGljRGlzcGF0Y2hlciBpbXBsZW1lbnRzIFByb3ZpZGVyRGlzcGF0Y2hlciB7XG4gIC8vIHRva2VuSWQg4oaSIO2SgCDtla3rqqkuIHN0YXJ0KCkvdG9rZW4g7J2067Kk7Yq466GcIOyxhOybgFxuICBwcml2YXRlIHRva2VuUG9vbCA9IG5ldyBNYXA8bnVtYmVyLCBQb29sZWRUb2tlbj4oKTtcbiAgcHJpdmF0ZSByZWFkb25seSB3ZWlnaHRlZFNlbGVjdG9yID0gbmV3IFNtb290aFdlaWdodGVkUm91bmRSb2JpbigpO1xuXG4gIGFzeW5jIHN0YXJ0KCk6IFByb21pc2U8dm9pZD4ge1xuICAgIC8vIE9wZW5BSURpc3BhdGNoZXIuc3RhcnQoKSDsmYAg64+Z7J287ZWY6rKMIERCIOyXkOyEnCDquLDsobQgYW50aHJvcGljIO2GoO2BsOydhCBzZWxmLWJvb3RzdHJhcCDtlZzri6QuXG4gICAgLy8gKOyEnOuyhCDsnqzsi5zsnpEg7IucIE5PVElGWSDqsIAg7JWIIOyYpOuvgOuhnCDrtoDtirjsiqTtirjrnqnsnbQg7JeG7Jy866m0IO2SgOydtCDruYgg7LGE66GcIOuCqOuKlOuLpC4pXG4gICAgLy8g7J207ZuEIOuzgOqyveu2hOydgCB0b2tlbi1zdWJzY3JpYmVyIOqwgCBvblRva2VuQWRkZWQvVXBkYXRlZC9SZW1vdmVkIOuhnCDsoITri6ztlZzri6QuXG4gICAgLy8gZmluZEFjdGl2ZUJ5UHJvdmlkZXIg6rCAIGFjdGl2ZT10cnVlICsgcHJvdmlkZXIg7ZWE7YSw66W8IERCIOyXkOyEnCDsspjrpqwg4oaSIGluYWN0aXZlIOuKlCDslaDstIjsl5Ag7JWIIOyYqOuLpC5cbiAgICBjb25zdCB0b2tlbnMgPSBhd2FpdCBUb2tlbk1vZGVsLmZpbmRBY3RpdmVCeVByb3ZpZGVyKFwiQVwiLCBcImFudGhyb3BpY1wiKTtcbiAgICBmb3IgKGNvbnN0IHQgb2YgdG9rZW5zKSB7XG4gICAgICB0aGlzLnRva2VuUG9vbC5zZXQodC5pZCwge1xuICAgICAgICBpZDogdC5pZCxcbiAgICAgICAgbmFtZTogdC5uYW1lLFxuICAgICAgICBjcmVkZW50aWFsczogdC5jcmVkZW50aWFscyBhcyBBbnRocm9waWNDcmVkZW50aWFscyxcbiAgICAgICAgcXVvdGFUaHJlc2hvbGQ6IHQucXVvdGFfdGhyZXNob2xkLFxuICAgICAgICB3ZWlnaHQ6IHQud2VpZ2h0LFxuICAgICAgfSk7XG4gICAgICB0aGlzLndlaWdodGVkU2VsZWN0b3Iuc2V0VG9rZW4odC5pZCwgdC53ZWlnaHQpO1xuICAgICAgbG9nZ2VyLmluZm8oYHdvcmtlciBzcGF3bmVkOiAke3QubmFtZX1gKTtcbiAgICB9XG4gIH1cblxuICBhc3luYyBzdG9wKCk6IFByb21pc2U8dm9pZD4ge1xuICAgIGNvbnN0IHRva2VuSWRzID0gWy4uLnRoaXMudG9rZW5Qb29sLmtleXMoKV07XG4gICAgZm9yIChjb25zdCBpZCBvZiB0b2tlbklkcykgdGhpcy53ZWlnaHRlZFNlbGVjdG9yLnJlbW92ZVRva2VuKGlkKTtcbiAgICB0aGlzLnRva2VuUG9vbC5jbGVhcigpO1xuICAgIHRoaXMud2VpZ2h0ZWRTZWxlY3Rvci5yZXNldFNjb3JlcygpO1xuICB9XG5cbiAgLy8g7ZiE7J6sIO2SgOydmCDthqDtgbAg7IiYKHN0YXJ0dXAg66Gc6re4L2hlYWx0aCDsmqkpLlxuICBnZXQgdG9rZW5Db3VudCgpOiBudW1iZXIge1xuICAgIHJldHVybiB0aGlzLnRva2VuUG9vbC5zaXplO1xuICB9XG5cbiAgLy8g7KeA6riIIOyLpO2WiSDspJHsnbggQ2xhdWRlIENvZGUg7ZSE66Gc7IS47IqkIOyImCDigJQgZnJlc2gtc3Bhd24g7J206528IOydtOqyjCDqs6cg64+Z7IucIOyalOyyrSDsiJjri6QuXG4gIHByaXZhdGUgaW5GbGlnaHRDb3VudCA9IDA7XG4gIGdldCBpbkZsaWdodCgpOiBudW1iZXIge1xuICAgIHJldHVybiB0aGlzLmluRmxpZ2h0Q291bnQ7XG4gIH1cblxuICAvLyBNb25pdCDtkZzsi5zsmqkg4oCUIO2SgOyXkCDsnojripQg7Yag7YGwIOydtOumhCDsiqTrg4Xsg7cgKOydtOumhOyInCDsoJXroKwpXG4gIGdldCB0b2tlbk5hbWVzKCk6IHN0cmluZ1tdIHtcbiAgICByZXR1cm4gWy4uLnRoaXMudG9rZW5Qb29sLnZhbHVlcygpXS5tYXAoKHRva2VuKSA9PiB0b2tlbi5uYW1lKS50b1NvcnRlZCgpO1xuICB9XG5cbiAgLy8gREIgYWN0aXZlIGFudGhyb3BpYyDthqDtgbAg66qp66Gd7Jy866GcIO2SgOydhCDsnqzrj5nquLDtmZTtlZzri6QocGVyaW9kaWMgcmVjb25jaWxlL+yerOyXsOqysOyaqSkuXG4gIC8vIExJU1RFTi9OT1RJRlkg6rCAIOuBiuq4tCDrj5nslYgg7Jyg7Iuk65CcIOy2lOqwgC/sgq3soJwv67mE7Zmc7ISx7ZmU66W8IERCIOq4sOykgOycvOuhnCDri6Tsi5wg66ee7LaY64ukLlxuICAvLyDsnbTrsqTtirgg7ZW465Ok65+s66W8IOyerOyCrOyaqe2VtCDtkoAg6rCx7Iug7J20IOydvOq0gOuQmOqyjCDsoIHsmqnrkJjrj4TroZ0g7ZWc64ukOlxuICAvLyAgLSBEQiDsl5Ag7JeG64qU642wIO2SgOyXkCDsnojripQg7Yag7YGwIOKGkiBvblRva2VuUmVtb3ZlZFxuICAvLyAgLSBEQiDsl5Ag7J6I64qUIO2GoO2BsCDihpIg7Iug6rec66m0IG9uVG9rZW5BZGRlZCwg6riw7KG07J2066m0IG9uVG9rZW5VcGRhdGVkXG4gIHJlcGxhY2VUb2tlbnMoXG4gICAgcm93czogQXJyYXk8e1xuICAgICAgaWQ6IG51bWJlcjtcbiAgICAgIG5hbWU6IHN0cmluZztcbiAgICAgIGNyZWRlbnRpYWxzOiBBbnRocm9waWNDcmVkZW50aWFscztcbiAgICAgIHF1b3RhVGhyZXNob2xkPzogbnVtYmVyIHwgbnVsbDtcbiAgICAgIHdlaWdodDogbnVtYmVyO1xuICAgIH0+LFxuICApOiB2b2lkIHtcbiAgICBjb25zdCBuZXh0ID0gbmV3IFNldChyb3dzLm1hcCgocikgPT4gci5pZCkpO1xuICAgIC8vIG9uVG9rZW5SZW1vdmVkIOqwgCB0b2tlblBvb2wg7J2EIGRlbGV0ZSDtlZjrr4DroZwg7Iic7ZqMIOykkSDsiJjsoJXsnYQg7ZS87ZWY66CkIO2CpOulvCDrqLzsoIAg7Iqk64OF7IO37ZWc64ukLlxuICAgIGNvbnN0IGN1cnJlbnRJZHMgPSBBcnJheS5mcm9tKHRoaXMudG9rZW5Qb29sLmtleXMoKSk7XG4gICAgZm9yIChjb25zdCBpZCBvZiBjdXJyZW50SWRzKSB7XG4gICAgICBpZiAoIW5leHQuaGFzKGlkKSkgdGhpcy5vblRva2VuUmVtb3ZlZChpZCk7XG4gICAgfVxuICAgIGZvciAoY29uc3QgciBvZiByb3dzKSB7XG4gICAgICBpZiAodGhpcy50b2tlblBvb2wuaGFzKHIuaWQpKSB7XG4gICAgICAgIHRoaXMub25Ub2tlblVwZGF0ZWQoci5pZCwgci5uYW1lLCByLmNyZWRlbnRpYWxzLCByLnF1b3RhVGhyZXNob2xkLCByLndlaWdodCk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICB0aGlzLm9uVG9rZW5BZGRlZChyLmlkLCByLm5hbWUsIHIuY3JlZGVudGlhbHMsIHIucXVvdGFUaHJlc2hvbGQsIHIud2VpZ2h0KTtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICAvLyB0b2tlbiBldmVudHMgKHRva2VuLXN1YnNjcmliZXIg6rCAIO2YuOy2nClcbiAgb25Ub2tlbkFkZGVkKFxuICAgIGlkOiBudW1iZXIsXG4gICAgbmFtZTogc3RyaW5nLFxuICAgIGNyZWRlbnRpYWxzOiBBbnRocm9waWNDcmVkZW50aWFscyxcbiAgICBxdW90YVRocmVzaG9sZD86IG51bWJlciB8IG51bGwsXG4gICAgd2VpZ2h0ID0gMSxcbiAgKTogdm9pZCB7XG4gICAgdGhpcy50b2tlblBvb2wuc2V0KGlkLCB7IGlkLCBuYW1lLCBjcmVkZW50aWFscywgcXVvdGFUaHJlc2hvbGQsIHdlaWdodCB9KTtcbiAgICB0aGlzLndlaWdodGVkU2VsZWN0b3Iuc2V0VG9rZW4oaWQsIHdlaWdodCk7XG4gIH1cblxuICBvblRva2VuVXBkYXRlZChcbiAgICBpZDogbnVtYmVyLFxuICAgIG5hbWU6IHN0cmluZyxcbiAgICBjcmVkZW50aWFsczogQW50aHJvcGljQ3JlZGVudGlhbHMsXG4gICAgcXVvdGFUaHJlc2hvbGQ/OiBudW1iZXIgfCBudWxsLFxuICAgIHdlaWdodCA9IDEsXG4gICk6IHZvaWQge1xuICAgIHRoaXMudG9rZW5Qb29sLnNldChpZCwgeyBpZCwgbmFtZSwgY3JlZGVudGlhbHMsIHF1b3RhVGhyZXNob2xkLCB3ZWlnaHQgfSk7XG4gICAgdGhpcy53ZWlnaHRlZFNlbGVjdG9yLnNldFRva2VuKGlkLCB3ZWlnaHQpO1xuICB9XG5cbiAgb25Ub2tlblJlbW92ZWQoaWQ6IG51bWJlcik6IHZvaWQge1xuICAgIHRoaXMudG9rZW5Qb29sLmRlbGV0ZShpZCk7XG4gICAgdGhpcy53ZWlnaHRlZFNlbGVjdG9yLnJlbW92ZVRva2VuKGlkKTtcbiAgfVxuXG4gIC8vIOyngOyglSDsmpTssq3snYAg7ZW064u5IO2GoO2BsOunjCBxdW90YSDtjJDsoJXtlZjqs6Agd2VpZ2h0ZWQg7IOB7YOc66W8IOqxtOuTnOumrOyngCDslYrripTri6QuXG4gIC8vIOuvuOyngOyglSDsmpTssq3rp4wgcXVvdGEg7Ya16rO8IO2bhOuztOuhnCBzbW9vdGggd2VpZ2h0ZWQgcm91bmQtcm9iaW4g7J2EIOynhO2Wie2VnOuLpC5cbiAgcHJpdmF0ZSBhc3luYyBzZWxlY3RUb2tlbihwcmVmZXJyZWRUb2tlbklkPzogbnVtYmVyKTogUHJvbWlzZTxQb29sZWRUb2tlbiB8IG51bGw+IHtcbiAgICBjb25zdCBwcmVmZXJyZWQgPVxuICAgICAgcHJlZmVycmVkVG9rZW5JZCA9PT0gdW5kZWZpbmVkID8gdW5kZWZpbmVkIDogdGhpcy50b2tlblBvb2wuZ2V0KHByZWZlcnJlZFRva2VuSWQpO1xuICAgIGlmIChwcmVmZXJyZWRUb2tlbklkICE9PSB1bmRlZmluZWQgJiYgIXByZWZlcnJlZCkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGBQcmVmZXJyZWQgYW50aHJvcGljIHRva2VuICR7cHJlZmVycmVkVG9rZW5JZH0gaXMgbm90IGF2YWlsYWJsZWApO1xuICAgIH1cblxuICAgIGNvbnN0IHJvd3MgPSBwcmVmZXJyZWQgPyBbcHJlZmVycmVkXSA6IFsuLi50aGlzLnRva2VuUG9vbC52YWx1ZXMoKV07XG4gICAgaWYgKHJvd3MubGVuZ3RoID09PSAwKSByZXR1cm4gbnVsbDtcbiAgICBjb25zdCB7IGVsaWdpYmxlLCBvdmVyVGhyZXNob2xkVG9rZW5zIH0gPSBhd2FpdCB0aGlzLmZpbHRlckVsaWdpYmxlVG9rZW5zKHJvd3MpO1xuICAgIGlmIChlbGlnaWJsZS5sZW5ndGggPT09IDApIHtcbiAgICAgIGxvZ2dlci53YXJuKFwicXVvdGFfdGhyZXNob2xkIGdhdGU6IGFsbF9leGNlZWRlZFwiLCB7XG4gICAgICAgIHByb3ZpZGVyOiBcImFudGhyb3BpY1wiLFxuICAgICAgICB0b2tlbkNvdW50OiByb3dzLmxlbmd0aCxcbiAgICAgICAgdGhyZXNob2xkZWRUb2tlbkNvdW50OiByb3dzLmZpbHRlcigocikgPT4gdGhpcy5oYXNRdW90YVRocmVzaG9sZChyKSkubGVuZ3RoLFxuICAgICAgICBvdmVyVGhyZXNob2xkVG9rZW5zLFxuICAgICAgICByZWFzb246IFwiYWxsX2V4Y2VlZGVkXCIsXG4gICAgICB9KTtcbiAgICAgIHRocm93IG5ldyBRdW90YVRocmVzaG9sZEV4Y2VlZGVkRXJyb3IoXG4gICAgICAgIHF1b3RhVGhyZXNob2xkRXhjZWVkZWRNZXNzYWdlKFwiYW50aHJvcGljXCIsIG92ZXJUaHJlc2hvbGRUb2tlbnMpLFxuICAgICAgKTtcbiAgICB9XG5cbiAgICBpZiAocHJlZmVycmVkKSByZXR1cm4gcHJlZmVycmVkO1xuXG4gICAgY29uc3Qgc2VsZWN0ZWRJZCA9IHRoaXMud2VpZ2h0ZWRTZWxlY3Rvci5zZWxlY3QobmV3IFNldChlbGlnaWJsZS5tYXAoKHRva2VuKSA9PiB0b2tlbi5pZCkpKTtcbiAgICBpZiAoc2VsZWN0ZWRJZCA9PT0gbnVsbCkgcmV0dXJuIG51bGw7XG4gICAgcmV0dXJuIHRoaXMudG9rZW5Qb29sLmdldChzZWxlY3RlZElkKSA/PyBudWxsO1xuICB9XG5cbiAgcHJpdmF0ZSBhc3luYyBmaWx0ZXJFbGlnaWJsZVRva2Vucyhyb3dzOiBQb29sZWRUb2tlbltdKTogUHJvbWlzZTx7XG4gICAgZWxpZ2libGU6IFBvb2xlZFRva2VuW107XG4gICAgb3ZlclRocmVzaG9sZFRva2VuczogQXJyYXk8eyB0b2tlbk5hbWU6IHN0cmluZzsgdGhyZXNob2xkOiBudW1iZXIgfT47XG4gIH0+IHtcbiAgICBjb25zdCB0aHJlc2hvbGRlZCA9IHJvd3MuZmlsdGVyKCh0b2tlbikgPT4gdGhpcy5oYXNRdW90YVRocmVzaG9sZCh0b2tlbikpO1xuICAgIGlmICh0aHJlc2hvbGRlZC5sZW5ndGggPT09IDApIHJldHVybiB7IGVsaWdpYmxlOiByb3dzLCBvdmVyVGhyZXNob2xkVG9rZW5zOiBbXSB9O1xuXG4gICAgY29uc3QgZWxpZ2libGVJZHMgPSBuZXcgU2V0KFxuICAgICAgcm93cy5maWx0ZXIoKHRva2VuKSA9PiAhdGhpcy5oYXNRdW90YVRocmVzaG9sZCh0b2tlbikpLm1hcCgodG9rZW4pID0+IHRva2VuLmlkKSxcbiAgICApO1xuICAgIGNvbnN0IG92ZXJUaHJlc2hvbGRUb2tlbnM6IEFycmF5PHsgdG9rZW5OYW1lOiBzdHJpbmc7IHRocmVzaG9sZDogbnVtYmVyIH0+ID0gW107XG4gICAgY29uc3QgY2hlY2tzID0gYXdhaXQgUHJvbWlzZS5hbGxTZXR0bGVkKFxuICAgICAgdGhyZXNob2xkZWQubWFwKGFzeW5jICh0b2tlbikgPT4gKHtcbiAgICAgICAgdG9rZW4sXG4gICAgICAgIHJlc3VsdDogYXdhaXQgcmVhZEFudGhyb3BpY1F1b3RhVXNhZ2UodG9rZW4uY3JlZGVudGlhbHMuYWNjZXNzVG9rZW4pLFxuICAgICAgfSkpLFxuICAgICk7XG5cbiAgICBjaGVja3MuZm9yRWFjaCgoY2hlY2ssIGluZGV4KSA9PiB7XG4gICAgICBpZiAoY2hlY2suc3RhdHVzID09PSBcInJlamVjdGVkXCIpIHtcbiAgICAgICAgY29uc3QgdG9rZW4gPSB0aHJlc2hvbGRlZFtpbmRleF07XG4gICAgICAgIGlmICghdG9rZW4pIHJldHVybjtcbiAgICAgICAgdGhpcy5sb2dRdW90YUxvb2t1cEZhaWxPcGVuKHRva2VuLCBTdHJpbmcoY2hlY2sucmVhc29uKSk7XG4gICAgICAgIGVsaWdpYmxlSWRzLmFkZCh0b2tlbi5pZCk7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgY29uc3QgdG9rZW4gPSBjaGVjay52YWx1ZS50b2tlbjtcbiAgICAgIGNvbnN0IHJlc3VsdCA9IGNoZWNrLnZhbHVlLnJlc3VsdDtcbiAgICAgIGlmIChyZXN1bHQua2luZCA9PT0gXCJsb29rdXBfZmFpbGVkXCIpIHtcbiAgICAgICAgdGhpcy5sb2dRdW90YUxvb2t1cEZhaWxPcGVuKHRva2VuLCByZXN1bHQucmVhc29uKTtcbiAgICAgICAgZWxpZ2libGVJZHMuYWRkKHRva2VuLmlkKTtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICBpZiAocmVzdWx0LnV0aWxpemF0aW9uUGN0ID49IHRva2VuLnF1b3RhVGhyZXNob2xkKSB7XG4gICAgICAgIHRoaXMubG9nUXVvdGFPdmVyVGhyZXNob2xkKHRva2VuLCByZXN1bHQpO1xuICAgICAgICBvdmVyVGhyZXNob2xkVG9rZW5zLnB1c2goeyB0b2tlbk5hbWU6IHRva2VuLm5hbWUsIHRocmVzaG9sZDogdG9rZW4ucXVvdGFUaHJlc2hvbGQgfSk7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgZWxpZ2libGVJZHMuYWRkKHRva2VuLmlkKTtcbiAgICB9KTtcblxuICAgIHJldHVybiB7IGVsaWdpYmxlOiByb3dzLmZpbHRlcigodG9rZW4pID0+IGVsaWdpYmxlSWRzLmhhcyh0b2tlbi5pZCkpLCBvdmVyVGhyZXNob2xkVG9rZW5zIH07XG4gIH1cblxuICBwcml2YXRlIGhhc1F1b3RhVGhyZXNob2xkKHRva2VuOiBQb29sZWRUb2tlbik6IHRva2VuIGlzIFBvb2xlZFRva2VuICYgeyBxdW90YVRocmVzaG9sZDogbnVtYmVyIH0ge1xuICAgIHJldHVybiB0b2tlbi5xdW90YVRocmVzaG9sZCAhPT0gdW5kZWZpbmVkICYmIHRva2VuLnF1b3RhVGhyZXNob2xkICE9PSBudWxsO1xuICB9XG5cbiAgcHJpdmF0ZSBsb2dRdW90YU92ZXJUaHJlc2hvbGQoXG4gICAgdG9rZW46IFBvb2xlZFRva2VuICYgeyBxdW90YVRocmVzaG9sZDogbnVtYmVyIH0sXG4gICAgcmVzdWx0OiBFeHRyYWN0PEFudGhyb3BpY1F1b3RhVXNhZ2VSZXN1bHQsIHsga2luZDogXCJva1wiIH0+LFxuICApOiB2b2lkIHtcbiAgICBsb2dnZXIuaW5mbyhcInF1b3RhX3RocmVzaG9sZCBnYXRlOiBvdmVyX3RocmVzaG9sZFwiLCB7XG4gICAgICB0b2tlbklkOiB0b2tlbi5pZCxcbiAgICAgIHRva2VuTmFtZTogdG9rZW4ubmFtZSxcbiAgICAgIHByb3ZpZGVyOiBcImFudGhyb3BpY1wiLFxuICAgICAgdGhyZXNob2xkOiB0b2tlbi5xdW90YVRocmVzaG9sZCxcbiAgICAgIGNhY2hlZFV0aWxpemF0aW9uOiByZXN1bHQudXRpbGl6YXRpb25QY3QsXG4gICAgICBjYWNoZUFnZTogcmVzdWx0LmNhY2hlQWdlTXMsXG4gICAgICByZWFzb246IFwib3Zlcl90aHJlc2hvbGRcIixcbiAgICB9KTtcbiAgfVxuXG4gIHByaXZhdGUgbG9nUXVvdGFMb29rdXBGYWlsT3BlbihcbiAgICB0b2tlbjogUG9vbGVkVG9rZW4gJiB7IHF1b3RhVGhyZXNob2xkOiBudW1iZXIgfSxcbiAgICByZWFzb246IHN0cmluZyxcbiAgKTogdm9pZCB7XG4gICAgbG9nZ2VyLndhcm4oXCJxdW90YV90aHJlc2hvbGQgZ2F0ZTogbG9va3VwX2ZhaWxfb3BlblwiLCB7XG4gICAgICB0b2tlbklkOiB0b2tlbi5pZCxcbiAgICAgIHRva2VuTmFtZTogdG9rZW4ubmFtZSxcbiAgICAgIHByb3ZpZGVyOiBcImFudGhyb3BpY1wiLFxuICAgICAgdGhyZXNob2xkOiB0b2tlbi5xdW90YVRocmVzaG9sZCxcbiAgICAgIHJlYXNvbjogXCJsb29rdXBfZmFpbF9vcGVuXCIsXG4gICAgICBsb29rdXBSZWFzb246IHJlYXNvbixcbiAgICB9KTtcbiAgfVxuXG4gIGFzeW5jIGdlbmVyYXRlKHJlcTogR2VuZXJhdGVSZXF1ZXN0KTogUHJvbWlzZTxHZW5lcmF0ZVJlc3VsdD4ge1xuICAgIHJldHVybiB0aGlzLnJ1bihyZXEsICgpID0+IHt9KTtcbiAgfVxuXG4gIGFzeW5jIGdlbmVyYXRlU3RyZWFtKHJlcTogR2VuZXJhdGVSZXF1ZXN0LCBjYjogR2VuZXJhdGVTdHJlYW1DYWxsYmFja3MpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICB0cnkge1xuICAgICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgdGhpcy5ydW4ocmVxLCBjYi5vbkRlbHRhLCB7IGluY2x1ZGVQYXJ0aWFsTWVzc2FnZXM6IHRydWUgfSk7XG4gICAgICBjYi5vblRocmVhZElkPy4ocmVzdWx0LnRocmVhZENvb3JkLnRocmVhZElkKTtcbiAgICAgIGNiLm9uQ29tcGxldGUocmVzdWx0KTtcbiAgICB9IGNhdGNoIChlKSB7XG4gICAgICBjYi5vbkVycm9yKGUgYXMgRXJyb3IpO1xuICAgIH1cbiAgfVxuXG4gIC8vIGdlbmVyYXRlL2dlbmVyYXRlU3RyZWFtIOqzte2GtSDsi6TtlokuIG9uRGVsdGEg64qUIOyKpO2KuOumvOydtOuptCDsoJDsp4Qg67Cp7LacLCDruYTsiqTtirjrprzsnbTrqbQgbm8tb3AuXG4gIHByaXZhdGUgYXN5bmMgcnVuKC4uLmFyZ3M6IFBhcmFtZXRlcnM8QW50aHJvcGljRGlzcGF0Y2hlcltcInJ1bklubmVyXCJdPik6IFByb21pc2U8R2VuZXJhdGVSZXN1bHQ+IHtcbiAgICB0aGlzLmluRmxpZ2h0Q291bnQrKztcbiAgICB0cnkge1xuICAgICAgcmV0dXJuIGF3YWl0IHRoaXMucnVuSW5uZXIoLi4uYXJncyk7XG4gICAgfSBmaW5hbGx5IHtcbiAgICAgIHRoaXMuaW5GbGlnaHRDb3VudC0tO1xuICAgIH1cbiAgfVxuXG4gIHByaXZhdGUgYXN5bmMgcnVuSW5uZXIoXG4gICAgcmVxOiBHZW5lcmF0ZVJlcXVlc3QsXG4gICAgb25EZWx0YTogKHQ6IHN0cmluZykgPT4gdm9pZCxcbiAgICBvcHRzPzogeyBpbmNsdWRlUGFydGlhbE1lc3NhZ2VzPzogYm9vbGVhbiB9LFxuICApOiBQcm9taXNlPEdlbmVyYXRlUmVzdWx0PiB7XG4gICAgLy8g7J2066+47KeAIOyDneyEseydgCBPcGVuQUkg6rK966GcIOyghOyaqS4gQW50aHJvcGljIOudvOyasO2MheyXkCDsnbTrr7jsp4Ag7ZSM656Y6re46rCAXG4gICAgLy8g64+E64us7ZWY66m0IOyhsOyaqe2eiCDthY3siqTtirjroZwg7Y+067Cx7ZWY7KeAIOyViuqzoCDrqoXsi5zsoIHsnLzroZwg6rGw67aA7ZWc64ukLlxuICAgIGlmIChyZXEuaW1hZ2VHZW5lcmF0aW9uKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXCJpbWFnZSBnZW5lcmF0aW9uIGlzIG5vdCBzdXBwb3J0ZWQgb24gdGhlIEFudGhyb3BpYyByb3V0ZVwiKTtcbiAgICB9XG4gICAgLy8gbW9kZWwg7KCV6rec7ZmU66W8IGRpc3BhdGNoZXIg7KeE7J6F7KCQ7JeQ7IScIO2VnCDrsogg7ZWc64ukOiByZXN1bHQubW9kZWwgLyBydW5DbGF1ZGVTZXNzaW9uIOyghOu2gFxuICAgIC8vIGNhbm9uaWNhbChwcmVmaXgg7JeG64qUIGNvc3Qg7YKkKSDsnYQg7JOw6rKMIO2GteydvC4g66+47KeA7KCV7J2066m0IEFOVEhST1BJQ19ERUZBVUxUX01PREVMIOKAlCBxZ3JpZC5kaXNwYXRjaGVyXG4gICAgLy8g7J2YIFwic29ubmV0XCIg67OE7LmtIOyasO2ajCDssKjri6guIOygleq3nO2ZlCDqt5zsuZnsnYAgZmFsbGJhY2sg6rK966Gc7JmAIOqzteycoChjYW5vbmljYWxBbnRocm9waWNNb2RlbCkuXG4gICAgYXNzZXJ0U3VwcG9ydGVkT25lTWlsbGlvblN1ZmZpeChyZXEubW9kZWwpO1xuICAgIGNvbnN0IG1vZGVsID0gY2Fub25pY2FsQW50aHJvcGljTW9kZWwocmVxLm1vZGVsKTtcbiAgICBjb25zdCBqc29uU2NoZW1hID0gc2VyaWFsaXplQW5kVmFsaWRhdGVEaXNwYXRjaFNjaGVtYShyZXEub3V0cHV0U2NoZW1hLCBcImFudGhyb3BpY1wiKTtcblxuICAgIGNvbnN0IHRva2VuID0gYXdhaXQgdGhpcy5zZWxlY3RUb2tlbihyZXEucHJlZmVycmVkVG9rZW5JZCk7XG4gICAgaWYgKCF0b2tlbikgdGhyb3cgbmV3IEVycm9yKFwiTm8gYW50aHJvcGljIHRva2VucyBhdmFpbGFibGVcIik7XG5cbiAgICBjb25zdCBleGVjID0gYXN5bmMgKCk6IFByb21pc2U8R2VuZXJhdGVSZXN1bHQ+ID0+IHtcbiAgICAgIC8vIOunjOujjCDsnoTrsJUg7Yag7YGwIHByZWVtcHRpdmUgcmVmcmVzaCjquLDsobQgc3RhbmRhbG9uZSDqsr3roZzsmYAg64+Z7J28KS4g7Iuk7Yyo7ZW064+EIOynhO2WiS5cbiAgICAgIGxldCBhY2Nlc3NUb2tlbiA9IHRva2VuLmNyZWRlbnRpYWxzLmFjY2Vzc1Rva2VuO1xuICAgICAgY29uc3QgZXhwaXJlc0F0ID0gZ2V0RXhwaXJlc0F0KHRva2VuLmNyZWRlbnRpYWxzKTtcbiAgICAgIGlmIChcbiAgICAgICAgZXhwaXJlc0F0ICYmXG4gICAgICAgIGV4cGlyZXNBdCAtIERhdGUubm93KCkgPCBSRUZSRVNIX1NBRkVUWV9NUyAmJlxuICAgICAgICBnZXRSZWZyZXNoVG9rZW4odG9rZW4uY3JlZGVudGlhbHMpXG4gICAgICApIHtcbiAgICAgICAgdHJ5IHtcbiAgICAgICAgICBjb25zdCB7IFFncmlkRnJhbWUgfSA9IGF3YWl0IGltcG9ydChcIi4uLy4uLy4uL2FwcGxpY2F0aW9uL3FncmlkL3FncmlkLmZyYW1lXCIpO1xuICAgICAgICAgIC8vIHByb3ZpZGVyIOulvCDrsJjrk5zsi5wg7LGE7JuM7JW8IHJlZnJlc2hUb2tlbiDrgrTrtoAgVG9rZW5Nb2RlbC5zYXZlIOqwgCDshLHqs7XtlZzri6QuXG4gICAgICAgICAgLy8gcmVmcmVzaFRva2VuKFRva2VuU3Vic2V0QSkg64qUIGlkL3Byb3ZpZGVyL2NyZWRlbnRpYWxzL25hbWUg66eMIOyCrOyaqe2VmOuvgOuhnCDqt7ggNOqwnOunjCDrhJjquLTri6QuXG4gICAgICAgICAgYWNjZXNzVG9rZW4gPSBhd2FpdCBRZ3JpZEZyYW1lLnJlZnJlc2hUb2tlbih7XG4gICAgICAgICAgICBpZDogdG9rZW4uaWQsXG4gICAgICAgICAgICBwcm92aWRlcjogXCJhbnRocm9waWNcIixcbiAgICAgICAgICAgIG5hbWU6IHRva2VuLm5hbWUsXG4gICAgICAgICAgICBjcmVkZW50aWFsczogdG9rZW4uY3JlZGVudGlhbHMsXG4gICAgICAgICAgfSBhcyBQYXJhbWV0ZXJzPHR5cGVvZiBRZ3JpZEZyYW1lLnJlZnJlc2hUb2tlbj5bMF0pO1xuICAgICAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgICAgbG9nZ2VyLndhcm4oYHJlZnJlc2ggZmFpbGVkIGZvciAke3Rva2VuLm5hbWV9OiAkeyhlIGFzIEVycm9yKS5tZXNzYWdlfWApO1xuICAgICAgICB9XG4gICAgICB9XG5cbiAgICAgIGxvZ2dlci5pbmZvKGDihpIgJHt0b2tlbi5uYW1lfSAobW9kZWw6ICR7bW9kZWx9KWApO1xuICAgICAgY29uc3Qgc2Vzc2lvbiA9IGF3YWl0IHJ1bkNsYXVkZVNlc3Npb24oXG4gICAgICAgIHtcbiAgICAgICAgICB0b2tlbklkOiB0b2tlbi5pZCxcbiAgICAgICAgICB0b2tlbjogYWNjZXNzVG9rZW4sXG4gICAgICAgICAgbW9kZWwsXG4gICAgICAgICAgc3lzdGVtOiByZXEuc3lzdGVtUHJvbXB0LFxuICAgICAgICAgIGpzb25TY2hlbWEsXG4gICAgICAgICAgZWZmb3J0OiByZXEuZWZmb3J0LFxuICAgICAgICAgIHRpbWVvdXRNczogcmVxLnRpbWVvdXRNcyA/PyBERUZBVUxUX1RJTUVPVVRfTVMsXG4gICAgICAgICAgY29sZEhpc3Rvcnk6IHJlcS5jb2xkSGlzdG9yeSxcbiAgICAgICAgICBpbnB1dDogcmVxLmNvbGRJbnB1dCxcbiAgICAgICAgICBhYm9ydFNpZ25hbDogcmVxLmFib3J0U2lnbmFsLFxuICAgICAgICAgIGluY2x1ZGVQYXJ0aWFsTWVzc2FnZXM6IG9wdHM/LmluY2x1ZGVQYXJ0aWFsTWVzc2FnZXMsXG4gICAgICAgIH0sXG4gICAgICAgIG9uRGVsdGEsXG4gICAgICApO1xuXG4gICAgICBpZiAoc2Vzc2lvbi5xdW90YUV4aGF1c3RlZCkgdGhyb3cgbmV3IEVycm9yKGBxdW90YSBleGhhdXN0ZWQgKCR7dG9rZW4ubmFtZX0pYCk7XG4gICAgICBpZiAoc2Vzc2lvbi5pc0Vycm9yKSB7XG4gICAgICAgIC8vIOynhOuLqChTT04tNDk1KTogaXNFcnJvciDtjJDsoJUg7IKs7JygKHN1YnR5cGUvdGVybWluYWxfcmVhc29uKeulvCDrqZTsi5zsp4Ag7JWe7JeQIOuTnOufrOuCuOuLpC5cbiAgICAgICAgLy8g6re464+Z7JWIIGRldGFpbCDsnbQgc2Vzc2lvbi50ZXh0KOyZhOyghO2VnCBKU09OIOuzuOusuCnrv5DsnbTrnbwgXCJzY2hlbWEg7JyE67CY7J247KeAIC8gbWF4IHJldHJpZXMg7J247KeAIC9cbiAgICAgICAgLy8gbWF4IHR1cm5zIOyduOyngFwi66W8IOq1rOu2hO2VoCDsiJgg7JeG7JeI64ukLiB0ZXh0IOuKlCDsp4Tri6jsl5Ag7ZWE7JqU7ZWcIOunjO2BvOunjCDsnpjrnbwg642n67aZ7J2464ukLlxuICAgICAgICBjb25zdCByZWFzb24gPVxuICAgICAgICAgIHNlc3Npb24uc3VidHlwZSA/PyBzZXNzaW9uLnRlcm1pbmFsUmVhc29uID8/IChzZXNzaW9uLmlzRXJyb3IgPyBcImlzX2Vycm9yXCIgOiBcInVua25vd25cIik7XG4gICAgICAgIGNvbnN0IGJvZHkgPSBzZXNzaW9uLnRleHRcbiAgICAgICAgICA/IHNlc3Npb24udGV4dC5sZW5ndGggPiA1MDBcbiAgICAgICAgICAgID8gYCR7c2Vzc2lvbi50ZXh0LnNsaWNlKDAsIDUwMCl94oCmKCR7c2Vzc2lvbi50ZXh0Lmxlbmd0aH0gY2hhcnMpYFxuICAgICAgICAgICAgOiBzZXNzaW9uLnRleHRcbiAgICAgICAgICA6IGBlbXB0eSB0ZXh0LCBvdXRwdXRUb2tlbnM9JHtzZXNzaW9uLnVzYWdlLm91dHB1dFRva2Vuc31gO1xuICAgICAgICBjb25zdCByZWZ1c2FsID0gc2Vzc2lvbi5yZWZ1c2FsID8gYCByZWZ1c2FsPSR7SlNPTi5zdHJpbmdpZnkoc2Vzc2lvbi5yZWZ1c2FsKX1gIDogXCJcIjtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBjbGF1ZGUgZXJyb3IgKCR7dG9rZW4ubmFtZX0pIFske3JlYXNvbn1dOiAke2JvZHl9JHtyZWZ1c2FsfWApO1xuICAgICAgfVxuXG4gICAgICByZXR1cm4ge1xuICAgICAgICB0ZXh0OiBzZXNzaW9uLnRleHQsXG4gICAgICAgIHRva2VuTmFtZTogdG9rZW4ubmFtZSxcbiAgICAgICAgdXNhZ2U6IHNlc3Npb24udXNhZ2UsXG4gICAgICAgIGR1cmF0aW9uTXM6IHNlc3Npb24uZHVyYXRpb25NcyxcbiAgICAgICAgdHRmdE1zOiBzZXNzaW9uLnR0ZnRNcyxcbiAgICAgICAgY29zdFVzZDogc2Vzc2lvbi5jb3N0VXNkLFxuICAgICAgICAvLyBDbGF1ZGUgQ29kZSDripQgRmFibGUgcmVmdXNhbCDsnYQgT3B1cyDroZwg7J6Q64+ZIGZhbGxiYWNrIO2VoCDsiJgg7J6I64ukLiDsmpTssq0g66qo64247J2EXG4gICAgICAgIC8vIOq3uOuMgOuhnCBzZXJ2aW5nIG1vZGVsIOuhnCDquLDroZ3tlZjrqbQg67mE7JqpL+qwkOyCrCDroZzqt7jqsIAg66qo65GQIO2LgOyWtOyngOuvgOuhnCDrkZjsnYQg6rWs67aE7ZWc64ukLlxuICAgICAgICBtb2RlbDogc2Vzc2lvbi5zZXJ2ZWRNb2RlbCA/PyBtb2RlbCxcbiAgICAgICAgcmVxdWVzdGVkTW9kZWw6IG1vZGVsLFxuICAgICAgICBtb2RlbEZhbGxiYWNrczogc2Vzc2lvbi5tb2RlbEZhbGxiYWNrcyxcbiAgICAgICAgLy8gc3lzdGVtSGFzaCDripQg7IOB7JyEIGlzc3VlQ29udkNvbnRleHQg6rCAIOyxhOyatOuLpCjsl6zquLDshKAg67mE7Jq064ukKS5cbiAgICAgICAgdGhyZWFkQ29vcmQ6IHtcbiAgICAgICAgICB3b3JrZXJJZDogbWFrZUFudGhyb3BpY1dvcmtlcklkKHRva2VuLmlkKSxcbiAgICAgICAgICB0aHJlYWRJZDogc2Vzc2lvbi5zZXNzaW9uSWQsXG4gICAgICAgICAgZXBvY2g6IDAsXG4gICAgICAgIH0sXG4gICAgICB9O1xuICAgIH07XG5cbiAgICByZXR1cm4gZXhlYygpO1xuICB9XG59XG4iXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7QUErQkEsTUFBTSxTQUFTLFVBQVUsQ0FBQyxTQUFTLHNCQUFzQixDQUFDO0FBSTFELE1BQU0scUJBQXFCO0FBRTNCLE1BQU0sb0JBQW9CO0FBVTFCLFNBQVMsOEJBQ1AsVUFDQSxRQUNRO0NBQ1IsTUFBTSxVQUFVLE9BQ2IsS0FBSyxVQUFVLEdBQUcsTUFBTSxVQUFVLGNBQWMsTUFBTSxVQUFVLEdBQUcsQ0FBQyxDQUNwRSxLQUFLLElBQUk7Q0FDWixPQUFPLFFBQVEsU0FBUyxJQUNwQixPQUFPLFNBQVMsb0NBQW9DLFlBQ3BELE9BQU8sU0FBUztBQUN0QjtBQUVBLElBQWEsc0JBQWIsTUFBK0Q7Q0FFN0QsNEJBQW9CLElBQUksSUFBeUI7Q0FDakQsbUJBQW9DLElBQUkseUJBQXlCO0NBRWpFLE1BQU0sUUFBdUI7RUFLM0IsTUFBTSxTQUFTLE1BQU0sV0FBVyxxQkFBcUIsS0FBSyxXQUFXO0VBQ3JFLEtBQUssTUFBTSxLQUFLLFFBQVE7R0FDdEIsS0FBSyxVQUFVLElBQUksRUFBRSxJQUFJ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
|
|
270
|
+
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYW50aHJvcGljLWRpc3BhdGNoZXIuanMiLCJuYW1lcyI6W10sInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vc3JjL3V0aWxzL3Byb3ZpZGVycy9hbnRocm9waWMvYW50aHJvcGljLWRpc3BhdGNoZXIudHMiXSwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBBbnRocm9waWNEaXNwYXRjaGVyXG4gKlxuICogT3BlbkFJRGlzcGF0Y2hlcuyZgCDri6zrpqwsIHdvcmtlciBwb29s7J2EIOuRkOuKlCDrjIDsi6Ag7JqU7LKt67OEIGZyZXNoIHNwYXduXG4gKiDthqDtgbDsnYAg7J2466mU66qo66asKE1BUCnsnLzroZwg6rSA66as7ZWY6rOgIHNtb290aCB3ZWlnaHRlZCByb3VuZC1yb2JpbiDsnLzroZwg6rOg66W464ukXG4gKlxuICogLSDrqqjrk6Ag7JqU7LKt7J2AIGZyZXNoIGAtLXNlc3Npb24taWRgIOuhnCDsi6TtlolcbiAqIC0g66mA7Yuw7YS0IOusuOunpeydgCDtgbTrnbzsnbTslrjtirjqsIAg66ekIO2YuOy2nCDrs7TrgrTripQgZnVsbCBoaXN0b3J5IOulvCDtj4ntg4TtmZTtlbQg7KCE64us7ZWc64ukLlxuICogLSDrsJzquIntlZwgc2Vzc2lvbi1pZCDrpbwgR2VuZXJhdGVSZXN1bHQudGhyZWFkQ29vcmQodGhyZWFkSWQ9c2Vzc2lvbi1pZCwgd29ya2VySWQ9dG9rZW5JZCxcbiAqICAgZXBvY2g9MCnroZwg7Jis66CkLCDsg4HsnIQoaXNzdWVDb252Q29udGV4dCnqsIAg7YG065287JeQIO2ajOyGoe2VoCDsooztkZzrpbwg66eM65Og64ukLiDri6TsnYwgdHVybiDsnbQg7KKM7ZGc66W8XG4gKiAgIO2ajOyGoe2VtOuPhCBBbnRocm9waWMg65287Jqw7YyF7JeQ64qUIOyTsOyngCDslYrripTri6QuXG4gKi9cblxuaW1wb3J0IHsgZ2V0TG9nZ2VyIH0gZnJvbSBcIkBsb2d0YXBlL2xvZ3RhcGVcIjtcblxuaW1wb3J0IHsgUXVvdGFUaHJlc2hvbGRFeGNlZWRlZEVycm9yIH0gZnJvbSBcIi4uLy4uLy4uL2FwcGxpY2F0aW9uL3FncmlkL3FncmlkLnR5cGVzXCI7XG5pbXBvcnQgeyBUb2tlbk1vZGVsIH0gZnJvbSBcIi4uLy4uLy4uL2FwcGxpY2F0aW9uL3Rva2VuL3Rva2VuLm1vZGVsXCI7XG5pbXBvcnQgeyB0eXBlIEFudGhyb3BpY0NyZWRlbnRpYWxzIH0gZnJvbSBcIi4uLy4uLy4uL2FwcGxpY2F0aW9uL3Rva2VuL3Rva2VuLnR5cGVzXCI7XG5pbXBvcnQgeyBnZXRFeHBpcmVzQXQsIGdldFJlZnJlc2hUb2tlbiB9IGZyb20gXCIuLi9jb21tb24vY3JlZGVudGlhbHNcIjtcbmltcG9ydCB7XG4gIHR5cGUgR2VuZXJhdGVSZXF1ZXN0LFxuICB0eXBlIEdlbmVyYXRlUmVzdWx0LFxuICB0eXBlIEdlbmVyYXRlU3RyZWFtQ2FsbGJhY2tzLFxuICB0eXBlIFByb3ZpZGVyRGlzcGF0Y2hlcixcbn0gZnJvbSBcIi4uL2NvbW1vbi9wcm92aWRlci1kaXNwYXRjaGVyXCI7XG5pbXBvcnQgeyBzZXJpYWxpemVBbmRWYWxpZGF0ZURpc3BhdGNoU2NoZW1hIH0gZnJvbSBcIi4uL2NvbW1vbi9zY2hlbWEtdmFsaWRhdGlvblwiO1xuaW1wb3J0IHsgU21vb3RoV2VpZ2h0ZWRSb3VuZFJvYmluIH0gZnJvbSBcIi4uL2NvbW1vbi9zbW9vdGgtd2VpZ2h0ZWQtcm91bmQtcm9iaW5cIjtcbmltcG9ydCB7IGFzc2VydFN1cHBvcnRlZE9uZU1pbGxpb25TdWZmaXgsIGNhbm9uaWNhbEFudGhyb3BpY01vZGVsIH0gZnJvbSBcIi4vYW50aHJvcGljLWNvbnN0YW50c1wiO1xuaW1wb3J0IHtcbiAgaW52YWxpZGF0ZUFudGhyb3BpY1F1b3RhVXNhZ2UsXG4gIHJlYWRBbnRocm9waWNRdW90YVVzYWdlLFxuICB0eXBlIEFudGhyb3BpY1F1b3RhVXNhZ2VSZXN1bHQsXG59IGZyb20gXCIuL2FudGhyb3BpYy1xdW90YVwiO1xuaW1wb3J0IHsgbWFrZUFudGhyb3BpY1dvcmtlcklkLCBydW5DbGF1ZGVTZXNzaW9uIH0gZnJvbSBcIi4vY2xhdWRlLXNlc3Npb25cIjtcblxuY29uc3QgbG9nZ2VyID0gZ2V0TG9nZ2VyKFtcInFncmlkXCIsIFwiYW50aHJvcGljLWRpc3BhdGNoZXJcIl0pO1xuXG4vLyAxTSBjb250ZXh0IOygleyDgSDsg53shLHsnYAg7Iuk7Lih7IOBIDEwMHMr6rmM7KeAIOqwhOuLpC4gMjQwc+uKlCDsmYTstqkg7J6l7LmY7J28IOu/kCxcbi8vIOqxsOu2gCvqsbDrjIAgc3lzdGVtIOyerOyDneyEsSDsp4Dsl7DsnYQg7JmE7KCE7Z6IIO2VtOqysO2VmOuKlCDqsJLsnYAg7JWE64uI64ukLlxuY29uc3QgREVGQVVMVF9USU1FT1VUX01TID0gMjQwXzAwMDtcbi8vIGFjY2VzcyB0b2tlbiDrp4zro4wg7J6E67CVIOyehOqzhCDigJQg6riw7KG0IHN0YW5kYWxvbmUg6rK966GcKHFncmlkLmRpc3BhdGNoZXIudHMp7JmAIOuPmeydvCg2MHMpLlxuY29uc3QgUkVGUkVTSF9TQUZFVFlfTVMgPSA2MF8wMDA7XG5cbmludGVyZmFjZSBQb29sZWRUb2tlbiB7XG4gIGlkOiBudW1iZXI7XG4gIG5hbWU6IHN0cmluZztcbiAgY3JlZGVudGlhbHM6IEFudGhyb3BpY0NyZWRlbnRpYWxzO1xuICBxdW90YVRocmVzaG9sZD86IG51bWJlciB8IG51bGw7XG4gIHdlaWdodDogbnVtYmVyO1xufVxuXG5mdW5jdGlvbiBxdW90YVRocmVzaG9sZEV4Y2VlZGVkTWVzc2FnZShcbiAgcHJvdmlkZXI6IHN0cmluZyxcbiAgdG9rZW5zOiBBcnJheTx7IHRva2VuTmFtZTogc3RyaW5nOyB0aHJlc2hvbGQ6IG51bWJlciB9Pixcbik6IHN0cmluZyB7XG4gIGNvbnN0IGRldGFpbHMgPSB0b2tlbnNcbiAgICAubWFwKCh0b2tlbikgPT4gYCR7dG9rZW4udG9rZW5OYW1lfSAodGhyZXNob2xkICR7dG9rZW4udGhyZXNob2xkfSUpYClcbiAgICAuam9pbihcIiwgXCIpO1xuICByZXR1cm4gZGV0YWlscy5sZW5ndGggPiAwXG4gICAgPyBgQWxsICR7cHJvdmlkZXJ9IHRva2VucyBleGNlZWRlZCBxdW90YSB0aHJlc2hvbGQ6ICR7ZGV0YWlsc31gXG4gICAgOiBgQWxsICR7cHJvdmlkZXJ9IHRva2VucyBleGNlZWRlZCBxdW90YSB0aHJlc2hvbGRgO1xufVxuXG5leHBvcnQgY2xhc3MgQW50aHJvcGljRGlzcGF0Y2hlciBpbXBsZW1lbnRzIFByb3ZpZGVyRGlzcGF0Y2hlciB7XG4gIC8vIHRva2VuSWQg4oaSIO2SgCDtla3rqqkuIHN0YXJ0KCkvdG9rZW4g7J2067Kk7Yq466GcIOyxhOybgFxuICBwcml2YXRlIHRva2VuUG9vbCA9IG5ldyBNYXA8bnVtYmVyLCBQb29sZWRUb2tlbj4oKTtcbiAgcHJpdmF0ZSByZWFkb25seSB3ZWlnaHRlZFNlbGVjdG9yID0gbmV3IFNtb290aFdlaWdodGVkUm91bmRSb2JpbigpO1xuXG4gIGFzeW5jIHN0YXJ0KCk6IFByb21pc2U8dm9pZD4ge1xuICAgIC8vIE9wZW5BSURpc3BhdGNoZXIuc3RhcnQoKSDsmYAg64+Z7J287ZWY6rKMIERCIOyXkOyEnCDquLDsobQgYW50aHJvcGljIO2GoO2BsOydhCBzZWxmLWJvb3RzdHJhcCDtlZzri6QuXG4gICAgLy8gKOyEnOuyhCDsnqzsi5zsnpEg7IucIE5PVElGWSDqsIAg7JWIIOyYpOuvgOuhnCDrtoDtirjsiqTtirjrnqnsnbQg7JeG7Jy866m0IO2SgOydtCDruYgg7LGE66GcIOuCqOuKlOuLpC4pXG4gICAgLy8g7J207ZuEIOuzgOqyveu2hOydgCB0b2tlbi1zdWJzY3JpYmVyIOqwgCBvblRva2VuQWRkZWQvVXBkYXRlZC9SZW1vdmVkIOuhnCDsoITri6ztlZzri6QuXG4gICAgLy8gZmluZEFjdGl2ZUJ5UHJvdmlkZXIg6rCAIGFjdGl2ZT10cnVlICsgcHJvdmlkZXIg7ZWE7YSw66W8IERCIOyXkOyEnCDsspjrpqwg4oaSIGluYWN0aXZlIOuKlCDslaDstIjsl5Ag7JWIIOyYqOuLpC5cbiAgICBjb25zdCB0b2tlbnMgPSBhd2FpdCBUb2tlbk1vZGVsLmZpbmRBY3RpdmVCeVByb3ZpZGVyKFwiQVwiLCBcImFudGhyb3BpY1wiKTtcbiAgICBmb3IgKGNvbnN0IHQgb2YgdG9rZW5zKSB7XG4gICAgICB0aGlzLnRva2VuUG9vbC5zZXQodC5pZCwge1xuICAgICAgICBpZDogdC5pZCxcbiAgICAgICAgbmFtZTogdC5uYW1lLFxuICAgICAgICBjcmVkZW50aWFsczogdC5jcmVkZW50aWFscyBhcyBBbnRocm9waWNDcmVkZW50aWFscyxcbiAgICAgICAgcXVvdGFUaHJlc2hvbGQ6IHQucXVvdGFfdGhyZXNob2xkLFxuICAgICAgICB3ZWlnaHQ6IHQud2VpZ2h0LFxuICAgICAgfSk7XG4gICAgICB0aGlzLndlaWdodGVkU2VsZWN0b3Iuc2V0VG9rZW4odC5pZCwgdC53ZWlnaHQpO1xuICAgICAgbG9nZ2VyLmluZm8oYHdvcmtlciBzcGF3bmVkOiAke3QubmFtZX1gKTtcbiAgICB9XG4gIH1cblxuICBhc3luYyBzdG9wKCk6IFByb21pc2U8dm9pZD4ge1xuICAgIGNvbnN0IHRva2VuSWRzID0gWy4uLnRoaXMudG9rZW5Qb29sLmtleXMoKV07XG4gICAgZm9yIChjb25zdCBpZCBvZiB0b2tlbklkcykgdGhpcy53ZWlnaHRlZFNlbGVjdG9yLnJlbW92ZVRva2VuKGlkKTtcbiAgICB0aGlzLnRva2VuUG9vbC5jbGVhcigpO1xuICAgIHRoaXMud2VpZ2h0ZWRTZWxlY3Rvci5yZXNldFNjb3JlcygpO1xuICB9XG5cbiAgLy8g7ZiE7J6sIO2SgOydmCDthqDtgbAg7IiYKHN0YXJ0dXAg66Gc6re4L2hlYWx0aCDsmqkpLlxuICBnZXQgdG9rZW5Db3VudCgpOiBudW1iZXIge1xuICAgIHJldHVybiB0aGlzLnRva2VuUG9vbC5zaXplO1xuICB9XG5cbiAgLy8g7KeA6riIIOyLpO2WiSDspJHsnbggQ2xhdWRlIENvZGUg7ZSE66Gc7IS47IqkIOyImCDigJQgZnJlc2gtc3Bhd24g7J206528IOydtOqyjCDqs6cg64+Z7IucIOyalOyyrSDsiJjri6QuXG4gIHByaXZhdGUgaW5GbGlnaHRDb3VudCA9IDA7XG4gIGdldCBpbkZsaWdodCgpOiBudW1iZXIge1xuICAgIHJldHVybiB0aGlzLmluRmxpZ2h0Q291bnQ7XG4gIH1cblxuICAvLyBNb25pdCDtkZzsi5zsmqkg4oCUIO2SgOyXkCDsnojripQg7Yag7YGwIOydtOumhCDsiqTrg4Xsg7cgKOydtOumhOyInCDsoJXroKwpXG4gIGdldCB0b2tlbk5hbWVzKCk6IHN0cmluZ1tdIHtcbiAgICByZXR1cm4gWy4uLnRoaXMudG9rZW5Qb29sLnZhbHVlcygpXS5tYXAoKHRva2VuKSA9PiB0b2tlbi5uYW1lKS50b1NvcnRlZCgpO1xuICB9XG5cbiAgLy8gREIgYWN0aXZlIGFudGhyb3BpYyDthqDtgbAg66qp66Gd7Jy866GcIO2SgOydhCDsnqzrj5nquLDtmZTtlZzri6QocGVyaW9kaWMgcmVjb25jaWxlL+yerOyXsOqysOyaqSkuXG4gIC8vIExJU1RFTi9OT1RJRlkg6rCAIOuBiuq4tCDrj5nslYgg7Jyg7Iuk65CcIOy2lOqwgC/sgq3soJwv67mE7Zmc7ISx7ZmU66W8IERCIOq4sOykgOycvOuhnCDri6Tsi5wg66ee7LaY64ukLlxuICAvLyDsnbTrsqTtirgg7ZW465Ok65+s66W8IOyerOyCrOyaqe2VtCDtkoAg6rCx7Iug7J20IOydvOq0gOuQmOqyjCDsoIHsmqnrkJjrj4TroZ0g7ZWc64ukOlxuICAvLyAgLSBEQiDsl5Ag7JeG64qU642wIO2SgOyXkCDsnojripQg7Yag7YGwIOKGkiBvblRva2VuUmVtb3ZlZFxuICAvLyAgLSBEQiDsl5Ag7J6I64qUIO2GoO2BsCDihpIg7Iug6rec66m0IG9uVG9rZW5BZGRlZCwg6riw7KG07J2066m0IG9uVG9rZW5VcGRhdGVkXG4gIHJlcGxhY2VUb2tlbnMoXG4gICAgcm93czogQXJyYXk8e1xuICAgICAgaWQ6IG51bWJlcjtcbiAgICAgIG5hbWU6IHN0cmluZztcbiAgICAgIGNyZWRlbnRpYWxzOiBBbnRocm9waWNDcmVkZW50aWFscztcbiAgICAgIHF1b3RhVGhyZXNob2xkPzogbnVtYmVyIHwgbnVsbDtcbiAgICAgIHdlaWdodDogbnVtYmVyO1xuICAgIH0+LFxuICApOiB2b2lkIHtcbiAgICBjb25zdCBuZXh0ID0gbmV3IFNldChyb3dzLm1hcCgocikgPT4gci5pZCkpO1xuICAgIC8vIG9uVG9rZW5SZW1vdmVkIOqwgCB0b2tlblBvb2wg7J2EIGRlbGV0ZSDtlZjrr4DroZwg7Iic7ZqMIOykkSDsiJjsoJXsnYQg7ZS87ZWY66CkIO2CpOulvCDrqLzsoIAg7Iqk64OF7IO37ZWc64ukLlxuICAgIGNvbnN0IGN1cnJlbnRJZHMgPSBBcnJheS5mcm9tKHRoaXMudG9rZW5Qb29sLmtleXMoKSk7XG4gICAgZm9yIChjb25zdCBpZCBvZiBjdXJyZW50SWRzKSB7XG4gICAgICBpZiAoIW5leHQuaGFzKGlkKSkgdGhpcy5vblRva2VuUmVtb3ZlZChpZCk7XG4gICAgfVxuICAgIGZvciAoY29uc3QgciBvZiByb3dzKSB7XG4gICAgICBpZiAodGhpcy50b2tlblBvb2wuaGFzKHIuaWQpKSB7XG4gICAgICAgIHRoaXMub25Ub2tlblVwZGF0ZWQoci5pZCwgci5uYW1lLCByLmNyZWRlbnRpYWxzLCByLnF1b3RhVGhyZXNob2xkLCByLndlaWdodCk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICB0aGlzLm9uVG9rZW5BZGRlZChyLmlkLCByLm5hbWUsIHIuY3JlZGVudGlhbHMsIHIucXVvdGFUaHJlc2hvbGQsIHIud2VpZ2h0KTtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICAvLyB0b2tlbiBldmVudHMgKHRva2VuLXN1YnNjcmliZXIg6rCAIO2YuOy2nClcbiAgb25Ub2tlbkFkZGVkKFxuICAgIGlkOiBudW1iZXIsXG4gICAgbmFtZTogc3RyaW5nLFxuICAgIGNyZWRlbnRpYWxzOiBBbnRocm9waWNDcmVkZW50aWFscyxcbiAgICBxdW90YVRocmVzaG9sZD86IG51bWJlciB8IG51bGwsXG4gICAgd2VpZ2h0ID0gMSxcbiAgKTogdm9pZCB7XG4gICAgdGhpcy50b2tlblBvb2wuc2V0KGlkLCB7IGlkLCBuYW1lLCBjcmVkZW50aWFscywgcXVvdGFUaHJlc2hvbGQsIHdlaWdodCB9KTtcbiAgICB0aGlzLndlaWdodGVkU2VsZWN0b3Iuc2V0VG9rZW4oaWQsIHdlaWdodCk7XG4gIH1cblxuICBvblRva2VuVXBkYXRlZChcbiAgICBpZDogbnVtYmVyLFxuICAgIG5hbWU6IHN0cmluZyxcbiAgICBjcmVkZW50aWFsczogQW50aHJvcGljQ3JlZGVudGlhbHMsXG4gICAgcXVvdGFUaHJlc2hvbGQ/OiBudW1iZXIgfCBudWxsLFxuICAgIHdlaWdodCA9IDEsXG4gICk6IHZvaWQge1xuICAgIHRoaXMudG9rZW5Qb29sLnNldChpZCwgeyBpZCwgbmFtZSwgY3JlZGVudGlhbHMsIHF1b3RhVGhyZXNob2xkLCB3ZWlnaHQgfSk7XG4gICAgdGhpcy53ZWlnaHRlZFNlbGVjdG9yLnNldFRva2VuKGlkLCB3ZWlnaHQpO1xuICB9XG5cbiAgb25Ub2tlblJlbW92ZWQoaWQ6IG51bWJlcik6IHZvaWQge1xuICAgIHRoaXMudG9rZW5Qb29sLmRlbGV0ZShpZCk7XG4gICAgdGhpcy53ZWlnaHRlZFNlbGVjdG9yLnJlbW92ZVRva2VuKGlkKTtcbiAgfVxuXG4gIC8vIOyngOyglSDsmpTssq3snYAg7ZW064u5IO2GoO2BsOunjCBxdW90YSDtjJDsoJXtlZjqs6Agd2VpZ2h0ZWQg7IOB7YOc66W8IOqxtOuTnOumrOyngCDslYrripTri6QuXG4gIC8vIOuvuOyngOyglSDsmpTssq3rp4wgcXVvdGEg7Ya16rO8IO2bhOuztOuhnCBzbW9vdGggd2VpZ2h0ZWQgcm91bmQtcm9iaW4g7J2EIOynhO2Wie2VnOuLpC5cbiAgcHJpdmF0ZSBhc3luYyBzZWxlY3RUb2tlbihtb2RlbDogc3RyaW5nLCBwcmVmZXJyZWRUb2tlbklkPzogbnVtYmVyKTogUHJvbWlzZTxQb29sZWRUb2tlbiB8IG51bGw+IHtcbiAgICBjb25zdCBwcmVmZXJyZWQgPVxuICAgICAgcHJlZmVycmVkVG9rZW5JZCA9PT0gdW5kZWZpbmVkID8gdW5kZWZpbmVkIDogdGhpcy50b2tlblBvb2wuZ2V0KHByZWZlcnJlZFRva2VuSWQpO1xuICAgIGlmIChwcmVmZXJyZWRUb2tlbklkICE9PSB1bmRlZmluZWQgJiYgIXByZWZlcnJlZCkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGBQcmVmZXJyZWQgYW50aHJvcGljIHRva2VuICR7cHJlZmVycmVkVG9rZW5JZH0gaXMgbm90IGF2YWlsYWJsZWApO1xuICAgIH1cblxuICAgIGNvbnN0IHJvd3MgPSBwcmVmZXJyZWQgPyBbcHJlZmVycmVkXSA6IFsuLi50aGlzLnRva2VuUG9vbC52YWx1ZXMoKV07XG4gICAgaWYgKHJvd3MubGVuZ3RoID09PSAwKSByZXR1cm4gbnVsbDtcbiAgICBjb25zdCB7IGVsaWdpYmxlLCBvdmVyVGhyZXNob2xkVG9rZW5zIH0gPSBhd2FpdCB0aGlzLmZpbHRlckVsaWdpYmxlVG9rZW5zKHJvd3MsIG1vZGVsKTtcbiAgICBpZiAoZWxpZ2libGUubGVuZ3RoID09PSAwKSB7XG4gICAgICBsb2dnZXIud2FybihcInF1b3RhX3RocmVzaG9sZCBnYXRlOiBhbGxfZXhjZWVkZWRcIiwge1xuICAgICAgICBwcm92aWRlcjogXCJhbnRocm9waWNcIixcbiAgICAgICAgdG9rZW5Db3VudDogcm93cy5sZW5ndGgsXG4gICAgICAgIHRocmVzaG9sZGVkVG9rZW5Db3VudDogcm93cy5maWx0ZXIoKHIpID0+IHRoaXMuaGFzUXVvdGFUaHJlc2hvbGQocikpLmxlbmd0aCxcbiAgICAgICAgb3ZlclRocmVzaG9sZFRva2VucyxcbiAgICAgICAgcmVhc29uOiBcImFsbF9leGNlZWRlZFwiLFxuICAgICAgfSk7XG4gICAgICB0aHJvdyBuZXcgUXVvdGFUaHJlc2hvbGRFeGNlZWRlZEVycm9yKFxuICAgICAgICBxdW90YVRocmVzaG9sZEV4Y2VlZGVkTWVzc2FnZShcImFudGhyb3BpY1wiLCBvdmVyVGhyZXNob2xkVG9rZW5zKSxcbiAgICAgICk7XG4gICAgfVxuXG4gICAgaWYgKHByZWZlcnJlZCkgcmV0dXJuIHByZWZlcnJlZDtcblxuICAgIGNvbnN0IHNlbGVjdGVkSWQgPSB0aGlzLndlaWdodGVkU2VsZWN0b3Iuc2VsZWN0KG5ldyBTZXQoZWxpZ2libGUubWFwKCh0b2tlbikgPT4gdG9rZW4uaWQpKSk7XG4gICAgaWYgKHNlbGVjdGVkSWQgPT09IG51bGwpIHJldHVybiBudWxsO1xuICAgIHJldHVybiB0aGlzLnRva2VuUG9vbC5nZXQoc2VsZWN0ZWRJZCkgPz8gbnVsbDtcbiAgfVxuXG4gIHByaXZhdGUgYXN5bmMgZmlsdGVyRWxpZ2libGVUb2tlbnMoXG4gICAgcm93czogUG9vbGVkVG9rZW5bXSxcbiAgICBtb2RlbDogc3RyaW5nLFxuICApOiBQcm9taXNlPHtcbiAgICBlbGlnaWJsZTogUG9vbGVkVG9rZW5bXTtcbiAgICBvdmVyVGhyZXNob2xkVG9rZW5zOiBBcnJheTx7IHRva2VuTmFtZTogc3RyaW5nOyB0aHJlc2hvbGQ6IG51bWJlciB9PjtcbiAgfT4ge1xuICAgIGNvbnN0IHRocmVzaG9sZGVkID0gcm93cy5maWx0ZXIoKHRva2VuKSA9PiB0aGlzLmhhc1F1b3RhVGhyZXNob2xkKHRva2VuKSk7XG4gICAgaWYgKHRocmVzaG9sZGVkLmxlbmd0aCA9PT0gMCkgcmV0dXJuIHsgZWxpZ2libGU6IHJvd3MsIG92ZXJUaHJlc2hvbGRUb2tlbnM6IFtdIH07XG5cbiAgICBjb25zdCBlbGlnaWJsZUlkcyA9IG5ldyBTZXQoXG4gICAgICByb3dzLmZpbHRlcigodG9rZW4pID0+ICF0aGlzLmhhc1F1b3RhVGhyZXNob2xkKHRva2VuKSkubWFwKCh0b2tlbikgPT4gdG9rZW4uaWQpLFxuICAgICk7XG4gICAgY29uc3Qgb3ZlclRocmVzaG9sZFRva2VuczogQXJyYXk8eyB0b2tlbk5hbWU6IHN0cmluZzsgdGhyZXNob2xkOiBudW1iZXIgfT4gPSBbXTtcbiAgICBjb25zdCBjaGVja3MgPSBhd2FpdCBQcm9taXNlLmFsbFNldHRsZWQoXG4gICAgICB0aHJlc2hvbGRlZC5tYXAoYXN5bmMgKHRva2VuKSA9PiAoe1xuICAgICAgICB0b2tlbixcbiAgICAgICAgcmVzdWx0OiBhd2FpdCByZWFkQW50aHJvcGljUXVvdGFVc2FnZSh0b2tlbi5jcmVkZW50aWFscy5hY2Nlc3NUb2tlbiwgbW9kZWwpLFxuICAgICAgfSkpLFxuICAgICk7XG5cbiAgICBjaGVja3MuZm9yRWFjaCgoY2hlY2ssIGluZGV4KSA9PiB7XG4gICAgICBpZiAoY2hlY2suc3RhdHVzID09PSBcInJlamVjdGVkXCIpIHtcbiAgICAgICAgY29uc3QgdG9rZW4gPSB0aHJlc2hvbGRlZFtpbmRleF07XG4gICAgICAgIGlmICghdG9rZW4pIHJldHVybjtcbiAgICAgICAgdGhpcy5sb2dRdW90YUxvb2t1cEZhaWxPcGVuKHRva2VuLCBTdHJpbmcoY2hlY2sucmVhc29uKSk7XG4gICAgICAgIGVsaWdpYmxlSWRzLmFkZCh0b2tlbi5pZCk7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgY29uc3QgdG9rZW4gPSBjaGVjay52YWx1ZS50b2tlbjtcbiAgICAgIGNvbnN0IHJlc3VsdCA9IGNoZWNrLnZhbHVlLnJlc3VsdDtcbiAgICAgIGlmIChyZXN1bHQua2luZCA9PT0gXCJsb29rdXBfZmFpbGVkXCIpIHtcbiAgICAgICAgdGhpcy5sb2dRdW90YUxvb2t1cEZhaWxPcGVuKHRva2VuLCByZXN1bHQucmVhc29uKTtcbiAgICAgICAgZWxpZ2libGVJZHMuYWRkKHRva2VuLmlkKTtcbiAgICAgICAgcmV0dXJuO1xuICAgICAgfVxuXG4gICAgICBpZiAocmVzdWx0LnV0aWxpemF0aW9uUGN0ID49IHRva2VuLnF1b3RhVGhyZXNob2xkKSB7XG4gICAgICAgIHRoaXMubG9nUXVvdGFPdmVyVGhyZXNob2xkKHRva2VuLCByZXN1bHQpO1xuICAgICAgICBvdmVyVGhyZXNob2xkVG9rZW5zLnB1c2goeyB0b2tlbk5hbWU6IHRva2VuLm5hbWUsIHRocmVzaG9sZDogdG9rZW4ucXVvdGFUaHJlc2hvbGQgfSk7XG4gICAgICAgIHJldHVybjtcbiAgICAgIH1cblxuICAgICAgZWxpZ2libGVJZHMuYWRkKHRva2VuLmlkKTtcbiAgICB9KTtcblxuICAgIHJldHVybiB7IGVsaWdpYmxlOiByb3dzLmZpbHRlcigodG9rZW4pID0+IGVsaWdpYmxlSWRzLmhhcyh0b2tlbi5pZCkpLCBvdmVyVGhyZXNob2xkVG9rZW5zIH07XG4gIH1cblxuICBwcml2YXRlIGhhc1F1b3RhVGhyZXNob2xkKHRva2VuOiBQb29sZWRUb2tlbik6IHRva2VuIGlzIFBvb2xlZFRva2VuICYgeyBxdW90YVRocmVzaG9sZDogbnVtYmVyIH0ge1xuICAgIHJldHVybiB0b2tlbi5xdW90YVRocmVzaG9sZCAhPT0gdW5kZWZpbmVkICYmIHRva2VuLnF1b3RhVGhyZXNob2xkICE9PSBudWxsO1xuICB9XG5cbiAgcHJpdmF0ZSBsb2dRdW90YU92ZXJUaHJlc2hvbGQoXG4gICAgdG9rZW46IFBvb2xlZFRva2VuICYgeyBxdW90YVRocmVzaG9sZDogbnVtYmVyIH0sXG4gICAgcmVzdWx0OiBFeHRyYWN0PEFudGhyb3BpY1F1b3RhVXNhZ2VSZXN1bHQsIHsga2luZDogXCJva1wiIH0+LFxuICApOiB2b2lkIHtcbiAgICBsb2dnZXIuaW5mbyhcInF1b3RhX3RocmVzaG9sZCBnYXRlOiBvdmVyX3RocmVzaG9sZFwiLCB7XG4gICAgICB0b2tlbklkOiB0b2tlbi5pZCxcbiAgICAgIHRva2VuTmFtZTogdG9rZW4ubmFtZSxcbiAgICAgIHByb3ZpZGVyOiBcImFudGhyb3BpY1wiLFxuICAgICAgdGhyZXNob2xkOiB0b2tlbi5xdW90YVRocmVzaG9sZCxcbiAgICAgIGNhY2hlZFV0aWxpemF0aW9uOiByZXN1bHQudXRpbGl6YXRpb25QY3QsXG4gICAgICBjYWNoZUFnZTogcmVzdWx0LmNhY2hlQWdlTXMsXG4gICAgICByZWFzb246IFwib3Zlcl90aHJlc2hvbGRcIixcbiAgICB9KTtcbiAgfVxuXG4gIHByaXZhdGUgbG9nUXVvdGFMb29rdXBGYWlsT3BlbihcbiAgICB0b2tlbjogUG9vbGVkVG9rZW4gJiB7IHF1b3RhVGhyZXNob2xkOiBudW1iZXIgfSxcbiAgICByZWFzb246IHN0cmluZyxcbiAgKTogdm9pZCB7XG4gICAgbG9nZ2VyLndhcm4oXCJxdW90YV90aHJlc2hvbGQgZ2F0ZTogbG9va3VwX2ZhaWxfb3BlblwiLCB7XG4gICAgICB0b2tlbklkOiB0b2tlbi5pZCxcbiAgICAgIHRva2VuTmFtZTogdG9rZW4ubmFtZSxcbiAgICAgIHByb3ZpZGVyOiBcImFudGhyb3BpY1wiLFxuICAgICAgdGhyZXNob2xkOiB0b2tlbi5xdW90YVRocmVzaG9sZCxcbiAgICAgIHJlYXNvbjogXCJsb29rdXBfZmFpbF9vcGVuXCIsXG4gICAgICBsb29rdXBSZWFzb246IHJlYXNvbixcbiAgICB9KTtcbiAgfVxuXG4gIGFzeW5jIGdlbmVyYXRlKHJlcTogR2VuZXJhdGVSZXF1ZXN0KTogUHJvbWlzZTxHZW5lcmF0ZVJlc3VsdD4ge1xuICAgIHJldHVybiB0aGlzLnJ1bihyZXEsICgpID0+IHt9KTtcbiAgfVxuXG4gIGFzeW5jIGdlbmVyYXRlU3RyZWFtKHJlcTogR2VuZXJhdGVSZXF1ZXN0LCBjYjogR2VuZXJhdGVTdHJlYW1DYWxsYmFja3MpOiBQcm9taXNlPHZvaWQ+IHtcbiAgICB0cnkge1xuICAgICAgY29uc3QgcmVzdWx0ID0gYXdhaXQgdGhpcy5ydW4ocmVxLCBjYi5vbkRlbHRhLCB7IGluY2x1ZGVQYXJ0aWFsTWVzc2FnZXM6IHRydWUgfSk7XG4gICAgICBjYi5vblRocmVhZElkPy4ocmVzdWx0LnRocmVhZENvb3JkLnRocmVhZElkKTtcbiAgICAgIGNiLm9uQ29tcGxldGUocmVzdWx0KTtcbiAgICB9IGNhdGNoIChlKSB7XG4gICAgICBjYi5vbkVycm9yKGUgYXMgRXJyb3IpO1xuICAgIH1cbiAgfVxuXG4gIC8vIGdlbmVyYXRlL2dlbmVyYXRlU3RyZWFtIOqzte2GtSDsi6TtlokuIG9uRGVsdGEg64qUIOyKpO2KuOumvOydtOuptCDsoJDsp4Qg67Cp7LacLCDruYTsiqTtirjrprzsnbTrqbQgbm8tb3AuXG4gIHByaXZhdGUgYXN5bmMgcnVuKC4uLmFyZ3M6IFBhcmFtZXRlcnM8QW50aHJvcGljRGlzcGF0Y2hlcltcInJ1bklubmVyXCJdPik6IFByb21pc2U8R2VuZXJhdGVSZXN1bHQ+IHtcbiAgICB0aGlzLmluRmxpZ2h0Q291bnQrKztcbiAgICB0cnkge1xuICAgICAgcmV0dXJuIGF3YWl0IHRoaXMucnVuSW5uZXIoLi4uYXJncyk7XG4gICAgfSBmaW5hbGx5IHtcbiAgICAgIHRoaXMuaW5GbGlnaHRDb3VudC0tO1xuICAgIH1cbiAgfVxuXG4gIHByaXZhdGUgYXN5bmMgcnVuSW5uZXIoXG4gICAgcmVxOiBHZW5lcmF0ZVJlcXVlc3QsXG4gICAgb25EZWx0YTogKHQ6IHN0cmluZykgPT4gdm9pZCxcbiAgICBvcHRzPzogeyBpbmNsdWRlUGFydGlhbE1lc3NhZ2VzPzogYm9vbGVhbiB9LFxuICApOiBQcm9taXNlPEdlbmVyYXRlUmVzdWx0PiB7XG4gICAgLy8g7J2066+47KeAIOyDneyEseydgCBPcGVuQUkg6rK966GcIOyghOyaqS4gQW50aHJvcGljIOudvOyasO2MheyXkCDsnbTrr7jsp4Ag7ZSM656Y6re46rCAXG4gICAgLy8g64+E64us7ZWY66m0IOyhsOyaqe2eiCDthY3siqTtirjroZwg7Y+067Cx7ZWY7KeAIOyViuqzoCDrqoXsi5zsoIHsnLzroZwg6rGw67aA7ZWc64ukLlxuICAgIGlmIChyZXEuaW1hZ2VHZW5lcmF0aW9uKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoXCJpbWFnZSBnZW5lcmF0aW9uIGlzIG5vdCBzdXBwb3J0ZWQgb24gdGhlIEFudGhyb3BpYyByb3V0ZVwiKTtcbiAgICB9XG4gICAgLy8gbW9kZWwg7KCV6rec7ZmU66W8IGRpc3BhdGNoZXIg7KeE7J6F7KCQ7JeQ7IScIO2VnCDrsogg7ZWc64ukOiByZXN1bHQubW9kZWwgLyBydW5DbGF1ZGVTZXNzaW9uIOyghOu2gFxuICAgIC8vIGNhbm9uaWNhbChwcmVmaXgg7JeG64qUIGNvc3Qg7YKkKSDsnYQg7JOw6rKMIO2GteydvC4g66+47KeA7KCV7J2066m0IEFOVEhST1BJQ19ERUZBVUxUX01PREVMIOKAlCBxZ3JpZC5kaXNwYXRjaGVyXG4gICAgLy8g7J2YIFwic29ubmV0XCIg67OE7LmtIOyasO2ajCDssKjri6guIOygleq3nO2ZlCDqt5zsuZnsnYAgZmFsbGJhY2sg6rK966Gc7JmAIOqzteycoChjYW5vbmljYWxBbnRocm9waWNNb2RlbCkuXG4gICAgYXNzZXJ0U3VwcG9ydGVkT25lTWlsbGlvblN1ZmZpeChyZXEubW9kZWwpO1xuICAgIGNvbnN0IG1vZGVsID0gY2Fub25pY2FsQW50aHJvcGljTW9kZWwocmVxLm1vZGVsKTtcbiAgICBjb25zdCBqc29uU2NoZW1hID0gc2VyaWFsaXplQW5kVmFsaWRhdGVEaXNwYXRjaFNjaGVtYShyZXEub3V0cHV0U2NoZW1hLCBcImFudGhyb3BpY1wiKTtcblxuICAgIGNvbnN0IHRva2VuID0gYXdhaXQgdGhpcy5zZWxlY3RUb2tlbihtb2RlbCwgcmVxLnByZWZlcnJlZFRva2VuSWQpO1xuICAgIGlmICghdG9rZW4pIHRocm93IG5ldyBFcnJvcihcIk5vIGFudGhyb3BpYyB0b2tlbnMgYXZhaWxhYmxlXCIpO1xuXG4gICAgY29uc3QgZXhlYyA9IGFzeW5jICgpOiBQcm9taXNlPEdlbmVyYXRlUmVzdWx0PiA9PiB7XG4gICAgICAvLyDrp4zro4wg7J6E67CVIO2GoO2BsCBwcmVlbXB0aXZlIHJlZnJlc2go6riw7KG0IHN0YW5kYWxvbmUg6rK966Gc7JmAIOuPmeydvCkuIOyLpO2MqO2VtOuPhCDsp4TtlokuXG4gICAgICBsZXQgYWNjZXNzVG9rZW4gPSB0b2tlbi5jcmVkZW50aWFscy5hY2Nlc3NUb2tlbjtcbiAgICAgIGNvbnN0IGV4cGlyZXNBdCA9IGdldEV4cGlyZXNBdCh0b2tlbi5jcmVkZW50aWFscyk7XG4gICAgICBpZiAoXG4gICAgICAgIGV4cGlyZXNBdCAmJlxuICAgICAgICBleHBpcmVzQXQgLSBEYXRlLm5vdygpIDwgUkVGUkVTSF9TQUZFVFlfTVMgJiZcbiAgICAgICAgZ2V0UmVmcmVzaFRva2VuKHRva2VuLmNyZWRlbnRpYWxzKVxuICAgICAgKSB7XG4gICAgICAgIHRyeSB7XG4gICAgICAgICAgY29uc3QgeyBRZ3JpZEZyYW1lIH0gPSBhd2FpdCBpbXBvcnQoXCIuLi8uLi8uLi9hcHBsaWNhdGlvbi9xZ3JpZC9xZ3JpZC5mcmFtZVwiKTtcbiAgICAgICAgICAvLyBwcm92aWRlciDrpbwg67CY65Oc7IucIOyxhOybjOyVvCByZWZyZXNoVG9rZW4g64K067aAIFRva2VuTW9kZWwuc2F2ZSDqsIAg7ISx6rO17ZWc64ukLlxuICAgICAgICAgIC8vIHJlZnJlc2hUb2tlbihUb2tlblN1YnNldEEpIOuKlCBpZC9wcm92aWRlci9jcmVkZW50aWFscy9uYW1lIOunjCDsgqzsmqntlZjrr4DroZwg6re4IDTqsJzrp4wg64SY6ri064ukLlxuICAgICAgICAgIGFjY2Vzc1Rva2VuID0gYXdhaXQgUWdyaWRGcmFtZS5yZWZyZXNoVG9rZW4oe1xuICAgICAgICAgICAgaWQ6IHRva2VuLmlkLFxuICAgICAgICAgICAgcHJvdmlkZXI6IFwiYW50aHJvcGljXCIsXG4gICAgICAgICAgICBuYW1lOiB0b2tlbi5uYW1lLFxuICAgICAgICAgICAgY3JlZGVudGlhbHM6IHRva2VuLmNyZWRlbnRpYWxzLFxuICAgICAgICAgIH0gYXMgUGFyYW1ldGVyczx0eXBlb2YgUWdyaWRGcmFtZS5yZWZyZXNoVG9rZW4+WzBdKTtcbiAgICAgICAgfSBjYXRjaCAoZSkge1xuICAgICAgICAgIGxvZ2dlci53YXJuKGByZWZyZXNoIGZhaWxlZCBmb3IgJHt0b2tlbi5uYW1lfTogJHsoZSBhcyBFcnJvcikubWVzc2FnZX1gKTtcbiAgICAgICAgfVxuICAgICAgfVxuXG4gICAgICBsb2dnZXIuaW5mbyhg4oaSICR7dG9rZW4ubmFtZX0gKG1vZGVsOiAke21vZGVsfSlgKTtcbiAgICAgIGNvbnN0IHNlc3Npb24gPSBhd2FpdCBydW5DbGF1ZGVTZXNzaW9uKFxuICAgICAgICB7XG4gICAgICAgICAgdG9rZW5JZDogdG9rZW4uaWQsXG4gICAgICAgICAgdG9rZW46IGFjY2Vzc1Rva2VuLFxuICAgICAgICAgIG1vZGVsLFxuICAgICAgICAgIHN5c3RlbTogcmVxLnN5c3RlbVByb21wdCxcbiAgICAgICAgICBqc29uU2NoZW1hLFxuICAgICAgICAgIGVmZm9ydDogcmVxLmVmZm9ydCxcbiAgICAgICAgICB0aW1lb3V0TXM6IHJlcS50aW1lb3V0TXMgPz8gREVGQVVMVF9USU1FT1VUX01TLFxuICAgICAgICAgIGNvbGRIaXN0b3J5OiByZXEuY29sZEhpc3RvcnksXG4gICAgICAgICAgaW5wdXQ6IHJlcS5jb2xkSW5wdXQsXG4gICAgICAgICAgYWJvcnRTaWduYWw6IHJlcS5hYm9ydFNpZ25hbCxcbiAgICAgICAgICBpbmNsdWRlUGFydGlhbE1lc3NhZ2VzOiBvcHRzPy5pbmNsdWRlUGFydGlhbE1lc3NhZ2VzLFxuICAgICAgICB9LFxuICAgICAgICBvbkRlbHRhLFxuICAgICAgKTtcblxuICAgICAgaWYgKHNlc3Npb24ucXVvdGFFeGhhdXN0ZWQpIHtcbiAgICAgICAgaW52YWxpZGF0ZUFudGhyb3BpY1F1b3RhVXNhZ2UodG9rZW4uY3JlZGVudGlhbHMuYWNjZXNzVG9rZW4pO1xuICAgICAgICBpZiAoYWNjZXNzVG9rZW4gIT09IHRva2VuLmNyZWRlbnRpYWxzLmFjY2Vzc1Rva2VuKSB7XG4gICAgICAgICAgaW52YWxpZGF0ZUFudGhyb3BpY1F1b3RhVXNhZ2UoYWNjZXNzVG9rZW4pO1xuICAgICAgICB9XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihgcXVvdGEgZXhoYXVzdGVkICgke3Rva2VuLm5hbWV9KWApO1xuICAgICAgfVxuICAgICAgaWYgKHNlc3Npb24uaXNFcnJvcikge1xuICAgICAgICAvLyDsp4Tri6goU09OLTQ5NSk6IGlzRXJyb3Ig7YyQ7KCVIOyCrOycoChzdWJ0eXBlL3Rlcm1pbmFsX3JlYXNvbinrpbwg66mU7Iuc7KeAIOyVnuyXkCDrk5zrn6zrgrjri6QuXG4gICAgICAgIC8vIOq3uOuPmeyViCBkZXRhaWwg7J20IHNlc3Npb24udGV4dCjsmYTsoITtlZwgSlNPTiDrs7jrrLgp67+Q7J206528IFwic2NoZW1hIOychOuwmOyduOyngCAvIG1heCByZXRyaWVzIOyduOyngCAvXG4gICAgICAgIC8vIG1heCB0dXJucyDsnbjsp4BcIuulvCDqtazrtoTtlaAg7IiYIOyXhuyXiOuLpC4gdGV4dCDripQg7KeE64uo7JeQIO2VhOyalO2VnCDrp4ztgbzrp4wg7J6Y6528IOuNp+u2meyduOuLpC5cbiAgICAgICAgY29uc3QgcmVhc29uID1cbiAgICAgICAgICBzZXNzaW9uLnN1YnR5cGUgPz8gc2Vzc2lvbi50ZXJtaW5hbFJlYXNvbiA/PyAoc2Vzc2lvbi5pc0Vycm9yID8gXCJpc19lcnJvclwiIDogXCJ1bmtub3duXCIpO1xuICAgICAgICBjb25zdCBib2R5ID0gc2Vzc2lvbi50ZXh0XG4gICAgICAgICAgPyBzZXNzaW9uLnRleHQubGVuZ3RoID4gNTAwXG4gICAgICAgICAgICA/IGAke3Nlc3Npb24udGV4dC5zbGljZSgwLCA1MDApfeKApigke3Nlc3Npb24udGV4dC5sZW5ndGh9IGNoYXJzKWBcbiAgICAgICAgICAgIDogc2Vzc2lvbi50ZXh0XG4gICAgICAgICAgOiBgZW1wdHkgdGV4dCwgb3V0cHV0VG9rZW5zPSR7c2Vzc2lvbi51c2FnZS5vdXRwdXRUb2tlbnN9YDtcbiAgICAgICAgY29uc3QgcmVmdXNhbCA9IHNlc3Npb24ucmVmdXNhbCA/IGAgcmVmdXNhbD0ke0pTT04uc3RyaW5naWZ5KHNlc3Npb24ucmVmdXNhbCl9YCA6IFwiXCI7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihgY2xhdWRlIGVycm9yICgke3Rva2VuLm5hbWV9KSBbJHtyZWFzb259XTogJHtib2R5fSR7cmVmdXNhbH1gKTtcbiAgICAgIH1cblxuICAgICAgcmV0dXJuIHtcbiAgICAgICAgdGV4dDogc2Vzc2lvbi50ZXh0LFxuICAgICAgICB0b2tlbk5hbWU6IHRva2VuLm5hbWUsXG4gICAgICAgIHVzYWdlOiBzZXNzaW9uLnVzYWdlLFxuICAgICAgICBkdXJhdGlvbk1zOiBzZXNzaW9uLmR1cmF0aW9uTXMsXG4gICAgICAgIHR0ZnRNczogc2Vzc2lvbi50dGZ0TXMsXG4gICAgICAgIGNvc3RVc2Q6IHNlc3Npb24uY29zdFVzZCxcbiAgICAgICAgLy8gQ2xhdWRlIENvZGUg64qUIEZhYmxlIHJlZnVzYWwg7J2EIE9wdXMg66GcIOyekOuPmSBmYWxsYmFjayDtlaAg7IiYIOyeiOuLpC4g7JqU7LKtIOuqqOuNuOydhFxuICAgICAgICAvLyDqt7jrjIDroZwgc2VydmluZyBtb2RlbCDroZwg6riw66Gd7ZWY66m0IOu5hOyaqS/qsJDsgqwg66Gc6re46rCAIOuqqOuRkCDti4DslrTsp4Drr4DroZwg65GY7J2EIOq1rOu2hO2VnOuLpC5cbiAgICAgICAgbW9kZWw6IHNlc3Npb24uc2VydmVkTW9kZWwgPz8gbW9kZWwsXG4gICAgICAgIHJlcXVlc3RlZE1vZGVsOiBtb2RlbCxcbiAgICAgICAgbW9kZWxGYWxsYmFja3M6IHNlc3Npb24ubW9kZWxGYWxsYmFja3MsXG4gICAgICAgIC8vIHN5c3RlbUhhc2gg64qUIOyDgeychCBpc3N1ZUNvbnZDb250ZXh0IOqwgCDssYTsmrTri6Qo7Jes6riw7ISgIOu5hOyatOuLpCkuXG4gICAgICAgIHRocmVhZENvb3JkOiB7XG4gICAgICAgICAgd29ya2VySWQ6IG1ha2VBbnRocm9waWNXb3JrZXJJZCh0b2tlbi5pZCksXG4gICAgICAgICAgdGhyZWFkSWQ6IHNlc3Npb24uc2Vzc2lvbklkLFxuICAgICAgICAgIGVwb2NoOiAwLFxuICAgICAgICB9LFxuICAgICAgfTtcbiAgICB9O1xuXG4gICAgcmV0dXJuIGV4ZWMoKTtcbiAgfVxufVxuIl0sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQW1DQSxNQUFNLFNBQVMsVUFBVSxDQUFDLFNBQVMsc0JBQXNCLENBQUM7QUFJMUQsTUFBTSxxQkFBcUI7QUFFM0IsTUFBTSxvQkFBb0I7QUFVMUIsU0FBUyw4QkFDUCxVQUNBLFFBQ1E7Q0FDUixNQUFN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
|
|
@@ -1,13 +1,15 @@
|
|
|
1
|
-
import { fetchUsageWithMeta } from "../../../application/qgrid/oauth.js";
|
|
1
|
+
import { fetchUsageWithMeta, invalidateAnthropicQuotaUsage } from "../../../application/qgrid/oauth.js";
|
|
2
2
|
//#region src/utils/providers/anthropic/anthropic-quota.ts
|
|
3
|
-
async function readAnthropicQuotaUsage(accessToken) {
|
|
3
|
+
async function readAnthropicQuotaUsage(accessToken, model) {
|
|
4
4
|
try {
|
|
5
5
|
const { data, cachedAt } = await fetchUsageWithMeta(accessToken);
|
|
6
6
|
if (data.error) return {
|
|
7
7
|
kind: "lookup_failed",
|
|
8
8
|
reason: data.error
|
|
9
9
|
};
|
|
10
|
-
const
|
|
10
|
+
const utilizations = [data.five_hour?.utilization];
|
|
11
|
+
if (model === "claude-fable-5") utilizations.push(data.seven_day_overage_included?.utilization);
|
|
12
|
+
const utilization = Math.max(...utilizations.filter((value) => typeof value === "number" && Number.isFinite(value)));
|
|
11
13
|
if (typeof utilization !== "number" || !Number.isFinite(utilization)) return {
|
|
12
14
|
kind: "lookup_failed",
|
|
13
15
|
reason: "five_hour utilization unavailable"
|
|
@@ -25,6 +27,6 @@ async function readAnthropicQuotaUsage(accessToken) {
|
|
|
25
27
|
}
|
|
26
28
|
}
|
|
27
29
|
//#endregion
|
|
28
|
-
export { readAnthropicQuotaUsage };
|
|
30
|
+
export { invalidateAnthropicQuotaUsage, readAnthropicQuotaUsage };
|
|
29
31
|
|
|
30
|
-
//# sourceMappingURL=data:application/json;charset=utf-8;base64,
|
|
32
|
+
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYW50aHJvcGljLXF1b3RhLmpzIiwibmFtZXMiOltdLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3NyYy91dGlscy9wcm92aWRlcnMvYW50aHJvcGljL2FudGhyb3BpYy1xdW90YS50cyJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQge1xuICBmZXRjaFVzYWdlV2l0aE1ldGEsXG4gIGludmFsaWRhdGVBbnRocm9waWNRdW90YVVzYWdlLFxufSBmcm9tIFwiLi4vLi4vLi4vYXBwbGljYXRpb24vcWdyaWQvb2F1dGhcIjtcblxuZXhwb3J0IHsgaW52YWxpZGF0ZUFudGhyb3BpY1F1b3RhVXNhZ2UgfTtcblxuZXhwb3J0IHR5cGUgQW50aHJvcGljUXVvdGFVc2FnZVJlc3VsdCA9XG4gIHwgeyBraW5kOiBcIm9rXCI7IHV0aWxpemF0aW9uUGN0OiBudW1iZXI7IGNhY2hlQWdlTXM6IG51bWJlciB9XG4gIHwgeyBraW5kOiBcImxvb2t1cF9mYWlsZWRcIjsgcmVhc29uOiBzdHJpbmcgfTtcblxuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHJlYWRBbnRocm9waWNRdW90YVVzYWdlKFxuICBhY2Nlc3NUb2tlbjogc3RyaW5nLFxuICBtb2RlbD86IHN0cmluZyxcbik6IFByb21pc2U8QW50aHJvcGljUXVvdGFVc2FnZVJlc3VsdD4ge1xuICB0cnkge1xuICAgIGNvbnN0IHsgZGF0YSwgY2FjaGVkQXQgfSA9IGF3YWl0IGZldGNoVXNhZ2VXaXRoTWV0YShhY2Nlc3NUb2tlbik7XG4gICAgaWYgKGRhdGEuZXJyb3IpIHJldHVybiB7IGtpbmQ6IFwibG9va3VwX2ZhaWxlZFwiLCByZWFzb246IGRhdGEuZXJyb3IgfTtcblxuICAgIGNvbnN0IHV0aWxpemF0aW9ucyA9IFtkYXRhLmZpdmVfaG91cj8udXRpbGl6YXRpb25dO1xuICAgIGlmIChtb2RlbCA9PT0gXCJjbGF1ZGUtZmFibGUtNVwiKSB7XG4gICAgICB1dGlsaXphdGlvbnMucHVzaChkYXRhLnNldmVuX2RheV9vdmVyYWdlX2luY2x1ZGVkPy51dGlsaXphdGlvbik7XG4gICAgfVxuICAgIGNvbnN0IHV0aWxpemF0aW9uID0gTWF0aC5tYXgoXG4gICAgICAuLi51dGlsaXphdGlvbnMuZmlsdGVyKFxuICAgICAgICAodmFsdWUpOiB2YWx1ZSBpcyBudW1iZXIgPT4gdHlwZW9mIHZhbHVlID09PSBcIm51bWJlclwiICYmIE51bWJlci5pc0Zpbml0ZSh2YWx1ZSksXG4gICAgICApLFxuICAgICk7XG4gICAgaWYgKHR5cGVvZiB1dGlsaXphdGlvbiAhPT0gXCJudW1iZXJcIiB8fCAhTnVtYmVyLmlzRmluaXRlKHV0aWxpemF0aW9uKSkge1xuICAgICAgcmV0dXJuIHsga2luZDogXCJsb29rdXBfZmFpbGVkXCIsIHJlYXNvbjogXCJmaXZlX2hvdXIgdXRpbGl6YXRpb24gdW5hdmFpbGFibGVcIiB9O1xuICAgIH1cblxuICAgIHJldHVybiB7XG4gICAgICBraW5kOiBcIm9rXCIsXG4gICAgICB1dGlsaXphdGlvblBjdDogdXRpbGl6YXRpb24sXG4gICAgICBjYWNoZUFnZU1zOiBNYXRoLm1heChEYXRlLm5vdygpIC0gY2FjaGVkQXQsIDApLFxuICAgIH07XG4gIH0gY2F0Y2ggKGUpIHtcbiAgICByZXR1cm4geyBraW5kOiBcImxvb2t1cF9mYWlsZWRcIiwgcmVhc29uOiAoZSBhcyBFcnJvcikubWVzc2FnZSB9O1xuICB9XG59XG4iXSwibWFwcGluZ3MiOiI7O0FBV0EsZUFBc0Isd0JBQ3BCLGFBQ0EsT0FDb0M7Q0FDcEMsSUFBSTtFQUNGLE1BQU0sRUFBRSxNQUFNLGFBQWEsTUFBTSxtQkFBbUIsV0FBVztFQUMvRCxJQUFJLEtBQUssT0FBTyxPQUFPO0dBQUUsTUFBTTtHQUFpQixRQUFRLEtBQUs7RUFBTTtFQUVuRSxNQUFNLGVBQWUsQ0FBQyxLQUFLLFdBQVcsV0FBVztFQUNqRCxJQUFJLFVBQVUsa0JBQ1osYUFBYSxLQUFLLEtBQUssNEJBQTRCLFdBQVc7RUFFaEUsTUFBTSxjQUFjLEtBQUssSUFDdkIsR0FBRyxhQUFhLFFBQ2IsVUFBMkIsT0FBTyxVQUFVLFlBQVksT0FBTyxTQUFTLEtBQUssQ0FDaEYsQ0FDRjtFQUNBLElBQUksT0FBTyxnQkFBZ0IsWUFBWSxDQUFDLE9BQU8sU0FBUyxXQUFXLEdBQ2pFLE9BQU87R0FBRSxNQUFNO0dBQWlCLFFBQVE7RUFBb0M7RUFHOUUsT0FBTztHQUNMLE1BQU07R0FDTixnQkFBZ0I7R0FDaEIsWUFBWSxLQUFLLElBQUksS0FBSyxJQUFJLElBQUksVUFBVSxDQUFDO0VBQy9DO0NBQ0YsU0FBUyxHQUFHO0VBQ1YsT0FBTztHQUFFLE1BQU07R0FBaUIsUUFBUyxFQUFZO0VBQVE7Q0FDL0Q7QUFDRiJ9
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import { getLogger } from "@logtape/logtape";
|
|
2
|
+
import http from "node:http";
|
|
3
|
+
//#region src/utils/providers/openai/openai-callback-relay.ts
|
|
4
|
+
const logger = getLogger(["qgrid", "oauth"]);
|
|
5
|
+
/**
|
|
6
|
+
* OpenAI matches the Codex CLI client's redirect URIs by exact string, and only these two loopback
|
|
7
|
+
* callbacks are registered. Any other host, port, or path makes /oauth/authorize fail with
|
|
8
|
+
* `invalid_authorize_request` before the login screen renders, so qgrid cannot point the callback
|
|
9
|
+
* at its own configurable server port. Keep in sync with the Codex CLI allow-list (default 1455,
|
|
10
|
+
* fallback 1457).
|
|
11
|
+
*/
|
|
12
|
+
const OPENAI_CALLBACK_PORTS = [1455, 1457];
|
|
13
|
+
const OPENAI_CALLBACK_PATH = "/auth/callback";
|
|
14
|
+
function openAICallbackRedirectUri(port) {
|
|
15
|
+
return `http://localhost:${port}${OPENAI_CALLBACK_PATH}`;
|
|
16
|
+
}
|
|
17
|
+
let relay = null;
|
|
18
|
+
function forward(request, response) {
|
|
19
|
+
const current = relay;
|
|
20
|
+
const incoming = new URL(request.url ?? "/", "http://localhost");
|
|
21
|
+
if (!current || incoming.pathname !== "/auth/callback") {
|
|
22
|
+
response.writeHead(404, { "Content-Type": "text/plain; charset=utf-8" });
|
|
23
|
+
response.end("not found");
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
const target = new URL(OPENAI_CALLBACK_PATH, current.dashboardBase);
|
|
27
|
+
for (const field of ["code", "state"]) {
|
|
28
|
+
const value = incoming.searchParams.get(field);
|
|
29
|
+
if (value) target.searchParams.set(field, value);
|
|
30
|
+
}
|
|
31
|
+
response.writeHead(302, {
|
|
32
|
+
Location: target.toString(),
|
|
33
|
+
"Cache-Control": "no-store"
|
|
34
|
+
});
|
|
35
|
+
response.end();
|
|
36
|
+
}
|
|
37
|
+
function listenOn(port) {
|
|
38
|
+
return new Promise((resolve, reject) => {
|
|
39
|
+
const server = http.createServer(forward);
|
|
40
|
+
server.once("error", (error) => {
|
|
41
|
+
server.close();
|
|
42
|
+
if (error.code === "EADDRINUSE" || error.code === "EACCES") resolve(null);
|
|
43
|
+
else reject(error);
|
|
44
|
+
});
|
|
45
|
+
server.listen(port, "127.0.0.1", () => resolve(server));
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Opens a short-lived loopback listener on a registered Codex callback port and forwards the
|
|
50
|
+
* authorization code to qgrid own callback route. Returns the redirect URI to put in the authorize
|
|
51
|
+
* request. Repeated logins reuse the running listener and refresh its lifetime.
|
|
52
|
+
*/
|
|
53
|
+
async function startOpenAICallbackRelay(dashboardBase, ttlMs, ports = OPENAI_CALLBACK_PORTS) {
|
|
54
|
+
if (relay) {
|
|
55
|
+
relay.dashboardBase = dashboardBase;
|
|
56
|
+
relay.expiryTimer.refresh();
|
|
57
|
+
return relay.redirectUri;
|
|
58
|
+
}
|
|
59
|
+
for (const port of ports) {
|
|
60
|
+
const server = await listenOn(port);
|
|
61
|
+
if (!server) continue;
|
|
62
|
+
const expiryTimer = setTimeout(() => stopOpenAICallbackRelay(), ttlMs);
|
|
63
|
+
expiryTimer.unref();
|
|
64
|
+
const address = server.address();
|
|
65
|
+
const boundPort = typeof address === "object" && address ? address.port : port;
|
|
66
|
+
relay = {
|
|
67
|
+
server,
|
|
68
|
+
redirectUri: openAICallbackRedirectUri(boundPort),
|
|
69
|
+
dashboardBase,
|
|
70
|
+
expiryTimer
|
|
71
|
+
};
|
|
72
|
+
logger.info(`openai oauth callback relay listening on 127.0.0.1:${boundPort}`);
|
|
73
|
+
return relay.redirectUri;
|
|
74
|
+
}
|
|
75
|
+
throw new Error(`OPENAI_CALLBACK_PORTS_UNAVAILABLE_${ports.join("_")}`);
|
|
76
|
+
}
|
|
77
|
+
function stopOpenAICallbackRelay() {
|
|
78
|
+
if (!relay) return;
|
|
79
|
+
clearTimeout(relay.expiryTimer);
|
|
80
|
+
relay.server.close();
|
|
81
|
+
relay = null;
|
|
82
|
+
}
|
|
83
|
+
//#endregion
|
|
84
|
+
export { OPENAI_CALLBACK_PATH, OPENAI_CALLBACK_PORTS, openAICallbackRedirectUri, startOpenAICallbackRelay, stopOpenAICallbackRelay };
|
|
85
|
+
|
|
86
|
+
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoib3BlbmFpLWNhbGxiYWNrLXJlbGF5LmpzIiwibmFtZXMiOltdLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3NyYy91dGlscy9wcm92aWRlcnMvb3BlbmFpL29wZW5haS1jYWxsYmFjay1yZWxheS50cyJdLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgaHR0cCBmcm9tIFwibm9kZTpodHRwXCI7XG5cbmltcG9ydCB7IGdldExvZ2dlciB9IGZyb20gXCJAbG9ndGFwZS9sb2d0YXBlXCI7XG5cbmNvbnN0IGxvZ2dlciA9IGdldExvZ2dlcihbXCJxZ3JpZFwiLCBcIm9hdXRoXCJdKTtcblxuLyoqXG4gKiBPcGVuQUkgbWF0Y2hlcyB0aGUgQ29kZXggQ0xJIGNsaWVudCdzIHJlZGlyZWN0IFVSSXMgYnkgZXhhY3Qgc3RyaW5nLCBhbmQgb25seSB0aGVzZSB0d28gbG9vcGJhY2tcbiAqIGNhbGxiYWNrcyBhcmUgcmVnaXN0ZXJlZC4gQW55IG90aGVyIGhvc3QsIHBvcnQsIG9yIHBhdGggbWFrZXMgL29hdXRoL2F1dGhvcml6ZSBmYWlsIHdpdGhcbiAqIGBpbnZhbGlkX2F1dGhvcml6ZV9yZXF1ZXN0YCBiZWZvcmUgdGhlIGxvZ2luIHNjcmVlbiByZW5kZXJzLCBzbyBxZ3JpZCBjYW5ub3QgcG9pbnQgdGhlIGNhbGxiYWNrXG4gKiBhdCBpdHMgb3duIGNvbmZpZ3VyYWJsZSBzZXJ2ZXIgcG9ydC4gS2VlcCBpbiBzeW5jIHdpdGggdGhlIENvZGV4IENMSSBhbGxvdy1saXN0IChkZWZhdWx0IDE0NTUsXG4gKiBmYWxsYmFjayAxNDU3KS5cbiAqL1xuZXhwb3J0IGNvbnN0IE9QRU5BSV9DQUxMQkFDS19QT1JUUyA9IFsxNDU1LCAxNDU3XSBhcyBjb25zdDtcbmV4cG9ydCBjb25zdCBPUEVOQUlfQ0FMTEJBQ0tfUEFUSCA9IFwiL2F1dGgvY2FsbGJhY2tcIjtcblxuZXhwb3J0IGZ1bmN0aW9uIG9wZW5BSUNhbGxiYWNrUmVkaXJlY3RVcmkocG9ydDogbnVtYmVyKTogc3RyaW5nIHtcbiAgcmV0dXJuIGBodHRwOi8vbG9jYWxob3N0OiR7cG9ydH0ke09QRU5BSV9DQUxMQkFDS19QQVRIfWA7XG59XG5cbnR5cGUgUmVsYXkgPSB7XG4gIHNlcnZlcjogaHR0cC5TZXJ2ZXI7XG4gIHJlZGlyZWN0VXJpOiBzdHJpbmc7XG4gIGRhc2hib2FyZEJhc2U6IHN0cmluZztcbiAgZXhwaXJ5VGltZXI6IE5vZGVKUy5UaW1lb3V0O1xufTtcblxubGV0IHJlbGF5OiBSZWxheSB8IG51bGwgPSBudWxsO1xuXG5mdW5jdGlvbiBmb3J3YXJkKHJlcXVlc3Q6IGh0dHAuSW5jb21pbmdNZXNzYWdlLCByZXNwb25zZTogaHR0cC5TZXJ2ZXJSZXNwb25zZSk6IHZvaWQge1xuICBjb25zdCBjdXJyZW50ID0gcmVsYXk7XG4gIGNvbnN0IGluY29taW5nID0gbmV3IFVSTChyZXF1ZXN0LnVybCA/PyBcIi9cIiwgXCJodHRwOi8vbG9jYWxob3N0XCIpO1xuICBpZiAoIWN1cnJlbnQgfHwgaW5jb21pbmcucGF0aG5hbWUgIT09IE9QRU5BSV9DQUxMQkFDS19QQVRIKSB7XG4gICAgcmVzcG9uc2Uud3JpdGVIZWFkKDQwNCwgeyBcIkNvbnRlbnQtVHlwZVwiOiBcInRleHQvcGxhaW47IGNoYXJzZXQ9dXRmLThcIiB9KTtcbiAgICByZXNwb25zZS5lbmQoXCJub3QgZm91bmRcIik7XG4gICAgcmV0dXJuO1xuICB9XG5cbiAgLy8gT25seSB0aGUgdHdvIE9BdXRoIHJlc3VsdCBmaWVsZHMgY3Jvc3Mgb3Zlciwgb250byBhIGZpeGVkIGxvb3BiYWNrIGJhc2UuIFRoZSByZXF1ZXN0IG5ldmVyXG4gIC8vIGNvbnRyaWJ1dGVzIHNjaGVtZSwgYXV0aG9yaXR5LCBvciBwYXRoIGJ5dGVzIHRvIHRoZSByZWRpcmVjdCB0YXJnZXQuXG4gIGNvbnN0IHRhcmdldCA9IG5ldyBVUkwoT1BFTkFJX0NBTExCQUNLX1BBVEgsIGN1cnJlbnQuZGFzaGJvYXJkQmFzZSk7XG4gIGZvciAoY29uc3QgZmllbGQgb2YgW1wiY29kZVwiLCBcInN0YXRlXCJdIGFzIGNvbnN0KSB7XG4gICAgY29uc3QgdmFsdWUgPSBpbmNvbWluZy5zZWFyY2hQYXJhbXMuZ2V0KGZpZWxkKTtcbiAgICBpZiAodmFsdWUpIHRhcmdldC5zZWFyY2hQYXJhbXMuc2V0KGZpZWxkLCB2YWx1ZSk7XG4gIH1cbiAgcmVzcG9uc2Uud3JpdGVIZWFkKDMwMiwgeyBMb2NhdGlvbjogdGFyZ2V0LnRvU3RyaW5nKCksIFwiQ2FjaGUtQ29udHJvbFwiOiBcIm5vLXN0b3JlXCIgfSk7XG4gIHJlc3BvbnNlLmVuZCgpO1xufVxuXG5mdW5jdGlvbiBsaXN0ZW5Pbihwb3J0OiBudW1iZXIpOiBQcm9taXNlPGh0dHAuU2VydmVyIHwgbnVsbD4ge1xuICByZXR1cm4gbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCkgPT4ge1xuICAgIGNvbnN0IHNlcnZlciA9IGh0dHAuY3JlYXRlU2VydmVyKGZvcndhcmQpO1xuICAgIHNlcnZlci5vbmNlKFwiZXJyb3JcIiwgKGVycm9yOiBOb2RlSlMuRXJybm9FeGNlcHRpb24pID0+IHtcbiAgICAgIHNlcnZlci5jbG9zZSgpO1xuICAgICAgaWYgKGVycm9yLmNvZGUgPT09IFwiRUFERFJJTlVTRVwiIHx8IGVycm9yLmNvZGUgPT09IFwiRUFDQ0VTXCIpIHJlc29sdmUobnVsbCk7XG4gICAgICBlbHNlIHJlamVjdChlcnJvcik7XG4gICAgfSk7XG4gICAgLy8gQmluZCBsb29wYmFjayBvbmx5LCBsaWtlIHRoZSBDb2RleCBDTEk6IHRoZSByZWxheSBtdXN0IG5vdCBiZSByZWFjaGFibGUgb2ZmLWhvc3QuXG4gICAgc2VydmVyLmxpc3Rlbihwb3J0LCBcIjEyNy4wLjAuMVwiLCAoKSA9PiByZXNvbHZlKHNlcnZlcikpO1xuICB9KTtcbn1cblxuLyoqXG4gKiBPcGVucyBhIHNob3J0LWxpdmVkIGxvb3BiYWNrIGxpc3RlbmVyIG9uIGEgcmVnaXN0ZXJlZCBDb2RleCBjYWxsYmFjayBwb3J0IGFuZCBmb3J3YXJkcyB0aGVcbiAqIGF1dGhvcml6YXRpb24gY29kZSB0byBxZ3JpZCBvd24gY2FsbGJhY2sgcm91dGUuIFJldHVybnMgdGhlIHJlZGlyZWN0IFVSSSB0byBwdXQgaW4gdGhlIGF1dGhvcml6ZVxuICogcmVxdWVzdC4gUmVwZWF0ZWQgbG9naW5zIHJldXNlIHRoZSBydW5uaW5nIGxpc3RlbmVyIGFuZCByZWZyZXNoIGl0cyBsaWZldGltZS5cbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHN0YXJ0T3BlbkFJQ2FsbGJhY2tSZWxheShcbiAgZGFzaGJvYXJkQmFzZTogc3RyaW5nLFxuICB0dGxNczogbnVtYmVyLFxuICBwb3J0czogcmVhZG9ubHkgbnVtYmVyW10gPSBPUEVOQUlfQ0FMTEJBQ0tfUE9SVFMsXG4pOiBQcm9taXNlPHN0cmluZz4ge1xuICBpZiAocmVsYXkpIHtcbiAgICByZWxheS5kYXNoYm9hcmRCYXNlID0gZGFzaGJvYXJkQmFzZTtcbiAgICByZWxheS5leHBpcnlUaW1lci5yZWZyZXNoKCk7XG4gICAgcmV0dXJuIHJlbGF5LnJlZGlyZWN0VXJpO1xuICB9XG5cbiAgZm9yIChjb25zdCBwb3J0IG9mIHBvcnRzKSB7XG4gICAgY29uc3Qgc2VydmVyID0gYXdhaXQgbGlzdGVuT24ocG9ydCk7XG4gICAgaWYgKCFzZXJ2ZXIpIGNvbnRpbnVlO1xuXG4gICAgY29uc3QgZXhwaXJ5VGltZXIgPSBzZXRUaW1lb3V0KCgpID0+IHN0b3BPcGVuQUlDYWxsYmFja1JlbGF5KCksIHR0bE1zKTtcbiAgICBleHBpcnlUaW1lci51bnJlZigpO1xuICAgIGNvbnN0IGFkZHJlc3MgPSBzZXJ2ZXIuYWRkcmVzcygpO1xuICAgIGNvbnN0IGJvdW5kUG9ydCA9IHR5cGVvZiBhZGRyZXNzID09PSBcIm9iamVjdFwiICYmIGFkZHJlc3MgPyBhZGRyZXNzLnBvcnQgOiBwb3J0O1xuICAgIHJlbGF5ID0ge1xuICAgICAgc2VydmVyLFxuICAgICAgcmVkaXJlY3RVcmk6IG9wZW5BSUNhbGxiYWNrUmVkaXJlY3RVcmkoYm91bmRQb3J0KSxcbiAgICAgIGRhc2hib2FyZEJhc2UsXG4gICAgICBleHBpcnlUaW1lcixcbiAgICB9O1xuICAgIGxvZ2dlci5pbmZvKGBvcGVuYWkgb2F1dGggY2FsbGJhY2sgcmVsYXkgbGlzdGVuaW5nIG9uIDEyNy4wLjAuMToke2JvdW5kUG9ydH1gKTtcbiAgICByZXR1cm4gcmVsYXkucmVkaXJlY3RVcmk7XG4gIH1cblxuICB0aHJvdyBuZXcgRXJyb3IoYE9QRU5BSV9DQUxMQkFDS19QT1JUU19VTkFWQUlMQUJMRV8ke3BvcnRzLmpvaW4oXCJfXCIpfWApO1xufVxuXG5leHBvcnQgZnVuY3Rpb24gc3RvcE9wZW5BSUNhbGxiYWNrUmVsYXkoKTogdm9pZCB7XG4gIGlmICghcmVsYXkpIHJldHVybjtcbiAgY2xlYXJUaW1lb3V0KHJlbGF5LmV4cGlyeVRpbWVyKTtcbiAgcmVsYXkuc2VydmVyLmNsb3NlKCk7XG4gIHJlbGF5ID0gbnVsbDtcbn1cbiJdLCJtYXBwaW5ncyI6Ijs7O0FBSUEsTUFBTSxTQUFTLFVBQVUsQ0FBQyxTQUFTLE9BQU8sQ0FBQzs7Ozs7Ozs7QUFTM0MsTUFBYSx3QkFBd0IsQ0FBQyxNQUFNLElBQUk7QUFDaEQsTUFBYSx1QkFBdUI7QUFFcEMsU0FBZ0IsMEJBQTBCLE1BQXNCO0NBQzlELE9BQU8sb0JBQW9CLE9BQU87QUFDcEM7QUFTQSxJQUFJLFFBQXNCO0FBRTFCLFNBQVMsUUFBUSxTQUErQixVQUFxQztDQUNuRixNQUFNLFVBQVU7Q0FDaEIsTUFBTSxXQUFXLElBQUksSUFBSSxRQUFRLE9BQU8sS0FBSyxrQkFBa0I7Q0FDL0QsSUFBSSxDQUFDLFdBQVcsU0FBUyxhQUFBLGtCQUFtQztFQUMxRCxTQUFTLFVBQVUsS0FBSyxFQUFFLGdCQUFnQiw0QkFBNEIsQ0FBQztFQUN2RSxTQUFTLElBQUksV0FBVztFQUN4QjtDQUNGO0NBSUEsTUFBTSxTQUFTLElBQUksSUFBSSxzQkFBc0IsUUFBUSxhQUFhO0NBQ2xFLEtBQUssTUFBTSxTQUFTLENBQUMsUUFBUSxPQUFPLEdBQVk7RUFDOUMsTUFBTSxRQUFRLFNBQVMsYUFBYSxJQUFJLEtBQUs7RUFDN0MsSUFBSSxPQUFPLE9BQU8sYUFBYSxJQUFJLE9BQU8sS0FBSztDQUNqRDtDQUNBLFNBQVMsVUFBVSxLQUFLO0VBQUUsVUFBVSxPQUFPLFNBQVM7RUFBRyxpQkFBaUI7Q0FBVyxDQUFDO0NBQ3BGLFNBQVMsSUFBSTtBQUNmO0FBRUEsU0FBUyxTQUFTLE1BQTJDO0NBQzNELE9BQU8sSUFBSSxTQUFTLFNBQVMsV0FBVztFQUN0QyxNQUFNLFNBQVMsS0FBSyxhQUFhLE9BQU87RUFDeEMsT0FBTyxLQUFLLFVBQVUsVUFBaUM7R0FDckQsT0FBTyxNQUFNO0dBQ2IsSUFBSSxNQUFNLFNBQVMsZ0JBQWdCLE1BQU0sU0FBUyxVQUFVLFFBQVEsSUFBSTtRQUNuRSxPQUFPLEtBQUs7RUFDbkIsQ0FBQztFQUVELE9BQU8sT0FBTyxNQUFNLG1CQUFtQixRQUFRLE1BQU0sQ0FBQztDQUN4RCxDQUFDO0FBQ0g7Ozs7OztBQU9BLGVBQXNCLHlCQUNwQixlQUNBLE9BQ0EsUUFBMkIsdUJBQ1Y7Q0FDakIsSUFBSSxPQUFPO0VBQ1QsTUFBTSxnQkFBZ0I7RUFDdEIsTUFBTSxZQUFZLFFBQVE7RUFDMUIsT0FBTyxNQUFNO0NBQ2Y7Q0FFQSxLQUFLLE1BQU0sUUFBUSxPQUFPO0VBQ3hCLE1BQU0sU0FBUyxNQUFNLFNBQVMsSUFBSTtFQUNsQyxJQUFJLENBQUMsUUFBUTtFQUViLE1BQU0sY0FBYyxpQkFBaUIsd0JBQXdCLEdBQUcsS0FBSztFQUNyRSxZQUFZLE1BQU07RUFDbEIsTUFBTSxVQUFVLE9BQU8sUUFBUTtFQUMvQixNQUFNLFlBQVksT0FBTyxZQUFZLFlBQVksVUFBVSxRQUFRLE9BQU87RUFDMUUsUUFBUTtHQUNOO0dBQ0EsYUFBYSwwQkFBMEIsU0FBUztHQUNoRDtHQUNBO0VBQ0Y7RUFDQSxPQUFPLEtBQUssc0RBQXNELFdBQVc7RUFDN0UsT0FBTyxNQUFNO0NBQ2Y7Q0FFQSxNQUFNLElBQUksTUFBTSxxQ0FBcUMsTUFBTSxLQUFLLEdBQUcsR0FBRztBQUN4RTtBQUVBLFNBQWdCLDBCQUFnQztDQUM5QyxJQUFJLENBQUMsT0FBTztDQUNaLGFBQWEsTUFBTSxXQUFXO0NBQzlCLE1BQU0sT0FBTyxNQUFNO0NBQ25CLFFBQVE7QUFDViJ9
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { afterEach, describe, expect, it, vi } from "vitest";
|
|
2
|
+
|
|
3
|
+
import { fetchUsageWithMeta, invalidateAnthropicQuotaUsage } from "./oauth";
|
|
4
|
+
|
|
5
|
+
describe("Anthropic usage cache", () => {
|
|
6
|
+
afterEach(() => {
|
|
7
|
+
vi.unstubAllGlobals();
|
|
8
|
+
});
|
|
9
|
+
|
|
10
|
+
it("fetches usage again after the token cache is invalidated", async () => {
|
|
11
|
+
const fetchMock = vi.fn(async () =>
|
|
12
|
+
new Response(
|
|
13
|
+
JSON.stringify({ five_hour: { utilization: 10, resets_at: null } }),
|
|
14
|
+
{ status: 200, headers: { "content-type": "application/json" } },
|
|
15
|
+
),
|
|
16
|
+
);
|
|
17
|
+
vi.stubGlobal("fetch", fetchMock);
|
|
18
|
+
const accessToken = "sk-ant-oat01-cache-test-unique";
|
|
19
|
+
|
|
20
|
+
await fetchUsageWithMeta(accessToken);
|
|
21
|
+
await fetchUsageWithMeta(accessToken);
|
|
22
|
+
expect(fetchMock).toHaveBeenCalledTimes(1);
|
|
23
|
+
|
|
24
|
+
invalidateAnthropicQuotaUsage(accessToken);
|
|
25
|
+
await fetchUsageWithMeta(accessToken);
|
|
26
|
+
expect(fetchMock).toHaveBeenCalledTimes(2);
|
|
27
|
+
});
|
|
28
|
+
});
|
|
@@ -9,6 +9,7 @@ export type AnthropicUsageRaw = {
|
|
|
9
9
|
error?: string;
|
|
10
10
|
five_hour?: { utilization: number | null; resets_at: string | null } | null;
|
|
11
11
|
seven_day?: { utilization: number | null; resets_at: string | null } | null;
|
|
12
|
+
seven_day_overage_included?: { utilization: number | null; resets_at: string | null } | null;
|
|
12
13
|
};
|
|
13
14
|
export type AnthropicUsageWithMeta = {
|
|
14
15
|
data: AnthropicUsageRaw;
|
|
@@ -169,6 +170,10 @@ export async function refreshAccessToken(refreshToken: string): Promise<OAuthTok
|
|
|
169
170
|
const usageCache: Record<string, AnthropicUsageWithMeta> = {};
|
|
170
171
|
const USAGE_API_CACHE_TTL = 60_000; // 1분
|
|
171
172
|
|
|
173
|
+
export function invalidateAnthropicQuotaUsage(accessToken: string): void {
|
|
174
|
+
delete usageCache[accessToken.slice(-10)];
|
|
175
|
+
}
|
|
176
|
+
|
|
172
177
|
export async function fetchUsage(accessToken: string): Promise<AnthropicUsageRaw> {
|
|
173
178
|
return (await fetchUsageWithMeta(accessToken)).data;
|
|
174
179
|
}
|
|
@@ -4,10 +4,18 @@ import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
|
|
|
4
4
|
import { CONSOLE_CALLBACK_URL } from "./oauth";
|
|
5
5
|
import { QgridFrame } from "./qgrid.frame";
|
|
6
6
|
|
|
7
|
-
const {
|
|
8
|
-
|
|
7
|
+
const {
|
|
8
|
+
exchangeMock,
|
|
9
|
+
openAIExchangeMock,
|
|
10
|
+
relayStartMock,
|
|
11
|
+
tokenSaveMock,
|
|
12
|
+
tokenDelMock,
|
|
13
|
+
findByAccountMock,
|
|
14
|
+
notifyMock,
|
|
15
|
+
} = vi.hoisted(() => ({
|
|
9
16
|
exchangeMock: vi.fn(),
|
|
10
17
|
openAIExchangeMock: vi.fn(),
|
|
18
|
+
relayStartMock: vi.fn(async () => "http://localhost:1455/auth/callback"),
|
|
11
19
|
tokenSaveMock: vi.fn(async () => [1]),
|
|
12
20
|
tokenDelMock: vi.fn(async () => 1),
|
|
13
21
|
findByAccountMock: vi.fn(async () => []),
|
|
@@ -40,6 +48,12 @@ vi.mock("../../utils/providers/openai/openai-oauth", async (importOriginal) => (
|
|
|
40
48
|
exchangeOpenAICode: openAIExchangeMock,
|
|
41
49
|
}));
|
|
42
50
|
|
|
51
|
+
// The relay binds a real loopback port; these tests only assert which redirect URI is signed in.
|
|
52
|
+
vi.mock("../../utils/providers/openai/openai-callback-relay", async (importOriginal) => ({
|
|
53
|
+
...(await importOriginal<typeof import("../../utils/providers/openai/openai-callback-relay")>()),
|
|
54
|
+
startOpenAICallbackRelay: relayStartMock,
|
|
55
|
+
}));
|
|
56
|
+
|
|
43
57
|
vi.mock("../token/token.model", () => ({
|
|
44
58
|
TokenModel: {
|
|
45
59
|
save: tokenSaveMock,
|
|
@@ -193,22 +207,36 @@ describe("QgridFrame direct OpenAI OAuth", () => {
|
|
|
193
207
|
tokenDelMock.mockClear();
|
|
194
208
|
findByAccountMock.mockClear().mockResolvedValue([]);
|
|
195
209
|
notifyMock.mockClear();
|
|
210
|
+
relayStartMock.mockClear();
|
|
196
211
|
});
|
|
197
212
|
|
|
198
|
-
it("uses
|
|
213
|
+
it("uses manual code completion without opening a server relay on remote origins", async () => {
|
|
199
214
|
mockHttpContext({ origin: "https://qgrid.example.com" });
|
|
200
215
|
|
|
201
216
|
const result = await QgridFrame.oauthStartOpenAI("openai-token");
|
|
202
217
|
const url = new URL(result.authUrl);
|
|
203
|
-
expect(result.mode).toBe("
|
|
218
|
+
expect(result.mode).toBe("code");
|
|
204
219
|
expect(url.origin + url.pathname).toBe("https://auth.openai.com/oauth/authorize");
|
|
205
|
-
expect(url.searchParams.get("redirect_uri")).toBe("http://localhost:
|
|
220
|
+
expect(url.searchParams.get("redirect_uri")).toBe("http://localhost:1455/auth/callback");
|
|
206
221
|
expect(url.searchParams.get("state")).toBeTruthy();
|
|
207
222
|
expect(url.searchParams.get("code_challenge_method")).toBe("S256");
|
|
223
|
+
expect(relayStartMock).not.toHaveBeenCalled();
|
|
224
|
+
});
|
|
225
|
+
|
|
226
|
+
it("keeps the automatic callback relay for loopback origins", async () => {
|
|
227
|
+
mockHttpContext({ origin: "http://localhost:44900" });
|
|
228
|
+
|
|
229
|
+
const result = await QgridFrame.oauthStartOpenAI("openai-token");
|
|
230
|
+
|
|
231
|
+
expect(result.mode).toBe("redirect");
|
|
232
|
+
expect(authUrlParam(result.authUrl, "redirect_uri")).toBe(
|
|
233
|
+
"http://localhost:1455/auth/callback",
|
|
234
|
+
);
|
|
235
|
+
expect(relayStartMock).toHaveBeenCalledWith("http://localhost:44900", 5 * 60_000);
|
|
208
236
|
});
|
|
209
237
|
|
|
210
238
|
it("exchanges an OpenAI callback, replaces the duplicate account, and notifies", async () => {
|
|
211
|
-
mockHttpContext({ origin: "
|
|
239
|
+
mockHttpContext({ origin: "http://localhost:44900" });
|
|
212
240
|
const { authUrl } = await QgridFrame.oauthStartOpenAI("openai-token");
|
|
213
241
|
const state = authUrlParam(authUrl, "state")!;
|
|
214
242
|
findByAccountMock.mockResolvedValueOnce([{ id: 9, active: true }] as never);
|
|
@@ -228,7 +256,7 @@ describe("QgridFrame direct OpenAI OAuth", () => {
|
|
|
228
256
|
expect(openAIExchangeMock).toHaveBeenCalledWith(
|
|
229
257
|
"the-code",
|
|
230
258
|
expect.any(String),
|
|
231
|
-
"http://localhost:
|
|
259
|
+
"http://localhost:1455/auth/callback",
|
|
232
260
|
);
|
|
233
261
|
expect(tokenDelMock).toHaveBeenCalledOnce();
|
|
234
262
|
expect(tokenSaveMock).toHaveBeenCalledWith([
|
|
@@ -242,8 +270,43 @@ describe("QgridFrame direct OpenAI OAuth", () => {
|
|
|
242
270
|
expect(reply.redirect).toHaveBeenCalledWith("/?oauth=success&name=openai-token");
|
|
243
271
|
});
|
|
244
272
|
|
|
245
|
-
it("
|
|
273
|
+
it("exchanges a pasted OpenAI callback URL for remote login", async () => {
|
|
246
274
|
mockHttpContext({ origin: "https://qgrid.example.com" });
|
|
275
|
+
const { authUrl } = await QgridFrame.oauthStartOpenAI("remote-openai-token");
|
|
276
|
+
const state = authUrlParam(authUrl, "state")!;
|
|
277
|
+
openAIExchangeMock.mockResolvedValueOnce({
|
|
278
|
+
accessToken: "access",
|
|
279
|
+
refreshToken: "refresh",
|
|
280
|
+
idToken: "id",
|
|
281
|
+
accessTokenExpiresAt: 123,
|
|
282
|
+
idTokenExpiresAt: 456,
|
|
283
|
+
accountId: "account-1",
|
|
284
|
+
planType: "pro",
|
|
285
|
+
});
|
|
286
|
+
|
|
287
|
+
await expect(
|
|
288
|
+
QgridFrame.oauthComplete(
|
|
289
|
+
`http://localhost:1455/auth/callback?code=the-code&state=${state}`,
|
|
290
|
+
),
|
|
291
|
+
).resolves.toEqual({ added: true, name: "remote-openai-token" });
|
|
292
|
+
|
|
293
|
+
expect(openAIExchangeMock).toHaveBeenCalledWith(
|
|
294
|
+
"the-code",
|
|
295
|
+
expect.any(String),
|
|
296
|
+
"http://localhost:1455/auth/callback",
|
|
297
|
+
);
|
|
298
|
+
expect(tokenSaveMock).toHaveBeenCalledWith([
|
|
299
|
+
expect.objectContaining({
|
|
300
|
+
provider: "openai",
|
|
301
|
+
name: "remote-openai-token",
|
|
302
|
+
credentials: expect.objectContaining({ accountId: "account-1" }),
|
|
303
|
+
}),
|
|
304
|
+
]);
|
|
305
|
+
expect(notifyMock).toHaveBeenCalledWith("remote-openai-token", "openai");
|
|
306
|
+
});
|
|
307
|
+
|
|
308
|
+
it("consumes OpenAI state before a failed exchange", async () => {
|
|
309
|
+
mockHttpContext({ origin: "http://localhost:44900" });
|
|
247
310
|
const { authUrl } = await QgridFrame.oauthStartOpenAI("openai-token");
|
|
248
311
|
const state = authUrlParam(authUrl, "state")!;
|
|
249
312
|
openAIExchangeMock.mockRejectedValueOnce(new Error("exchange rejected"));
|
|
@@ -14,6 +14,7 @@ const {
|
|
|
14
14
|
updateFieldsMock,
|
|
15
15
|
requestLogSaveMock,
|
|
16
16
|
requestLogCreateRunMock,
|
|
17
|
+
requestLogFinishRunMock,
|
|
17
18
|
appendStepMock,
|
|
18
19
|
dispatcherQueryMock,
|
|
19
20
|
dispatcherQueryStreamMock,
|
|
@@ -36,6 +37,7 @@ const {
|
|
|
36
37
|
updateFieldsMock: vi.fn(),
|
|
37
38
|
requestLogSaveMock: vi.fn(),
|
|
38
39
|
requestLogCreateRunMock: vi.fn(),
|
|
40
|
+
requestLogFinishRunMock: vi.fn(),
|
|
39
41
|
appendStepMock: vi.fn(),
|
|
40
42
|
dispatcherQueryMock: vi.fn(),
|
|
41
43
|
dispatcherQueryStreamMock: vi.fn(),
|
|
@@ -53,6 +55,7 @@ vi.mock("../request-log/request-log.model", () => ({
|
|
|
53
55
|
RequestLogModel: {
|
|
54
56
|
save: requestLogSaveMock,
|
|
55
57
|
createRun: requestLogCreateRunMock,
|
|
58
|
+
finishRun: requestLogFinishRunMock,
|
|
56
59
|
appendStep: appendStepMock,
|
|
57
60
|
},
|
|
58
61
|
}));
|
|
@@ -890,6 +893,46 @@ describe("QgridFrame raw lifecycle API", () => {
|
|
|
890
893
|
expect.not.objectContaining({ model_name: expect.anything() }),
|
|
891
894
|
);
|
|
892
895
|
});
|
|
896
|
+
|
|
897
|
+
it("passes optional structured metadata through the external createRun API", async () => {
|
|
898
|
+
requestLogCreateRunMock.mockReset().mockResolvedValue(82);
|
|
899
|
+
const jsonSchema = JSON.stringify({
|
|
900
|
+
type: "object",
|
|
901
|
+
properties: { answer: { type: "string" } },
|
|
902
|
+
required: ["answer"],
|
|
903
|
+
});
|
|
904
|
+
|
|
905
|
+
await QgridFrame.createRun({
|
|
906
|
+
userPrompt: "hi",
|
|
907
|
+
modelName: "google/gemini-3.5-flash-lite",
|
|
908
|
+
isStructured: true,
|
|
909
|
+
jsonSchema,
|
|
910
|
+
});
|
|
911
|
+
|
|
912
|
+
expect(requestLogCreateRunMock).toHaveBeenCalledWith(
|
|
913
|
+
expect.objectContaining({
|
|
914
|
+
is_structured: true,
|
|
915
|
+
json_schema: jsonSchema,
|
|
916
|
+
}),
|
|
917
|
+
);
|
|
918
|
+
});
|
|
919
|
+
|
|
920
|
+
it("passes optional response JSON validity through the external finishRun API", async () => {
|
|
921
|
+
requestLogFinishRunMock.mockReset().mockResolvedValue(undefined);
|
|
922
|
+
|
|
923
|
+
await QgridFrame.finishRun({
|
|
924
|
+
requestLogId: 82,
|
|
925
|
+
status: "succeeded",
|
|
926
|
+
response: '{"answer":"ok"}',
|
|
927
|
+
tokenName: "external",
|
|
928
|
+
responseJsonOk: true,
|
|
929
|
+
});
|
|
930
|
+
|
|
931
|
+
expect(requestLogFinishRunMock).toHaveBeenCalledWith(
|
|
932
|
+
82,
|
|
933
|
+
expect.objectContaining({ response_json_ok: true }),
|
|
934
|
+
);
|
|
935
|
+
});
|
|
893
936
|
});
|
|
894
937
|
|
|
895
938
|
describe("QgridFrame.queryStream request logging", () => {
|