@cartanova/qgrid-cli 2.10.9 → 2.11.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/_virtual/_rolldown/runtime.js +1 -10
- package/bundle/dist/application/monit/log-buffer.js +12 -6
- package/bundle/dist/application/monit/monit.frame.js +11 -3
- package/bundle/dist/application/monit/monit.types.js +1 -1
- package/bundle/dist/application/qgrid/conv-routing.js +9 -6
- package/bundle/dist/application/qgrid/expired-token-reminder.js +2 -2
- package/bundle/dist/application/qgrid/oauth.js +31 -4
- package/bundle/dist/application/qgrid/qgrid-image-generation.js +1 -1
- package/bundle/dist/application/qgrid/qgrid-response-format.js +22 -20
- package/bundle/dist/application/qgrid/qgrid-run-lifecycle.js +43 -34
- package/bundle/dist/application/qgrid/qgrid.dispatcher.js +128 -93
- package/bundle/dist/application/qgrid/qgrid.frame.js +930 -49
- package/bundle/dist/application/qgrid/qgrid.types.js +212 -5
- package/bundle/dist/application/qgrid/schema-prompt.js +75 -48
- package/bundle/dist/application/qgrid/slack-user-map.js +1 -1
- package/bundle/dist/application/qgrid/token-death.js +1 -1
- package/bundle/dist/application/qgrid/token-subscriber.js +83 -30
- package/bundle/dist/application/qgrid/token-trigger-setup.js +1 -1
- package/bundle/dist/application/qgrid/token-window-keepalive.js +8 -6
- package/bundle/dist/application/qgrid/tool-emulation-schema.js +13 -13
- package/bundle/dist/application/qgrid/tool-emulation.js +19 -15
- package/bundle/dist/application/request-log/json-schema-type-text.js +29 -12
- package/bundle/dist/application/request-log/request-log.model.js +83 -69
- package/bundle/dist/application/request-log/request-log.types.js +8 -2
- package/bundle/dist/application/request-log/zod-code-format.js +1 -1
- package/bundle/dist/application/request-log-step/request-log-step.model.js +1 -1
- package/bundle/dist/application/request-log-step/request-log-step.types.js +1 -1
- package/bundle/dist/application/setting/setting.constant.js +1 -1
- package/bundle/dist/application/setting/setting.model.js +2 -2
- package/bundle/dist/application/setting/setting.store.js +2 -2
- package/bundle/dist/application/setting/setting.types.js +1 -1
- package/bundle/dist/application/sonamu.generated.js +40 -16
- package/bundle/dist/application/sonamu.generated.sso.js +2 -1
- package/bundle/dist/application/token/token.model.js +26 -9
- package/bundle/dist/application/token/token.types.js +20 -3
- package/bundle/dist/i18n/en.js +15 -1
- package/bundle/dist/i18n/ko.js +15 -1
- package/bundle/dist/i18n/sd.generated.js +2 -1
- package/bundle/dist/migrations/20260807133553_manual__backfill_request_log_cost.js +8 -6
- package/bundle/dist/migrations/20261018215031_alter_request_logs_add1_alter1.js +15 -0
- package/bundle/dist/server-bootstrap.js +4 -2
- package/bundle/dist/server-error-handler.js +1 -1
- package/bundle/dist/sonamu.config.js +37 -8
- package/bundle/dist/startup-migrations.js +17 -7
- package/bundle/dist/testing/global.js +1 -1
- package/bundle/dist/testing/schema-bench.js +0 -0
- package/bundle/dist/testing/test-database-name.js +1 -1
- package/bundle/dist/utils/providers/anthropic/anthropic-constants.js +1 -1
- package/bundle/dist/utils/providers/anthropic/anthropic-dispatcher.js +11 -5
- package/bundle/dist/utils/providers/anthropic/anthropic-quota.js +4 -4
- package/bundle/dist/utils/providers/anthropic/anthropic-thinking.js +1 -1
- package/bundle/dist/utils/providers/anthropic/claude-session.js +20 -19
- package/bundle/dist/utils/providers/anthropic/fence-strip.js +1 -1
- package/bundle/dist/utils/providers/anthropic/stream-json-adapter.js +49 -23
- package/bundle/dist/utils/providers/common/credentials.js +5 -1
- package/bundle/dist/utils/providers/common/effort.js +3 -3
- package/bundle/dist/utils/providers/common/model-cost.js +69 -14
- package/bundle/dist/utils/providers/common/provider-types.js +29 -1
- package/bundle/dist/utils/providers/common/schema-validation.js +78 -40
- package/bundle/dist/utils/providers/common/smooth-weighted-round-robin.js +1 -1
- package/bundle/dist/utils/providers/common/strictifier.js +62 -43
- package/bundle/dist/utils/providers/common/thinking.js +3 -2
- package/bundle/dist/utils/providers/common/ttft.js +1 -1
- package/bundle/dist/utils/providers/grok/grok-backend-protocol.js +427 -0
- package/bundle/dist/utils/providers/grok/grok-constants.js +55 -0
- package/bundle/dist/utils/providers/grok/grok-direct-client.js +196 -0
- package/bundle/dist/utils/providers/grok/grok-dispatcher.js +1313 -0
- package/bundle/dist/utils/providers/grok/grok-headers.js +118 -0
- package/bundle/dist/utils/providers/grok/grok-media-client.js +420 -0
- package/bundle/dist/utils/providers/grok/grok-models.js +114 -0
- package/bundle/dist/utils/providers/grok/grok-oauth.js +455 -0
- package/bundle/dist/utils/providers/grok/grok-quota.js +119 -0
- package/bundle/dist/utils/providers/grok/grok-refresh.js +192 -0
- package/bundle/dist/utils/providers/grok/grok-types.js +186 -0
- package/bundle/dist/utils/providers/grok/grok-voice-client.js +199 -0
- package/bundle/dist/utils/providers/grok/index.js +11 -0
- package/bundle/dist/utils/providers/openai/openai-backend-protocol.js +111 -83
- package/bundle/dist/utils/providers/openai/openai-callback-relay.js +3 -2
- package/bundle/dist/utils/providers/openai/openai-constants.js +1 -1
- package/bundle/dist/utils/providers/openai/openai-direct-client.js +23 -7
- package/bundle/dist/utils/providers/openai/openai-dispatcher.js +143 -106
- package/bundle/dist/utils/providers/openai/openai-image-generation.js +48 -33
- package/bundle/dist/utils/providers/openai/openai-oauth.js +28 -13
- package/bundle/dist/utils/providers/openai/openai-quota.js +38 -27
- package/bundle/dist/utils/providers/openai/openai-refresh.js +17 -9
- package/bundle/dist/utils/providers/openai/openai-sse.js +1 -1
- package/bundle/dist/utils/providers/openai/openai-transport-config.js +1 -1
- package/bundle/dist/utils/quiet-hours.js +1 -1
- package/bundle/dist/utils/slack-notify.js +14 -8
- package/bundle/dist/utils/subset-loaders.js +4 -5
- package/bundle/src/application/monit/log-buffer.ts +23 -9
- package/bundle/src/application/monit/monit.frame.ts +22 -5
- package/bundle/src/application/monit/monit.types.ts +6 -0
- package/bundle/src/application/qgrid/conv-routing.test.ts +76 -4
- package/bundle/src/application/qgrid/conv-routing.ts +35 -9
- package/bundle/src/application/qgrid/expired-token-reminder.ts +9 -1
- package/bundle/src/application/qgrid/oauth.ts +51 -15
- package/bundle/src/application/qgrid/qgrid-image-generation.ts +9 -0
- package/bundle/src/application/qgrid/qgrid-response-format.ts +50 -25
- package/bundle/src/application/qgrid/qgrid-run-lifecycle.test.ts +33 -0
- package/bundle/src/application/qgrid/qgrid-run-lifecycle.ts +87 -40
- package/bundle/src/application/qgrid/qgrid.dispatcher.test.ts +97 -0
- package/bundle/src/application/qgrid/qgrid.dispatcher.ts +274 -126
- package/bundle/src/application/qgrid/qgrid.frame.test.ts +1013 -3
- package/bundle/src/application/qgrid/qgrid.frame.ts +1415 -60
- package/bundle/src/application/qgrid/qgrid.types.ts +335 -0
- package/bundle/src/application/qgrid/schema-prompt.ts +105 -41
- package/bundle/src/application/qgrid/slack-user-map.ts +5 -0
- package/bundle/src/application/qgrid/token-death.ts +4 -0
- package/bundle/src/application/qgrid/token-subscriber.test.ts +21 -19
- package/bundle/src/application/qgrid/token-subscriber.ts +186 -53
- package/bundle/src/application/qgrid/token-trigger-setup.ts +2 -0
- package/bundle/src/application/qgrid/token-window-keepalive.ts +49 -6
- package/bundle/src/application/qgrid/tool-emulation-schema.ts +33 -29
- package/bundle/src/application/qgrid/tool-emulation.ts +52 -27
- package/bundle/src/application/request-log/json-schema-type-text.test.ts +5 -5
- package/bundle/src/application/request-log/json-schema-type-text.ts +81 -26
- package/bundle/src/application/request-log/request-log.entity.json +8 -0
- package/bundle/src/application/request-log/request-log.model.test.ts +111 -4
- package/bundle/src/application/request-log/request-log.model.ts +279 -145
- package/bundle/src/application/request-log/request-log.types.ts +17 -0
- package/bundle/src/application/request-log/zod-code-format.ts +11 -0
- package/bundle/src/application/request-log-step/request-log-step.model.ts +1 -0
- package/bundle/src/application/request-log-step/request-log-step.types.ts +2 -0
- package/bundle/src/application/setting/setting.constant.ts +9 -0
- package/bundle/src/application/setting/setting.model.ts +12 -2
- package/bundle/src/application/setting/setting.store.ts +5 -1
- package/bundle/src/application/setting/setting.types.ts +8 -0
- package/bundle/src/application/sonamu.generated.http +135 -0
- package/bundle/src/application/sonamu.generated.sso.ts +3 -0
- package/bundle/src/application/sonamu.generated.ts +29 -0
- package/bundle/src/application/token/token.identity.test.ts +20 -0
- package/bundle/src/application/token/token.model.ts +66 -7
- package/bundle/src/application/token/token.types.ts +24 -1
- package/bundle/src/i18n/en.ts +19 -0
- package/bundle/src/i18n/ko.ts +21 -0
- package/bundle/src/i18n/sd.generated.ts +24 -2
- package/bundle/src/migrations/20260807133553_manual__backfill_request_log_cost.ts +16 -8
- package/bundle/src/migrations/20261018215031_alter_request_logs_add1_alter1.ts +15 -0
- package/bundle/src/server-bootstrap.ts +4 -2
- package/bundle/src/server-error-handler.ts +1 -0
- package/bundle/src/sonamu.config.ts +69 -7
- package/bundle/src/startup-migrations.ts +27 -9
- package/bundle/src/testing/global.ts +20 -0
- package/bundle/src/testing/schema-bench.ts +105 -30
- package/bundle/src/testing/test-database-name.ts +2 -0
- package/bundle/src/utils/providers/anthropic/anthropic-constants.ts +8 -0
- package/bundle/src/utils/providers/anthropic/anthropic-dispatcher.ts +41 -6
- package/bundle/src/utils/providers/anthropic/anthropic-quota.ts +7 -3
- package/bundle/src/utils/providers/anthropic/anthropic-thinking.ts +6 -0
- package/bundle/src/utils/providers/anthropic/claude-session.ts +58 -24
- package/bundle/src/utils/providers/anthropic/fence-strip.ts +11 -0
- package/bundle/src/utils/providers/anthropic/stream-json-adapter.ts +110 -45
- package/bundle/src/utils/providers/common/credentials.ts +8 -0
- package/bundle/src/utils/providers/common/effort.ts +9 -2
- package/bundle/src/utils/providers/common/model-cost.test.ts +48 -1
- package/bundle/src/utils/providers/common/model-cost.ts +259 -158
- package/bundle/src/utils/providers/common/provider-dispatcher.ts +98 -2
- package/bundle/src/utils/providers/common/provider-types.ts +46 -3
- package/bundle/src/utils/providers/common/schema-validation.test.ts +5 -1
- package/bundle/src/utils/providers/common/schema-validation.ts +124 -56
- package/bundle/src/utils/providers/common/smooth-weighted-round-robin.ts +4 -0
- package/bundle/src/utils/providers/common/strictifier.ts +185 -59
- package/bundle/src/utils/providers/common/thinking.ts +2 -2
- package/bundle/src/utils/providers/common/ttft.ts +4 -2
- package/bundle/src/utils/providers/grok/__fixtures__/golden-responses-1.0.60.json +164 -0
- package/bundle/src/utils/providers/grok/grok-backend-protocol.test.ts +325 -0
- package/bundle/src/utils/providers/grok/grok-backend-protocol.ts +721 -0
- package/bundle/src/utils/providers/grok/grok-constants.ts +105 -0
- package/bundle/src/utils/providers/grok/grok-direct-client.test.ts +179 -0
- package/bundle/src/utils/providers/grok/grok-direct-client.ts +313 -0
- package/bundle/src/utils/providers/grok/grok-dispatcher.test.ts +1395 -0
- package/bundle/src/utils/providers/grok/grok-dispatcher.ts +2105 -0
- package/bundle/src/utils/providers/grok/grok-headers.test.ts +149 -0
- package/bundle/src/utils/providers/grok/grok-headers.ts +199 -0
- package/bundle/src/utils/providers/grok/grok-media-client.test.ts +446 -0
- package/bundle/src/utils/providers/grok/grok-media-client.ts +703 -0
- package/bundle/src/utils/providers/grok/grok-models.test.ts +96 -0
- package/bundle/src/utils/providers/grok/grok-models.ts +161 -0
- package/bundle/src/utils/providers/grok/grok-oauth.test.ts +406 -0
- package/bundle/src/utils/providers/grok/grok-oauth.ts +771 -0
- package/bundle/src/utils/providers/grok/grok-quota.test.ts +142 -0
- package/bundle/src/utils/providers/grok/grok-quota.ts +198 -0
- package/bundle/src/utils/providers/grok/grok-refresh.test.ts +239 -0
- package/bundle/src/utils/providers/grok/grok-refresh.ts +325 -0
- package/bundle/src/utils/providers/grok/grok-types.test.ts +252 -0
- package/bundle/src/utils/providers/grok/grok-types.ts +374 -0
- package/bundle/src/utils/providers/grok/grok-voice-client.test.ts +321 -0
- package/bundle/src/utils/providers/grok/grok-voice-client.ts +284 -0
- package/bundle/src/utils/providers/grok/index.ts +20 -0
- package/bundle/src/utils/providers/openai/openai-backend-protocol.ts +221 -137
- package/bundle/src/utils/providers/openai/openai-callback-relay.ts +12 -1
- package/bundle/src/utils/providers/openai/openai-constants.ts +2 -0
- package/bundle/src/utils/providers/openai/openai-direct-client.ts +111 -21
- package/bundle/src/utils/providers/openai/openai-dispatcher.ts +322 -169
- package/bundle/src/utils/providers/openai/openai-image-generation.ts +116 -36
- package/bundle/src/utils/providers/openai/openai-oauth.ts +48 -20
- package/bundle/src/utils/providers/openai/openai-quota.ts +77 -46
- package/bundle/src/utils/providers/openai/openai-refresh.ts +42 -18
- package/bundle/src/utils/providers/openai/openai-sse.ts +27 -3
- package/bundle/src/utils/providers/openai/openai-transport-config.ts +2 -0
- package/bundle/src/utils/quiet-hours.ts +12 -1
- package/bundle/src/utils/slack-notify.ts +44 -13
- package/bundle/src/utils/subset-loaders.ts +7 -7
- package/bundle/web-dist/client/assets/clsx-5XM_pHvN.js +1 -0
- package/bundle/web-dist/client/assets/index-BA7uQ-6c.js +31 -0
- package/bundle/web-dist/client/assets/index-Be2qCZmI.css +1 -0
- package/bundle/web-dist/client/assets/logs-C47OJGEI.js +1 -0
- package/bundle/web-dist/client/assets/monit-BS9no0dU.js +4 -0
- package/bundle/web-dist/client/assets/plus-sdACTfH0.js +1 -0
- package/bundle/web-dist/client/assets/refresh-cw-CY8o_1cT.js +1 -0
- package/bundle/web-dist/client/assets/request-model-BRtFuZvj.js +1 -0
- package/bundle/web-dist/client/assets/routes-kqgkUxE8.js +5 -0
- package/bundle/web-dist/client/assets/{services.generated-BsieU37H.js → services.generated-CefiDXEv.js} +5 -5
- package/bundle/web-dist/client/assets/settings-DNDvFGSw.js +1 -0
- package/bundle/web-dist/client/assets/show-u8Np69q3.js +2 -0
- package/bundle/web-dist/client/assets/tokens-QvP410NW.js +1 -0
- package/bundle/web-dist/client/assets/total-cost-MnfKU8IN.js +1 -0
- package/bundle/web-dist/client/assets/use-oauth-login-flow-Bzdh28Ws.js +1 -0
- package/bundle/web-dist/client/assets/use-update-token-mutation-CfJKaxmR.js +1 -0
- package/bundle/web-dist/client/assets/vendor-react-CUFFrVN9.js +244 -0
- package/bundle/web-dist/client/assets/vendor-tanstack-Bf_jag9G.js +1 -0
- package/bundle/web-dist/client/index.html +6 -6
- package/bundle/web-dist/server/assets/clsx-D_N5PN_2.js +16 -0
- package/bundle/web-dist/server/assets/{lazyRouteComponent-Dtd0NR4r.js → lazyRouteComponent-D8iTIHyn.js} +129 -2
- package/bundle/web-dist/server/assets/logs-B3OTd9hy.js +825 -0
- package/bundle/web-dist/server/assets/{monit-DvzribSE.js → monit-B2hqorPe.js} +385 -126
- package/bundle/web-dist/server/assets/plus-DwG7h9kq.js +28 -0
- package/bundle/web-dist/server/assets/{react-dom-B4a6-uuR.js → react-dom-BIYQzBqG.js} +2 -129
- package/bundle/web-dist/server/assets/refresh-cw-mMBkwOq0.js +44 -0
- package/bundle/web-dist/server/assets/{request-model-CbqfnQOJ.js → request-model-I6OdODSH.js} +15 -6
- package/bundle/web-dist/server/assets/{routes-BAPWTizT.js → routes-B95YlUv2.js} +760 -213
- package/bundle/web-dist/server/assets/{services.generated-CEbGjsI0.js → services.generated-DQATJ6qf.js} +12821 -12194
- package/bundle/web-dist/server/assets/settings-C3gbGk0m.js +830 -0
- package/bundle/web-dist/server/assets/{show-CxVZTAdv.js → show-Bxaj3rhH.js} +1355 -419
- package/bundle/web-dist/server/assets/tokens-CZjH3cB7.js +1038 -0
- package/bundle/web-dist/server/assets/total-cost-fTE9Xy82.js +18 -0
- package/bundle/web-dist/server/assets/use-oauth-login-flow-CKDHgc3U.js +2379 -0
- package/bundle/web-dist/server/assets/{use-update-token-mutation-CfYmk_4_.js → use-update-token-mutation-BEbgOzaa.js} +1 -1
- package/bundle/web-dist/server/entry-server.generated.js +4303 -22810
- package/dist/cli.js +9 -9
- package/package.json +4 -11
- package/postinstall.mjs +12 -0
- package/skills/qgrid/SKILL.md +1 -0
- package/skills/qgrid/references/cli-env-and-server-boot.md +4 -1
- package/skills/qgrid/references/decision-rationale.md +24 -1
- package/skills/qgrid/references/grok-runtime.md +89 -0
- package/skills/qgrid/references/provider-runtime-differences.md +30 -29
- package/skills/qgrid/references/repo-map.md +10 -0
- package/skills/qgrid/references/request-log-run-lifecycle.md +1 -1
- package/skills/qgrid/references/sonamu-api-web-flow.md +1 -1
- package/skills/qgrid/references/token-auth-quota-lifecycle.md +56 -3
- package/bundle/dist/node_modules/.pnpm/@jridgewell_sourcemap-codec@1.5.5/node_modules/@jridgewell/sourcemap-codec/dist/sourcemap-codec.js +0 -406
- package/bundle/dist/node_modules/.pnpm/@vitest_expect@4.1.10/node_modules/@vitest/expect/dist/index.js +0 -1507
- package/bundle/dist/node_modules/.pnpm/@vitest_pretty-format@4.1.10/node_modules/@vitest/pretty-format/dist/index.js +0 -887
- package/bundle/dist/node_modules/.pnpm/@vitest_runner@4.1.10/node_modules/@vitest/runner/dist/chunk-artifact.js +0 -2756
- package/bundle/dist/node_modules/.pnpm/@vitest_runner@4.1.10/node_modules/@vitest/runner/dist/index.js +0 -8
- package/bundle/dist/node_modules/.pnpm/@vitest_runner@4.1.10/node_modules/@vitest/runner/dist/utils.js +0 -8
- package/bundle/dist/node_modules/.pnpm/@vitest_snapshot@4.1.10/node_modules/@vitest/snapshot/dist/index.js +0 -922
- package/bundle/dist/node_modules/.pnpm/@vitest_spy@4.1.10/node_modules/@vitest/spy/dist/index.js +0 -386
- package/bundle/dist/node_modules/.pnpm/@vitest_utils@4.1.10/node_modules/@vitest/utils/dist/chunk-pathe.M-eThtNZ.js +0 -121
- package/bundle/dist/node_modules/.pnpm/@vitest_utils@4.1.10/node_modules/@vitest/utils/dist/constants.js +0 -51
- package/bundle/dist/node_modules/.pnpm/@vitest_utils@4.1.10/node_modules/@vitest/utils/dist/diff.js +0 -1317
- package/bundle/dist/node_modules/.pnpm/@vitest_utils@4.1.10/node_modules/@vitest/utils/dist/display.js +0 -561
- package/bundle/dist/node_modules/.pnpm/@vitest_utils@4.1.10/node_modules/@vitest/utils/dist/error.js +0 -40
- package/bundle/dist/node_modules/.pnpm/@vitest_utils@4.1.10/node_modules/@vitest/utils/dist/helpers.js +0 -272
- package/bundle/dist/node_modules/.pnpm/@vitest_utils@4.1.10/node_modules/@vitest/utils/dist/offset.js +0 -27
- package/bundle/dist/node_modules/.pnpm/@vitest_utils@4.1.10/node_modules/@vitest/utils/dist/serialize.js +0 -77
- package/bundle/dist/node_modules/.pnpm/@vitest_utils@4.1.10/node_modules/@vitest/utils/dist/source-map.js +0 -381
- package/bundle/dist/node_modules/.pnpm/@vitest_utils@4.1.10/node_modules/@vitest/utils/dist/timers.js +0 -51
- package/bundle/dist/node_modules/.pnpm/chai@6.2.2/node_modules/chai/index.js +0 -2986
- package/bundle/dist/node_modules/.pnpm/expect-type@1.3.0/node_modules/expect-type/dist/branding.js +0 -10
- package/bundle/dist/node_modules/.pnpm/expect-type@1.3.0/node_modules/expect-type/dist/index.js +0 -109
- package/bundle/dist/node_modules/.pnpm/expect-type@1.3.0/node_modules/expect-type/dist/messages.js +0 -10
- package/bundle/dist/node_modules/.pnpm/expect-type@1.3.0/node_modules/expect-type/dist/overloads.js +0 -10
- package/bundle/dist/node_modules/.pnpm/expect-type@1.3.0/node_modules/expect-type/dist/utils.js +0 -10
- package/bundle/dist/node_modules/.pnpm/magic-string@0.30.21/node_modules/magic-string/dist/magic-string.es.js +0 -1126
- package/bundle/dist/node_modules/.pnpm/pathe@2.0.3/node_modules/pathe/dist/index.js +0 -21
- package/bundle/dist/node_modules/.pnpm/pathe@2.0.3/node_modules/pathe/dist/shared/pathe.M-eThtNZ.js +0 -432
- package/bundle/dist/node_modules/.pnpm/tinybench@2.9.0/node_modules/tinybench/dist/index.js +0 -517
- package/bundle/dist/node_modules/.pnpm/tinyrainbow@3.1.0/node_modules/tinyrainbow/dist/index.js +0 -101
- package/bundle/dist/node_modules/.pnpm/vite@8.0.3_@emnapi_core@1.11.2_@emnapi_runtime@1.11.2_@types_node@25.0.7_esbuild@0.27.4_5b35fc1fb85d2af4d105e0d74f940f50/node_modules/vite/dist/node/module-runner.js +0 -1265
- package/bundle/dist/node_modules/.pnpm/vitest@4.1.10_@opentelemetry_api@1.9.0_@types_node@25.0.7_@vitest_coverage-v8@4.1.10_vi_a1977b93af7bb69308bcb1dbab39b618/node_modules/vitest/dist/chunks/_commonjsHelpers.D26ty3Ew.js +0 -9
- package/bundle/dist/node_modules/.pnpm/vitest@4.1.10_@opentelemetry_api@1.9.0_@types_node@25.0.7_@vitest_coverage-v8@4.1.10_vi_a1977b93af7bb69308bcb1dbab39b618/node_modules/vitest/dist/chunks/benchmark.CX_oY03V.js +0 -41
- package/bundle/dist/node_modules/.pnpm/vitest@4.1.10_@opentelemetry_api@1.9.0_@types_node@25.0.7_@vitest_coverage-v8@4.1.10_vi_a1977b93af7bb69308bcb1dbab39b618/node_modules/vitest/dist/chunks/evaluatedModules.Dg1zASAC.js +0 -19
- package/bundle/dist/node_modules/.pnpm/vitest@4.1.10_@opentelemetry_api@1.9.0_@types_node@25.0.7_@vitest_coverage-v8@4.1.10_vi_a1977b93af7bb69308bcb1dbab39b618/node_modules/vitest/dist/chunks/index.Chj8NDwU.js +0 -202
- package/bundle/dist/node_modules/.pnpm/vitest@4.1.10_@opentelemetry_api@1.9.0_@types_node@25.0.7_@vitest_coverage-v8@4.1.10_vi_a1977b93af7bb69308bcb1dbab39b618/node_modules/vitest/dist/chunks/index.DdgEv5B1.js +0 -46
- package/bundle/dist/node_modules/.pnpm/vitest@4.1.10_@opentelemetry_api@1.9.0_@types_node@25.0.7_@vitest_coverage-v8@4.1.10_vi_a1977b93af7bb69308bcb1dbab39b618/node_modules/vitest/dist/chunks/rpc.MzXet3jl.js +0 -119
- package/bundle/dist/node_modules/.pnpm/vitest@4.1.10_@opentelemetry_api@1.9.0_@types_node@25.0.7_@vitest_coverage-v8@4.1.10_vi_a1977b93af7bb69308bcb1dbab39b618/node_modules/vitest/dist/chunks/test.DNmyFkvJ.js +0 -3044
- package/bundle/dist/node_modules/.pnpm/vitest@4.1.10_@opentelemetry_api@1.9.0_@types_node@25.0.7_@vitest_coverage-v8@4.1.10_vi_a1977b93af7bb69308bcb1dbab39b618/node_modules/vitest/dist/chunks/utils.BX5Fg8C4.js +0 -59
- package/bundle/dist/node_modules/.pnpm/vitest@4.1.10_@opentelemetry_api@1.9.0_@types_node@25.0.7_@vitest_coverage-v8@4.1.10_vi_a1977b93af7bb69308bcb1dbab39b618/node_modules/vitest/dist/index.js +0 -28
- package/bundle/dist/testing/setup-mocks.js +0 -16
- package/bundle/src/testing/setup-mocks.ts +0 -44
- package/bundle/web-dist/client/assets/index-Bw2s88Ot.css +0 -1
- package/bundle/web-dist/client/assets/index-CrXKu_J8.js +0 -106
- package/bundle/web-dist/client/assets/logs-B2SmWJXA.js +0 -1
- package/bundle/web-dist/client/assets/monit-D-JwXXoA.js +0 -1
- package/bundle/web-dist/client/assets/plus-B62CuqT8.js +0 -1
- package/bundle/web-dist/client/assets/refresh-cw-NNcU0Cmq.js +0 -1
- package/bundle/web-dist/client/assets/request-model-CojtinqK.js +0 -1
- package/bundle/web-dist/client/assets/routes-C5r4gTvY.js +0 -5
- package/bundle/web-dist/client/assets/settings-D3tDSAck.js +0 -1
- package/bundle/web-dist/client/assets/show-Cah_kUKC.js +0 -2
- package/bundle/web-dist/client/assets/tokens-DU2Iyxxd.js +0 -1
- package/bundle/web-dist/client/assets/use-oauth-login-flow-D0UaR9_e.js +0 -1
- package/bundle/web-dist/client/assets/use-update-token-mutation-DAq0F8p-.js +0 -1
- package/bundle/web-dist/client/assets/vendor-react-DH4kUfK2.js +0 -9
- package/bundle/web-dist/client/assets/vendor-tanstack-DJRQAbrY.js +0 -1
- package/bundle/web-dist/server/assets/logs-l91avYif.js +0 -509
- package/bundle/web-dist/server/assets/plus-KZrECewT.js +0 -19
- package/bundle/web-dist/server/assets/refresh-cw-BND93JrF.js +0 -23
- package/bundle/web-dist/server/assets/settings-BZR5HSAL.js +0 -461
- package/bundle/web-dist/server/assets/tokens-D1hb4eKk.js +0 -448
- package/bundle/web-dist/server/assets/use-oauth-login-flow-Cvdy0zF8.js +0 -178
- package/dist/cli.d.ts +0 -10
- /package/bundle/web-dist/client/assets/{cost-DH2jZbrw.js → cost-DB3HbU7T.js} +0 -0
- /package/bundle/web-dist/client/assets/{preload-helper-ca-nBW7U.js → preload-helper-DWTEM3RW.js} +0 -0
- /package/bundle/web-dist/server/assets/{cost-eEHeTRT5.js → cost-BC9yzyA9.js} +0 -0
|
@@ -0,0 +1,455 @@
|
|
|
1
|
+
import { GROK_AUTH_ISSUER, GROK_BUILD_VERSION, GROK_CHAT_PROXY_URL, GROK_DEVICE_CODE_URL, GROK_DEVICE_TOKEN_URL, GROK_OAUTH_CLIENT_ID, GROK_OAUTH_REFERRER, GROK_OAUTH_SCOPES } from "./grok-constants.js";
|
|
2
|
+
import { buildGrokProxyGetHeaders, grokShellUserAgent } from "./grok-headers.js";
|
|
3
|
+
import { GrokCredentials, GrokUserSubscription, decodeGrokJwt, isGrokAccessToken } from "./grok-types.js";
|
|
4
|
+
import { z } from "zod";
|
|
5
|
+
import { createHash, randomBytes, randomInt, randomUUID, timingSafeEqual } from "node:crypto";
|
|
6
|
+
//#region src/utils/providers/grok/grok-oauth.ts
|
|
7
|
+
/** Login failure. `retryable` marks network/5xx failures where the same step may be retried. */
|
|
8
|
+
var GrokOAuthError = class extends Error {
|
|
9
|
+
code;
|
|
10
|
+
options;
|
|
11
|
+
name = "GrokOAuthError";
|
|
12
|
+
constructor(code, message, options = {}) {
|
|
13
|
+
super(message);
|
|
14
|
+
this.code = code;
|
|
15
|
+
this.options = options;
|
|
16
|
+
}
|
|
17
|
+
get status() {
|
|
18
|
+
return this.options.status;
|
|
19
|
+
}
|
|
20
|
+
get retryable() {
|
|
21
|
+
return this.options.retryable ?? false;
|
|
22
|
+
}
|
|
23
|
+
/** OAuth `error` code, only when it is a plain lowercase identifier. */
|
|
24
|
+
get oauthError() {
|
|
25
|
+
return this.options.oauthError;
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
const GROK_DISCOVERY_TTL_MS = 1440 * 60 * 1e3;
|
|
29
|
+
const GROK_FALLBACK_AUTHORIZATION_ENDPOINT = `${GROK_AUTH_ISSUER}/oauth2/authorize`;
|
|
30
|
+
const GROK_FALLBACK_TOKEN_ENDPOINT = `${GROK_AUTH_ISSUER}/oauth2/token`;
|
|
31
|
+
const DISCOVERY_TIMEOUT_MS = 1e4;
|
|
32
|
+
const TOKEN_TIMEOUT_MS = 15e3;
|
|
33
|
+
const USER_LOOKUP_TIMEOUT_MS = 15e3;
|
|
34
|
+
const DiscoveryDocument = z.looseObject({
|
|
35
|
+
authorization_endpoint: z.string(),
|
|
36
|
+
token_endpoint: z.string()
|
|
37
|
+
});
|
|
38
|
+
let discoveryCache;
|
|
39
|
+
/** Clears the module-level discovery cache (tests and operator resets). */
|
|
40
|
+
function resetGrokDiscoveryCache() {
|
|
41
|
+
discoveryCache = void 0;
|
|
42
|
+
}
|
|
43
|
+
function isTrustedEndpoint(value) {
|
|
44
|
+
let url;
|
|
45
|
+
try {
|
|
46
|
+
url = new URL(value);
|
|
47
|
+
} catch {
|
|
48
|
+
return false;
|
|
49
|
+
}
|
|
50
|
+
return url.protocol === "https:" && !url.username && !url.password && (url.hostname === "x.ai" || url.hostname.endsWith(".x.ai"));
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* `GET {issuer}/.well-known/openid-configuration`, cached 24 h. Any failure uses the fallback
|
|
54
|
+
* endpoints without caching them, so the next call retries discovery.
|
|
55
|
+
*/
|
|
56
|
+
async function getGrokOAuthEndpoints(io = {}) {
|
|
57
|
+
const fetchImpl = io.fetch ?? globalThis.fetch;
|
|
58
|
+
const now = io.now ?? Date.now;
|
|
59
|
+
const cached = discoveryCache;
|
|
60
|
+
if (cached && now() - cached.fetchedAt < 864e5) return cached.endpoints;
|
|
61
|
+
try {
|
|
62
|
+
const response = await fetchImpl(`${GROK_AUTH_ISSUER}/.well-known/openid-configuration`, {
|
|
63
|
+
method: "GET",
|
|
64
|
+
headers: {
|
|
65
|
+
accept: "application/json",
|
|
66
|
+
"user-agent": grokShellUserAgent()
|
|
67
|
+
},
|
|
68
|
+
signal: AbortSignal.timeout(DISCOVERY_TIMEOUT_MS)
|
|
69
|
+
});
|
|
70
|
+
if (response.ok) {
|
|
71
|
+
const document = DiscoveryDocument.safeParse(await response.json());
|
|
72
|
+
if (document.success && isTrustedEndpoint(document.data.authorization_endpoint) && isTrustedEndpoint(document.data.token_endpoint)) {
|
|
73
|
+
const endpoints = {
|
|
74
|
+
authorizationEndpoint: document.data.authorization_endpoint,
|
|
75
|
+
tokenEndpoint: document.data.token_endpoint,
|
|
76
|
+
source: "discovery"
|
|
77
|
+
};
|
|
78
|
+
discoveryCache = {
|
|
79
|
+
endpoints,
|
|
80
|
+
fetchedAt: now()
|
|
81
|
+
};
|
|
82
|
+
return endpoints;
|
|
83
|
+
}
|
|
84
|
+
} else await response.body?.cancel().catch(() => void 0);
|
|
85
|
+
} catch {}
|
|
86
|
+
return {
|
|
87
|
+
authorizationEndpoint: GROK_FALLBACK_AUTHORIZATION_ENDPOINT,
|
|
88
|
+
tokenEndpoint: GROK_FALLBACK_TOKEN_ENDPOINT,
|
|
89
|
+
source: "fallback"
|
|
90
|
+
};
|
|
91
|
+
}
|
|
92
|
+
/** S256 over a base64url verifier of 32 random bytes (oidc/protocol.rs:314-320). */
|
|
93
|
+
function generateGrokPkce() {
|
|
94
|
+
const codeVerifier = randomBytes(32).toString("base64url");
|
|
95
|
+
return {
|
|
96
|
+
codeVerifier,
|
|
97
|
+
codeChallenge: createHash("sha256").update(codeVerifier).digest("base64url")
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
/** RFC 3986 unreserved-only encoding, matching Rust `urlencoding::encode` (space → %20). */
|
|
101
|
+
function encodeQueryValue(value) {
|
|
102
|
+
return encodeURIComponent(value).replace(/[!'()*]/g, (char) => `%${char.charCodeAt(0).toString(16).toUpperCase()}`);
|
|
103
|
+
}
|
|
104
|
+
const GROK_OAUTH_SCOPE = GROK_OAUTH_SCOPES.join(" ");
|
|
105
|
+
/** Authorize URL with grok-build's query order (oidc/protocol.rs:321-366). */
|
|
106
|
+
function buildGrokAuthorizeUrl(input) {
|
|
107
|
+
const search = [
|
|
108
|
+
["response_type", "code"],
|
|
109
|
+
["client_id", GROK_OAUTH_CLIENT_ID],
|
|
110
|
+
["redirect_uri", input.redirectUri],
|
|
111
|
+
["scope", GROK_OAUTH_SCOPE],
|
|
112
|
+
["code_challenge", input.codeChallenge],
|
|
113
|
+
["code_challenge_method", "S256"],
|
|
114
|
+
["state", input.state],
|
|
115
|
+
["nonce", input.nonce],
|
|
116
|
+
["referrer", GROK_OAUTH_REFERRER]
|
|
117
|
+
].map(([key, value]) => `${key}=${encodeQueryValue(value)}`).join("&");
|
|
118
|
+
return `${input.authorizationEndpoint}?${search}`;
|
|
119
|
+
}
|
|
120
|
+
function grokLoopbackRedirectUri(port) {
|
|
121
|
+
if (!Number.isInteger(port) || port < 1 || port > 65535) throw new RangeError("redirect port must be an integer in 1..65535");
|
|
122
|
+
return `http://127.0.0.1:${port}/callback`;
|
|
123
|
+
}
|
|
124
|
+
async function startGrokOAuth(input) {
|
|
125
|
+
if (!input.state) throw new TypeError("state must be non-empty");
|
|
126
|
+
const endpoints = await getGrokOAuthEndpoints(input);
|
|
127
|
+
const pkce = generateGrokPkce();
|
|
128
|
+
const redirectUri = grokLoopbackRedirectUri(input.redirectPort ?? randomInt(49152, 65536));
|
|
129
|
+
return {
|
|
130
|
+
authorizeUrl: buildGrokAuthorizeUrl({
|
|
131
|
+
authorizationEndpoint: endpoints.authorizationEndpoint,
|
|
132
|
+
redirectUri,
|
|
133
|
+
codeChallenge: pkce.codeChallenge,
|
|
134
|
+
state: input.state,
|
|
135
|
+
nonce: randomUUID()
|
|
136
|
+
}),
|
|
137
|
+
verifier: pkce.codeVerifier,
|
|
138
|
+
redirectUri
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
const OAUTH_ERROR_CODE = /^[a-z_]{1,80}$/;
|
|
142
|
+
function safeOAuthErrorCode(value) {
|
|
143
|
+
return OAUTH_ERROR_CODE.test(value) ? value : void 0;
|
|
144
|
+
}
|
|
145
|
+
/** Accepts the full callback URL or a bare authorization code (oidc/login.rs:30-60). */
|
|
146
|
+
function parseGrokCallbackInput(input) {
|
|
147
|
+
const trimmed = input.trim();
|
|
148
|
+
if (!trimmed) throw new GrokOAuthError("invalid_callback_input", "empty callback input");
|
|
149
|
+
let url;
|
|
150
|
+
try {
|
|
151
|
+
url = new URL(trimmed);
|
|
152
|
+
} catch {
|
|
153
|
+
url = void 0;
|
|
154
|
+
}
|
|
155
|
+
if (url) {
|
|
156
|
+
const code = url.searchParams.get("code");
|
|
157
|
+
if (code) return {
|
|
158
|
+
code,
|
|
159
|
+
state: url.searchParams.get("state") ?? ""
|
|
160
|
+
};
|
|
161
|
+
const error = url.searchParams.get("error");
|
|
162
|
+
if (error) {
|
|
163
|
+
const oauthError = safeOAuthErrorCode(error);
|
|
164
|
+
throw new GrokOAuthError("authorization_failed", `authorization failed: ${oauthError ?? "unknown_error"}`, oauthError === void 0 ? {} : { oauthError });
|
|
165
|
+
}
|
|
166
|
+
throw new GrokOAuthError("invalid_callback_input", "callback URL has no code parameter");
|
|
167
|
+
}
|
|
168
|
+
if (/\s/.test(trimmed)) throw new GrokOAuthError("invalid_callback_input", "authorization code contains whitespace");
|
|
169
|
+
return {
|
|
170
|
+
code: trimmed,
|
|
171
|
+
state: ""
|
|
172
|
+
};
|
|
173
|
+
}
|
|
174
|
+
function statesEqual(expected, received) {
|
|
175
|
+
const a = Buffer.from(expected);
|
|
176
|
+
const b = Buffer.from(received);
|
|
177
|
+
return a.length === b.length && timingSafeEqual(a, b);
|
|
178
|
+
}
|
|
179
|
+
const GrokTokenResponse = z.looseObject({
|
|
180
|
+
access_token: z.string().min(1),
|
|
181
|
+
refresh_token: z.string().min(1).nullish(),
|
|
182
|
+
id_token: z.string().nullish(),
|
|
183
|
+
expires_in: z.number().nonnegative().nullish(),
|
|
184
|
+
scope: z.string().nullish(),
|
|
185
|
+
token_type: z.string().nullish()
|
|
186
|
+
});
|
|
187
|
+
const OAuthErrorBody = z.looseObject({ error: z.string() });
|
|
188
|
+
/** Reads the OAuth `error` code from a failed response without retaining the body. */
|
|
189
|
+
async function readGrokOAuthErrorCode(response) {
|
|
190
|
+
const text = await response.text().catch(() => "");
|
|
191
|
+
try {
|
|
192
|
+
const parsed = OAuthErrorBody.safeParse(JSON.parse(text));
|
|
193
|
+
return parsed.success ? safeOAuthErrorCode(parsed.data.error) : void 0;
|
|
194
|
+
} catch {
|
|
195
|
+
return;
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
function formHeaders(extra = {}) {
|
|
199
|
+
return {
|
|
200
|
+
"user-agent": grokShellUserAgent(),
|
|
201
|
+
...extra,
|
|
202
|
+
"content-type": "application/x-www-form-urlencoded",
|
|
203
|
+
accept: "application/json"
|
|
204
|
+
};
|
|
205
|
+
}
|
|
206
|
+
async function parseTokenResponse(response) {
|
|
207
|
+
let body;
|
|
208
|
+
try {
|
|
209
|
+
body = await response.json();
|
|
210
|
+
} catch {
|
|
211
|
+
throw new GrokOAuthError("invalid_token_response", "token response is not JSON");
|
|
212
|
+
}
|
|
213
|
+
const parsed = GrokTokenResponse.safeParse(body);
|
|
214
|
+
if (!parsed.success) throw new GrokOAuthError("invalid_token_response", "token response failed validation");
|
|
215
|
+
return parsed.data;
|
|
216
|
+
}
|
|
217
|
+
function networkError(code, what, cause) {
|
|
218
|
+
return new GrokOAuthError(code, `${what} request failed (${cause instanceof Error ? cause.name : "unknown"})`, { retryable: true });
|
|
219
|
+
}
|
|
220
|
+
/**
|
|
221
|
+
* Validates the token response, resolves the account id (JWT `sub`, confirmed by
|
|
222
|
+
* `GET /user?include=subscription`), and builds stored credentials.
|
|
223
|
+
*/
|
|
224
|
+
async function finishGrokLogin(input) {
|
|
225
|
+
const fetchImpl = input.fetch ?? globalThis.fetch;
|
|
226
|
+
const now = input.now ?? Date.now;
|
|
227
|
+
const { tokens } = input;
|
|
228
|
+
if (!isGrokAccessToken(tokens.access_token)) throw new GrokOAuthError("invalid_access_token", `access token is not an at+jwt issued by ${GROK_AUTH_ISSUER}`);
|
|
229
|
+
if (!tokens.refresh_token) throw new GrokOAuthError("missing_refresh_token", "token response has no refresh token");
|
|
230
|
+
const decoded = decodeGrokJwt(tokens.access_token);
|
|
231
|
+
const subject = decoded?.payload.sub;
|
|
232
|
+
if (!subject) throw new GrokOAuthError("user_id_unresolved", "access token has no subject (sub) claim");
|
|
233
|
+
let response;
|
|
234
|
+
try {
|
|
235
|
+
response = await fetchImpl(`${GROK_CHAT_PROXY_URL}/user?include=subscription`, {
|
|
236
|
+
method: "GET",
|
|
237
|
+
headers: buildGrokProxyGetHeaders({
|
|
238
|
+
bearer: tokens.access_token,
|
|
239
|
+
userId: subject
|
|
240
|
+
}),
|
|
241
|
+
signal: AbortSignal.timeout(USER_LOOKUP_TIMEOUT_MS)
|
|
242
|
+
});
|
|
243
|
+
} catch (error) {
|
|
244
|
+
throw networkError("user_lookup_failed", "user lookup", error);
|
|
245
|
+
}
|
|
246
|
+
if (!response.ok) {
|
|
247
|
+
await response.body?.cancel().catch(() => void 0);
|
|
248
|
+
throw new GrokOAuthError("user_lookup_failed", `user lookup failed: HTTP ${response.status}`, {
|
|
249
|
+
status: response.status,
|
|
250
|
+
retryable: response.status >= 500 || response.status === 429
|
|
251
|
+
});
|
|
252
|
+
}
|
|
253
|
+
let userBody;
|
|
254
|
+
try {
|
|
255
|
+
userBody = await response.json();
|
|
256
|
+
} catch {
|
|
257
|
+
throw new GrokOAuthError("user_id_unresolved", "user lookup returned non-JSON");
|
|
258
|
+
}
|
|
259
|
+
const user = GrokUserSubscription.safeParse(userBody);
|
|
260
|
+
if (!user.success) throw new GrokOAuthError("user_id_unresolved", "user lookup did not return a valid userId");
|
|
261
|
+
const issuedAt = now();
|
|
262
|
+
const expiresIn = tokens.expires_in;
|
|
263
|
+
const jwtExpiry = decoded?.payload.exp;
|
|
264
|
+
const expiresAtMs = expiresIn !== void 0 && expiresIn !== null ? issuedAt + expiresIn * 1e3 : jwtExpiry !== void 0 ? jwtExpiry * 1e3 : void 0;
|
|
265
|
+
if (expiresAtMs === void 0 || !Number.isFinite(expiresAtMs)) throw new GrokOAuthError("missing_expiry", "token response has no expiry");
|
|
266
|
+
const grantedScopes = tokens.scope?.split(" ").filter(Boolean);
|
|
267
|
+
const candidate = {
|
|
268
|
+
authMode: "oauth",
|
|
269
|
+
accessToken: tokens.access_token,
|
|
270
|
+
refreshToken: tokens.refresh_token,
|
|
271
|
+
expiresAt: new Date(expiresAtMs).toISOString(),
|
|
272
|
+
issuer: GROK_AUTH_ISSUER,
|
|
273
|
+
clientId: GROK_OAUTH_CLIENT_ID,
|
|
274
|
+
scopes: grantedScopes && grantedScopes.length > 0 ? grantedScopes : [...input.requestedScopes ?? GROK_OAUTH_SCOPES],
|
|
275
|
+
userId: user.data.userId,
|
|
276
|
+
sessionId: randomUUID(),
|
|
277
|
+
agentId: randomUUID()
|
|
278
|
+
};
|
|
279
|
+
if (user.data.subscriptionTier) candidate.subscriptionTier = user.data.subscriptionTier;
|
|
280
|
+
const credentials = GrokCredentials.safeParse(candidate);
|
|
281
|
+
if (!credentials.success) throw new GrokOAuthError("invalid_credentials", "credentials failed validation");
|
|
282
|
+
return credentials.data;
|
|
283
|
+
}
|
|
284
|
+
async function completeGrokOAuth(input) {
|
|
285
|
+
const fetchImpl = input.fetch ?? globalThis.fetch;
|
|
286
|
+
const callback = parseGrokCallbackInput(input.codeOrUrl);
|
|
287
|
+
if (callback.state && !statesEqual(input.state, callback.state)) throw new GrokOAuthError("state_mismatch", "OAuth state mismatch");
|
|
288
|
+
const endpoints = await getGrokOAuthEndpoints(input);
|
|
289
|
+
let response;
|
|
290
|
+
try {
|
|
291
|
+
response = await fetchImpl(endpoints.tokenEndpoint, {
|
|
292
|
+
method: "POST",
|
|
293
|
+
headers: formHeaders({ "x-grok-client-version": GROK_BUILD_VERSION }),
|
|
294
|
+
body: new URLSearchParams([
|
|
295
|
+
["grant_type", "authorization_code"],
|
|
296
|
+
["code", callback.code],
|
|
297
|
+
["redirect_uri", input.redirectUri],
|
|
298
|
+
["client_id", GROK_OAUTH_CLIENT_ID],
|
|
299
|
+
["code_verifier", input.verifier]
|
|
300
|
+
]),
|
|
301
|
+
signal: AbortSignal.timeout(TOKEN_TIMEOUT_MS)
|
|
302
|
+
});
|
|
303
|
+
} catch (error) {
|
|
304
|
+
throw networkError("token_exchange_failed", "token exchange", error);
|
|
305
|
+
}
|
|
306
|
+
if (!response.ok) {
|
|
307
|
+
const oauthError = await readGrokOAuthErrorCode(response);
|
|
308
|
+
const errorOptions = { status: response.status };
|
|
309
|
+
if (oauthError !== void 0) errorOptions.oauthError = oauthError;
|
|
310
|
+
errorOptions.retryable = response.status >= 500;
|
|
311
|
+
throw new GrokOAuthError("token_exchange_failed", `token exchange failed: HTTP ${response.status} ${oauthError ?? "unknown"}`, errorOptions);
|
|
312
|
+
}
|
|
313
|
+
return finishGrokLogin({
|
|
314
|
+
...input,
|
|
315
|
+
fetch: fetchImpl,
|
|
316
|
+
tokens: await parseTokenResponse(response)
|
|
317
|
+
});
|
|
318
|
+
}
|
|
319
|
+
const GROK_DEVICE_DEFAULT_INTERVAL_S = 5;
|
|
320
|
+
const GROK_DEVICE_SLOW_DOWN_INCREMENT_S = 5;
|
|
321
|
+
const DEVICE_GRANT_TYPE = "urn:ietf:params:oauth:grant-type:device_code";
|
|
322
|
+
const DEVICE_CLIENT_SURFACE = "ui";
|
|
323
|
+
function isAllowedVerificationUri(value) {
|
|
324
|
+
for (let index = 0; index < value.length; index++) {
|
|
325
|
+
const code = value.charCodeAt(index);
|
|
326
|
+
if (code < 32 || code === 127) return false;
|
|
327
|
+
}
|
|
328
|
+
let url;
|
|
329
|
+
try {
|
|
330
|
+
url = new URL(value);
|
|
331
|
+
} catch {
|
|
332
|
+
return false;
|
|
333
|
+
}
|
|
334
|
+
if (url.protocol === "https:") return true;
|
|
335
|
+
return url.protocol === "http:" && (url.hostname === "localhost" || url.hostname === "127.0.0.1");
|
|
336
|
+
}
|
|
337
|
+
const DeviceCodeResponse = z.looseObject({
|
|
338
|
+
device_code: z.string().min(1),
|
|
339
|
+
user_code: z.string().regex(/^[A-Za-z0-9-]+$/),
|
|
340
|
+
verification_uri: z.string().refine(isAllowedVerificationUri),
|
|
341
|
+
verification_uri_complete: z.string().refine(isAllowedVerificationUri).nullish(),
|
|
342
|
+
expires_in: z.number().positive(),
|
|
343
|
+
interval: z.number().int().positive().nullish()
|
|
344
|
+
});
|
|
345
|
+
function deviceHeaders() {
|
|
346
|
+
return formHeaders({
|
|
347
|
+
"x-grok-client-version": GROK_BUILD_VERSION,
|
|
348
|
+
"x-grok-client-surface": DEVICE_CLIENT_SURFACE
|
|
349
|
+
});
|
|
350
|
+
}
|
|
351
|
+
async function startGrokDeviceCode(io = {}) {
|
|
352
|
+
const fetchImpl = io.fetch ?? globalThis.fetch;
|
|
353
|
+
let response;
|
|
354
|
+
try {
|
|
355
|
+
response = await fetchImpl(GROK_DEVICE_CODE_URL, {
|
|
356
|
+
method: "POST",
|
|
357
|
+
headers: deviceHeaders(),
|
|
358
|
+
body: new URLSearchParams([
|
|
359
|
+
["client_id", GROK_OAUTH_CLIENT_ID],
|
|
360
|
+
["scope", GROK_OAUTH_SCOPE],
|
|
361
|
+
["referrer", GROK_OAUTH_REFERRER]
|
|
362
|
+
]),
|
|
363
|
+
signal: AbortSignal.timeout(TOKEN_TIMEOUT_MS)
|
|
364
|
+
});
|
|
365
|
+
} catch (error) {
|
|
366
|
+
throw networkError("device_code_failed", "device code", error);
|
|
367
|
+
}
|
|
368
|
+
if (!response.ok) {
|
|
369
|
+
await response.body?.cancel().catch(() => void 0);
|
|
370
|
+
if (response.status === 404) throw new GrokOAuthError("device_flow_not_enabled", "device-code login is not available", { status: 404 });
|
|
371
|
+
throw new GrokOAuthError("device_code_failed", `device code request failed: HTTP ${response.status}`, {
|
|
372
|
+
status: response.status,
|
|
373
|
+
retryable: response.status >= 500 || response.status === 429
|
|
374
|
+
});
|
|
375
|
+
}
|
|
376
|
+
let body;
|
|
377
|
+
try {
|
|
378
|
+
body = await response.json();
|
|
379
|
+
} catch {
|
|
380
|
+
throw new GrokOAuthError("invalid_device_code_response", "device code response is not JSON");
|
|
381
|
+
}
|
|
382
|
+
const parsed = DeviceCodeResponse.safeParse(body);
|
|
383
|
+
if (!parsed.success) throw new GrokOAuthError("invalid_device_code_response", "device code response failed validation");
|
|
384
|
+
const data = parsed.data;
|
|
385
|
+
const deviceCode = {
|
|
386
|
+
deviceCode: data.device_code,
|
|
387
|
+
userCode: data.user_code,
|
|
388
|
+
verificationUri: data.verification_uri,
|
|
389
|
+
expiresIn: data.expires_in,
|
|
390
|
+
interval: data.interval ?? 5
|
|
391
|
+
};
|
|
392
|
+
if (data.verification_uri_complete) deviceCode.verificationUriComplete = data.verification_uri_complete;
|
|
393
|
+
return deviceCode;
|
|
394
|
+
}
|
|
395
|
+
/**
|
|
396
|
+
* One poll of the device token endpoint. The caller sleeps `interval` seconds between polls and
|
|
397
|
+
* enforces the device-code expiry; this function never loops.
|
|
398
|
+
*/
|
|
399
|
+
async function pollGrokDeviceCode(input) {
|
|
400
|
+
const fetchImpl = input.fetch ?? globalThis.fetch;
|
|
401
|
+
const interval = Math.max(1, Math.ceil(input.interval));
|
|
402
|
+
let response;
|
|
403
|
+
try {
|
|
404
|
+
response = await fetchImpl(GROK_DEVICE_TOKEN_URL, {
|
|
405
|
+
method: "POST",
|
|
406
|
+
headers: deviceHeaders(),
|
|
407
|
+
body: new URLSearchParams([
|
|
408
|
+
["grant_type", DEVICE_GRANT_TYPE],
|
|
409
|
+
["device_code", input.deviceCode],
|
|
410
|
+
["client_id", GROK_OAUTH_CLIENT_ID]
|
|
411
|
+
]),
|
|
412
|
+
signal: AbortSignal.timeout(TOKEN_TIMEOUT_MS)
|
|
413
|
+
});
|
|
414
|
+
} catch (error) {
|
|
415
|
+
throw networkError("device_token_failed", "device token", error);
|
|
416
|
+
}
|
|
417
|
+
if (response.ok) return {
|
|
418
|
+
status: "complete",
|
|
419
|
+
credentials: await finishGrokLogin({
|
|
420
|
+
...input,
|
|
421
|
+
fetch: fetchImpl,
|
|
422
|
+
tokens: await parseTokenResponse(response)
|
|
423
|
+
})
|
|
424
|
+
};
|
|
425
|
+
const oauthError = await readGrokOAuthErrorCode(response);
|
|
426
|
+
switch (oauthError) {
|
|
427
|
+
case "authorization_pending": return {
|
|
428
|
+
status: "pending",
|
|
429
|
+
interval
|
|
430
|
+
};
|
|
431
|
+
case "slow_down": return {
|
|
432
|
+
status: "pending",
|
|
433
|
+
interval: interval + 5
|
|
434
|
+
};
|
|
435
|
+
case "access_denied": throw new GrokOAuthError("access_denied", "authorization denied by the user", {
|
|
436
|
+
status: response.status,
|
|
437
|
+
oauthError
|
|
438
|
+
});
|
|
439
|
+
case "expired_token": throw new GrokOAuthError("expired_token", "device code expired", {
|
|
440
|
+
status: response.status,
|
|
441
|
+
oauthError
|
|
442
|
+
});
|
|
443
|
+
default: throw new GrokOAuthError("device_token_failed", `device token request failed: HTTP ${response.status} ${oauthError ?? "unknown"}`, deviceTokenErrorOptions(response.status, oauthError));
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
function deviceTokenErrorOptions(status, oauthError) {
|
|
447
|
+
const errorOptions = { status };
|
|
448
|
+
if (oauthError !== void 0) errorOptions.oauthError = oauthError;
|
|
449
|
+
errorOptions.retryable = oauthError === void 0 && status >= 500;
|
|
450
|
+
return errorOptions;
|
|
451
|
+
}
|
|
452
|
+
//#endregion
|
|
453
|
+
export { GROK_DEVICE_DEFAULT_INTERVAL_S, GROK_DEVICE_SLOW_DOWN_INCREMENT_S, GROK_DISCOVERY_TTL_MS, GROK_FALLBACK_AUTHORIZATION_ENDPOINT, GROK_FALLBACK_TOKEN_ENDPOINT, GROK_OAUTH_SCOPE, GrokOAuthError, GrokTokenResponse, buildGrokAuthorizeUrl, completeGrokOAuth, finishGrokLogin, generateGrokPkce, getGrokOAuthEndpoints, grokLoopbackRedirectUri, parseGrokCallbackInput, pollGrokDeviceCode, readGrokOAuthErrorCode, resetGrokDiscoveryCache, startGrokDeviceCode, startGrokOAuth };
|
|
454
|
+
|
|
455
|
+
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZ3Jvay1vYXV0aC5qcyIsIm5hbWVzIjpbXSwic291cmNlcyI6WyIuLi8uLi8uLi8uLi9zcmMvdXRpbHMvcHJvdmlkZXJzL2dyb2svZ3Jvay1vYXV0aC50cyJdLCJzb3VyY2VzQ29udGVudCI6WyIvLyBHcm9rICh4QUkpIGxvZ2luOiBPSURDIGRpc2NvdmVyeSwgUEtDRSBhdXRob3JpemUgVVJMLCBsb29wYmFjay9wYXN0ZSBjb2RlIGV4Y2hhbmdlLCBSRkMgODYyOFxuLy8gZGV2aWNlIGNvZGUsIGFuZCB0aGUgcG9zdC1sb2dpbiBpZGVudGl0eSBsb29rdXAuIE1lY2hhbmlzbSBmb2xsb3dzIGdyb2stYnVpbGQgMS4wLjQ1XG4vLyBjcmF0ZXMvY29kZWdlbi94YWktZ3Jvay1sb2dpbi9zcmMgKG9pZGMvcHJvdG9jb2wucnMsIG9pZGMvbG9naW4ucnMsIGRldmljZV9jb2RlLnJzKS5cbi8vIEVycm9yIG1lc3NhZ2VzIG5ldmVyIGNhcnJ5IHJlc3BvbnNlIGJvZGllczogdG9rZW4gZW5kcG9pbnRzIGNhbiBlY2hvIGNyZWRlbnRpYWxzLlxuaW1wb3J0IHsgY3JlYXRlSGFzaCwgcmFuZG9tQnl0ZXMsIHJhbmRvbUludCwgcmFuZG9tVVVJRCwgdGltaW5nU2FmZUVxdWFsIH0gZnJvbSBcIm5vZGU6Y3J5cHRvXCI7XG5cbmltcG9ydCB7IHogfSBmcm9tIFwiem9kXCI7XG5cbmltcG9ydCB7XG4gIEdST0tfQVVUSF9JU1NVRVIsXG4gIEdST0tfQlVJTERfVkVSU0lPTixcbiAgR1JPS19DSEFUX1BST1hZX1VSTCxcbiAgR1JPS19ERVZJQ0VfQ09ERV9VUkwsXG4gIEdST0tfREVWSUNFX1RPS0VOX1VSTCxcbiAgR1JPS19PQVVUSF9DTElFTlRfSUQsXG4gIEdST0tfT0FVVEhfUkVGRVJSRVIsXG4gIEdST0tfT0FVVEhfU0NPUEVTLFxufSBmcm9tIFwiLi9ncm9rLWNvbnN0YW50c1wiO1xuaW1wb3J0IHsgYnVpbGRHcm9rUHJveHlHZXRIZWFkZXJzLCBncm9rU2hlbGxVc2VyQWdlbnQgfSBmcm9tIFwiLi9ncm9rLWhlYWRlcnNcIjtcbmltcG9ydCB7XG4gIEdyb2tDcmVkZW50aWFscyxcbiAgR3Jva1VzZXJTdWJzY3JpcHRpb24sXG4gIGRlY29kZUdyb2tKd3QsXG4gIGlzR3Jva0FjY2Vzc1Rva2VuLFxufSBmcm9tIFwiLi9ncm9rLXR5cGVzXCI7XG5cbmV4cG9ydCB0eXBlIEdyb2tGZXRjaCA9IHR5cGVvZiBnbG9iYWxUaGlzLmZldGNoO1xuXG4vLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbi8vIEVycm9yc1xuLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG5cbmV4cG9ydCB0eXBlIEdyb2tPQXV0aEVycm9yQ29kZSA9XG4gIHwgXCJpbnZhbGlkX2NhbGxiYWNrX2lucHV0XCJcbiAgfCBcImF1dGhvcml6YXRpb25fZmFpbGVkXCJcbiAgfCBcInN0YXRlX21pc21hdGNoXCJcbiAgfCBcInRva2VuX2V4Y2hhbmdlX2ZhaWxlZFwiXG4gIHwgXCJpbnZhbGlkX3Rva2VuX3Jlc3BvbnNlXCJcbiAgfCBcImludmFsaWRfYWNjZXNzX3Rva2VuXCJcbiAgfCBcIm1pc3NpbmdfcmVmcmVzaF90b2tlblwiXG4gIHwgXCJtaXNzaW5nX2V4cGlyeVwiXG4gIHwgXCJ1c2VyX2lkX3VucmVzb2x2ZWRcIlxuICB8IFwidXNlcl9sb29rdXBfZmFpbGVkXCJcbiAgfCBcImludmFsaWRfY3JlZGVudGlhbHNcIlxuICB8IFwiZGV2aWNlX2Zsb3dfbm90X2VuYWJsZWRcIlxuICB8IFwiZGV2aWNlX2NvZGVfZmFpbGVkXCJcbiAgfCBcImludmFsaWRfZGV2aWNlX2NvZGVfcmVzcG9uc2VcIlxuICB8IFwiZGV2aWNlX3Rva2VuX2ZhaWxlZFwiXG4gIHwgXCJhY2Nlc3NfZGVuaWVkXCJcbiAgfCBcImV4cGlyZWRfdG9rZW5cIjtcblxuLyoqIExvZ2luIGZhaWx1cmUuIGByZXRyeWFibGVgIG1hcmtzIG5ldHdvcmsvNXh4IGZhaWx1cmVzIHdoZXJlIHRoZSBzYW1lIHN0ZXAgbWF5IGJlIHJldHJpZWQuICovXG5leHBvcnQgY2xhc3MgR3Jva09BdXRoRXJyb3IgZXh0ZW5kcyBFcnJvciB7XG4gIG92ZXJyaWRlIHJlYWRvbmx5IG5hbWUgPSBcIkdyb2tPQXV0aEVycm9yXCI7XG4gIGNvbnN0cnVjdG9yKFxuICAgIHJlYWRvbmx5IGNvZGU6IEdyb2tPQXV0aEVycm9yQ29kZSxcbiAgICBtZXNzYWdlOiBzdHJpbmcsXG4gICAgcmVhZG9ubHkgb3B0aW9uczogeyBzdGF0dXM/OiBudW1iZXI7IG9hdXRoRXJyb3I/OiBzdHJpbmc7IHJldHJ5YWJsZT86IGJvb2xlYW4gfSA9IHt9LFxuICApIHtcbiAgICBzdXBlcihtZXNzYWdlKTtcbiAgfVxuXG4gIGdldCBzdGF0dXMoKTogbnVtYmVyIHwgdW5kZWZpbmVkIHtcbiAgICByZXR1cm4gdGhpcy5vcHRpb25zLnN0YXR1cztcbiAgfVxuXG4gIGdldCByZXRyeWFibGUoKTogYm9vbGVhbiB7XG4gICAgcmV0dXJuIHRoaXMub3B0aW9ucy5yZXRyeWFibGUgPz8gZmFsc2U7XG4gIH1cblxuICAvKiogT0F1dGggYGVycm9yYCBjb2RlLCBvbmx5IHdoZW4gaXQgaXMgYSBwbGFpbiBsb3dlcmNhc2UgaWRlbnRpZmllci4gKi9cbiAgZ2V0IG9hdXRoRXJyb3IoKTogc3RyaW5nIHwgdW5kZWZpbmVkIHtcbiAgICByZXR1cm4gdGhpcy5vcHRpb25zLm9hdXRoRXJyb3I7XG4gIH1cbn1cblxuLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4vLyBEaXNjb3Zlcnlcbi8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuXG5leHBvcnQgaW50ZXJmYWNlIEdyb2tPQXV0aEVuZHBvaW50cyB7XG4gIGF1dGhvcml6YXRpb25FbmRwb2ludDogc3RyaW5nO1xuICB0b2tlbkVuZHBvaW50OiBzdHJpbmc7XG4gIHNvdXJjZTogXCJkaXNjb3ZlcnlcIiB8IFwiZmFsbGJhY2tcIjtcbn1cblxuLy8gZ3Jvay1idWlsZCBjYWNoZXMgMSBoIChvaWRjL3Byb3RvY29sLnJzOjI2OSkgYW5kIGhhcyBubyBmYWxsYmFjayAoZGlzY292ZXJ5IGVycm9ycyBhYm9ydCB0aGVcbi8vIGxvZ2luLCBwcm90b2NvbC5yczoyNzktMzAyKS4gcWdyaWQgY2FjaGVzIDI0IGggYW5kIGZhbGxzIGJhY2sgdG8gZml4ZWQgcGF0aHM6IHRoZSB0b2tlbiBwYXRoXG4vLyBpcyB0aGUgb25lIGdyb2stYnVpbGQgaXRzZWxmIGhhcmQtY29kZXMgZm9yIHRoZSBkZXZpY2UgZ3JhbnQgKGRldmljZV9jb2RlLnJzOjE4Nyk7IHRoZVxuLy8gYXV0aG9yaXplIHBhdGggaXMgbm90IHByZXNlbnQgaW4gdGhlIHNvdXJjZSBhbmQgaXMgdW52ZXJpZmllZC5cbmV4cG9ydCBjb25zdCBHUk9LX0RJU0NPVkVSWV9UVExfTVMgPSAyNCAqIDYwICogNjAgKiAxMDAwO1xuZXhwb3J0IGNvbnN0IEdST0tfRkFMTEJBQ0tfQVVUSE9SSVpBVElPTl9FTkRQT0lOVCA9IGAke0dST0tfQVVUSF9JU1NVRVJ9L29hdXRoMi9hdXRob3JpemVgO1xuZXhwb3J0IGNvbnN0IEdST0tfRkFMTEJBQ0tfVE9LRU5fRU5EUE9JTlQgPSBgJHtHUk9LX0FVVEhfSVNTVUVSfS9vYXV0aDIvdG9rZW5gO1xuXG5jb25zdCBESVNDT1ZFUllfVElNRU9VVF9NUyA9IDEwXzAwMDtcbmNvbnN0IFRPS0VOX1RJTUVPVVRfTVMgPSAxNV8wMDA7XG5jb25zdCBVU0VSX0xPT0tVUF9USU1FT1VUX01TID0gMTVfMDAwO1xuXG5jb25zdCBEaXNjb3ZlcnlEb2N1bWVudCA9IHoubG9vc2VPYmplY3Qoe1xuICBhdXRob3JpemF0aW9uX2VuZHBvaW50OiB6LnN0cmluZygpLFxuICB0b2tlbl9lbmRwb2ludDogei5zdHJpbmcoKSxcbn0pO1xuXG5sZXQgZGlzY292ZXJ5Q2FjaGU6IHsgZW5kcG9pbnRzOiBHcm9rT0F1dGhFbmRwb2ludHM7IGZldGNoZWRBdDogbnVtYmVyIH0gfCB1bmRlZmluZWQ7XG5cbi8qKiBDbGVhcnMgdGhlIG1vZHVsZS1sZXZlbCBkaXNjb3ZlcnkgY2FjaGUgKHRlc3RzIGFuZCBvcGVyYXRvciByZXNldHMpLiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHJlc2V0R3Jva0Rpc2NvdmVyeUNhY2hlKCk6IHZvaWQge1xuICBkaXNjb3ZlcnlDYWNoZSA9IHVuZGVmaW5lZDtcbn1cblxuLy8gQSBkaXNjb3ZlcnkgZG9jdW1lbnQgdGhhdCByZWRpcmVjdGVkIHRoZSB0b2tlbiBlbmRwb2ludCBvZmYgeEFJIHdvdWxkIHNoaXAgcmVmcmVzaCB0b2tlbnMgdG8gYVxuLy8gdGhpcmQgcGFydHksIHNvIG9ubHkgaHR0cHMgZW5kcG9pbnRzIG9uIHguYWkgaG9zdHMgYXJlIGFjY2VwdGVkOyBhbnl0aGluZyBlbHNlIGZhbGxzIGJhY2suXG5mdW5jdGlvbiBpc1RydXN0ZWRFbmRwb2ludCh2YWx1ZTogc3RyaW5nKTogYm9vbGVhbiB7XG4gIGxldCB1cmw6IFVSTDtcblxuICB0cnkge1xuICAgIHVybCA9IG5ldyBVUkwodmFsdWUpO1xuICB9IGNhdGNoIHtcbiAgICByZXR1cm4gZmFsc2U7XG4gIH1cblxuICByZXR1cm4gKFxuICAgIHVybC5wcm90b2NvbCA9PT0gXCJodHRwczpcIiAmJlxuICAgICF1cmwudXNlcm5hbWUgJiZcbiAgICAhdXJsLnBhc3N3b3JkICYmXG4gICAgKHVybC5ob3N0bmFtZSA9PT0gXCJ4LmFpXCIgfHwgdXJsLmhvc3RuYW1lLmVuZHNXaXRoKFwiLnguYWlcIikpXG4gICk7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgR3Jva09BdXRoSW8ge1xuICBmZXRjaD86IEdyb2tGZXRjaDtcbiAgbm93PzogKCkgPT4gbnVtYmVyO1xufVxuXG4vKipcbiAqIGBHRVQge2lzc3Vlcn0vLndlbGwta25vd24vb3BlbmlkLWNvbmZpZ3VyYXRpb25gLCBjYWNoZWQgMjQgaC4gQW55IGZhaWx1cmUgdXNlcyB0aGUgZmFsbGJhY2tcbiAqIGVuZHBvaW50cyB3aXRob3V0IGNhY2hpbmcgdGhlbSwgc28gdGhlIG5leHQgY2FsbCByZXRyaWVzIGRpc2NvdmVyeS5cbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIGdldEdyb2tPQXV0aEVuZHBvaW50cyhpbzogR3Jva09BdXRoSW8gPSB7fSk6IFByb21pc2U8R3Jva09BdXRoRW5kcG9pbnRzPiB7XG4gIGNvbnN0IGZldGNoSW1wbCA9IGlvLmZldGNoID8/IGdsb2JhbFRoaXMuZmV0Y2g7XG4gIGNvbnN0IG5vdyA9IGlvLm5vdyA/PyBEYXRlLm5vdztcbiAgY29uc3QgY2FjaGVkID0gZGlzY292ZXJ5Q2FjaGU7XG5cbiAgaWYgKGNhY2hlZCAmJiBub3coKSAtIGNhY2hlZC5mZXRjaGVkQXQgPCBHUk9LX0RJU0NPVkVSWV9UVExfTVMpIHJldHVybiBjYWNoZWQuZW5kcG9pbnRzO1xuXG4gIHRyeSB7XG4gICAgY29uc3QgcmVzcG9uc2UgPSBhd2FpdCBmZXRjaEltcGwoYCR7R1JPS19BVVRIX0lTU1VFUn0vLndlbGwta25vd24vb3BlbmlkLWNvbmZpZ3VyYXRpb25gLCB7XG4gICAgICBtZXRob2Q6IFwiR0VUXCIsXG4gICAgICBoZWFkZXJzOiB7IGFjY2VwdDogXCJhcHBsaWNhdGlvbi9qc29uXCIsIFwidXNlci1hZ2VudFwiOiBncm9rU2hlbGxVc2VyQWdlbnQoKSB9LFxuICAgICAgc2lnbmFsOiBBYm9ydFNpZ25hbC50aW1lb3V0KERJU0NPVkVSWV9USU1FT1VUX01TKSxcbiAgICB9KTtcblxuICAgIGlmIChyZXNwb25zZS5vaykge1xuICAgICAgY29uc3QgZG9jdW1lbnQgPSBEaXNjb3ZlcnlEb2N1bWVudC5zYWZlUGFyc2UoYXdhaXQgcmVzcG9uc2UuanNvbigpKTtcblxuICAgICAgaWYgKFxuICAgICAgICBkb2N1bWVudC5zdWNjZXNzICYmXG4gICAgICAgIGlzVHJ1c3RlZEVuZHBvaW50KGRvY3VtZW50LmRhdGEuYXV0aG9yaXphdGlvbl9lbmRwb2ludCkgJiZcbiAgICAgICAgaXNUcnVzdGVkRW5kcG9pbnQoZG9jdW1lbnQuZGF0YS50b2tlbl9lbmRwb2ludClcbiAgICAgICkge1xuICAgICAgICBjb25zdCBlbmRwb2ludHM6IEdyb2tPQXV0aEVuZHBvaW50cyA9IHtcbiAgICAgICAgICBhdXRob3JpemF0aW9uRW5kcG9pbnQ6IGRvY3VtZW50LmRhdGEuYXV0aG9yaXphdGlvbl9lbmRwb2ludCxcbiAgICAgICAgICB0b2tlbkVuZHBvaW50OiBkb2N1bWVudC5kYXRhLnRva2VuX2VuZHBvaW50LFxuICAgICAgICAgIHNvdXJjZTogXCJkaXNjb3ZlcnlcIixcbiAgICAgICAgfTtcblxuICAgICAgICBkaXNjb3ZlcnlDYWNoZSA9IHsgZW5kcG9pbnRzLCBmZXRjaGVkQXQ6IG5vdygpIH07XG5cbiAgICAgICAgcmV0dXJuIGVuZHBvaW50cztcbiAgICAgIH1cbiAgICB9IGVsc2Uge1xuICAgICAgYXdhaXQgcmVzcG9uc2UuYm9keT8uY2FuY2VsKCkuY2F0Y2goKCkgPT4gdW5kZWZpbmVkKTtcbiAgICB9XG4gIH0gY2F0Y2gge1xuICAgIC8vIE5ldHdvcmsgZmFpbHVyZSwgdGltZW91dCwgb3IgYSBub24tSlNPTiBib2R5OiBmYWxsIHRocm91Z2ggdG8gdGhlIGZpeGVkIGVuZHBvaW50cy5cbiAgfVxuXG4gIHJldHVybiB7XG4gICAgYXV0aG9yaXphdGlvbkVuZHBvaW50OiBHUk9LX0ZBTExCQUNLX0FVVEhPUklaQVRJT05fRU5EUE9JTlQsXG4gICAgdG9rZW5FbmRwb2ludDogR1JPS19GQUxMQkFDS19UT0tFTl9FTkRQT0lOVCxcbiAgICBzb3VyY2U6IFwiZmFsbGJhY2tcIixcbiAgfTtcbn1cblxuLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG4vLyBQS0NFIGFuZCBhdXRob3JpemUgVVJMXG4vLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cblxuZXhwb3J0IGludGVyZmFjZSBHcm9rUGtjZSB7XG4gIGNvZGVWZXJpZmllcjogc3RyaW5nO1xuICBjb2RlQ2hhbGxlbmdlOiBzdHJpbmc7XG59XG5cbi8qKiBTMjU2IG92ZXIgYSBiYXNlNjR1cmwgdmVyaWZpZXIgb2YgMzIgcmFuZG9tIGJ5dGVzIChvaWRjL3Byb3RvY29sLnJzOjMxNC0zMjApLiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGdlbmVyYXRlR3Jva1BrY2UoKTogR3Jva1BrY2Uge1xuICBjb25zdCBjb2RlVmVyaWZpZXIgPSByYW5kb21CeXRlcygzMikudG9TdHJpbmcoXCJiYXNlNjR1cmxcIik7XG5cbiAgcmV0dXJuIHtcbiAgICBjb2RlVmVyaWZpZXIsXG4gICAgY29kZUNoYWxsZW5nZTogY3JlYXRlSGFzaChcInNoYTI1NlwiKS51cGRhdGUoY29kZVZlcmlmaWVyKS5kaWdlc3QoXCJiYXNlNjR1cmxcIiksXG4gIH07XG59XG5cbi8qKiBSRkMgMzk4NiB1bnJlc2VydmVkLW9ubHkgZW5jb2RpbmcsIG1hdGNoaW5nIFJ1c3QgYHVybGVuY29kaW5nOjplbmNvZGVgIChzcGFjZSDihpIgJTIwKS4gKi9cbmZ1bmN0aW9uIGVuY29kZVF1ZXJ5VmFsdWUodmFsdWU6IHN0cmluZyk6IHN0cmluZyB7XG4gIHJldHVybiBlbmNvZGVVUklDb21wb25lbnQodmFsdWUpLnJlcGxhY2UoXG4gICAgL1shJygpKl0vZyxcbiAgICAoY2hhcikgPT4gYCUke2NoYXIuY2hhckNvZGVBdCgwKS50b1N0cmluZygxNikudG9VcHBlckNhc2UoKX1gLFxuICApO1xufVxuXG5leHBvcnQgY29uc3QgR1JPS19PQVVUSF9TQ09QRSA9IEdST0tfT0FVVEhfU0NPUEVTLmpvaW4oXCIgXCIpO1xuXG5leHBvcnQgaW50ZXJmYWNlIEdyb2tBdXRob3JpemVVcmxJbnB1dCB7XG4gIGF1dGhvcml6YXRpb25FbmRwb2ludDogc3RyaW5nO1xuICByZWRpcmVjdFVyaTogc3RyaW5nO1xuICBjb2RlQ2hhbGxlbmdlOiBzdHJpbmc7XG4gIHN0YXRlOiBzdHJpbmc7XG4gIG5vbmNlOiBzdHJpbmc7XG59XG5cbi8qKiBBdXRob3JpemUgVVJMIHdpdGggZ3Jvay1idWlsZCdzIHF1ZXJ5IG9yZGVyIChvaWRjL3Byb3RvY29sLnJzOjMyMS0zNjYpLiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGJ1aWxkR3Jva0F1dGhvcml6ZVVybChpbnB1dDogR3Jva0F1dGhvcml6ZVVybElucHV0KTogc3RyaW5nIHtcbiAgY29uc3QgcXVlcnk6IFtzdHJpbmcsIHN0cmluZ11bXSA9IFtcbiAgICBbXCJyZXNwb25zZV90eXBlXCIsIFwiY29kZVwiXSxcbiAgICBbXCJjbGllbnRfaWRcIiwgR1JPS19PQVVUSF9DTElFTlRfSURdLFxuICAgIFtcInJlZGlyZWN0X3VyaVwiLCBpbnB1dC5yZWRpcmVjdFVyaV0sXG4gICAgW1wic2NvcGVcIiwgR1JPS19PQVVUSF9TQ09QRV0sXG4gICAgW1wiY29kZV9jaGFsbGVuZ2VcIiwgaW5wdXQuY29kZUNoYWxsZW5nZV0sXG4gICAgW1wiY29kZV9jaGFsbGVuZ2VfbWV0aG9kXCIsIFwiUzI1NlwiXSxcbiAgICBbXCJzdGF0ZVwiLCBpbnB1dC5zdGF0ZV0sXG4gICAgW1wibm9uY2VcIiwgaW5wdXQubm9uY2VdLFxuICAgIFtcInJlZmVycmVyXCIsIEdST0tfT0FVVEhfUkVGRVJSRVJdLFxuICBdO1xuXG4gIGNvbnN0IHNlYXJjaCA9IHF1ZXJ5Lm1hcCgoW2tleSwgdmFsdWVdKSA9PiBgJHtrZXl9PSR7ZW5jb2RlUXVlcnlWYWx1ZSh2YWx1ZSl9YCkuam9pbihcIiZcIik7XG5cbiAgcmV0dXJuIGAke2lucHV0LmF1dGhvcml6YXRpb25FbmRwb2ludH0/JHtzZWFyY2h9YDtcbn1cblxuZXhwb3J0IGZ1bmN0aW9uIGdyb2tMb29wYmFja1JlZGlyZWN0VXJpKHBvcnQ6IG51bWJlcik6IHN0cmluZyB7XG4gIGlmICghTnVtYmVyLmlzSW50ZWdlcihwb3J0KSB8fCBwb3J0IDwgMSB8fCBwb3J0ID4gNjVfNTM1KVxuICAgIHRocm93IG5ldyBSYW5nZUVycm9yKFwicmVkaXJlY3QgcG9ydCBtdXN0IGJlIGFuIGludGVnZXIgaW4gMS4uNjU1MzVcIik7XG5cbiAgcmV0dXJuIGBodHRwOi8vMTI3LjAuMC4xOiR7cG9ydH0vY2FsbGJhY2tgO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIFN0YXJ0R3Jva09BdXRoSW5wdXQgZXh0ZW5kcyBHcm9rT0F1dGhJbyB7XG4gIHN0YXRlOiBzdHJpbmc7XG4gIC8qKiBMb29wYmFjayBwb3J0OyBkZWZhdWx0cyB0byBhIHJhbmRvbSBwb3J0IGluIHRoZSBlcGhlbWVyYWwgcmFuZ2UuICovXG4gIHJlZGlyZWN0UG9ydD86IG51bWJlcjtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBTdGFydEdyb2tPQXV0aFJlc3VsdCB7XG4gIGF1dGhvcml6ZVVybDogc3RyaW5nO1xuICB2ZXJpZmllcjogc3RyaW5nO1xuICByZWRpcmVjdFVyaTogc3RyaW5nO1xufVxuXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gc3RhcnRHcm9rT0F1dGgoaW5wdXQ6IFN0YXJ0R3Jva09BdXRoSW5wdXQpOiBQcm9taXNlPFN0YXJ0R3Jva09BdXRoUmVzdWx0PiB7XG4gIGlmICghaW5wdXQuc3RhdGUpIHRocm93IG5ldyBUeXBlRXJyb3IoXCJzdGF0ZSBtdXN0IGJlIG5vbi1lbXB0eVwiKTtcbiAgY29uc3QgZW5kcG9pbnRzID0gYXdhaXQgZ2V0R3Jva09BdXRoRW5kcG9pbnRzKGlucHV0KTtcbiAgY29uc3QgcGtjZSA9IGdlbmVyYXRlR3Jva1BrY2UoKTtcbiAgY29uc3QgcmVkaXJlY3RVcmkgPSBncm9rTG9vcGJhY2tSZWRpcmVjdFVyaShpbnB1dC5yZWRpcmVjdFBvcnQgPz8gcmFuZG9tSW50KDQ5XzE1MiwgNjVfNTM2KSk7XG5cbiAgcmV0dXJuIHtcbiAgICBhdXRob3JpemVVcmw6IGJ1aWxkR3Jva0F1dGhvcml6ZVVybCh7XG4gICAgICBhdXRob3JpemF0aW9uRW5kcG9pbnQ6IGVuZHBvaW50cy5hdXRob3JpemF0aW9uRW5kcG9pbnQsXG4gICAgICByZWRpcmVjdFVyaSxcbiAgICAgIGNvZGVDaGFsbGVuZ2U6IHBrY2UuY29kZUNoYWxsZW5nZSxcbiAgICAgIHN0YXRlOiBpbnB1dC5zdGF0ZSxcbiAgICAgIG5vbmNlOiByYW5kb21VVUlEKCksXG4gICAgfSksXG4gICAgdmVyaWZpZXI6IHBrY2UuY29kZVZlcmlmaWVyLFxuICAgIHJlZGlyZWN0VXJpLFxuICB9O1xufVxuXG4vLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbi8vIENhbGxiYWNrIC8gcGFzdGUgcGFyc2luZ1xuLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG5cbmV4cG9ydCBpbnRlcmZhY2UgR3Jva0NhbGxiYWNrSW5wdXQge1xuICBjb2RlOiBzdHJpbmc7XG4gIC8qKiBFbXB0eSBmb3IgYSBiYXJlIHBhc3RlZCBjb2RlLCB3aGljaCBjYXJyaWVzIG5vIHN0YXRlIChvaWRjL2xvZ2luLnJzOjMzLTYwKS4gKi9cbiAgc3RhdGU6IHN0cmluZztcbn1cblxuY29uc3QgT0FVVEhfRVJST1JfQ09ERSA9IC9eW2Etel9dezEsODB9JC87XG5cbmZ1bmN0aW9uIHNhZmVPQXV0aEVycm9yQ29kZSh2YWx1ZTogc3RyaW5nKTogc3RyaW5nIHwgdW5kZWZpbmVkIHtcbiAgcmV0dXJuIE9BVVRIX0VSUk9SX0NPREUudGVzdCh2YWx1ZSkgPyB2YWx1ZSA6IHVuZGVmaW5lZDtcbn1cblxuLyoqIEFjY2VwdHMgdGhlIGZ1bGwgY2FsbGJhY2sgVVJMIG9yIGEgYmFyZSBhdXRob3JpemF0aW9uIGNvZGUgKG9pZGMvbG9naW4ucnM6MzAtNjApLiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHBhcnNlR3Jva0NhbGxiYWNrSW5wdXQoaW5wdXQ6IHN0cmluZyk6IEdyb2tDYWxsYmFja0lucHV0IHtcbiAgY29uc3QgdHJpbW1lZCA9IGlucHV0LnRyaW0oKTtcblxuICBpZiAoIXRyaW1tZWQpIHRocm93IG5ldyBHcm9rT0F1dGhFcnJvcihcImludmFsaWRfY2FsbGJhY2tfaW5wdXRcIiwgXCJlbXB0eSBjYWxsYmFjayBpbnB1dFwiKTtcblxuICBsZXQgdXJsOiBVUkwgfCB1bmRlZmluZWQ7XG5cbiAgdHJ5IHtcbiAgICB1cmwgPSBuZXcgVVJMKHRyaW1tZWQpO1xuICB9IGNhdGNoIHtcbiAgICB1cmwgPSB1bmRlZmluZWQ7XG4gIH1cblxuICBpZiAodXJsKSB7XG4gICAgY29uc3QgY29kZSA9IHVybC5zZWFyY2hQYXJhbXMuZ2V0KFwiY29kZVwiKTtcblxuICAgIGlmIChjb2RlKSByZXR1cm4geyBjb2RlLCBzdGF0ZTogdXJsLnNlYXJjaFBhcmFtcy5nZXQoXCJzdGF0ZVwiKSA/PyBcIlwiIH07XG4gICAgY29uc3QgZXJyb3IgPSB1cmwuc2VhcmNoUGFyYW1zLmdldChcImVycm9yXCIpO1xuXG4gICAgaWYgKGVycm9yKSB7XG4gICAgICBjb25zdCBvYXV0aEVycm9yID0gc2FmZU9BdXRoRXJyb3JDb2RlKGVycm9yKTtcbiAgICAgIHRocm93IG5ldyBHcm9rT0F1dGhFcnJvcihcbiAgICAgICAgXCJhdXRob3JpemF0aW9uX2ZhaWxlZFwiLFxuICAgICAgICBgYXV0aG9yaXphdGlvbiBmYWlsZWQ6ICR7b2F1dGhFcnJvciA/PyBcInVua25vd25fZXJyb3JcIn1gLFxuICAgICAgICBvYXV0aEVycm9yID09PSB1bmRlZmluZWQgPyB7fSA6IHsgb2F1dGhFcnJvciB9LFxuICAgICAgKTtcbiAgICB9XG5cbiAgICB0aHJvdyBuZXcgR3Jva09BdXRoRXJyb3IoXCJpbnZhbGlkX2NhbGxiYWNrX2lucHV0XCIsIFwiY2FsbGJhY2sgVVJMIGhhcyBubyBjb2RlIHBhcmFtZXRlclwiKTtcbiAgfVxuXG4gIGlmICgvXFxzLy50ZXN0KHRyaW1tZWQpKVxuICAgIHRocm93IG5ldyBHcm9rT0F1dGhFcnJvcihcImludmFsaWRfY2FsbGJhY2tfaW5wdXRcIiwgXCJhdXRob3JpemF0aW9uIGNvZGUgY29udGFpbnMgd2hpdGVzcGFjZVwiKTtcblxuICByZXR1cm4geyBjb2RlOiB0cmltbWVkLCBzdGF0ZTogXCJcIiB9O1xufVxuXG5mdW5jdGlvbiBzdGF0ZXNFcXVhbChleHBlY3RlZDogc3RyaW5nLCByZWNlaXZlZDogc3RyaW5nKTogYm9vbGVhbiB7XG4gIGNvbnN0IGEgPSBCdWZmZXIuZnJvbShleHBlY3RlZCk7XG4gIGNvbnN0IGIgPSBCdWZmZXIuZnJvbShyZWNlaXZlZCk7XG5cbiAgcmV0dXJuIGEubGVuZ3RoID09PSBiLmxlbmd0aCAmJiB0aW1pbmdTYWZlRXF1YWwoYSwgYik7XG59XG5cbi8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuLy8gVG9rZW4gZXhjaGFuZ2UgYW5kIGZpbmlzaGluZ1xuLy8gLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tXG5cbmV4cG9ydCBjb25zdCBHcm9rVG9rZW5SZXNwb25zZSA9IHoubG9vc2VPYmplY3Qoe1xuICBhY2Nlc3NfdG9rZW46IHouc3RyaW5nKCkubWluKDEpLFxuICByZWZyZXNoX3Rva2VuOiB6LnN0cmluZygpLm1pbigxKS5udWxsaXNoKCksXG4gIGlkX3Rva2VuOiB6LnN0cmluZygpLm51bGxpc2goKSxcbiAgZXhwaXJlc19pbjogei5udW1iZXIoKS5ub25uZWdhdGl2ZSgpLm51bGxpc2goKSxcbiAgc2NvcGU6IHouc3RyaW5nKCkubnVsbGlzaCgpLFxuICB0b2tlbl90eXBlOiB6LnN0cmluZygpLm51bGxpc2goKSxcbn0pO1xuXG5leHBvcnQgdHlwZSBHcm9rVG9rZW5SZXNwb25zZSA9IHouaW5mZXI8dHlwZW9mIEdyb2tUb2tlblJlc3BvbnNlPjtcblxuY29uc3QgT0F1dGhFcnJvckJvZHkgPSB6Lmxvb3NlT2JqZWN0KHsgZXJyb3I6IHouc3RyaW5nKCkgfSk7XG5cbi8qKiBSZWFkcyB0aGUgT0F1dGggYGVycm9yYCBjb2RlIGZyb20gYSBmYWlsZWQgcmVzcG9uc2Ugd2l0aG91dCByZXRhaW5pbmcgdGhlIGJvZHkuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gcmVhZEdyb2tPQXV0aEVycm9yQ29kZShyZXNwb25zZTogUmVzcG9uc2UpOiBQcm9taXNlPHN0cmluZyB8IHVuZGVmaW5lZD4ge1xuICBjb25zdCB0ZXh0ID0gYXdhaXQgcmVzcG9uc2UudGV4dCgpLmNhdGNoKCgpID0+IFwiXCIpO1xuXG4gIHRyeSB7XG4gICAgY29uc3QgcGFyc2VkID0gT0F1dGhFcnJvckJvZHkuc2FmZVBhcnNlKEpTT04ucGFyc2UodGV4dCkpO1xuXG4gICAgcmV0dXJuIHBhcnNlZC5zdWNjZXNzID8gc2FmZU9BdXRoRXJyb3JDb2RlKHBhcnNlZC5kYXRhLmVycm9yKSA6IHVuZGVmaW5lZDtcbiAgfSBjYXRjaCB7XG4gICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgfVxufVxuXG5mdW5jdGlvbiBmb3JtSGVhZGVycyhleHRyYTogUmVjb3JkPHN0cmluZywgc3RyaW5nPiA9IHt9KSB7XG4gIHJldHVybiB7XG4gICAgXCJ1c2VyLWFnZW50XCI6IGdyb2tTaGVsbFVzZXJBZ2VudCgpLFxuICAgIC4uLmV4dHJhLFxuICAgIFwiY29udGVudC10eXBlXCI6IFwiYXBwbGljYXRpb24veC13d3ctZm9ybS11cmxlbmNvZGVkXCIsXG4gICAgYWNjZXB0OiBcImFwcGxpY2F0aW9uL2pzb25cIixcbiAgfTtcbn1cblxuYXN5bmMgZnVuY3Rpb24gcGFyc2VUb2tlblJlc3BvbnNlKHJlc3BvbnNlOiBSZXNwb25zZSk6IFByb21pc2U8R3Jva1Rva2VuUmVzcG9uc2U+IHtcbiAgbGV0IGJvZHk6IHVua25vd247XG5cbiAgdHJ5IHtcbiAgICBib2R5ID0gYXdhaXQgcmVzcG9uc2UuanNvbigpO1xuICB9IGNhdGNoIHtcbiAgICB0aHJvdyBuZXcgR3Jva09BdXRoRXJyb3IoXCJpbnZhbGlkX3Rva2VuX3Jlc3BvbnNlXCIsIFwidG9rZW4gcmVzcG9uc2UgaXMgbm90IEpTT05cIik7XG4gIH1cblxuICBjb25zdCBwYXJzZWQgPSBHcm9rVG9rZW5SZXNwb25zZS5zYWZlUGFyc2UoYm9keSk7XG5cbiAgaWYgKCFwYXJzZWQuc3VjY2VzcylcbiAgICB0aHJvdyBuZXcgR3Jva09BdXRoRXJyb3IoXCJpbnZhbGlkX3Rva2VuX3Jlc3BvbnNlXCIsIFwidG9rZW4gcmVzcG9uc2UgZmFpbGVkIHZhbGlkYXRpb25cIik7XG5cbiAgcmV0dXJuIHBhcnNlZC5kYXRhO1xufVxuXG5mdW5jdGlvbiBuZXR3b3JrRXJyb3IoY29kZTogR3Jva09BdXRoRXJyb3JDb2RlLCB3aGF0OiBzdHJpbmcsIGNhdXNlOiB1bmtub3duKTogR3Jva09BdXRoRXJyb3Ige1xuICBjb25zdCByZWFzb24gPSBjYXVzZSBpbnN0YW5jZW9mIEVycm9yID8gY2F1c2UubmFtZSA6IFwidW5rbm93blwiO1xuXG4gIHJldHVybiBuZXcgR3Jva09BdXRoRXJyb3IoY29kZSwgYCR7d2hhdH0gcmVxdWVzdCBmYWlsZWQgKCR7cmVhc29ufSlgLCB7IHJldHJ5YWJsZTogdHJ1ZSB9KTtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBGaW5pc2hHcm9rTG9naW5JbnB1dCBleHRlbmRzIEdyb2tPQXV0aElvIHtcbiAgdG9rZW5zOiBHcm9rVG9rZW5SZXNwb25zZTtcbiAgcmVxdWVzdGVkU2NvcGVzPzogcmVhZG9ubHkgc3RyaW5nW107XG59XG5cbi8qKlxuICogVmFsaWRhdGVzIHRoZSB0b2tlbiByZXNwb25zZSwgcmVzb2x2ZXMgdGhlIGFjY291bnQgaWQgKEpXVCBgc3ViYCwgY29uZmlybWVkIGJ5XG4gKiBgR0VUIC91c2VyP2luY2x1ZGU9c3Vic2NyaXB0aW9uYCksIGFuZCBidWlsZHMgc3RvcmVkIGNyZWRlbnRpYWxzLlxuICovXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gZmluaXNoR3Jva0xvZ2luKGlucHV0OiBGaW5pc2hHcm9rTG9naW5JbnB1dCk6IFByb21pc2U8R3Jva0NyZWRlbnRpYWxzPiB7XG4gIGNvbnN0IGZldGNoSW1wbCA9IGlucHV0LmZldGNoID8/IGdsb2JhbFRoaXMuZmV0Y2g7XG4gIGNvbnN0IG5vdyA9IGlucHV0Lm5vdyA/PyBEYXRlLm5vdztcbiAgY29uc3QgeyB0b2tlbnMgfSA9IGlucHV0O1xuXG4gIGlmICghaXNHcm9rQWNjZXNzVG9rZW4odG9rZW5zLmFjY2Vzc190b2tlbikpXG4gICAgdGhyb3cgbmV3IEdyb2tPQXV0aEVycm9yKFxuICAgICAgXCJpbnZhbGlkX2FjY2Vzc190b2tlblwiLFxuICAgICAgYGFjY2VzcyB0b2tlbiBpcyBub3QgYW4gYXQrand0IGlzc3VlZCBieSAke0dST0tfQVVUSF9JU1NVRVJ9YCxcbiAgICApO1xuXG4gIGlmICghdG9rZW5zLnJlZnJlc2hfdG9rZW4pXG4gICAgdGhyb3cgbmV3IEdyb2tPQXV0aEVycm9yKFwibWlzc2luZ19yZWZyZXNoX3Rva2VuXCIsIFwidG9rZW4gcmVzcG9uc2UgaGFzIG5vIHJlZnJlc2ggdG9rZW5cIik7XG5cbiAgY29uc3QgZGVjb2RlZCA9IGRlY29kZUdyb2tKd3QodG9rZW5zLmFjY2Vzc190b2tlbik7XG4gIGNvbnN0IHN1YmplY3QgPSBkZWNvZGVkPy5wYXlsb2FkLnN1YjtcblxuICBpZiAoIXN1YmplY3QpXG4gICAgdGhyb3cgbmV3IEdyb2tPQXV0aEVycm9yKFwidXNlcl9pZF91bnJlc29sdmVkXCIsIFwiYWNjZXNzIHRva2VuIGhhcyBubyBzdWJqZWN0IChzdWIpIGNsYWltXCIpO1xuXG4gIGxldCByZXNwb25zZTogUmVzcG9uc2U7XG5cbiAgdHJ5IHtcbiAgICByZXNwb25zZSA9IGF3YWl0IGZldGNoSW1wbChgJHtHUk9LX0NIQVRfUFJPWFlfVVJMfS91c2VyP2luY2x1ZGU9c3Vic2NyaXB0aW9uYCwge1xuICAgICAgbWV0aG9kOiBcIkdFVFwiLFxuICAgICAgaGVhZGVyczogYnVpbGRHcm9rUHJveHlHZXRIZWFkZXJzKHsgYmVhcmVyOiB0b2tlbnMuYWNjZXNzX3Rva2VuLCB1c2VySWQ6IHN1YmplY3QgfSksXG4gICAgICBzaWduYWw6IEFib3J0U2lnbmFsLnRpbWVvdXQoVVNFUl9MT09LVVBfVElNRU9VVF9NUyksXG4gICAgfSk7XG4gIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgdGhyb3cgbmV0d29ya0Vycm9yKFwidXNlcl9sb29rdXBfZmFpbGVkXCIsIFwidXNlciBsb29rdXBcIiwgZXJyb3IpO1xuICB9XG5cbiAgaWYgKCFyZXNwb25zZS5vaykge1xuICAgIGF3YWl0IHJlc3BvbnNlLmJvZHk/LmNhbmNlbCgpLmNhdGNoKCgpID0+IHVuZGVmaW5lZCk7XG4gICAgdGhyb3cgbmV3IEdyb2tPQXV0aEVycm9yKFwidXNlcl9sb29rdXBfZmFpbGVkXCIsIGB1c2VyIGxvb2t1cCBmYWlsZWQ6IEhUVFAgJHtyZXNwb25zZS5zdGF0dXN9YCwge1xuICAgICAgc3RhdHVzOiByZXNwb25zZS5zdGF0dXMsXG4gICAgICByZXRyeWFibGU6IHJlc3BvbnNlLnN0YXR1cyA+PSA1MDAgfHwgcmVzcG9uc2Uuc3RhdHVzID09PSA0MjksXG4gICAgfSk7XG4gIH1cblxuICBsZXQgdXNlckJvZHk6IHVua25vd247XG5cbiAgdHJ5IHtcbiAgICB1c2VyQm9keSA9IGF3YWl0IHJlc3BvbnNlLmpzb24oKTtcbiAgfSBjYXRjaCB7XG4gICAgdGhyb3cgbmV3IEdyb2tPQXV0aEVycm9yKFwidXNlcl9pZF91bnJlc29sdmVkXCIsIFwidXNlciBsb29rdXAgcmV0dXJuZWQgbm9uLUpTT05cIik7XG4gIH1cblxuICBjb25zdCB1c2VyID0gR3Jva1VzZXJTdWJzY3JpcHRpb24uc2FmZVBhcnNlKHVzZXJCb2R5KTtcblxuICBpZiAoIXVzZXIuc3VjY2VzcylcbiAgICB0aHJvdyBuZXcgR3Jva09BdXRoRXJyb3IoXCJ1c2VyX2lkX3VucmVzb2x2ZWRcIiwgXCJ1c2VyIGxvb2t1cCBkaWQgbm90IHJldHVybiBhIHZhbGlkIHVzZXJJZFwiKTtcblxuICBjb25zdCBpc3N1ZWRBdCA9IG5vdygpO1xuICBjb25zdCBleHBpcmVzSW4gPSB0b2tlbnMuZXhwaXJlc19pbjtcbiAgY29uc3Qgand0RXhwaXJ5ID0gZGVjb2RlZD8ucGF5bG9hZC5leHA7XG5cbiAgY29uc3QgZXhwaXJlc0F0TXMgPVxuICAgIGV4cGlyZXNJbiAhPT0gdW5kZWZpbmVkICYmIGV4cGlyZXNJbiAhPT0gbnVsbFxuICAgICAgPyBpc3N1ZWRBdCArIGV4cGlyZXNJbiAqIDEwMDBcbiAgICAgIDogand0RXhwaXJ5ICE9PSB1bmRlZmluZWRcbiAgICAgICAgPyBqd3RFeHBpcnkgKiAxMDAwXG4gICAgICAgIDogdW5kZWZpbmVkO1xuXG4gIGlmIChleHBpcmVzQXRNcyA9PT0gdW5kZWZpbmVkIHx8ICFOdW1iZXIuaXNGaW5pdGUoZXhwaXJlc0F0TXMpKVxuICAgIHRocm93IG5ldyBHcm9rT0F1dGhFcnJvcihcIm1pc3NpbmdfZXhwaXJ5XCIsIFwidG9rZW4gcmVzcG9uc2UgaGFzIG5vIGV4cGlyeVwiKTtcblxuICBjb25zdCBncmFudGVkU2NvcGVzID0gdG9rZW5zLnNjb3BlPy5zcGxpdChcIiBcIikuZmlsdGVyKEJvb2xlYW4pO1xuXG4gIGNvbnN0IGNhbmRpZGF0ZTogR3Jva0NyZWRlbnRpYWxzID0ge1xuICAgIGF1dGhNb2RlOiBcIm9hdXRoXCIgYXMgY29uc3QsXG4gICAgYWNjZXNzVG9rZW46IHRva2Vucy5hY2Nlc3NfdG9rZW4sXG4gICAgcmVmcmVzaFRva2VuOiB0b2tlbnMucmVmcmVzaF90b2tlbixcbiAgICBleHBpcmVzQXQ6IG5ldyBEYXRlKGV4cGlyZXNBdE1zKS50b0lTT1N0cmluZygpLFxuICAgIGlzc3VlcjogR1JPS19BVVRIX0lTU1VFUixcbiAgICBjbGllbnRJZDogR1JPS19PQVVUSF9DTElFTlRfSUQsXG4gICAgc2NvcGVzOlxuICAgICAgZ3JhbnRlZFNjb3BlcyAmJiBncmFudGVkU2NvcGVzLmxlbmd0aCA+IDBcbiAgICAgICAgPyBncmFudGVkU2NvcGVzXG4gICAgICAgIDogWy4uLihpbnB1dC5yZXF1ZXN0ZWRTY29wZXMgPz8gR1JPS19PQVVUSF9TQ09QRVMpXSxcbiAgICB1c2VySWQ6IHVzZXIuZGF0YS51c2VySWQsXG4gICAgc2Vzc2lvbklkOiByYW5kb21VVUlEKCksXG4gICAgYWdlbnRJZDogcmFuZG9tVVVJRCgpLFxuICB9O1xuXG4gIGlmICh1c2VyLmRhdGEuc3Vic2NyaXB0aW9uVGllcikgY2FuZGlkYXRlLnN1YnNjcmlwdGlvblRpZXIgPSB1c2VyLmRhdGEuc3Vic2NyaXB0aW9uVGllcjtcblxuICBjb25zdCBjcmVkZW50aWFscyA9IEdyb2tDcmVkZW50aWFscy5zYWZlUGFyc2UoY2FuZGlkYXRlKTtcblxuICBpZiAoIWNyZWRlbnRpYWxzLnN1Y2Nlc3MpXG4gICAgdGhyb3cgbmV3IEdyb2tPQXV0aEVycm9yKFwiaW52YWxpZF9jcmVkZW50aWFsc1wiLCBcImNyZWRlbnRpYWxzIGZhaWxlZCB2YWxpZGF0aW9uXCIpO1xuXG4gIHJldHVybiBjcmVkZW50aWFscy5kYXRhO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIENvbXBsZXRlR3Jva09BdXRoSW5wdXQgZXh0ZW5kcyBHcm9rT0F1dGhJbyB7XG4gIGNvZGVPclVybDogc3RyaW5nO1xuICB2ZXJpZmllcjogc3RyaW5nO1xuICByZWRpcmVjdFVyaTogc3RyaW5nO1xuICAvKiogVGhlIHN0YXRlIGlzc3VlZCB3aXRoIHRoZSBhdXRob3JpemUgVVJMOyBhIHBhc3RlZCBVUkwgbXVzdCBlY2hvIGl0LiAqL1xuICBzdGF0ZTogc3RyaW5nO1xufVxuXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gY29tcGxldGVHcm9rT0F1dGgoaW5wdXQ6IENvbXBsZXRlR3Jva09BdXRoSW5wdXQpOiBQcm9taXNlPEdyb2tDcmVkZW50aWFscz4ge1xuICBjb25zdCBmZXRjaEltcGwgPSBpbnB1dC5mZXRjaCA/PyBnbG9iYWxUaGlzLmZldGNoO1xuICBjb25zdCBjYWxsYmFjayA9IHBhcnNlR3Jva0NhbGxiYWNrSW5wdXQoaW5wdXQuY29kZU9yVXJsKTtcblxuICAvLyBBIGJhcmUgY29kZSBjYXJyaWVzIG5vIHN0YXRlOyB0aGUgY2FsbGVyIGJpbmRzIGl0IHRvIHRoZSBwZW5kaW5nIGxvZ2luIChvaWRjL2xvZ2luLnJzOjQ1Mi00NTUpLlxuICBpZiAoY2FsbGJhY2suc3RhdGUgJiYgIXN0YXRlc0VxdWFsKGlucHV0LnN0YXRlLCBjYWxsYmFjay5zdGF0ZSkpXG4gICAgdGhyb3cgbmV3IEdyb2tPQXV0aEVycm9yKFwic3RhdGVfbWlzbWF0Y2hcIiwgXCJPQXV0aCBzdGF0ZSBtaXNtYXRjaFwiKTtcblxuICBjb25zdCBlbmRwb2ludHMgPSBhd2FpdCBnZXRHcm9rT0F1dGhFbmRwb2ludHMoaW5wdXQpO1xuICBsZXQgcmVzcG9uc2U6IFJlc3BvbnNlO1xuXG4gIHRyeSB7XG4gICAgcmVzcG9uc2UgPSBhd2FpdCBmZXRjaEltcGwoZW5kcG9pbnRzLnRva2VuRW5kcG9pbnQsIHtcbiAgICAgIG1ldGhvZDogXCJQT1NUXCIsXG4gICAgICAvLyBvaWRjL3Byb3RvY29sLnJzOjM4NS0zOTk6IGZvcm0gYm9keSwgeC1ncm9rLWNsaWVudC12ZXJzaW9uLCBzaGFyZWQtY2xpZW50IFVBLlxuICAgICAgaGVhZGVyczogZm9ybUhlYWRlcnMoeyBcIngtZ3Jvay1jbGllbnQtdmVyc2lvblwiOiBHUk9LX0JVSUxEX1ZFUlNJT04gfSksXG4gICAgICBib2R5OiBuZXcgVVJMU2VhcmNoUGFyYW1zKFtcbiAgICAgICAgW1wiZ3JhbnRfdHlwZVwiLCBcImF1dGhvcml6YXRpb25fY29kZVwiXSxcbiAgICAgICAgW1wiY29kZVwiLCBjYWxsYmFjay5jb2RlXSxcbiAgICAgICAgW1wicmVkaXJlY3RfdXJpXCIsIGlucHV0LnJlZGlyZWN0VXJpXSxcbiAgICAgICAgW1wiY2xpZW50X2lkXCIsIEdST0tfT0FVVEhfQ0xJRU5UX0lEXSxcbiAgICAgICAgW1wiY29kZV92ZXJpZmllclwiLCBpbnB1dC52ZXJpZmllcl0sXG4gICAgICBdKSxcbiAgICAgIHNpZ25hbDogQWJvcnRTaWduYWwudGltZW91dChUT0tFTl9USU1FT1VUX01TKSxcbiAgICB9KTtcbiAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICB0aHJvdyBuZXR3b3JrRXJyb3IoXCJ0b2tlbl9leGNoYW5nZV9mYWlsZWRcIiwgXCJ0b2tlbiBleGNoYW5nZVwiLCBlcnJvcik7XG4gIH1cblxuICBpZiAoIXJlc3BvbnNlLm9rKSB7XG4gICAgY29uc3Qgb2F1dGhFcnJvciA9IGF3YWl0IHJlYWRHcm9rT0F1dGhFcnJvckNvZGUocmVzcG9uc2UpO1xuICAgIGNvbnN0IGVycm9yT3B0aW9uczogR3Jva09BdXRoRXJyb3JbXCJvcHRpb25zXCJdID0geyBzdGF0dXM6IHJlc3BvbnNlLnN0YXR1cyB9O1xuXG4gICAgaWYgKG9hdXRoRXJyb3IgIT09IHVuZGVmaW5lZCkgZXJyb3JPcHRpb25zLm9hdXRoRXJyb3IgPSBvYXV0aEVycm9yO1xuICAgIGVycm9yT3B0aW9ucy5yZXRyeWFibGUgPSByZXNwb25zZS5zdGF0dXMgPj0gNTAwO1xuICAgIHRocm93IG5ldyBHcm9rT0F1dGhFcnJvcihcbiAgICAgIFwidG9rZW5fZXhjaGFuZ2VfZmFpbGVkXCIsXG4gICAgICBgdG9rZW4gZXhjaGFuZ2UgZmFpbGVkOiBIVFRQICR7cmVzcG9uc2Uuc3RhdHVzfSAke29hdXRoRXJyb3IgPz8gXCJ1bmtub3duXCJ9YCxcbiAgICAgIGVycm9yT3B0aW9ucyxcbiAgICApO1xuICB9XG5cbiAgcmV0dXJuIGZpbmlzaEdyb2tMb2dpbih7XG4gICAgLi4uaW5wdXQsXG4gICAgZmV0Y2g6IGZldGNoSW1wbCxcbiAgICB0b2tlbnM6IGF3YWl0IHBhcnNlVG9rZW5SZXNwb25zZShyZXNwb25zZSksXG4gIH0pO1xufVxuXG4vLyAtLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS1cbi8vIERldmljZSBjb2RlIChSRkMgODYyOClcbi8vIC0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLS0tLVxuXG4vLyBkZXZpY2VfY29kZS5yczoxOS0yMFxuZXhwb3J0IGNvbnN0IEdST0tfREVWSUNFX0RFRkFVTFRfSU5URVJWQUxfUyA9IDU7XG5leHBvcnQgY29uc3QgR1JPS19ERVZJQ0VfU0xPV19ET1dOX0lOQ1JFTUVOVF9TID0gNTtcbmNvbnN0IERFVklDRV9HUkFOVF9UWVBFID0gXCJ1cm46aWV0ZjpwYXJhbXM6b2F1dGg6Z3JhbnQtdHlwZTpkZXZpY2VfY29kZVwiO1xuXG4vLyBUaGUgZGFzaGJvYXJkIHJlbmRlcnMgdGhlIFVSTCBhbmQgY29kZSB0byBhIGh1bWFuIChkZXZpY2VfY29kZS5yczoyNjYtMjcxIOKGkiBgdWlgKS5cbmNvbnN0IERFVklDRV9DTElFTlRfU1VSRkFDRSA9IFwidWlcIjtcblxuZnVuY3Rpb24gaXNBbGxvd2VkVmVyaWZpY2F0aW9uVXJpKHZhbHVlOiBzdHJpbmcpOiBib29sZWFuIHtcbiAgLy8gZGV2aWNlX2NvZGUucnM6NDc1LTQ4ODogcmVqZWN0IGNvbnRyb2wgY2hhcmFjdGVycywgcmVxdWlyZSBodHRwcyAoaHR0cCBvbmx5IG9uIGxvb3BiYWNrKS5cbiAgLy8gQ29udHJvbCBjaGFyYWN0ZXJzIGFyZSBzaW5nbGUgVVRGLTE2IGNvZGUgdW5pdHMsIHNvIHNjYW5uaW5nIGNvZGUgdW5pdHMgaXMgZXhhY3QuXG4gIGZvciAobGV0IGluZGV4ID0gMDsgaW5kZXggPCB2YWx1ZS5sZW5ndGg7IGluZGV4KyspIHtcbiAgICBjb25zdCBjb2RlID0gdmFsdWUuY2hhckNvZGVBdChpbmRleCk7XG5cbiAgICBpZiAoY29kZSA8IDB4MjAgfHwgY29kZSA9PT0gMHg3ZikgcmV0dXJuIGZhbHNlO1xuICB9XG5cbiAgbGV0IHVybDogVVJMO1xuXG4gIHRyeSB7XG4gICAgdXJsID0gbmV3IFVSTCh2YWx1ZSk7XG4gIH0gY2F0Y2gge1xuICAgIHJldHVybiBmYWxzZTtcbiAgfVxuXG4gIGlmICh1cmwucHJvdG9jb2wgPT09IFwiaHR0cHM6XCIpIHJldHVybiB0cnVlO1xuXG4gIHJldHVybiB1cmwucHJvdG9jb2wgPT09IFwiaHR0cDpcIiAmJiAodXJsLmhvc3RuYW1lID09PSBcImxvY2FsaG9zdFwiIHx8IHVybC5ob3N0bmFtZSA9PT0gXCIxMjcuMC4wLjFcIik7XG59XG5cbmNvbnN0IERldmljZUNvZGVSZXNwb25zZSA9IHoubG9vc2VPYmplY3Qoe1xuICBkZXZpY2VfY29kZTogei5zdHJpbmcoKS5taW4oMSksXG4gIHVzZXJfY29kZTogei5zdHJpbmcoKS5yZWdleCgvXltBLVphLXowLTktXSskLyksXG4gIHZlcmlmaWNhdGlvbl91cmk6IHouc3RyaW5nKCkucmVmaW5lKGlzQWxsb3dlZFZlcmlmaWNhdGlvblVyaSksXG4gIHZlcmlmaWNhdGlvbl91cmlfY29tcGxldGU6IHouc3RyaW5nKCkucmVmaW5lKGlzQWxsb3dlZFZlcmlmaWNhdGlvblVyaSkubnVsbGlzaCgpLFxuICBleHBpcmVzX2luOiB6Lm51bWJlcigpLnBvc2l0aXZlKCksXG4gIGludGVydmFsOiB6Lm51bWJlcigpLmludCgpLnBvc2l0aXZlKCkubnVsbGlzaCgpLFxufSk7XG5cbmV4cG9ydCBpbnRlcmZhY2UgR3Jva0RldmljZUNvZGUge1xuICBkZXZpY2VDb2RlOiBzdHJpbmc7XG4gIHVzZXJDb2RlOiBzdHJpbmc7XG4gIHZlcmlmaWNhdGlvblVyaTogc3RyaW5nO1xuICB2ZXJpZmljYXRpb25VcmlDb21wbGV0ZT86IHN0cmluZztcbiAgLyoqIFNlY29uZHMgdW50aWwgdGhlIGRldmljZSBjb2RlIGV4cGlyZXMuICovXG4gIGV4cGlyZXNJbjogbnVtYmVyO1xuICAvKiogU2Vjb25kcyB0byB3YWl0IGJlZm9yZSB0aGUgbmV4dCBwb2xsLiAqL1xuICBpbnRlcnZhbDogbnVtYmVyO1xufVxuXG5mdW5jdGlvbiBkZXZpY2VIZWFkZXJzKCk6IFJlY29yZDxzdHJpbmcsIHN0cmluZz4ge1xuICByZXR1cm4gZm9ybUhlYWRlcnMoe1xuICAgIFwieC1ncm9rLWNsaWVudC12ZXJzaW9uXCI6IEdST0tfQlVJTERfVkVSU0lPTixcbiAgICBcIngtZ3Jvay1jbGllbnQtc3VyZmFjZVwiOiBERVZJQ0VfQ0xJRU5UX1NVUkZBQ0UsXG4gIH0pO1xufVxuXG5leHBvcnQgYXN5bmMgZnVuY3Rpb24gc3RhcnRHcm9rRGV2aWNlQ29kZShpbzogR3Jva09BdXRoSW8gPSB7fSk6IFByb21pc2U8R3Jva0RldmljZUNvZGU+IHtcbiAgY29uc3QgZmV0Y2hJbXBsID0gaW8uZmV0Y2ggPz8gZ2xvYmFsVGhpcy5mZXRjaDtcbiAgbGV0IHJlc3BvbnNlOiBSZXNwb25zZTtcblxuICB0cnkge1xuICAgIHJlc3BvbnNlID0gYXdhaXQgZmV0Y2hJbXBsKEdST0tfREVWSUNFX0NPREVfVVJMLCB7XG4gICAgICBtZXRob2Q6IFwiUE9TVFwiLFxuICAgICAgaGVhZGVyczogZGV2aWNlSGVhZGVycygpLFxuICAgICAgYm9keTogbmV3IFVSTFNlYXJjaFBhcmFtcyhbXG4gICAgICAgIFtcImNsaWVudF9pZFwiLCBHUk9LX09BVVRIX0NMSUVOVF9JRF0sXG4gICAgICAgIFtcInNjb3BlXCIsIEdST0tfT0FVVEhfU0NPUEVdLFxuICAgICAgICBbXCJyZWZlcnJlclwiLCBHUk9LX09BVVRIX1JFRkVSUkVSXSxcbiAgICAgIF0pLFxuICAgICAgc2lnbmFsOiBBYm9ydFNpZ25hbC50aW1lb3V0KFRPS0VOX1RJTUVPVVRfTVMpLFxuICAgIH0pO1xuICB9IGNhdGNoIChlcnJvcikge1xuICAgIHRocm93IG5ldHdvcmtFcnJvcihcImRldmljZV9jb2RlX2ZhaWxlZFwiLCBcImRldmljZSBjb2RlXCIsIGVycm9yKTtcbiAgfVxuXG4gIGlmICghcmVzcG9uc2Uub2spIHtcbiAgICBhd2FpdCByZXNwb25zZS5ib2R5Py5jYW5jZWwoKS5jYXRjaCgoKSA9PiB1bmRlZmluZWQpO1xuXG4gICAgaWYgKHJlc3BvbnNlLnN0YXR1cyA9PT0gNDA0KVxuICAgICAgdGhyb3cgbmV3IEdyb2tPQXV0aEVycm9yKFwiZGV2aWNlX2Zsb3dfbm90X2VuYWJsZWRcIiwgXCJkZXZpY2UtY29kZSBsb2dpbiBpcyBub3QgYXZhaWxhYmxlXCIsIHtcbiAgICAgICAgc3RhdHVzOiA0MDQsXG4gICAgICB9KTtcbiAgICB0aHJvdyBuZXcgR3Jva09BdXRoRXJyb3IoXG4gICAgICBcImRldmljZV9jb2RlX2ZhaWxlZFwiLFxuICAgICAgYGRldmljZSBjb2RlIHJlcXVlc3QgZmFpbGVkOiBIVFRQICR7cmVzcG9uc2Uuc3RhdHVzfWAsXG4gICAgICB7IHN0YXR1czogcmVzcG9uc2Uuc3RhdHVzLCByZXRyeWFibGU6IHJlc3BvbnNlLnN0YXR1cyA+PSA1MDAgfHwgcmVzcG9uc2Uuc3RhdHVzID09PSA0MjkgfSxcbiAgICApO1xuICB9XG5cbiAgbGV0IGJvZHk6IHVua25vd247XG5cbiAgdHJ5IHtcbiAgICBib2R5ID0gYXdhaXQgcmVzcG9uc2UuanNvbigpO1xuICB9IGNhdGNoIHtcbiAgICB0aHJvdyBuZXcgR3Jva09BdXRoRXJyb3IoXCJpbnZhbGlkX2RldmljZV9jb2RlX3Jlc3BvbnNlXCIsIFwiZGV2aWNlIGNvZGUgcmVzcG9uc2UgaXMgbm90IEpTT05cIik7XG4gIH1cblxuICBjb25zdCBwYXJzZWQgPSBEZXZpY2VDb2RlUmVzcG9uc2Uuc2FmZVBhcnNlKGJvZHkpO1xuXG4gIGlmICghcGFyc2VkLnN1Y2Nlc3MpXG4gICAgdGhyb3cgbmV3IEdyb2tPQXV0aEVycm9yKFxuICAgICAgXCJpbnZhbGlkX2RldmljZV9jb2RlX3Jlc3BvbnNlXCIsXG4gICAgICBcImRldmljZSBjb2RlIHJlc3BvbnNlIGZhaWxlZCB2YWxpZGF0aW9uXCIsXG4gICAgKTtcbiAgY29uc3QgZGF0YSA9IHBhcnNlZC5kYXRhO1xuXG4gIGNvbnN0IGRldmljZUNvZGU6IEdyb2tEZXZpY2VDb2RlID0ge1xuICAgIGRldmljZUNvZGU6IGRhdGEuZGV2aWNlX2NvZGUsXG4gICAgdXNlckNvZGU6IGRhdGEudXNlcl9jb2RlLFxuICAgIHZlcmlmaWNhdGlvblVyaTogZGF0YS52ZXJpZmljYXRpb25fdXJpLFxuICAgIGV4cGlyZXNJbjogZGF0YS5leHBpcmVzX2luLFxuICAgIGludGVydmFsOiBkYXRhLmludGVydmFsID8/IEdST0tfREVWSUNFX0RFRkFVTFRfSU5URVJWQUxfUyxcbiAgfTtcblxuICBpZiAoZGF0YS52ZXJpZmljYXRpb25fdXJpX2NvbXBsZXRlKSB7XG4gICAgZGV2aWNlQ29kZS52ZXJpZmljYXRpb25VcmlDb21wbGV0ZSA9IGRhdGEudmVyaWZpY2F0aW9uX3VyaV9jb21wbGV0ZTtcbiAgfVxuXG4gIHJldHVybiBkZXZpY2VDb2RlO1xufVxuXG5leHBvcnQgdHlwZSBHcm9rRGV2aWNlUG9sbFJlc3VsdCA9XG4gIHwgeyBzdGF0dXM6IFwicGVuZGluZ1wiOyBpbnRlcnZhbDogbnVtYmVyIH1cbiAgfCB7IHN0YXR1czogXCJjb21wbGV0ZVwiOyBjcmVkZW50aWFsczogR3Jva0NyZWRlbnRpYWxzIH07XG5cbmV4cG9ydCBpbnRlcmZhY2UgUG9sbEdyb2tEZXZpY2VDb2RlSW5wdXQgZXh0ZW5kcyBHcm9rT0F1dGhJbyB7XG4gIGRldmljZUNvZGU6IHN0cmluZztcbiAgLyoqIEN1cnJlbnQgcG9sbCBpbnRlcnZhbCBpbiBzZWNvbmRzOyB0aGUgcmVzdWx0IGNhcnJpZXMgdGhlIGludGVydmFsIGZvciB0aGUgbmV4dCBwb2xsLiAqL1xuICBpbnRlcnZhbDogbnVtYmVyO1xufVxuXG4vKipcbiAqIE9uZSBwb2xsIG9mIHRoZSBkZXZpY2UgdG9rZW4gZW5kcG9pbnQuIFRoZSBjYWxsZXIgc2xlZXBzIGBpbnRlcnZhbGAgc2Vjb25kcyBiZXR3ZWVuIHBvbGxzIGFuZFxuICogZW5mb3JjZXMgdGhlIGRldmljZS1jb2RlIGV4cGlyeTsgdGhpcyBmdW5jdGlvbiBuZXZlciBsb29wcy5cbiAqL1xuZXhwb3J0IGFzeW5jIGZ1bmN0aW9uIHBvbGxHcm9rRGV2aWNlQ29kZShcbiAgaW5wdXQ6IFBvbGxHcm9rRGV2aWNlQ29kZUlucHV0LFxuKTogUHJvbWlzZTxHcm9rRGV2aWNlUG9sbFJlc3VsdD4ge1xuICBjb25zdCBmZXRjaEltcGwgPSBpbnB1dC5mZXRjaCA/PyBnbG9iYWxUaGlzLmZldGNoO1xuICBjb25zdCBpbnRlcnZhbCA9IE1hdGgubWF4KDEsIE1hdGguY2VpbChpbnB1dC5pbnRlcnZhbCkpO1xuICBsZXQgcmVzcG9uc2U6IFJlc3BvbnNlO1xuXG4gIHRyeSB7XG4gICAgcmVzcG9uc2UgPSBhd2FpdCBmZXRjaEltcGwoR1JPS19ERVZJQ0VfVE9LRU5fVVJMLCB7XG4gICAgICBtZXRob2Q6IFwiUE9TVFwiLFxuICAgICAgaGVhZGVyczogZGV2aWNlSGVhZGVycygpLFxuICAgICAgYm9keTogbmV3IFVSTFNlYXJjaFBhcmFtcyhbXG4gICAgICAgIFtcImdyYW50X3R5cGVcIiwgREVWSUNFX0dSQU5UX1RZUEVdLFxuICAgICAgICBbXCJkZXZpY2VfY29kZVwiLCBpbnB1dC5kZXZpY2VDb2RlXSxcbiAgICAgICAgW1wiY2xpZW50X2lkXCIsIEdST0tfT0FVVEhfQ0xJRU5UX0lEXSxcbiAgICAgIF0pLFxuICAgICAgc2lnbmFsOiBBYm9ydFNpZ25hbC50aW1lb3V0KFRPS0VOX1RJTUVPVVRfTVMpLFxuICAgIH0pO1xuICB9IGNhdGNoIChlcnJvcikge1xuICAgIHRocm93IG5ldHdvcmtFcnJvcihcImRldmljZV90b2tlbl9mYWlsZWRcIiwgXCJkZXZpY2UgdG9rZW5cIiwgZXJyb3IpO1xuICB9XG5cbiAgaWYgKHJlc3BvbnNlLm9rKVxuICAgIHJldHVybiB7XG4gICAgICBzdGF0dXM6IFwiY29tcGxldGVcIixcbiAgICAgIGNyZWRlbnRpYWxzOiBhd2FpdCBmaW5pc2hHcm9rTG9naW4oe1xuICAgICAgICAuLi5pbnB1dCxcbiAgICAgICAgZmV0Y2g6IGZldGNoSW1wbCxcbiAgICAgICAgdG9rZW5zOiBhd2FpdCBwYXJzZVRva2VuUmVzcG9uc2UocmVzcG9uc2UpLFxuICAgICAgfSksXG4gICAgfTtcblxuICBjb25zdCBvYXV0aEVycm9yID0gYXdhaXQgcmVhZEdyb2tPQXV0aEVycm9yQ29kZShyZXNwb25zZSk7XG5cbiAgc3dpdGNoIChvYXV0aEVycm9yKSB7XG4gICAgY2FzZSBcImF1dGhvcml6YXRpb25fcGVuZGluZ1wiOlxuICAgICAgcmV0dXJuIHsgc3RhdHVzOiBcInBlbmRpbmdcIiwgaW50ZXJ2YWwgfTtcbiAgICBjYXNlIFwic2xvd19kb3duXCI6XG4gICAgICByZXR1cm4geyBzdGF0dXM6IFwicGVuZGluZ1wiLCBpbnRlcnZhbDogaW50ZXJ2YWwgKyBHUk9LX0RFVklDRV9TTE9XX0RPV05fSU5DUkVNRU5UX1MgfTtcbiAgICBjYXNlIFwiYWNjZXNzX2RlbmllZFwiOlxuICAgICAgdGhyb3cgbmV3IEdyb2tPQXV0aEVycm9yKFwiYWNjZXNzX2RlbmllZFwiLCBcImF1dGhvcml6YXRpb24gZGVuaWVkIGJ5IHRoZSB1c2VyXCIsIHtcbiAgICAgICAgc3RhdHVzOiByZXNwb25zZS5zdGF0dXMsXG4gICAgICAgIG9hdXRoRXJyb3IsXG4gICAgICB9KTtcbiAgICBjYXNlIFwiZXhwaXJlZF90b2tlblwiOlxuICAgICAgdGhyb3cgbmV3IEdyb2tPQXV0aEVycm9yKFwiZXhwaXJlZF90b2tlblwiLCBcImRldmljZSBjb2RlIGV4cGlyZWRcIiwge1xuICAgICAgICBzdGF0dXM6IHJlc3BvbnNlLnN0YXR1cyxcbiAgICAgICAgb2F1dGhFcnJvcixcbiAgICAgIH0pO1xuICAgIGRlZmF1bHQ6XG4gICAgICB0aHJvdyBuZXcgR3Jva09BdXRoRXJyb3IoXG4gICAgICAgIFwiZGV2aWNlX3Rva2VuX2ZhaWxlZFwiLFxuICAgICAgICBgZGV2aWNlIHRva2VuIHJlcXVlc3QgZmFpbGVkOiBIVFRQICR7cmVzcG9uc2Uuc3RhdHVzfSAke29hdXRoRXJyb3IgPz8gXCJ1bmtub3duXCJ9YCxcbiAgICAgICAgZGV2aWNlVG9rZW5FcnJvck9wdGlvbnMocmVzcG9uc2Uuc3RhdHVzLCBvYXV0aEVycm9yKSxcbiAgICAgICk7XG4gIH1cbn1cblxuZnVuY3Rpb24gZGV2aWNlVG9rZW5FcnJvck9wdGlvbnMoXG4gIHN0YXR1czogbnVtYmVyLFxuICBvYXV0aEVycm9yOiBzdHJpbmcgfCB1bmRlZmluZWQsXG4pOiBHcm9rT0F1dGhFcnJvcltcIm9wdGlvbnNcIl0ge1xuICBjb25zdCBlcnJvck9wdGlvbnM6IEdyb2tPQXV0aEVycm9yW1wib3B0aW9uc1wiXSA9IHsgc3RhdHVzIH07XG5cbiAgaWYgKG9hdXRoRXJyb3IgIT09IHVuZGVmaW5lZCkgZXJyb3JPcHRpb25zLm9hdXRoRXJyb3IgPSBvYXV0aEVycm9yO1xuICBlcnJvck9wdGlvbnMucmV0cnlhYmxlID0gb2F1dGhFcnJvciA9PT0gdW5kZWZpbmVkICYmIHN0YXR1cyA+PSA1MDA7XG5cbiAgcmV0dXJuIGVycm9yT3B0aW9ucztcbn1cbiJdLCJtYXBwaW5ncyI6Ijs7Ozs7OztBQW9EQSxJQUFhLGlCQUFiLGNBQW9DLE1BQU07Q0FHN0I7Q0FFQTtDQUpYLE9BQXlCO0NBQ3pCLFlBQ0UsTUFDQSxTQUNBLFVBQWtGLENBQUMsR0FDbkY7RUFDQSxNQUFNLE9BQU87RUFKSixLQUFBLE9BQUE7RUFFQSxLQUFBLFVBQUE7Q0FHWDtDQUVBLElBQUksU0FBNkI7RUFDL0IsT0FBTyxLQUFLLFFBQVE7Q0FDdEI7Q0FFQSxJQUFJLFlBQXFCO0VBQ3ZCLE9BQU8sS0FBSyxRQUFRLGFBQWE7Q0FDbkM7O0NBR0EsSUFBSSxhQUFpQztFQUNuQyxPQUFPLEtBQUssUUFBUTtDQUN0QjtBQUNGO0FBZ0JBLE1BQWEsd0JBQXdCLE9BQVUsS0FBSztBQUNwRCxNQUFhLHVDQUF1QyxHQUFHLGlCQUFpQjtBQUN4RSxNQUFhLCtCQUErQixHQUFHLGlCQUFpQjtBQUVoRSxNQUFNLHVCQUF1QjtBQUM3QixN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
|