@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,118 @@
|
|
|
1
|
+
import { GROK_BUILD_VERSION, GROK_CLIENT_IDENTIFIER, GROK_CLIENT_MODE, GROK_COMPACTION_AT, GROK_DOOM_LOOP_CHECK } from "./grok-constants.js";
|
|
2
|
+
import { randomBytes } from "node:crypto";
|
|
3
|
+
//#region src/utils/providers/grok/grok-headers.ts
|
|
4
|
+
/** Maps Node platform/arch to the Rust `std::env::consts` names grok-build reports. */
|
|
5
|
+
function grokPlatform(platform = process.platform, arch = process.arch) {
|
|
6
|
+
return {
|
|
7
|
+
os: platform === "darwin" ? "macos" : platform === "win32" ? "windows" : "linux",
|
|
8
|
+
arch: arch === "arm64" ? "aarch64" : "x86_64"
|
|
9
|
+
};
|
|
10
|
+
}
|
|
11
|
+
/** `grok-shell/<ver> (<os>; <arch>)` (grok-build 1.0.45 xai-grok-sampler/src/client.rs:457-463). */
|
|
12
|
+
function grokShellUserAgent(platform = grokPlatform()) {
|
|
13
|
+
return `grok-shell/${GROK_BUILD_VERSION} (${platform.os}; ${platform.arch})`;
|
|
14
|
+
}
|
|
15
|
+
/** `xai-grok-build/<ver>` (grok-build 1.0.45 media_tool_config.rs:104). */
|
|
16
|
+
function grokMediaUserAgent() {
|
|
17
|
+
return `xai-grok-build/${GROK_BUILD_VERSION}`;
|
|
18
|
+
}
|
|
19
|
+
const TRACEPARENT_PATTERN = /^00-(?!0{32})[0-9a-f]{32}-(?!0{16})[0-9a-f]{16}-01$/;
|
|
20
|
+
/** W3C trace context `00-<trace-id>-<parent-id>-01` with non-zero random ids. */
|
|
21
|
+
function generateTraceparent() {
|
|
22
|
+
for (;;) {
|
|
23
|
+
const traceparent = `00-${randomBytes(16).toString("hex")}-${randomBytes(8).toString("hex")}-01`;
|
|
24
|
+
if (TRACEPARENT_PATTERN.test(traceparent)) return traceparent;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
function bearerValue(bearer) {
|
|
28
|
+
if (!bearer || /\s/.test(bearer)) throw new TypeError("Grok bearer token must be non-empty");
|
|
29
|
+
return `Bearer ${bearer}`;
|
|
30
|
+
}
|
|
31
|
+
function nonNegativeInteger(name, value) {
|
|
32
|
+
if (!Number.isSafeInteger(value) || value < 0) throw new TypeError(`${name} must be a non-negative integer`);
|
|
33
|
+
return String(value);
|
|
34
|
+
}
|
|
35
|
+
function requiredValue(name, value) {
|
|
36
|
+
if (!value || /[\r\n]/.test(value)) throw new TypeError(`${name} must be a non-empty header value`);
|
|
37
|
+
return value;
|
|
38
|
+
}
|
|
39
|
+
/** Headers for `POST {proxy}/responses`, in the order of the 1.0.60 golden capture. */
|
|
40
|
+
function buildGrokChatHeaders(options) {
|
|
41
|
+
const traceparent = options.traceparent ?? generateTraceparent();
|
|
42
|
+
if (!TRACEPARENT_PATTERN.test(traceparent)) throw new TypeError("traceparent must be a W3C 00-<32hex>-<16hex>-01 value");
|
|
43
|
+
const headers = new Map(Object.entries({
|
|
44
|
+
"content-type": "application/json",
|
|
45
|
+
"user-agent": grokShellUserAgent(options.platform),
|
|
46
|
+
"x-grok-client-mode": GROK_CLIENT_MODE,
|
|
47
|
+
"x-xai-token-auth": "xai-grok-cli",
|
|
48
|
+
"x-authenticateresponse": "authenticate-response",
|
|
49
|
+
"x-compactions-remaining": nonNegativeInteger("compactionsRemaining", options.compactionsRemaining ?? 1),
|
|
50
|
+
"x-compaction-at": String(GROK_COMPACTION_AT),
|
|
51
|
+
"x-grok-client-version": GROK_BUILD_VERSION,
|
|
52
|
+
"x-grok-user-id": requiredValue("userId", options.userId),
|
|
53
|
+
"x-grok-conv-group-id": requiredValue("convGroupId", options.convGroupId),
|
|
54
|
+
"x-grok-client-identifier": GROK_CLIENT_IDENTIFIER,
|
|
55
|
+
authorization: bearerValue(options.bearer),
|
|
56
|
+
traceparent,
|
|
57
|
+
"x-grok-conv-id": requiredValue("convId", options.convId),
|
|
58
|
+
"x-grok-req-id": requiredValue("reqId", options.reqId),
|
|
59
|
+
"x-grok-model-override": requiredValue("model", options.model),
|
|
60
|
+
"x-grok-session-id": requiredValue("sessionId", options.sessionId),
|
|
61
|
+
"x-grok-agent-id": requiredValue("agentId", options.agentId),
|
|
62
|
+
"x-grok-turn-idx": nonNegativeInteger("turnIdx", options.turnIdx)
|
|
63
|
+
}));
|
|
64
|
+
if (options.transientRetry !== void 0) headers.set("x-grok-transient-retry", nonNegativeInteger("transientRetry", options.transientRetry));
|
|
65
|
+
headers.set("accept", "text/event-stream");
|
|
66
|
+
headers.set("x-grok-doom-loop-check", String(GROK_DOOM_LOOP_CHECK));
|
|
67
|
+
headers.set("x-grok-exact-repetition-check", String(64));
|
|
68
|
+
if (options.zstd) headers.set("content-encoding", "zstd");
|
|
69
|
+
return Object.fromEntries(headers);
|
|
70
|
+
}
|
|
71
|
+
/**
|
|
72
|
+
* Headers for proxy GETs (`/settings`, `/models`, `/billing`, `/user`). Order follows the
|
|
73
|
+
* 1.0.60 capture of `GET /settings`.
|
|
74
|
+
*/
|
|
75
|
+
function buildGrokProxyGetHeaders(options) {
|
|
76
|
+
const headers = /* @__PURE__ */ new Map([
|
|
77
|
+
["authorization", bearerValue(options.bearer)],
|
|
78
|
+
["x-xai-token-auth", "xai-grok-cli"],
|
|
79
|
+
["x-userid", requiredValue("userId", options.userId)],
|
|
80
|
+
["x-grok-client-version", GROK_BUILD_VERSION]
|
|
81
|
+
]);
|
|
82
|
+
if (options.email !== void 0) headers.set("x-email", requiredValue("email", options.email));
|
|
83
|
+
headers.set("x-grok-client-identifier", GROK_CLIENT_IDENTIFIER);
|
|
84
|
+
headers.set("x-grok-client-mode", GROK_CLIENT_MODE);
|
|
85
|
+
headers.set("accept", "*/*");
|
|
86
|
+
headers.set("user-agent", grokShellUserAgent(options.platform));
|
|
87
|
+
return Object.fromEntries(headers);
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Headers for `api.x.ai` image/video calls. The proxy auth trio is never attached.
|
|
91
|
+
* `x-grok-session-id` is attached per request right after the bearer (grok-build xai-grok-tools
|
|
92
|
+
* image_gen/mod.rs:199-213, video_gen/mod.rs:258-270).
|
|
93
|
+
*/
|
|
94
|
+
function buildGrokMediaHeaders(options) {
|
|
95
|
+
return {
|
|
96
|
+
"user-agent": grokMediaUserAgent(),
|
|
97
|
+
authorization: bearerValue(options.bearer),
|
|
98
|
+
"x-grok-session-id": requiredValue("sessionId", options.sessionId),
|
|
99
|
+
"x-grok-client-version": GROK_BUILD_VERSION,
|
|
100
|
+
"x-grok-client-identifier": GROK_CLIENT_IDENTIFIER
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
/**
|
|
104
|
+
* Headers for `api.x.ai` STT/TTS calls (grok-build 1.0.45 xai-grok-pager client_identity.rs).
|
|
105
|
+
* No session id: the voice client sends none (xai-grok-voice stt/streaming.rs:42-57).
|
|
106
|
+
*/
|
|
107
|
+
function buildGrokVoiceHeaders(options) {
|
|
108
|
+
return {
|
|
109
|
+
"user-agent": grokShellUserAgent(options.platform),
|
|
110
|
+
authorization: bearerValue(options.bearer),
|
|
111
|
+
"x-grok-client-version": GROK_BUILD_VERSION,
|
|
112
|
+
"x-grok-client-identifier": GROK_CLIENT_IDENTIFIER
|
|
113
|
+
};
|
|
114
|
+
}
|
|
115
|
+
//#endregion
|
|
116
|
+
export { buildGrokChatHeaders, buildGrokMediaHeaders, buildGrokProxyGetHeaders, buildGrokVoiceHeaders, generateTraceparent, grokMediaUserAgent, grokPlatform, grokShellUserAgent };
|
|
117
|
+
|
|
118
|
+
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZ3Jvay1oZWFkZXJzLmpzIiwibmFtZXMiOltdLCJzb3VyY2VzIjpbIi4uLy4uLy4uLy4uL3NyYy91dGlscy9wcm92aWRlcnMvZ3Jvay9ncm9rLWhlYWRlcnMudHMiXSwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgcmFuZG9tQnl0ZXMgfSBmcm9tIFwibm9kZTpjcnlwdG9cIjtcblxuaW1wb3J0IHtcbiAgR1JPS19CVUlMRF9WRVJTSU9OLFxuICBHUk9LX0NMSUVOVF9JREVOVElGSUVSLFxuICBHUk9LX0NMSUVOVF9NT0RFLFxuICBHUk9LX0NPTVBBQ1RJT05fQVQsXG4gIEdST0tfQ09NUEFDVElPTlNfUkVNQUlOSU5HX0RFRkFVTFQsXG4gIEdST0tfRE9PTV9MT09QX0NIRUNLLFxuICBHUk9LX0VYQUNUX1JFUEVUSVRJT05fQ0hFQ0ssXG59IGZyb20gXCIuL2dyb2stY29uc3RhbnRzXCI7XG5cbi8vIEJ1aWxkZXJzIHJldHVybiBwbGFpbiBsb3dlcmNhc2Uta2V5IHJlY29yZHMgd2hvc2UgaW5zZXJ0aW9uIG9yZGVyIGlzIHRoZSB3aXJlIG9yZGVyIHRoZVxuLy8gcGlubmVkIGdyb2stYnVpbGQgZW1pdHMuIGBob3N0YCwgYGNvbnRlbnQtbGVuZ3RoYCBhbmQgYGFjY2VwdC1lbmNvZGluZ2AgYXJlIGxlZnQgdG8gdGhlXG4vLyB0cmFuc3BvcnQuIFRoZSB0aHJlZSBoZWFkZXIgZmFtaWxpZXMgKGNoYXQgcHJveHksIHByb3h5IEdFVCwgYXBpLnguYWkpIGFyZSBuZXZlciBtZXJnZWQuXG5cbmV4cG9ydCBpbnRlcmZhY2UgR3Jva1BsYXRmb3JtIHtcbiAgb3M6IFwibWFjb3NcIiB8IFwid2luZG93c1wiIHwgXCJsaW51eFwiO1xuICBhcmNoOiBcImFhcmNoNjRcIiB8IFwieDg2XzY0XCI7XG59XG5cbi8qKiBNYXBzIE5vZGUgcGxhdGZvcm0vYXJjaCB0byB0aGUgUnVzdCBgc3RkOjplbnY6OmNvbnN0c2AgbmFtZXMgZ3Jvay1idWlsZCByZXBvcnRzLiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGdyb2tQbGF0Zm9ybShcbiAgcGxhdGZvcm06IE5vZGVKUy5QbGF0Zm9ybSA9IHByb2Nlc3MucGxhdGZvcm0sXG4gIGFyY2g6IE5vZGVKUy5BcmNoaXRlY3R1cmUgPSBwcm9jZXNzLmFyY2gsXG4pOiBHcm9rUGxhdGZvcm0ge1xuICAvLyBncm9rLWJ1aWxkIHNoaXBzIG9ubHkgdGhlc2UgdGFyZ2V0czsgYW55dGhpbmcgZWxzZSBpcyByZXBvcnRlZCBhcyB0aGUgbmVhcmVzdCBzaGlwcGVkIG9uZVxuICAvLyBzbyB0aGUgVXNlci1BZ2VudCBuZXZlciBjYXJyaWVzIGEgdmFsdWUgdGhlIHJlYWwgYmluYXJ5IGNhbm5vdCBlbWl0LlxuICBjb25zdCBvcyA9IHBsYXRmb3JtID09PSBcImRhcndpblwiID8gXCJtYWNvc1wiIDogcGxhdGZvcm0gPT09IFwid2luMzJcIiA/IFwid2luZG93c1wiIDogXCJsaW51eFwiO1xuXG4gIHJldHVybiB7IG9zLCBhcmNoOiBhcmNoID09PSBcImFybTY0XCIgPyBcImFhcmNoNjRcIiA6IFwieDg2XzY0XCIgfTtcbn1cblxuLyoqIGBncm9rLXNoZWxsLzx2ZXI+ICg8b3M+OyA8YXJjaD4pYCAoZ3Jvay1idWlsZCAxLjAuNDUgeGFpLWdyb2stc2FtcGxlci9zcmMvY2xpZW50LnJzOjQ1Ny00NjMpLiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGdyb2tTaGVsbFVzZXJBZ2VudChwbGF0Zm9ybTogR3Jva1BsYXRmb3JtID0gZ3Jva1BsYXRmb3JtKCkpOiBzdHJpbmcge1xuICByZXR1cm4gYGdyb2stc2hlbGwvJHtHUk9LX0JVSUxEX1ZFUlNJT059ICgke3BsYXRmb3JtLm9zfTsgJHtwbGF0Zm9ybS5hcmNofSlgO1xufVxuXG4vKiogYHhhaS1ncm9rLWJ1aWxkLzx2ZXI+YCAoZ3Jvay1idWlsZCAxLjAuNDUgbWVkaWFfdG9vbF9jb25maWcucnM6MTA0KS4gKi9cbmV4cG9ydCBmdW5jdGlvbiBncm9rTWVkaWFVc2VyQWdlbnQoKTogc3RyaW5nIHtcbiAgcmV0dXJuIGB4YWktZ3Jvay1idWlsZC8ke0dST0tfQlVJTERfVkVSU0lPTn1gO1xufVxuXG5jb25zdCBUUkFDRVBBUkVOVF9QQVRURVJOID0gL14wMC0oPyEwezMyfSlbMC05YS1mXXszMn0tKD8hMHsxNn0pWzAtOWEtZl17MTZ9LTAxJC87XG5cbi8qKiBXM0MgdHJhY2UgY29udGV4dCBgMDAtPHRyYWNlLWlkPi08cGFyZW50LWlkPi0wMWAgd2l0aCBub24temVybyByYW5kb20gaWRzLiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGdlbmVyYXRlVHJhY2VwYXJlbnQoKTogc3RyaW5nIHtcbiAgZm9yICg7Oykge1xuICAgIGNvbnN0IHRyYWNlcGFyZW50ID0gYDAwLSR7cmFuZG9tQnl0ZXMoMTYpLnRvU3RyaW5nKFwiaGV4XCIpfS0ke3JhbmRvbUJ5dGVzKDgpLnRvU3RyaW5nKFwiaGV4XCIpfS0wMWA7XG5cbiAgICBpZiAoVFJBQ0VQQVJFTlRfUEFUVEVSTi50ZXN0KHRyYWNlcGFyZW50KSkgcmV0dXJuIHRyYWNlcGFyZW50O1xuICB9XG59XG5cbmZ1bmN0aW9uIGJlYXJlclZhbHVlKGJlYXJlcjogc3RyaW5nKTogc3RyaW5nIHtcbiAgaWYgKCFiZWFyZXIgfHwgL1xccy8udGVzdChiZWFyZXIpKSB0aHJvdyBuZXcgVHlwZUVycm9yKFwiR3JvayBiZWFyZXIgdG9rZW4gbXVzdCBiZSBub24tZW1wdHlcIik7XG5cbiAgcmV0dXJuIGBCZWFyZXIgJHtiZWFyZXJ9YDtcbn1cblxuZnVuY3Rpb24gbm9uTmVnYXRpdmVJbnRlZ2VyKG5hbWU6IHN0cmluZywgdmFsdWU6IG51bWJlcik6IHN0cmluZyB7XG4gIGlmICghTnVtYmVyLmlzU2FmZUludGVnZXIodmFsdWUpIHx8IHZhbHVlIDwgMClcbiAgICB0aHJvdyBuZXcgVHlwZUVycm9yKGAke25hbWV9IG11c3QgYmUgYSBub24tbmVnYXRpdmUgaW50ZWdlcmApO1xuXG4gIHJldHVybiBTdHJpbmcodmFsdWUpO1xufVxuXG5mdW5jdGlvbiByZXF1aXJlZFZhbHVlKG5hbWU6IHN0cmluZywgdmFsdWU6IHN0cmluZyk6IHN0cmluZyB7XG4gIGlmICghdmFsdWUgfHwgL1tcXHJcXG5dLy50ZXN0KHZhbHVlKSlcbiAgICB0aHJvdyBuZXcgVHlwZUVycm9yKGAke25hbWV9IG11c3QgYmUgYSBub24tZW1wdHkgaGVhZGVyIHZhbHVlYCk7XG5cbiAgcmV0dXJuIHZhbHVlO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIEdyb2tDaGF0SGVhZGVyT3B0aW9ucyB7XG4gIGJlYXJlcjogc3RyaW5nO1xuICBtb2RlbDogc3RyaW5nO1xuICBjb252SWQ6IHN0cmluZztcbiAgcmVxSWQ6IHN0cmluZztcbiAgc2Vzc2lvbklkOiBzdHJpbmc7XG4gIGFnZW50SWQ6IHN0cmluZztcbiAgdXNlcklkOiBzdHJpbmc7XG4gIGNvbnZHcm91cElkOiBzdHJpbmc7XG4gIHR1cm5JZHg6IG51bWJlcjtcbiAgdHJhY2VwYXJlbnQ/OiBzdHJpbmc7XG4gIHRyYW5zaWVudFJldHJ5PzogbnVtYmVyO1xuICBjb21wYWN0aW9uc1JlbWFpbmluZz86IG51bWJlcjtcbiAgenN0ZDogYm9vbGVhbjtcbiAgcGxhdGZvcm0/OiBHcm9rUGxhdGZvcm07XG59XG5cbi8qKiBIZWFkZXJzIGZvciBgUE9TVCB7cHJveHl9L3Jlc3BvbnNlc2AsIGluIHRoZSBvcmRlciBvZiB0aGUgMS4wLjYwIGdvbGRlbiBjYXB0dXJlLiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGJ1aWxkR3Jva0NoYXRIZWFkZXJzKG9wdGlvbnM6IEdyb2tDaGF0SGVhZGVyT3B0aW9ucyk6IFJlY29yZDxzdHJpbmcsIHN0cmluZz4ge1xuICBjb25zdCB0cmFjZXBhcmVudCA9IG9wdGlvbnMudHJhY2VwYXJlbnQgPz8gZ2VuZXJhdGVUcmFjZXBhcmVudCgpO1xuXG4gIGlmICghVFJBQ0VQQVJFTlRfUEFUVEVSTi50ZXN0KHRyYWNlcGFyZW50KSlcbiAgICB0aHJvdyBuZXcgVHlwZUVycm9yKFwidHJhY2VwYXJlbnQgbXVzdCBiZSBhIFczQyAwMC08MzJoZXg+LTwxNmhleD4tMDEgdmFsdWVcIik7XG5cbiAgLy8gQSBNYXAga2VlcHMgaW5zZXJ0aW9uIG9yZGVyLCB3aGljaCBpcyB0aGUgd2lyZSBvcmRlciBvZiB0aGUgZ29sZGVuIGNhcHR1cmUuXG4gIGNvbnN0IGhlYWRlcnMgPSBuZXcgTWFwKFxuICAgIE9iamVjdC5lbnRyaWVzKHtcbiAgICAgIFwiY29udGVudC10eXBlXCI6IFwiYXBwbGljYXRpb24vanNvblwiLFxuICAgICAgXCJ1c2VyLWFnZW50XCI6IGdyb2tTaGVsbFVzZXJBZ2VudChvcHRpb25zLnBsYXRmb3JtKSxcbiAgICAgIFwieC1ncm9rLWNsaWVudC1tb2RlXCI6IEdST0tfQ0xJRU5UX01PREUsXG4gICAgICBcIngteGFpLXRva2VuLWF1dGhcIjogXCJ4YWktZ3Jvay1jbGlcIixcbiAgICAgIFwieC1hdXRoZW50aWNhdGVyZXNwb25zZVwiOiBcImF1dGhlbnRpY2F0ZS1yZXNwb25zZVwiLFxuICAgICAgXCJ4LWNvbXBhY3Rpb25zLXJlbWFpbmluZ1wiOiBub25OZWdhdGl2ZUludGVnZXIoXG4gICAgICAgIFwiY29tcGFjdGlvbnNSZW1haW5pbmdcIixcbiAgICAgICAgb3B0aW9ucy5jb21wYWN0aW9uc1JlbWFpbmluZyA/PyBHUk9LX0NPTVBBQ1RJT05TX1JFTUFJTklOR19ERUZBVUxULFxuICAgICAgKSxcbiAgICAgIFwieC1jb21wYWN0aW9uLWF0XCI6IFN0cmluZyhHUk9LX0NPTVBBQ1RJT05fQVQpLFxuICAgICAgXCJ4LWdyb2stY2xpZW50LXZlcnNpb25cIjogR1JPS19CVUlMRF9WRVJTSU9OLFxuICAgICAgXCJ4LWdyb2stdXNlci1pZFwiOiByZXF1aXJlZFZhbHVlKFwidXNlcklkXCIsIG9wdGlvbnMudXNlcklkKSxcbiAgICAgIFwieC1ncm9rLWNvbnYtZ3JvdXAtaWRcIjogcmVxdWlyZWRWYWx1ZShcImNvbnZHcm91cElkXCIsIG9wdGlvbnMuY29udkdyb3VwSWQpLFxuICAgICAgXCJ4LWdyb2stY2xpZW50LWlkZW50aWZpZXJcIjogR1JPS19DTElFTlRfSURFTlRJRklFUixcbiAgICAgIGF1dGhvcml6YXRpb246IGJlYXJlclZhbHVlKG9wdGlvbnMuYmVhcmVyKSxcbiAgICAgIHRyYWNlcGFyZW50LFxuICAgICAgXCJ4LWdyb2stY29udi1pZFwiOiByZXF1aXJlZFZhbHVlKFwiY29udklkXCIsIG9wdGlvbnMuY29udklkKSxcbiAgICAgIFwieC1ncm9rLXJlcS1pZFwiOiByZXF1aXJlZFZhbHVlKFwicmVxSWRcIiwgb3B0aW9ucy5yZXFJZCksXG4gICAgICBcIngtZ3Jvay1tb2RlbC1vdmVycmlkZVwiOiByZXF1aXJlZFZhbHVlKFwibW9kZWxcIiwgb3B0aW9ucy5tb2RlbCksXG4gICAgICBcIngtZ3Jvay1zZXNzaW9uLWlkXCI6IHJlcXVpcmVkVmFsdWUoXCJzZXNzaW9uSWRcIiwgb3B0aW9ucy5zZXNzaW9uSWQpLFxuICAgICAgXCJ4LWdyb2stYWdlbnQtaWRcIjogcmVxdWlyZWRWYWx1ZShcImFnZW50SWRcIiwgb3B0aW9ucy5hZ2VudElkKSxcbiAgICAgIFwieC1ncm9rLXR1cm4taWR4XCI6IG5vbk5lZ2F0aXZlSW50ZWdlcihcInR1cm5JZHhcIiwgb3B0aW9ucy50dXJuSWR4KSxcbiAgICB9KSxcbiAgKTtcblxuICAvLyBOb3QgcHJlc2VudCBpbiB0aGUgY2FwdHVyZTsgZ3Jvay1idWlsZCAxLjAuNDUgY2xpZW50LnJzOjU2MC02MDUgc2VuZHMgaXQgd2l0aCB0aGUgdHVyblxuICAvLyBpbmRleCBncm91cCBvbiByZXRyaWVzIG9ubHkuXG4gIGlmIChvcHRpb25zLnRyYW5zaWVudFJldHJ5ICE9PSB1bmRlZmluZWQpXG4gICAgaGVhZGVycy5zZXQoXG4gICAgICBcIngtZ3Jvay10cmFuc2llbnQtcmV0cnlcIixcbiAgICAgIG5vbk5lZ2F0aXZlSW50ZWdlcihcInRyYW5zaWVudFJldHJ5XCIsIG9wdGlvbnMudHJhbnNpZW50UmV0cnkpLFxuICAgICk7XG4gIGhlYWRlcnMuc2V0KFwiYWNjZXB0XCIsIFwidGV4dC9ldmVudC1zdHJlYW1cIik7XG4gIGhlYWRlcnMuc2V0KFwieC1ncm9rLWRvb20tbG9vcC1jaGVja1wiLCBTdHJpbmcoR1JPS19ET09NX0xPT1BfQ0hFQ0spKTtcbiAgaGVhZGVycy5zZXQoXCJ4LWdyb2stZXhhY3QtcmVwZXRpdGlvbi1jaGVja1wiLCBTdHJpbmcoR1JPS19FWEFDVF9SRVBFVElUSU9OX0NIRUNLKSk7XG5cbiAgaWYgKG9wdGlvbnMuenN0ZCkgaGVhZGVycy5zZXQoXCJjb250ZW50LWVuY29kaW5nXCIsIFwienN0ZFwiKTtcblxuICByZXR1cm4gT2JqZWN0LmZyb21FbnRyaWVzKGhlYWRlcnMpO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIEdyb2tQcm94eUdldEhlYWRlck9wdGlvbnMge1xuICBiZWFyZXI6IHN0cmluZztcbiAgdXNlcklkOiBzdHJpbmc7XG4gIGVtYWlsPzogc3RyaW5nO1xuICBwbGF0Zm9ybT86IEdyb2tQbGF0Zm9ybTtcbn1cblxuLyoqXG4gKiBIZWFkZXJzIGZvciBwcm94eSBHRVRzIChgL3NldHRpbmdzYCwgYC9tb2RlbHNgLCBgL2JpbGxpbmdgLCBgL3VzZXJgKS4gT3JkZXIgZm9sbG93cyB0aGVcbiAqIDEuMC42MCBjYXB0dXJlIG9mIGBHRVQgL3NldHRpbmdzYC5cbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGJ1aWxkR3Jva1Byb3h5R2V0SGVhZGVycyhcbiAgb3B0aW9uczogR3Jva1Byb3h5R2V0SGVhZGVyT3B0aW9ucyxcbik6IFJlY29yZDxzdHJpbmcsIHN0cmluZz4ge1xuICBjb25zdCBoZWFkZXJzID0gbmV3IE1hcChbXG4gICAgW1wiYXV0aG9yaXphdGlvblwiLCBiZWFyZXJWYWx1ZShvcHRpb25zLmJlYXJlcildLFxuICAgIFtcIngteGFpLXRva2VuLWF1dGhcIiwgXCJ4YWktZ3Jvay1jbGlcIl0sXG4gICAgW1wieC11c2VyaWRcIiwgcmVxdWlyZWRWYWx1ZShcInVzZXJJZFwiLCBvcHRpb25zLnVzZXJJZCldLFxuICAgIFtcIngtZ3Jvay1jbGllbnQtdmVyc2lvblwiLCBHUk9LX0JVSUxEX1ZFUlNJT05dLFxuICBdKTtcblxuICBpZiAob3B0aW9ucy5lbWFpbCAhPT0gdW5kZWZpbmVkKSBoZWFkZXJzLnNldChcIngtZW1haWxcIiwgcmVxdWlyZWRWYWx1ZShcImVtYWlsXCIsIG9wdGlvbnMuZW1haWwpKTtcbiAgaGVhZGVycy5zZXQoXCJ4LWdyb2stY2xpZW50LWlkZW50aWZpZXJcIiwgR1JPS19DTElFTlRfSURFTlRJRklFUik7XG4gIGhlYWRlcnMuc2V0KFwieC1ncm9rLWNsaWVudC1tb2RlXCIsIEdST0tfQ0xJRU5UX01PREUpO1xuICBoZWFkZXJzLnNldChcImFjY2VwdFwiLCBcIiovKlwiKTtcbiAgaGVhZGVycy5zZXQoXCJ1c2VyLWFnZW50XCIsIGdyb2tTaGVsbFVzZXJBZ2VudChvcHRpb25zLnBsYXRmb3JtKSk7XG5cbiAgcmV0dXJuIE9iamVjdC5mcm9tRW50cmllcyhoZWFkZXJzKTtcbn1cblxuLyoqXG4gKiBIZWFkZXJzIGZvciBgYXBpLnguYWlgIGltYWdlL3ZpZGVvIGNhbGxzLiBUaGUgcHJveHkgYXV0aCB0cmlvIGlzIG5ldmVyIGF0dGFjaGVkLlxuICogYHgtZ3Jvay1zZXNzaW9uLWlkYCBpcyBhdHRhY2hlZCBwZXIgcmVxdWVzdCByaWdodCBhZnRlciB0aGUgYmVhcmVyIChncm9rLWJ1aWxkIHhhaS1ncm9rLXRvb2xzXG4gKiBpbWFnZV9nZW4vbW9kLnJzOjE5OS0yMTMsIHZpZGVvX2dlbi9tb2QucnM6MjU4LTI3MCkuXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiBidWlsZEdyb2tNZWRpYUhlYWRlcnMob3B0aW9uczogeyBiZWFyZXI6IHN0cmluZzsgc2Vzc2lvbklkOiBzdHJpbmcgfSkge1xuICByZXR1cm4ge1xuICAgIFwidXNlci1hZ2VudFwiOiBncm9rTWVkaWFVc2VyQWdlbnQoKSxcbiAgICBhdXRob3JpemF0aW9uOiBiZWFyZXJWYWx1ZShvcHRpb25zLmJlYXJlciksXG4gICAgXCJ4LWdyb2stc2Vzc2lvbi1pZFwiOiByZXF1aXJlZFZhbHVlKFwic2Vzc2lvbklkXCIsIG9wdGlvbnMuc2Vzc2lvbklkKSxcbiAgICBcIngtZ3Jvay1jbGllbnQtdmVyc2lvblwiOiBHUk9LX0JVSUxEX1ZFUlNJT04sXG4gICAgXCJ4LWdyb2stY2xpZW50LWlkZW50aWZpZXJcIjogR1JPS19DTElFTlRfSURFTlRJRklFUixcbiAgfTtcbn1cblxuLyoqXG4gKiBIZWFkZXJzIGZvciBgYXBpLnguYWlgIFNUVC9UVFMgY2FsbHMgKGdyb2stYnVpbGQgMS4wLjQ1IHhhaS1ncm9rLXBhZ2VyIGNsaWVudF9pZGVudGl0eS5ycykuXG4gKiBObyBzZXNzaW9uIGlkOiB0aGUgdm9pY2UgY2xpZW50IHNlbmRzIG5vbmUgKHhhaS1ncm9rLXZvaWNlIHN0dC9zdHJlYW1pbmcucnM6NDItNTcpLlxuICovXG5leHBvcnQgZnVuY3Rpb24gYnVpbGRHcm9rVm9pY2VIZWFkZXJzKG9wdGlvbnM6IHsgYmVhcmVyOiBzdHJpbmc7IHBsYXRmb3JtPzogR3Jva1BsYXRmb3JtIH0pIHtcbiAgcmV0dXJuIHtcbiAgICBcInVzZXItYWdlbnRcIjogZ3Jva1NoZWxsVXNlckFnZW50KG9wdGlvbnMucGxhdGZvcm0pLFxuICAgIGF1dGhvcml6YXRpb246IGJlYXJlclZhbHVlKG9wdGlvbnMuYmVhcmVyKSxcbiAgICBcIngtZ3Jvay1jbGllbnQtdmVyc2lvblwiOiBHUk9LX0JVSUxEX1ZFUlNJT04sXG4gICAgXCJ4LWdyb2stY2xpZW50LWlkZW50aWZpZXJcIjogR1JPS19DTElFTlRfSURFTlRJRklFUixcbiAgfTtcbn1cbiJdLCJtYXBwaW5ncyI6Ijs7OztBQXNCQSxTQUFnQixhQUNkLFdBQTRCLFFBQVEsVUFDcEMsT0FBNEIsUUFBUSxNQUN0QjtDQUtkLE9BQU87RUFBRSxJQUZFLGFBQWEsV0FBVyxVQUFVLGFBQWEsVUFBVSxZQUFZO0VBRW5FLE1BQU0sU0FBUyxVQUFVLFlBQVk7Q0FBUztBQUM3RDs7QUFHQSxTQUFnQixtQkFBbUIsV0FBeUIsYUFBYSxHQUFXO0NBQ2xGLE9BQU8sY0FBYyxtQkFBbUIs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
|
|
@@ -0,0 +1,420 @@
|
|
|
1
|
+
import { GROK_IMAGE_DEFAULT_MODEL } from "./grok-constants.js";
|
|
2
|
+
import { GrokProtocolError, classifyGrokHttpError, readGrokResponseHeaders } from "./grok-backend-protocol.js";
|
|
3
|
+
import { GrokHttpError } from "./grok-direct-client.js";
|
|
4
|
+
import { buildGrokMediaHeaders } from "./grok-headers.js";
|
|
5
|
+
import { GrokImageResponse, GrokVideoStart, GrokVideoStatus, grokVideoUrl } from "./grok-types.js";
|
|
6
|
+
import { GrokInvalidRequestError } from "./grok-dispatcher.js";
|
|
7
|
+
import { z } from "zod";
|
|
8
|
+
//#region src/utils/providers/grok/grok-media-client.ts
|
|
9
|
+
const GROK_IMAGE_TOTAL_TIMEOUT_MS = 3e5;
|
|
10
|
+
const GROK_IMAGE_READ_TIMEOUT_MS = 24e4;
|
|
11
|
+
const GROK_VIDEO_START_TIMEOUT_MS = 6e4;
|
|
12
|
+
const GROK_VIDEO_POLL_TIMEOUT_MS = 3e4;
|
|
13
|
+
const GROK_IMAGE_MAX_PER_CALL = 3;
|
|
14
|
+
const GROK_IMAGE_DEFAULT_RESOLUTION = "1k";
|
|
15
|
+
const GROK_IMAGE_EDIT_DEFAULT_MODEL = GROK_IMAGE_DEFAULT_MODEL;
|
|
16
|
+
const GROK_VIDEO_MAX_DURATION_SEC = 15;
|
|
17
|
+
const MAX_IMAGE_RESPONSE_BYTES = 64 * 1024 * 1024;
|
|
18
|
+
const MAX_JSON_RESPONSE_BYTES = 1024 * 1024;
|
|
19
|
+
const MAX_ERROR_BODY_BYTES = 64 * 1024;
|
|
20
|
+
const DEFAULT_TIMEOUTS = {
|
|
21
|
+
imageTotalMs: GROK_IMAGE_TOTAL_TIMEOUT_MS,
|
|
22
|
+
imageReadMs: GROK_IMAGE_READ_TIMEOUT_MS,
|
|
23
|
+
videoStartMs: GROK_VIDEO_START_TIMEOUT_MS,
|
|
24
|
+
videoPollMs: GROK_VIDEO_POLL_TIMEOUT_MS
|
|
25
|
+
};
|
|
26
|
+
/** Upstream flagged the output with `respect_moderation: false`. Never retried. */
|
|
27
|
+
var GrokContentPolicyError = class extends Error {
|
|
28
|
+
constructor(kind) {
|
|
29
|
+
super(`${kind === "image" ? "Image" : "Video"} generation was blocked due to a content policy violation.`);
|
|
30
|
+
this.name = "GrokContentPolicyError";
|
|
31
|
+
}
|
|
32
|
+
};
|
|
33
|
+
/** A total or read timeout fired. For a POST, upstream may already be executing the job. */
|
|
34
|
+
var GrokMediaTimeoutError = class extends Error {
|
|
35
|
+
phase;
|
|
36
|
+
timeoutMs;
|
|
37
|
+
constructor(phase, timeoutMs) {
|
|
38
|
+
super(`Grok media request ${phase === "total" ? "timed out" : "stalled"} after ${timeoutMs} ms`);
|
|
39
|
+
this.name = "GrokMediaTimeoutError";
|
|
40
|
+
this.phase = phase;
|
|
41
|
+
this.timeoutMs = timeoutMs;
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
/** A POST failed after it may have been written; replaying it could run the job twice. */
|
|
45
|
+
var GrokMediaDeliveryError = class extends Error {
|
|
46
|
+
constructor(message, options) {
|
|
47
|
+
super(`Grok media request failed after it may have been sent: ${message}`, options);
|
|
48
|
+
this.name = "GrokMediaDeliveryError";
|
|
49
|
+
}
|
|
50
|
+
};
|
|
51
|
+
const PRE_SEND_ERROR_CODES = /* @__PURE__ */ new Set([
|
|
52
|
+
"ECONNREFUSED",
|
|
53
|
+
"ENOTFOUND",
|
|
54
|
+
"EAI_AGAIN",
|
|
55
|
+
"EAI_FAIL",
|
|
56
|
+
"EHOSTUNREACH",
|
|
57
|
+
"EHOSTDOWN",
|
|
58
|
+
"ENETUNREACH",
|
|
59
|
+
"ENETDOWN",
|
|
60
|
+
"UND_ERR_CONNECT_TIMEOUT",
|
|
61
|
+
"ERR_TLS_CERT_ALTNAME_INVALID",
|
|
62
|
+
"CERT_HAS_EXPIRED",
|
|
63
|
+
"DEPTH_ZERO_SELF_SIGNED_CERT",
|
|
64
|
+
"SELF_SIGNED_CERT_IN_CHAIN",
|
|
65
|
+
"UNABLE_TO_GET_ISSUER_CERT_LOCALLY",
|
|
66
|
+
"UNABLE_TO_VERIFY_LEAF_SIGNATURE"
|
|
67
|
+
]);
|
|
68
|
+
const ErrorWithCode = z.looseObject({ code: z.string() });
|
|
69
|
+
const ErrorWithCause = z.looseObject({ cause: z.unknown() });
|
|
70
|
+
/** The first `code` along the `cause` chain (undici wraps socket errors in `TypeError`). */
|
|
71
|
+
function errorCode(cause) {
|
|
72
|
+
let current = cause;
|
|
73
|
+
for (let depth = 0; depth < 5 && current !== void 0 && current !== null; depth++) {
|
|
74
|
+
const withCode = ErrorWithCode.safeParse(current);
|
|
75
|
+
if (withCode.success) return withCode.data.code;
|
|
76
|
+
const withCause = ErrorWithCause.safeParse(current);
|
|
77
|
+
current = withCause.success ? withCause.data.cause : void 0;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
function errorMessage(cause) {
|
|
81
|
+
return cause instanceof Error ? cause.message : String(cause);
|
|
82
|
+
}
|
|
83
|
+
function abortReason(signal) {
|
|
84
|
+
const reason = signal.reason;
|
|
85
|
+
return reason instanceof Error ? reason : new DOMException("Aborted", "AbortError");
|
|
86
|
+
}
|
|
87
|
+
function connectFailure(cause) {
|
|
88
|
+
const code = errorCode(cause);
|
|
89
|
+
const message = `${errorMessage(cause)}${code ? ` (${code})` : ""}`;
|
|
90
|
+
return new GrokHttpError({
|
|
91
|
+
...classifyGrokHttpError(0, "", {}),
|
|
92
|
+
message
|
|
93
|
+
}, "", {}, { cause });
|
|
94
|
+
}
|
|
95
|
+
const BASE64 = /^[A-Za-z0-9+/]*={0,2}$/;
|
|
96
|
+
function sniffImageMediaType(bytes) {
|
|
97
|
+
if (bytes[0] === 255 && bytes[1] === 216 && bytes[2] === 255) return "image/jpeg";
|
|
98
|
+
if (bytes[0] === 137 && bytes[1] === 80 && bytes[2] === 78 && bytes[3] === 71) return "image/png";
|
|
99
|
+
if (bytes[0] === 71 && bytes[1] === 73 && bytes[2] === 70) return "image/gif";
|
|
100
|
+
const ascii = (from, to) => String.fromCharCode(...bytes.subarray(from, to));
|
|
101
|
+
if (ascii(0, 4) === "RIFF" && ascii(8, 12) === "WEBP") return "image/webp";
|
|
102
|
+
}
|
|
103
|
+
function assertImagesAllowed(response) {
|
|
104
|
+
if (response.data.some((image) => image.respect_moderation === false)) throw new GrokContentPolicyError("image");
|
|
105
|
+
for (const image of response.data) if (image.b64_json.length % 4 !== 0 || !BASE64.test(image.b64_json)) throw new GrokProtocolError("Grok image response carried invalid base64 data");
|
|
106
|
+
}
|
|
107
|
+
/** Decodes a validated image response. `mime_type` wins; otherwise the bytes are sniffed. */
|
|
108
|
+
function decodeGrokImages(response) {
|
|
109
|
+
assertImagesAllowed(response);
|
|
110
|
+
const images = response.data.map((image) => {
|
|
111
|
+
const bytes = new Uint8Array(Buffer.from(image.b64_json, "base64"));
|
|
112
|
+
const decoded = {
|
|
113
|
+
bytes,
|
|
114
|
+
mediaType: image.mime_type?.startsWith("image/") ? image.mime_type : sniffImageMediaType(bytes) ?? "image/jpeg"
|
|
115
|
+
};
|
|
116
|
+
if (image.revised_prompt) decoded.revisedPrompt = image.revised_prompt;
|
|
117
|
+
if (image.respect_moderation !== void 0) decoded.respectModeration = image.respect_moderation;
|
|
118
|
+
return decoded;
|
|
119
|
+
});
|
|
120
|
+
const ticks = response.usage?.cost_in_usd_ticks;
|
|
121
|
+
const result = { images };
|
|
122
|
+
if (ticks !== void 0) result.costInUsdTicks = ticks;
|
|
123
|
+
return result;
|
|
124
|
+
}
|
|
125
|
+
const VideoStatusExtras = z.looseObject({
|
|
126
|
+
video: z.looseObject({ respect_moderation: z.boolean().nullish() }).nullish(),
|
|
127
|
+
error: z.looseObject({
|
|
128
|
+
code: z.string().nullish(),
|
|
129
|
+
message: z.string().nullish()
|
|
130
|
+
}).nullish()
|
|
131
|
+
});
|
|
132
|
+
/**
|
|
133
|
+
* Collapses a poll response to the SDK's three outcomes. The URL is returned unchanged (D4);
|
|
134
|
+
* `expired` and a `done` without a URL are failures (xai-video-model.ts:643-705).
|
|
135
|
+
*/
|
|
136
|
+
function summarizeGrokVideoStatus(status) {
|
|
137
|
+
const extras = VideoStatusExtras.parse(status);
|
|
138
|
+
if (extras.video?.respect_moderation === false) throw new GrokContentPolicyError("video");
|
|
139
|
+
const ticks = status.usage?.cost_in_usd_ticks;
|
|
140
|
+
const base = { mimeType: "video/mp4" };
|
|
141
|
+
if (ticks !== void 0) base.usageTicks = ticks;
|
|
142
|
+
if (status.status === "expired") return {
|
|
143
|
+
...base,
|
|
144
|
+
status: "failed",
|
|
145
|
+
error: "Video generation request expired."
|
|
146
|
+
};
|
|
147
|
+
if (status.status === "failed") {
|
|
148
|
+
const error = extras.error?.message ?? extras.error?.code ?? "Video generation failed.";
|
|
149
|
+
return {
|
|
150
|
+
...base,
|
|
151
|
+
status: "failed",
|
|
152
|
+
error
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
if (status.status === "done") {
|
|
156
|
+
const url = grokVideoUrl(status);
|
|
157
|
+
if (!url) return {
|
|
158
|
+
...base,
|
|
159
|
+
status: "failed",
|
|
160
|
+
error: "Video generation completed but no video URL was returned."
|
|
161
|
+
};
|
|
162
|
+
return {
|
|
163
|
+
...base,
|
|
164
|
+
status: "done",
|
|
165
|
+
url
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
return {
|
|
169
|
+
...base,
|
|
170
|
+
status: "pending"
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
var BodyLimitError = class extends Error {};
|
|
174
|
+
var GrokMediaClient = class {
|
|
175
|
+
fetchImpl;
|
|
176
|
+
baseUrl;
|
|
177
|
+
timeouts;
|
|
178
|
+
constructor(options = {}) {
|
|
179
|
+
this.fetchImpl = options.fetch ?? fetch;
|
|
180
|
+
this.baseUrl = (options.baseUrl ?? "https://api.x.ai/v1").replace(/\/+$/, "");
|
|
181
|
+
this.timeouts = {
|
|
182
|
+
...DEFAULT_TIMEOUTS,
|
|
183
|
+
...options.timeouts
|
|
184
|
+
};
|
|
185
|
+
}
|
|
186
|
+
async generateImages(auth, request) {
|
|
187
|
+
const body = imageBody(request, request.model.trim() || "grok-imagine-image-quality");
|
|
188
|
+
return this.postImages("/images/generations", auth, body, request.signal);
|
|
189
|
+
}
|
|
190
|
+
async editImages(auth, request) {
|
|
191
|
+
if (request.images.length === 0) throw new GrokInvalidRequestError("Grok image edit needs at least one reference image");
|
|
192
|
+
const urls = request.images.map((url) => {
|
|
193
|
+
if (!url.trim()) throw new GrokInvalidRequestError("Grok image edit reference must be a non-empty URL");
|
|
194
|
+
return { url };
|
|
195
|
+
});
|
|
196
|
+
const body = imageBody(request, request.model.trim() || GROK_IMAGE_EDIT_DEFAULT_MODEL);
|
|
197
|
+
if (urls.length === 1) body.image = urls[0];
|
|
198
|
+
else body.images = urls;
|
|
199
|
+
return this.postImages("/images/edits", auth, body, request.signal);
|
|
200
|
+
}
|
|
201
|
+
async startVideo(auth, request) {
|
|
202
|
+
const body = videoBody(request);
|
|
203
|
+
const { text } = await this.call({
|
|
204
|
+
method: "POST",
|
|
205
|
+
path: "/videos/generations",
|
|
206
|
+
auth,
|
|
207
|
+
body,
|
|
208
|
+
totalMs: this.timeouts.videoStartMs,
|
|
209
|
+
readMs: this.timeouts.videoStartMs,
|
|
210
|
+
maxBytes: MAX_JSON_RESPONSE_BYTES,
|
|
211
|
+
signal: request.signal
|
|
212
|
+
});
|
|
213
|
+
return parseJson(GrokVideoStart, text, "video start");
|
|
214
|
+
}
|
|
215
|
+
async getVideo(auth, requestId, signal) {
|
|
216
|
+
if (!requestId.trim()) throw new TypeError("Grok video request id must be non-empty");
|
|
217
|
+
const { response, text } = await this.call({
|
|
218
|
+
method: "GET",
|
|
219
|
+
path: `/videos/${encodeURIComponent(requestId)}`,
|
|
220
|
+
auth,
|
|
221
|
+
totalMs: this.timeouts.videoPollMs,
|
|
222
|
+
readMs: this.timeouts.videoPollMs,
|
|
223
|
+
maxBytes: MAX_JSON_RESPONSE_BYTES,
|
|
224
|
+
signal
|
|
225
|
+
});
|
|
226
|
+
const status = parseVideoStatus(response.status, text);
|
|
227
|
+
if (VideoStatusExtras.parse(status).video?.respect_moderation === false) throw new GrokContentPolicyError("video");
|
|
228
|
+
return status;
|
|
229
|
+
}
|
|
230
|
+
async postImages(path, auth, body, signal) {
|
|
231
|
+
const { text } = await this.call({
|
|
232
|
+
method: "POST",
|
|
233
|
+
path,
|
|
234
|
+
auth,
|
|
235
|
+
body,
|
|
236
|
+
totalMs: this.timeouts.imageTotalMs,
|
|
237
|
+
readMs: this.timeouts.imageReadMs,
|
|
238
|
+
maxBytes: MAX_IMAGE_RESPONSE_BYTES,
|
|
239
|
+
signal
|
|
240
|
+
});
|
|
241
|
+
const response = parseJson(GrokImageResponse, text, "image");
|
|
242
|
+
assertImagesAllowed(response);
|
|
243
|
+
return response;
|
|
244
|
+
}
|
|
245
|
+
/** One HTTP exchange with total and read timeouts composed with the caller's signal. */
|
|
246
|
+
async call(call) {
|
|
247
|
+
const { signal } = call;
|
|
248
|
+
if (signal?.aborted) throw abortReason(signal);
|
|
249
|
+
const headers = {
|
|
250
|
+
"content-type": "application/json",
|
|
251
|
+
...buildGrokMediaHeaders({
|
|
252
|
+
bearer: call.auth.bearer,
|
|
253
|
+
sessionId: call.auth.sessionId
|
|
254
|
+
})
|
|
255
|
+
};
|
|
256
|
+
const controller = new AbortController();
|
|
257
|
+
let timeout;
|
|
258
|
+
const fire = (error) => {
|
|
259
|
+
if (timeout || controller.signal.aborted) return;
|
|
260
|
+
timeout = error;
|
|
261
|
+
controller.abort(error);
|
|
262
|
+
};
|
|
263
|
+
const totalTimer = setTimeout(() => fire(new GrokMediaTimeoutError("total", call.totalMs)), call.totalMs);
|
|
264
|
+
let readTimer;
|
|
265
|
+
const armRead = () => {
|
|
266
|
+
clearTimeout(readTimer);
|
|
267
|
+
readTimer = setTimeout(() => fire(new GrokMediaTimeoutError("read", call.readMs)), call.readMs);
|
|
268
|
+
};
|
|
269
|
+
const onAbort = () => controller.abort(signal?.reason);
|
|
270
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
271
|
+
const settle = (cause, responded) => {
|
|
272
|
+
if (signal?.aborted) return abortReason(signal);
|
|
273
|
+
if (timeout) return timeout;
|
|
274
|
+
if (cause instanceof GrokProtocolError || cause instanceof GrokHttpError) return cause;
|
|
275
|
+
if (call.method === "GET") return connectFailure(cause);
|
|
276
|
+
if (!responded && PRE_SEND_ERROR_CODES.has(errorCode(cause) ?? "")) return connectFailure(cause);
|
|
277
|
+
return new GrokMediaDeliveryError(errorMessage(cause), { cause });
|
|
278
|
+
};
|
|
279
|
+
try {
|
|
280
|
+
armRead();
|
|
281
|
+
let response;
|
|
282
|
+
try {
|
|
283
|
+
response = await this.fetchImpl(`${this.baseUrl}${call.path}`, {
|
|
284
|
+
method: call.method,
|
|
285
|
+
headers,
|
|
286
|
+
body: call.body === void 0 ? void 0 : JSON.stringify(call.body),
|
|
287
|
+
signal: controller.signal
|
|
288
|
+
});
|
|
289
|
+
} catch (error) {
|
|
290
|
+
throw settle(error, false);
|
|
291
|
+
}
|
|
292
|
+
armRead();
|
|
293
|
+
try {
|
|
294
|
+
if (!response.ok) {
|
|
295
|
+
const bodyText = await readBody(response, MAX_ERROR_BODY_BYTES, armRead, true);
|
|
296
|
+
throw new GrokHttpError(classifyGrokHttpError(response.status, bodyText, response.headers), bodyText, readGrokResponseHeaders(response.headers));
|
|
297
|
+
}
|
|
298
|
+
const text = await readBody(response, call.maxBytes, armRead, false);
|
|
299
|
+
return {
|
|
300
|
+
response,
|
|
301
|
+
text
|
|
302
|
+
};
|
|
303
|
+
} catch (error) {
|
|
304
|
+
if (error instanceof BodyLimitError) throw new GrokProtocolError(error.message);
|
|
305
|
+
throw settle(error, true);
|
|
306
|
+
}
|
|
307
|
+
} finally {
|
|
308
|
+
clearTimeout(totalTimer);
|
|
309
|
+
clearTimeout(readTimer);
|
|
310
|
+
signal?.removeEventListener("abort", onAbort);
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
};
|
|
314
|
+
function imageBody(request, model) {
|
|
315
|
+
const n = request.n ?? 1;
|
|
316
|
+
if (!Number.isSafeInteger(n) || n < 1 || n > 3) throw new RangeError(`Grok image count must be an integer from 1 to 3`);
|
|
317
|
+
return {
|
|
318
|
+
model,
|
|
319
|
+
prompt: request.prompt,
|
|
320
|
+
n,
|
|
321
|
+
aspect_ratio: request.aspectRatio,
|
|
322
|
+
resolution: request.resolution ?? GROK_IMAGE_DEFAULT_RESOLUTION,
|
|
323
|
+
response_format: "b64_json",
|
|
324
|
+
quality: request.quality,
|
|
325
|
+
output_format: request.outputFormat
|
|
326
|
+
};
|
|
327
|
+
}
|
|
328
|
+
function videoBody(request) {
|
|
329
|
+
const references = request.referenceImages ?? [];
|
|
330
|
+
if (request.mode === "reference-to-video" && references.length === 0) throw new GrokInvalidRequestError("Grok reference-to-video needs at least one reference image");
|
|
331
|
+
const { duration } = request;
|
|
332
|
+
if (duration !== void 0 && (!Number.isSafeInteger(duration) || duration < 1 || duration > GROK_VIDEO_MAX_DURATION_SEC)) throw new GrokInvalidRequestError(`Grok video duration must be an integer from 1 to ${GROK_VIDEO_MAX_DURATION_SEC}`);
|
|
333
|
+
return {
|
|
334
|
+
model: request.model.trim() || "grok-imagine-video-1.5",
|
|
335
|
+
prompt: request.prompt,
|
|
336
|
+
image: request.image === void 0 ? void 0 : { url: request.image },
|
|
337
|
+
duration,
|
|
338
|
+
aspect_ratio: request.aspectRatio,
|
|
339
|
+
resolution: request.resolution,
|
|
340
|
+
reference_images: references.length === 0 ? void 0 : references.map((url) => ({ url })),
|
|
341
|
+
last_frame: request.lastFrame === void 0 ? void 0 : { url: request.lastFrame }
|
|
342
|
+
};
|
|
343
|
+
}
|
|
344
|
+
function parseJsonText(text, what) {
|
|
345
|
+
try {
|
|
346
|
+
return JSON.parse(text);
|
|
347
|
+
} catch {
|
|
348
|
+
throw new GrokProtocolError(`Grok ${what} response is not JSON`);
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
function parseJson(schema, text, what) {
|
|
352
|
+
const parsed = schema.safeParse(parseJsonText(text, what));
|
|
353
|
+
if (!parsed.success) throw new GrokProtocolError(`Grok ${what} response has an unexpected shape`);
|
|
354
|
+
return parsed.data;
|
|
355
|
+
}
|
|
356
|
+
const JsonObject = z.record(z.string(), z.unknown());
|
|
357
|
+
const LooseVideoStatus = z.looseObject({
|
|
358
|
+
status: z.string().nullish(),
|
|
359
|
+
video: z.looseObject({ url: z.string().nullish() }).nullish()
|
|
360
|
+
});
|
|
361
|
+
/**
|
|
362
|
+
* 202 means pending, possibly with an empty or partial body (xai-video-model.ts:876-894;
|
|
363
|
+
* grok-build video_gen/mod.rs:442 accepts it too). A 200 without `status` but with a video URL
|
|
364
|
+
* is done (xai-video-model.ts:673-676).
|
|
365
|
+
*/
|
|
366
|
+
function parseVideoStatus(httpStatus, text) {
|
|
367
|
+
if (httpStatus === 202) {
|
|
368
|
+
if (!text.trim()) return { status: "pending" };
|
|
369
|
+
let json;
|
|
370
|
+
try {
|
|
371
|
+
json = JSON.parse(text);
|
|
372
|
+
} catch {
|
|
373
|
+
return { status: "pending" };
|
|
374
|
+
}
|
|
375
|
+
const object = JsonObject.safeParse(json);
|
|
376
|
+
const loose = LooseVideoStatus.safeParse(json);
|
|
377
|
+
if (!object.success || !loose.success) return { status: "pending" };
|
|
378
|
+
const parsed = GrokVideoStatus.safeParse({
|
|
379
|
+
...object.data,
|
|
380
|
+
status: loose.data.status ?? "pending"
|
|
381
|
+
});
|
|
382
|
+
return parsed.success ? parsed.data : { status: "pending" };
|
|
383
|
+
}
|
|
384
|
+
const json = parseJsonText(text, "video status");
|
|
385
|
+
const object = JsonObject.safeParse(json);
|
|
386
|
+
const loose = LooseVideoStatus.safeParse(json);
|
|
387
|
+
if (!object.success || !loose.success) throw new GrokProtocolError("Grok video status response has an unexpected shape");
|
|
388
|
+
const status = loose.data.status ?? (loose.data.video?.url ? "done" : "pending");
|
|
389
|
+
const parsed = GrokVideoStatus.safeParse({
|
|
390
|
+
...object.data,
|
|
391
|
+
status
|
|
392
|
+
});
|
|
393
|
+
if (!parsed.success) throw new GrokProtocolError("Grok video status response has an unexpected shape");
|
|
394
|
+
return parsed.data;
|
|
395
|
+
}
|
|
396
|
+
/** Reads the body, re-arming the read timer per chunk. `truncate` caps instead of failing. */
|
|
397
|
+
async function readBody(response, maxBytes, onChunk, truncate) {
|
|
398
|
+
if (!response.body) return "";
|
|
399
|
+
const reader = response.body.getReader();
|
|
400
|
+
const decoder = new TextDecoder();
|
|
401
|
+
let text = "";
|
|
402
|
+
let total = 0;
|
|
403
|
+
for (;;) {
|
|
404
|
+
const { done, value } = await reader.read();
|
|
405
|
+
if (done) break;
|
|
406
|
+
onChunk();
|
|
407
|
+
total += value.byteLength;
|
|
408
|
+
if (total > maxBytes) {
|
|
409
|
+
await reader.cancel().catch(() => void 0);
|
|
410
|
+
if (truncate) return text + decoder.decode(value.subarray(0, maxBytes - (total - value.byteLength)));
|
|
411
|
+
throw new BodyLimitError(`Grok media response exceeded ${maxBytes} bytes`);
|
|
412
|
+
}
|
|
413
|
+
text += decoder.decode(value, { stream: true });
|
|
414
|
+
}
|
|
415
|
+
return text + decoder.decode();
|
|
416
|
+
}
|
|
417
|
+
//#endregion
|
|
418
|
+
export { GROK_IMAGE_MAX_PER_CALL, GROK_IMAGE_READ_TIMEOUT_MS, GROK_IMAGE_TOTAL_TIMEOUT_MS, GROK_VIDEO_POLL_TIMEOUT_MS, GROK_VIDEO_START_TIMEOUT_MS, GrokContentPolicyError, GrokMediaClient, GrokMediaDeliveryError, GrokMediaTimeoutError, decodeGrokImages, summarizeGrokVideoStatus };
|
|
419
|
+
|
|
420
|
+
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZ3Jvay1tZWRpYS1jbGllbnQuanMiLCJuYW1lcyI6W10sInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vc3JjL3V0aWxzL3Byb3ZpZGVycy9ncm9rL2dyb2stbWVkaWEtY2xpZW50LnRzIl0sInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IHogfSBmcm9tIFwiem9kXCI7XG5cbmltcG9ydCB7IHR5cGUgSnNvblZhbHVlIH0gZnJvbSBcIi4uL2NvbW1vbi9wcm92aWRlci10eXBlc1wiO1xuaW1wb3J0IHtcbiAgY2xhc3NpZnlHcm9rSHR0cEVycm9yLFxuICBHcm9rUHJvdG9jb2xFcnJvcixcbiAgcmVhZEdyb2tSZXNwb25zZUhlYWRlcnMsXG59IGZyb20gXCIuL2dyb2stYmFja2VuZC1wcm90b2NvbFwiO1xuaW1wb3J0IHtcbiAgR1JPS19JTUFHRV9ERUZBVUxUX01PREVMLFxuICBHUk9LX1BVQkxJQ19BUElfVVJMLFxuICBHUk9LX1ZJREVPX0RFRkFVTFRfTU9ERUwsXG59IGZyb20gXCIuL2dyb2stY29uc3RhbnRzXCI7XG5pbXBvcnQgeyBHcm9rSHR0cEVycm9yIH0gZnJvbSBcIi4vZ3Jvay1kaXJlY3QtY2xpZW50XCI7XG5pbXBvcnQgeyBHcm9rSW52YWxpZFJlcXVlc3RFcnJvciB9IGZyb20gXCIuL2dyb2stZGlzcGF0Y2hlclwiO1xuaW1wb3J0IHsgYnVpbGRHcm9rTWVkaWFIZWFkZXJzIH0gZnJvbSBcIi4vZ3Jvay1oZWFkZXJzXCI7XG5pbXBvcnQge1xuICBHcm9rSW1hZ2VSZXNwb25zZSxcbiAgR3Jva1ZpZGVvU3RhcnQsXG4gIEdyb2tWaWRlb1N0YXR1cyxcbiAgZ3Jva1ZpZGVvVXJsLFxuICB0eXBlIEdyb2tJbWFnZUVkaXRSZXF1ZXN0LFxuICB0eXBlIEdyb2tJbWFnZUdlbmVyYXRlUmVxdWVzdCxcbiAgdHlwZSBHcm9rTWVkaWFBdXRoLFxuICB0eXBlIEdyb2tNZWRpYVBvcnQsXG4gIHR5cGUgR3Jva1ZpZGVvU3RhcnRSZXF1ZXN0LFxufSBmcm9tIFwiLi9ncm9rLXR5cGVzXCI7XG5cbi8vIGFwaS54LmFpIEltYWdpbmUgY2xpZW50IChpbWFnZXMgKyB2aWRlbykuIEJvZGllcyBhcmUgcGxhaW4gSlNPTjogZ3Jvay1idWlsZCBzZW5kcyB0aGVtIHdpdGhcbi8vIHJlcXdlc3QgYC5qc29uKHBheWxvYWQpYCBhbmQgbm8gY29udGVudC1lbmNvZGluZyAoMS4wLjQ1IHhhaS1ncm9rLXRvb2xzIGltYWdlX2dlbi9tb2QucnM6MTk5LTIxNCxcbi8vIGltYWdlX2VkaXQvbW9kLnJzOjM5OCwgdmlkZW9fZ2VuL21vZC5yczozNjQtMzY3KS4gRXZlcnkgcmVxdWVzdCBjYXJyaWVzIGBjb250ZW50LXR5cGU6XG4vLyBhcHBsaWNhdGlvbi9qc29uYCBiZWNhdXNlIGdyb2stYnVpbGQgaW5zdGFsbHMgaXQgYXMgYSBjbGllbnQgZGVmYXVsdCBoZWFkZXIsIEdFVCBpbmNsdWRlZFxuLy8gKGltYWdlX2dlbi9tb2QucnM6MTA0LTEwNSwgdmlkZW9fZ2VuL21vZC5yczoxODUtMTg2KS5cbi8vXG4vLyBSZXRyeSBzYWZldHkgKHBsYW4gwqc1LjUpOiB0aGlzIGNsaWVudCBuZXZlciByZXRyaWVzLiBBIFBPU1QgdGhhdCBtYXkgaGF2ZSByZWFjaGVkIHVwc3RyZWFtXG4vLyBmYWlscyB3aXRoIEdyb2tNZWRpYURlbGl2ZXJ5RXJyb3Igb3IgR3Jva01lZGlhVGltZW91dEVycm9yLCB3aGljaCB0aGUgZGlzcGF0Y2hlciBjYW5ub3Rcbi8vIGNsYXNzaWZ5IGFuZCB0aGVyZWZvcmUgbmV2ZXIgcmVwbGF5cy4gT25seSBhIGNvbm5lY3QgZmFpbHVyZSB0aGF0IHByb3ZhYmx5IGhhcHBlbmVkIGJlZm9yZVxuLy8gdGhlIHJlcXVlc3Qgd2FzIHdyaXR0ZW4gYmVjb21lcyBhIHRyYW5zaWVudCBHcm9rSHR0cEVycm9yIChzdGF0dXMgMCk7IHRoZSBkaXNwYXRjaGVyIGZhaWxzXG4vLyBvdmVyIG9uIGV4YWN0bHkgdGhhdCBlcnJvciBvbmNlLiBHRVRzICh2aWRlbyBwb2xscykgYWxzbyBtYXAgZXZlcnkgdHJhbnNwb3J0IGZhaWx1cmUgdG9cbi8vIHN0YXR1cyAwOiB0aGV5IGFyZSBpZGVtcG90ZW50LCBhbmQgdGhlIGRpc3BhdGNoZXIgcGlucyBwb2xscyB0byB0aGVpciB0b2tlbi5cblxuLy8gaW1hZ2VfZ2VuL21vZC5yczozNy0zOCAodGhlIHByb3h5IGJ1ZmZlcnMgdGhlIHdob2xlIGltYWdlIGJlZm9yZSB0aGUgZmlyc3QgYnl0ZSlcbmV4cG9ydCBjb25zdCBHUk9LX0lNQUdFX1RPVEFMX1RJTUVPVVRfTVMgPSAzMDBfMDAwO1xuZXhwb3J0IGNvbnN0IEdST0tfSU1BR0VfUkVBRF9USU1FT1VUX01TID0gMjQwXzAwMDtcblxuLy8gdmlkZW9fZ2VuL21vZC5yczozNyw0MFxuZXhwb3J0IGNvbnN0IEdST0tfVklERU9fU1RBUlRfVElNRU9VVF9NUyA9IDYwXzAwMDtcbmV4cG9ydCBjb25zdCBHUk9LX1ZJREVPX1BPTExfVElNRU9VVF9NUyA9IDMwXzAwMDtcblxuLy8gQGFpLXNkay94YWkgeGFpLWltYWdlLW1vZGVsLnRzIG1heEltYWdlc1BlckNhbGxcbmV4cG9ydCBjb25zdCBHUk9LX0lNQUdFX01BWF9QRVJfQ0FMTCA9IDM7XG5cbi8vIGdyb2stYnVpbGQgaW1hZ2VfZ2VuL21vZC5yczoyMzYgYW5kIGltYWdlX2VkaXQvbW9kLnJzOjM2NyBhbHdheXMgc2VuZCBcIjFrXCJcbmNvbnN0IEdST0tfSU1BR0VfREVGQVVMVF9SRVNPTFVUSU9OID0gXCIxa1wiO1xuXG4vLyBpbWFnZV9lZGl0L21vZC5yczoyOCAoWEFJX0lNQUdJTkVfRURJVF9NT0RFTCBlcXVhbHMgdGhlIGdlbmVyYXRpb24gZGVmYXVsdClcbmNvbnN0IEdST0tfSU1BR0VfRURJVF9ERUZBVUxUX01PREVMID0gR1JPS19JTUFHRV9ERUZBVUxUX01PREVMO1xuXG4vLyBAYWktc2RrL3hhaSB2aWRlbyBkdXJhdGlvbiByYW5nZSAxLTE1IHMgKHBsYW4gwqczLjYpXG5jb25zdCBHUk9LX1ZJREVPX01BWF9EVVJBVElPTl9TRUMgPSAxNTtcblxuY29uc3QgTUFYX0lNQUdFX1JFU1BPTlNFX0JZVEVTID0gNjQgKiAxMDI0ICogMTAyNDtcbmNvbnN0IE1BWF9KU09OX1JFU1BPTlNFX0JZVEVTID0gMTAyNCAqIDEwMjQ7XG5jb25zdCBNQVhfRVJST1JfQk9EWV9CWVRFUyA9IDY0ICogMTAyNDtcblxuZXhwb3J0IGludGVyZmFjZSBHcm9rTWVkaWFUaW1lb3V0cyB7XG4gIGltYWdlVG90YWxNczogbnVtYmVyO1xuICBpbWFnZVJlYWRNczogbnVtYmVyO1xuICB2aWRlb1N0YXJ0TXM6IG51bWJlcjtcbiAgdmlkZW9Qb2xsTXM6IG51bWJlcjtcbn1cblxuY29uc3QgREVGQVVMVF9USU1FT1VUUzogR3Jva01lZGlhVGltZW91dHMgPSB7XG4gIGltYWdlVG90YWxNczogR1JPS19JTUFHRV9UT1RBTF9USU1FT1VUX01TLFxuICBpbWFnZVJlYWRNczogR1JPS19JTUFHRV9SRUFEX1RJTUVPVVRfTVMsXG4gIHZpZGVvU3RhcnRNczogR1JPS19WSURFT19TVEFSVF9USU1FT1VUX01TLFxuICB2aWRlb1BvbGxNczogR1JPS19WSURFT19QT0xMX1RJTUVPVVRfTVMsXG59O1xuXG4vKiogVXBzdHJlYW0gZmxhZ2dlZCB0aGUgb3V0cHV0IHdpdGggYHJlc3BlY3RfbW9kZXJhdGlvbjogZmFsc2VgLiBOZXZlciByZXRyaWVkLiAqL1xuZXhwb3J0IGNsYXNzIEdyb2tDb250ZW50UG9saWN5RXJyb3IgZXh0ZW5kcyBFcnJvciB7XG4gIGNvbnN0cnVjdG9yKGtpbmQ6IFwiaW1hZ2VcIiB8IFwidmlkZW9cIikge1xuICAgIHN1cGVyKFxuICAgICAgYCR7a2luZCA9PT0gXCJpbWFnZVwiID8gXCJJbWFnZVwiIDogXCJWaWRlb1wifSBnZW5lcmF0aW9uIHdhcyBibG9ja2VkIGR1ZSB0byBhIGNvbnRlbnQgcG9saWN5IHZpb2xhdGlvbi5gLFxuICAgICk7XG4gICAgdGhpcy5uYW1lID0gXCJHcm9rQ29udGVudFBvbGljeUVycm9yXCI7XG4gIH1cbn1cblxuLyoqIEEgdG90YWwgb3IgcmVhZCB0aW1lb3V0IGZpcmVkLiBGb3IgYSBQT1NULCB1cHN0cmVhbSBtYXkgYWxyZWFkeSBiZSBleGVjdXRpbmcgdGhlIGpvYi4gKi9cbmV4cG9ydCBjbGFzcyBHcm9rTWVkaWFUaW1lb3V0RXJyb3IgZXh0ZW5kcyBFcnJvciB7XG4gIHJlYWRvbmx5IHBoYXNlOiBcInRvdGFsXCIgfCBcInJlYWRcIjtcbiAgcmVhZG9ubHkgdGltZW91dE1zOiBudW1iZXI7XG5cbiAgY29uc3RydWN0b3IocGhhc2U6IFwidG90YWxcIiB8IFwicmVhZFwiLCB0aW1lb3V0TXM6IG51bWJlcikge1xuICAgIHN1cGVyKFxuICAgICAgYEdyb2sgbWVkaWEgcmVxdWVzdCAke3BoYXNlID09PSBcInRvdGFsXCIgPyBcInRpbWVkIG91dFwiIDogXCJzdGFsbGVkXCJ9IGFmdGVyICR7dGltZW91dE1zfSBtc2AsXG4gICAgKTtcbiAgICB0aGlzLm5hbWUgPSBcIkdyb2tNZWRpYVRpbWVvdXRFcnJvclwiO1xuICAgIHRoaXMucGhhc2UgPSBwaGFzZTtcbiAgICB0aGlzLnRpbWVvdXRNcyA9IHRpbWVvdXRNcztcbiAgfVxufVxuXG4vKiogQSBQT1NUIGZhaWxlZCBhZnRlciBpdCBtYXkgaGF2ZSBiZWVuIHdyaXR0ZW47IHJlcGxheWluZyBpdCBjb3VsZCBydW4gdGhlIGpvYiB0d2ljZS4gKi9cbmV4cG9ydCBjbGFzcyBHcm9rTWVkaWFEZWxpdmVyeUVycm9yIGV4dGVuZHMgRXJyb3Ige1xuICBjb25zdHJ1Y3RvcihtZXNzYWdlOiBzdHJpbmcsIG9wdGlvbnM/OiBFcnJvck9wdGlvbnMpIHtcbiAgICBzdXBlcihgR3JvayBtZWRpYSByZXF1ZXN0IGZhaWxlZCBhZnRlciBpdCBtYXkgaGF2ZSBiZWVuIHNlbnQ6ICR7bWVzc2FnZX1gLCBvcHRpb25zKTtcbiAgICB0aGlzLm5hbWUgPSBcIkdyb2tNZWRpYURlbGl2ZXJ5RXJyb3JcIjtcbiAgfVxufVxuXG5leHBvcnQgaW50ZXJmYWNlIEdyb2tNZWRpYUNsaWVudE9wdGlvbnMge1xuICBmZXRjaD86IHR5cGVvZiBmZXRjaDtcbiAgYmFzZVVybD86IHN0cmluZztcbiAgdGltZW91dHM/OiBQYXJ0aWFsPEdyb2tNZWRpYVRpbWVvdXRzPjtcbn1cblxuLy8gRXJyb3IgY29kZXMgcmFpc2VkIHdoaWxlIHJlc29sdmluZyBvciBjb25uZWN0aW5nLCBpLmUuIGJlZm9yZSBhbnkgcmVxdWVzdCBieXRlIHdhcyB3cml0dGVuLlxuY29uc3QgUFJFX1NFTkRfRVJST1JfQ09ERVMgPSBuZXcgU2V0KFtcbiAgXCJFQ09OTlJFRlVTRURcIixcbiAgXCJFTk9URk9VTkRcIixcbiAgXCJFQUlfQUdBSU5cIixcbiAgXCJFQUlfRkFJTFwiLFxuICBcIkVIT1NUVU5SRUFDSFwiLFxuICBcIkVIT1NURE9XTlwiLFxuICBcIkVORVRVTlJFQUNIXCIsXG4gIFwiRU5FVERPV05cIixcbiAgXCJVTkRfRVJSX0NPTk5FQ1RfVElNRU9VVFwiLFxuICBcIkVSUl9UTFNfQ0VSVF9BTFROQU1FX0lOVkFMSURcIixcbiAgXCJDRVJUX0hBU19FWFBJUkVEXCIsXG4gIFwiREVQVEhfWkVST19TRUxGX1NJR05FRF9DRVJUXCIsXG4gIFwiU0VMRl9TSUdORURfQ0VSVF9JTl9DSEFJTlwiLFxuICBcIlVOQUJMRV9UT19HRVRfSVNTVUVSX0NFUlRfTE9DQUxMWVwiLFxuICBcIlVOQUJMRV9UT19WRVJJRllfTEVBRl9TSUdOQVRVUkVcIixcbl0pO1xuXG5jb25zdCBFcnJvcldpdGhDb2RlID0gei5sb29zZU9iamVjdCh7IGNvZGU6IHouc3RyaW5nKCkgfSk7XG5jb25zdCBFcnJvcldpdGhDYXVzZSA9IHoubG9vc2VPYmplY3QoeyBjYXVzZTogei51bmtub3duKCkgfSk7XG5cbi8qKiBUaGUgZmlyc3QgYGNvZGVgIGFsb25nIHRoZSBgY2F1c2VgIGNoYWluICh1bmRpY2kgd3JhcHMgc29ja2V0IGVycm9ycyBpbiBgVHlwZUVycm9yYCkuICovXG5mdW5jdGlvbiBlcnJvckNvZGUoY2F1c2U6IHVua25vd24pOiBzdHJpbmcgfCB1bmRlZmluZWQge1xuICBsZXQgY3VycmVudDogdW5rbm93biA9IGNhdXNlO1xuXG4gIGZvciAobGV0IGRlcHRoID0gMDsgZGVwdGggPCA1ICYmIGN1cnJlbnQgIT09IHVuZGVmaW5lZCAmJiBjdXJyZW50ICE9PSBudWxsOyBkZXB0aCsrKSB7XG4gICAgY29uc3Qgd2l0aENvZGUgPSBFcnJvcldpdGhDb2RlLnNhZmVQYXJzZShjdXJyZW50KTtcblxuICAgIGlmICh3aXRoQ29kZS5zdWNjZXNzKSByZXR1cm4gd2l0aENvZGUuZGF0YS5jb2RlO1xuICAgIGNvbnN0IHdpdGhDYXVzZSA9IEVycm9yV2l0aENhdXNlLnNhZmVQYXJzZShjdXJyZW50KTtcbiAgICBjdXJyZW50ID0gd2l0aENhdXNlLnN1Y2Nlc3MgPyB3aXRoQ2F1c2UuZGF0YS5jYXVzZSA6IHVuZGVmaW5lZDtcbiAgfVxuXG4gIHJldHVybiB1bmRlZmluZWQ7XG59XG5cbmZ1bmN0aW9uIGVycm9yTWVzc2FnZShjYXVzZTogdW5rbm93bik6IHN0cmluZyB7XG4gIHJldHVybiBjYXVzZSBpbnN0YW5jZW9mIEVycm9yID8gY2F1c2UubWVzc2FnZSA6IFN0cmluZyhjYXVzZSk7XG59XG5cbmZ1bmN0aW9uIGFib3J0UmVhc29uKHNpZ25hbDogQWJvcnRTaWduYWwpOiBFcnJvciB7XG4gIGNvbnN0IHJlYXNvbjogdW5rbm93biA9IHNpZ25hbC5yZWFzb247XG5cbiAgcmV0dXJuIHJlYXNvbiBpbnN0YW5jZW9mIEVycm9yID8gcmVhc29uIDogbmV3IERPTUV4Y2VwdGlvbihcIkFib3J0ZWRcIiwgXCJBYm9ydEVycm9yXCIpO1xufVxuXG5mdW5jdGlvbiBjb25uZWN0RmFpbHVyZShjYXVzZTogdW5rbm93bik6IEdyb2tIdHRwRXJyb3Ige1xuICBjb25zdCBjb2RlID0gZXJyb3JDb2RlKGNhdXNlKTtcbiAgY29uc3QgbWVzc2FnZSA9IGAke2Vycm9yTWVzc2FnZShjYXVzZSl9JHtjb2RlID8gYCAoJHtjb2RlfSlgIDogXCJcIn1gO1xuXG4gIHJldHVybiBuZXcgR3Jva0h0dHBFcnJvcih7IC4uLmNsYXNzaWZ5R3Jva0h0dHBFcnJvcigwLCBcIlwiLCB7fSksIG1lc3NhZ2UgfSwgXCJcIiwge30sIHsgY2F1c2UgfSk7XG59XG5cbmNvbnN0IEJBU0U2NCA9IC9eW0EtWmEtejAtOSsvXSo9ezAsMn0kLztcblxuZnVuY3Rpb24gc25pZmZJbWFnZU1lZGlhVHlwZShieXRlczogVWludDhBcnJheSk6IHN0cmluZyB8IHVuZGVmaW5lZCB7XG4gIGlmIChieXRlc1swXSA9PT0gMHhmZiAmJiBieXRlc1sxXSA9PT0gMHhkOCAmJiBieXRlc1syXSA9PT0gMHhmZikgcmV0dXJuIFwiaW1hZ2UvanBlZ1wiO1xuXG4gIGlmIChieXRlc1swXSA9PT0gMHg4OSAmJiBieXRlc1sxXSA9PT0gMHg1MCAmJiBieXRlc1syXSA9PT0gMHg0ZSAmJiBieXRlc1szXSA9PT0gMHg0NylcbiAgICByZXR1cm4gXCJpbWFnZS9wbmdcIjtcblxuICBpZiAoYnl0ZXNbMF0gPT09IDB4NDcgJiYgYnl0ZXNbMV0gPT09IDB4NDkgJiYgYnl0ZXNbMl0gPT09IDB4NDYpIHJldHVybiBcImltYWdlL2dpZlwiO1xuICBjb25zdCBhc2NpaSA9IChmcm9tOiBudW1iZXIsIHRvOiBudW1iZXIpID0+IFN0cmluZy5mcm9tQ2hhckNvZGUoLi4uYnl0ZXMuc3ViYXJyYXkoZnJvbSwgdG8pKTtcblxuICBpZiAoYXNjaWkoMCwgNCkgPT09IFwiUklGRlwiICYmIGFzY2lpKDgsIDEyKSA9PT0gXCJXRUJQXCIpIHJldHVybiBcImltYWdlL3dlYnBcIjtcblxuICByZXR1cm4gdW5kZWZpbmVkO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIEdyb2tEZWNvZGVkSW1hZ2Uge1xuICBieXRlczogVWludDhBcnJheTtcbiAgbWVkaWFUeXBlOiBzdHJpbmc7XG4gIHJldmlzZWRQcm9tcHQ/OiBzdHJpbmc7XG4gIHJlc3BlY3RNb2RlcmF0aW9uPzogYm9vbGVhbjtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBHcm9rRGVjb2RlZEltYWdlcyB7XG4gIGltYWdlczogR3Jva0RlY29kZWRJbWFnZVtdO1xuICBjb3N0SW5Vc2RUaWNrcz86IG51bWJlcjtcbn1cblxuZnVuY3Rpb24gYXNzZXJ0SW1hZ2VzQWxsb3dlZChyZXNwb25zZTogR3Jva0ltYWdlUmVzcG9uc2UpOiB2b2lkIHtcbiAgaWYgKHJlc3BvbnNlLmRhdGEuc29tZSgoaW1hZ2UpID0+IGltYWdlLnJlc3BlY3RfbW9kZXJhdGlvbiA9PT0gZmFsc2UpKVxuICAgIHRocm93IG5ldyBHcm9rQ29udGVudFBvbGljeUVycm9yKFwiaW1hZ2VcIik7XG5cbiAgZm9yIChjb25zdCBpbWFnZSBvZiByZXNwb25zZS5kYXRhKSB7XG4gICAgaWYgKGltYWdlLmI2NF9qc29uLmxlbmd0aCAlIDQgIT09IDAgfHwgIUJBU0U2NC50ZXN0KGltYWdlLmI2NF9qc29uKSlcbiAgICAgIHRocm93IG5ldyBHcm9rUHJvdG9jb2xFcnJvcihcIkdyb2sgaW1hZ2UgcmVzcG9uc2UgY2FycmllZCBpbnZhbGlkIGJhc2U2NCBkYXRhXCIpO1xuICB9XG59XG5cbi8qKiBEZWNvZGVzIGEgdmFsaWRhdGVkIGltYWdlIHJlc3BvbnNlLiBgbWltZV90eXBlYCB3aW5zOyBvdGhlcndpc2UgdGhlIGJ5dGVzIGFyZSBzbmlmZmVkLiAqL1xuZXhwb3J0IGZ1bmN0aW9uIGRlY29kZUdyb2tJbWFnZXMocmVzcG9uc2U6IEdyb2tJbWFnZVJlc3BvbnNlKTogR3Jva0RlY29kZWRJbWFnZXMge1xuICBhc3NlcnRJbWFnZXNBbGxvd2VkKHJlc3BvbnNlKTtcblxuICBjb25zdCBpbWFnZXMgPSByZXNwb25zZS5kYXRhLm1hcCgoaW1hZ2UpOiBHcm9rRGVjb2RlZEltYWdlID0+IHtcbiAgICBjb25zdCBieXRlcyA9IG5ldyBVaW50OEFycmF5KEJ1ZmZlci5mcm9tKGltYWdlLmI2NF9qc29uLCBcImJhc2U2NFwiKSk7XG5cbiAgICBjb25zdCBtZWRpYVR5cGUgPSBpbWFnZS5taW1lX3R5cGU/LnN0YXJ0c1dpdGgoXCJpbWFnZS9cIilcbiAgICAgID8gaW1hZ2UubWltZV90eXBlXG4gICAgICA6IChzbmlmZkltYWdlTWVkaWFUeXBlKGJ5dGVzKSA/PyBcImltYWdlL2pwZWdcIik7XG5cbiAgICBjb25zdCBkZWNvZGVkOiBHcm9rRGVjb2RlZEltYWdlID0geyBieXRlcywgbWVkaWFUeXBlIH07XG5cbiAgICBpZiAoaW1hZ2UucmV2aXNlZF9wcm9tcHQpIGRlY29kZWQucmV2aXNlZFByb21wdCA9IGltYWdlLnJldmlzZWRfcHJvbXB0O1xuXG4gICAgaWYgKGltYWdlLnJlc3BlY3RfbW9kZXJhdGlvbiAhPT0gdW5kZWZpbmVkKSB7XG4gICAgICBkZWNvZGVkLnJlc3BlY3RNb2RlcmF0aW9uID0gaW1hZ2UucmVzcGVjdF9tb2RlcmF0aW9uO1xuICAgIH1cblxuICAgIHJldHVybiBkZWNvZGVkO1xuICB9KTtcblxuICBjb25zdCB0aWNrcyA9IHJlc3BvbnNlLnVzYWdlPy5jb3N0X2luX3VzZF90aWNrcztcbiAgY29uc3QgcmVzdWx0OiBHcm9rRGVjb2RlZEltYWdlcyA9IHsgaW1hZ2VzIH07XG5cbiAgaWYgKHRpY2tzICE9PSB1bmRlZmluZWQpIHJlc3VsdC5jb3N0SW5Vc2RUaWNrcyA9IHRpY2tzO1xuXG4gIHJldHVybiByZXN1bHQ7XG59XG5cbi8vIEZpZWxkcyBAYWktc2RrL3hhaSByZWFkcyB0aGF0IGdyb2stdHlwZXMnIEdyb2tWaWRlb1N0YXR1cyBsZWF2ZXMgbG9vc2Vcbi8vICh4YWktdmlkZW8tbW9kZWwudHM6NzgyLTgxMik6IGByZXNwZWN0X21vZGVyYXRpb25gIG5lc3RzIHVuZGVyIGB2aWRlb2AuXG5jb25zdCBWaWRlb1N0YXR1c0V4dHJhcyA9IHoubG9vc2VPYmplY3Qoe1xuICB2aWRlbzogei5sb29zZU9iamVjdCh7IHJlc3BlY3RfbW9kZXJhdGlvbjogei5ib29sZWFuKCkubnVsbGlzaCgpIH0pLm51bGxpc2goKSxcbiAgZXJyb3I6IHoubG9vc2VPYmplY3QoeyBjb2RlOiB6LnN0cmluZygpLm51bGxpc2goKSwgbWVzc2FnZTogei5zdHJpbmcoKS5udWxsaXNoKCkgfSkubnVsbGlzaCgpLFxufSk7XG5cbmV4cG9ydCBpbnRlcmZhY2UgR3Jva1ZpZGVvU3VtbWFyeSB7XG4gIHN0YXR1czogXCJwZW5kaW5nXCIgfCBcImRvbmVcIiB8IFwiZmFpbGVkXCI7XG4gIHVybD86IHN0cmluZztcbiAgbWltZVR5cGU6IFwidmlkZW8vbXA0XCI7XG4gIHVzYWdlVGlja3M/OiBudW1iZXI7XG4gIGVycm9yPzogc3RyaW5nO1xufVxuXG4vKipcbiAqIENvbGxhcHNlcyBhIHBvbGwgcmVzcG9uc2UgdG8gdGhlIFNESydzIHRocmVlIG91dGNvbWVzLiBUaGUgVVJMIGlzIHJldHVybmVkIHVuY2hhbmdlZCAoRDQpO1xuICogYGV4cGlyZWRgIGFuZCBhIGBkb25lYCB3aXRob3V0IGEgVVJMIGFyZSBmYWlsdXJlcyAoeGFpLXZpZGVvLW1vZGVsLnRzOjY0My03MDUpLlxuICovXG5leHBvcnQgZnVuY3Rpb24gc3VtbWFyaXplR3Jva1ZpZGVvU3RhdHVzKHN0YXR1czogR3Jva1ZpZGVvU3RhdHVzKTogR3Jva1ZpZGVvU3VtbWFyeSB7XG4gIGNvbnN0IGV4dHJhcyA9IFZpZGVvU3RhdHVzRXh0cmFzLnBhcnNlKHN0YXR1cyk7XG5cbiAgaWYgKGV4dHJhcy52aWRlbz8ucmVzcGVjdF9tb2RlcmF0aW9uID09PSBmYWxzZSkgdGhyb3cgbmV3IEdyb2tDb250ZW50UG9saWN5RXJyb3IoXCJ2aWRlb1wiKTtcbiAgY29uc3QgdGlja3MgPSBzdGF0dXMudXNhZ2U/LmNvc3RfaW5fdXNkX3RpY2tzO1xuXG4gIGNvbnN0IGJhc2U6IE9taXQ8R3Jva1ZpZGVvU3VtbWFyeSwgXCJzdGF0dXNcIj4gPSB7IG1pbWVUeXBlOiBcInZpZGVvL21wNFwiIH07XG5cbiAgaWYgKHRpY2tzICE9PSB1bmRlZmluZWQpIGJhc2UudXNhZ2VUaWNrcyA9IHRpY2tzO1xuXG4gIGlmIChzdGF0dXMuc3RhdHVzID09PSBcImV4cGlyZWRcIilcbiAgICByZXR1cm4geyAuLi5iYXNlLCBzdGF0dXM6IFwiZmFpbGVkXCIsIGVycm9yOiBcIlZpZGVvIGdlbmVyYXRpb24gcmVxdWVzdCBleHBpcmVkLlwiIH07XG5cbiAgaWYgKHN0YXR1cy5zdGF0dXMgPT09IFwiZmFpbGVkXCIpIHtcbiAgICBjb25zdCBlcnJvciA9IGV4dHJhcy5lcnJvcj8ubWVzc2FnZSA/PyBleHRyYXMuZXJyb3I/LmNvZGUgPz8gXCJWaWRlbyBnZW5lcmF0aW9uIGZhaWxlZC5cIjtcblxuICAgIHJldHVybiB7IC4uLmJhc2UsIHN0YXR1czogXCJmYWlsZWRcIiwgZXJyb3IgfTtcbiAgfVxuXG4gIGlmIChzdGF0dXMuc3RhdHVzID09PSBcImRvbmVcIikge1xuICAgIGNvbnN0IHVybCA9IGdyb2tWaWRlb1VybChzdGF0dXMpO1xuXG4gICAgaWYgKCF1cmwpXG4gICAgICByZXR1cm4ge1xuICAgICAgICAuLi5iYXNlLFxuICAgICAgICBzdGF0dXM6IFwiZmFpbGVkXCIsXG4gICAgICAgIGVycm9yOiBcIlZpZGVvIGdlbmVyYXRpb24gY29tcGxldGVkIGJ1dCBubyB2aWRlbyBVUkwgd2FzIHJldHVybmVkLlwiLFxuICAgICAgfTtcblxuICAgIHJldHVybiB7IC4uLmJhc2UsIHN0YXR1czogXCJkb25lXCIsIHVybCB9O1xuICB9XG5cbiAgcmV0dXJuIHsgLi4uYmFzZSwgc3RhdHVzOiBcInBlbmRpbmdcIiB9O1xufVxuXG5pbnRlcmZhY2UgTWVkaWFDYWxsIHtcbiAgbWV0aG9kOiBcIkdFVFwiIHwgXCJQT1NUXCI7XG4gIHBhdGg6IHN0cmluZztcbiAgYXV0aDogR3Jva01lZGlhQXV0aDtcbiAgYm9keT86IEdyb2tJbWFnZUJvZHkgfCBHcm9rVmlkZW9Cb2R5O1xuICB0b3RhbE1zOiBudW1iZXI7XG4gIHJlYWRNczogbnVtYmVyO1xuICBtYXhCeXRlczogbnVtYmVyO1xuICBzaWduYWw6IEFib3J0U2lnbmFsIHwgdW5kZWZpbmVkO1xufVxuXG5pbnRlcmZhY2UgTWVkaWFSZXBseSB7XG4gIHJlc3BvbnNlOiBSZXNwb25zZTtcbiAgdGV4dDogc3RyaW5nO1xufVxuXG5jbGFzcyBCb2R5TGltaXRFcnJvciBleHRlbmRzIEVycm9yIHt9XG5cbmV4cG9ydCBjbGFzcyBHcm9rTWVkaWFDbGllbnQgaW1wbGVtZW50cyBHcm9rTWVkaWFQb3J0IHtcbiAgcmVhZG9ubHkgZmV0Y2hJbXBsOiB0eXBlb2YgZmV0Y2g7XG4gIHJlYWRvbmx5IGJhc2VVcmw6IHN0cmluZztcbiAgcmVhZG9ubHkgdGltZW91dHM6IEdyb2tNZWRpYVRpbWVvdXRzO1xuXG4gIGNvbnN0cnVjdG9yKG9wdGlvbnM6IEdyb2tNZWRpYUNsaWVudE9wdGlvbnMgPSB7fSkge1xuICAgIHRoaXMuZmV0Y2hJbXBsID0gb3B0aW9ucy5mZXRjaCA/PyBmZXRjaDtcbiAgICB0aGlzLmJhc2VVcmwgPSAob3B0aW9ucy5iYXNlVXJsID8/IEdST0tfUFVCTElDX0FQSV9VUkwpLnJlcGxhY2UoL1xcLyskLywgXCJcIik7XG4gICAgdGhpcy50aW1lb3V0cyA9IHsgLi4uREVGQVVMVF9USU1FT1VUUywgLi4ub3B0aW9ucy50aW1lb3V0cyB9O1xuICB9XG5cbiAgYXN5bmMgZ2VuZXJhdGVJbWFnZXMoXG4gICAgYXV0aDogR3Jva01lZGlhQXV0aCxcbiAgICByZXF1ZXN0OiBHcm9rSW1hZ2VHZW5lcmF0ZVJlcXVlc3QsXG4gICk6IFByb21pc2U8R3Jva0ltYWdlUmVzcG9uc2U+IHtcbiAgICBjb25zdCBib2R5ID0gaW1hZ2VCb2R5KHJlcXVlc3QsIHJlcXVlc3QubW9kZWwudHJpbSgpIHx8IEdST0tfSU1BR0VfREVGQVVMVF9NT0RFTCk7XG5cbiAgICByZXR1cm4gdGhpcy5wb3N0SW1hZ2VzKFwiL2ltYWdlcy9nZW5lcmF0aW9uc1wiLCBhdXRoLCBib2R5LCByZXF1ZXN0LnNpZ25hbCk7XG4gIH1cblxuICBhc3luYyBlZGl0SW1hZ2VzKGF1dGg6IEdyb2tNZWRpYUF1dGgsIHJlcXVlc3Q6IEdyb2tJbWFnZUVkaXRSZXF1ZXN0KTogUHJvbWlzZTxHcm9rSW1hZ2VSZXNwb25zZT4ge1xuICAgIGlmIChyZXF1ZXN0LmltYWdlcy5sZW5ndGggPT09IDApXG4gICAgICB0aHJvdyBuZXcgR3Jva0ludmFsaWRSZXF1ZXN0RXJyb3IoXCJHcm9rIGltYWdlIGVkaXQgbmVlZHMgYXQgbGVhc3Qgb25lIHJlZmVyZW5jZSBpbWFnZVwiKTtcblxuICAgIGNvbnN0IHVybHMgPSByZXF1ZXN0LmltYWdlcy5tYXAoKHVybCkgPT4ge1xuICAgICAgaWYgKCF1cmwudHJpbSgpKVxuICAgICAgICB0aHJvdyBuZXcgR3Jva0ludmFsaWRSZXF1ZXN0RXJyb3IoXCJHcm9rIGltYWdlIGVkaXQgcmVmZXJlbmNlIG11c3QgYmUgYSBub24tZW1wdHkgVVJMXCIpO1xuXG4gICAgICByZXR1cm4geyB1cmwgfTtcbiAgICB9KTtcblxuICAgIGNvbnN0IGJvZHkgPSBpbWFnZUJvZHkocmVxdWVzdCwgcmVxdWVzdC5tb2RlbC50cmltKCkgfHwgR1JPS19JTUFHRV9FRElUX0RFRkFVTFRfTU9ERUwpO1xuXG4gICAgLy8gaW1hZ2VfZWRpdC9tb2QucnM6MzcxLTM5Njogb25lIHJlZmVyZW5jZSBpcyBgaW1hZ2U6IHt1cmx9YCwgc2V2ZXJhbCBhcmUgYGltYWdlczogW3t1cmx9XWAuXG4gICAgaWYgKHVybHMubGVuZ3RoID09PSAxKSBib2R5LmltYWdlID0gdXJsc1swXTtcbiAgICBlbHNlIGJvZHkuaW1hZ2VzID0gdXJscztcblxuICAgIHJldHVybiB0aGlzLnBvc3RJbWFnZXMoXCIvaW1hZ2VzL2VkaXRzXCIsIGF1dGgsIGJvZHksIHJlcXVlc3Quc2lnbmFsKTtcbiAgfVxuXG4gIGFzeW5jIHN0YXJ0VmlkZW8oYXV0aDogR3Jva01lZGlhQXV0aCwgcmVxdWVzdDogR3Jva1ZpZGVvU3RhcnRSZXF1ZXN0KTogUHJvbWlzZTxHcm9rVmlkZW9TdGFydD4ge1xuICAgIGNvbnN0IGJvZHkgPSB2aWRlb0JvZHkocmVxdWVzdCk7XG5cbiAgICBjb25zdCB7IHRleHQgfSA9IGF3YWl0IHRoaXMuY2FsbCh7XG4gICAgICBtZXRob2Q6IFwiUE9TVFwiLFxuICAgICAgcGF0aDogXCIvdmlkZW9zL2dlbmVyYXRpb25zXCIsXG4gICAgICBhdXRoLFxuICAgICAgYm9keSxcbiAgICAgIHRvdGFsTXM6IHRoaXMudGltZW91dHMudmlkZW9TdGFydE1zLFxuICAgICAgcmVhZE1zOiB0aGlzLnRpbWVvdXRzLnZpZGVvU3RhcnRNcyxcbiAgICAgIG1heEJ5dGVzOiBNQVhfSlNPTl9SRVNQT05TRV9CWVRFUyxcbiAgICAgIHNpZ25hbDogcmVxdWVzdC5zaWduYWwsXG4gICAgfSk7XG5cbiAgICByZXR1cm4gcGFyc2VKc29uKEdyb2tWaWRlb1N0YXJ0LCB0ZXh0LCBcInZpZGVvIHN0YXJ0XCIpO1xuICB9XG5cbiAgYXN5bmMgZ2V0VmlkZW8oXG4gICAgYXV0aDogR3Jva01lZGlhQXV0aCxcbiAgICByZXF1ZXN0SWQ6IHN0cmluZyxcbiAgICBzaWduYWw/OiBBYm9ydFNpZ25hbCxcbiAgKTogUHJvbWlzZTxHcm9rVmlkZW9TdGF0dXM+IHtcbiAgICBpZiAoIXJlcXVlc3RJZC50cmltKCkpIHRocm93IG5ldyBUeXBlRXJyb3IoXCJHcm9rIHZpZGVvIHJlcXVlc3QgaWQgbXVzdCBiZSBub24tZW1wdHlcIik7XG5cbiAgICBjb25zdCB7IHJlc3BvbnNlLCB0ZXh0IH0gPSBhd2FpdCB0aGlzLmNhbGwoe1xuICAgICAgbWV0aG9kOiBcIkdFVFwiLFxuICAgICAgcGF0aDogYC92aWRlb3MvJHtlbmNvZGVVUklDb21wb25lbnQocmVxdWVzdElkKX1gLFxuICAgICAgYXV0aCxcbiAgICAgIHRvdGFsTXM6IHRoaXMudGltZW91dHMudmlkZW9Qb2xsTXMsXG4gICAgICByZWFkTXM6IHRoaXMudGltZW91dHMudmlkZW9Qb2xsTXMsXG4gICAgICBtYXhCeXRlczogTUFYX0pTT05fUkVTUE9OU0VfQllURVMsXG4gICAgICBzaWduYWwsXG4gICAgfSk7XG5cbiAgICBjb25zdCBzdGF0dXMgPSBwYXJzZVZpZGVvU3RhdHVzKHJlc3BvbnNlLnN0YXR1cywgdGV4dCk7XG5cbiAgICBpZiAoVmlkZW9TdGF0dXNFeHRyYXMucGFyc2Uoc3RhdHVzKS52aWRlbz8ucmVzcGVjdF9tb2RlcmF0aW9uID09PSBmYWxzZSlcbiAgICAgIHRocm93IG5ldyBHcm9rQ29udGVudFBvbGljeUVycm9yKFwidmlkZW9cIik7XG5cbiAgICByZXR1cm4gc3RhdHVzO1xuICB9XG5cbiAgYXN5bmMgcG9zdEltYWdlcyhcbiAgICBwYXRoOiBzdHJpbmcsXG4gICAgYXV0aDogR3Jva01lZGlhQXV0aCxcbiAgICBib2R5OiBHcm9rSW1hZ2VCb2R5LFxuICAgIHNpZ25hbDogQWJvcnRTaWduYWwgfCB1bmRlZmluZWQsXG4gICk6IFByb21pc2U8R3Jva0ltYWdlUmVzcG9uc2U+IHtcbiAgICBjb25zdCB7IHRleHQgfSA9IGF3YWl0IHRoaXMuY2FsbCh7XG4gICAgICBtZXRob2Q6IFwiUE9TVFwiLFxuICAgICAgcGF0aCxcbiAgICAgIGF1dGgsXG4gICAgICBib2R5LFxuICAgICAgdG90YWxNczogdGhpcy50aW1lb3V0cy5pbWFnZVRvdGFsTXMsXG4gICAgICByZWFkTXM6IHRoaXMudGltZW91dHMuaW1hZ2VSZWFkTXMsXG4gICAgICBtYXhCeXRlczogTUFYX0lNQUdFX1JFU1BPTlNFX0JZVEVTLFxuICAgICAgc2lnbmFsLFxuICAgIH0pO1xuXG4gICAgY29uc3QgcmVzcG9uc2UgPSBwYXJzZUpzb24oR3Jva0ltYWdlUmVzcG9uc2UsIHRleHQsIFwiaW1hZ2VcIik7XG4gICAgYXNzZXJ0SW1hZ2VzQWxsb3dlZChyZXNwb25zZSk7XG5cbiAgICByZXR1cm4gcmVzcG9uc2U7XG4gIH1cblxuICAvKiogT25lIEhUVFAgZXhjaGFuZ2Ugd2l0aCB0b3RhbCBhbmQgcmVhZCB0aW1lb3V0cyBjb21wb3NlZCB3aXRoIHRoZSBjYWxsZXIncyBzaWduYWwuICovXG4gIGFzeW5jIGNhbGwoY2FsbDogTWVkaWFDYWxsKTogUHJvbWlzZTxNZWRpYVJlcGx5PiB7XG4gICAgY29uc3QgeyBzaWduYWwgfSA9IGNhbGw7XG5cbiAgICBpZiAoc2lnbmFsPy5hYm9ydGVkKSB0aHJvdyBhYm9ydFJlYXNvbihzaWduYWwpO1xuXG4gICAgY29uc3QgaGVhZGVycyA9IHtcbiAgICAgIFwiY29udGVudC10eXBlXCI6IFwiYXBwbGljYXRpb24vanNvblwiLFxuICAgICAgLi4uYnVpbGRHcm9rTWVkaWFIZWFkZXJzKHsgYmVhcmVyOiBjYWxsLmF1dGguYmVhcmVyLCBzZXNzaW9uSWQ6IGNhbGwuYXV0aC5zZXNzaW9uSWQgfSksXG4gICAgfTtcblxuICAgIGNvbnN0IGNvbnRyb2xsZXIgPSBuZXcgQWJvcnRDb250cm9sbGVyKCk7XG4gICAgbGV0IHRpbWVvdXQ6IEdyb2tNZWRpYVRpbWVvdXRFcnJvciB8IHVuZGVmaW5lZDtcblxuICAgIGNvbnN0IGZpcmUgPSAoZXJyb3I6IEdyb2tNZWRpYVRpbWVvdXRFcnJvcikgPT4ge1xuICAgICAgaWYgKHRpbWVvdXQgfHwgY29udHJvbGxlci5zaWduYWwuYWJvcnRlZCkgcmV0dXJuO1xuICAgICAgdGltZW91dCA9IGVycm9yO1xuICAgICAgY29udHJvbGxlci5hYm9ydChlcnJvcik7XG4gICAgfTtcblxuICAgIGNvbnN0IHRvdGFsVGltZXIgPSBzZXRUaW1lb3V0KFxuICAgICAgKCkgPT4gZmlyZShuZXcgR3Jva01lZGlhVGltZW91dEVycm9yKFwidG90YWxcIiwgY2FsbC50b3RhbE1zKSksXG4gICAgICBjYWxsLnRvdGFsTXMsXG4gICAgKTtcblxuICAgIGxldCByZWFkVGltZXI6IFJldHVyblR5cGU8dHlwZW9mIHNldFRpbWVvdXQ+IHwgdW5kZWZpbmVkO1xuXG4gICAgY29uc3QgYXJtUmVhZCA9ICgpID0+IHtcbiAgICAgIGNsZWFyVGltZW91dChyZWFkVGltZXIpO1xuICAgICAgcmVhZFRpbWVyID0gc2V0VGltZW91dChcbiAgICAgICAgKCkgPT4gZmlyZShuZXcgR3Jva01lZGlhVGltZW91dEVycm9yKFwicmVhZFwiLCBjYWxsLnJlYWRNcykpLFxuICAgICAgICBjYWxsLnJlYWRNcyxcbiAgICAgICk7XG4gICAgfTtcblxuICAgIGNvbnN0IG9uQWJvcnQgPSAoKSA9PiBjb250cm9sbGVyLmFib3J0KHNpZ25hbD8ucmVhc29uKTtcbiAgICBzaWduYWw/LmFkZEV2ZW50TGlzdGVuZXIoXCJhYm9ydFwiLCBvbkFib3J0LCB7IG9uY2U6IHRydWUgfSk7XG5cbiAgICAvLyBDYWxsZWQgZm9yIGV2ZXJ5IGZhaWx1cmU6IGEgY2FsbGVyIGFib3J0IG9yIGEgdGltZW91dCB3aW5zIG92ZXIgdGhlIHRyYW5zcG9ydCBlcnJvci5cbiAgICBjb25zdCBzZXR0bGUgPSAoY2F1c2U6IHVua25vd24sIHJlc3BvbmRlZDogYm9vbGVhbik6IEVycm9yID0+IHtcbiAgICAgIGlmIChzaWduYWw/LmFib3J0ZWQpIHJldHVybiBhYm9ydFJlYXNvbihzaWduYWwpO1xuXG4gICAgICBpZiAodGltZW91dCkgcmV0dXJuIHRpbWVvdXQ7XG5cbiAgICAgIGlmIChjYXVzZSBpbnN0YW5jZW9mIEdyb2tQcm90b2NvbEVycm9yIHx8IGNhdXNlIGluc3RhbmNlb2YgR3Jva0h0dHBFcnJvcikgcmV0dXJuIGNhdXNlO1xuXG4gICAgICBpZiAoY2FsbC5tZXRob2QgPT09IFwiR0VUXCIpIHJldHVybiBjb25uZWN0RmFpbHVyZShjYXVzZSk7XG5cbiAgICAgIGlmICghcmVzcG9uZGVkICYmIFBSRV9TRU5EX0VSUk9SX0NPREVTLmhhcyhlcnJvckNvZGUoY2F1c2UpID8/IFwiXCIpKVxuICAgICAgICByZXR1cm4gY29ubmVjdEZhaWx1cmUoY2F1c2UpO1xuXG4gICAgICByZXR1cm4gbmV3IEdyb2tNZWRpYURlbGl2ZXJ5RXJyb3IoZXJyb3JNZXNzYWdlKGNhdXNlKSwgeyBjYXVzZSB9KTtcbiAgICB9O1xuXG4gICAgdHJ5IHtcbiAgICAgIGFybVJlYWQoKTtcbiAgICAgIGxldCByZXNwb25zZTogUmVzcG9uc2U7XG5cbiAgICAgIHRyeSB7XG4gICAgICAgIHJlc3BvbnNlID0gYXdhaXQgdGhpcy5mZXRjaEltcGwoYCR7dGhpcy5iYXNlVXJsfSR7Y2FsbC5wYXRofWAsIHtcbiAgICAgICAgICBtZXRob2Q6IGNhbGwubWV0aG9kLFxuICAgICAgICAgIGhlYWRlcnMsXG4gICAgICAgICAgYm9keTogY2FsbC5ib2R5ID09PSB1bmRlZmluZWQgPyB1bmRlZmluZWQgOiBKU09OLnN0cmluZ2lmeShjYWxsLmJvZHkpLFxuICAgICAgICAgIHNpZ25hbDogY29udHJvbGxlci5zaWduYWwsXG4gICAgICAgIH0pO1xuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgdGhyb3cgc2V0dGxlKGVycm9yLCBmYWxzZSk7XG4gICAgICB9XG5cbiAgICAgIGFybVJlYWQoKTtcblxuICAgICAgdHJ5IHtcbiAgICAgICAgaWYgKCFyZXNwb25zZS5vaykge1xuICAgICAgICAgIGNvbnN0IGJvZHlUZXh0ID0gYXdhaXQgcmVhZEJvZHkocmVzcG9uc2UsIE1BWF9FUlJPUl9CT0RZX0JZVEVTLCBhcm1SZWFkLCB0cnVlKTtcbiAgICAgICAgICB0aHJvdyBuZXcgR3Jva0h0dHBFcnJvcihcbiAgICAgICAgICAgIGNsYXNzaWZ5R3Jva0h0dHBFcnJvcihyZXNwb25zZS5zdGF0dXMsIGJvZHlUZXh0LCByZXNwb25zZS5oZWFkZXJzKSxcbiAgICAgICAgICAgIGJvZHlUZXh0LFxuICAgICAgICAgICAgcmVhZEdyb2tSZXNwb25zZUhlYWRlcnMocmVzcG9uc2UuaGVhZGVycyksXG4gICAgICAgICAgKTtcbiAgICAgICAgfVxuXG4gICAgICAgIGNvbnN0IHRleHQgPSBhd2FpdCByZWFkQm9keShyZXNwb25zZSwgY2FsbC5tYXhCeXRlcywgYXJtUmVhZCwgZmFsc2UpO1xuXG4gICAgICAgIHJldHVybiB7IHJlc3BvbnNlLCB0ZXh0IH07XG4gICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICBpZiAoZXJyb3IgaW5zdGFuY2VvZiBCb2R5TGltaXRFcnJvcikgdGhyb3cgbmV3IEdyb2tQcm90b2NvbEVycm9yKGVycm9yLm1lc3NhZ2UpO1xuICAgICAgICB0aHJvdyBzZXR0bGUoZXJyb3IsIHRydWUpO1xuICAgICAgfVxuICAgIH0gZmluYWxseSB7XG4gICAgICBjbGVhclRpbWVvdXQodG90YWxUaW1lcik7XG4gICAgICBjbGVhclRpbWVvdXQocmVhZFRpbWVyKTtcbiAgICAgIHNpZ25hbD8ucmVtb3ZlRXZlbnRMaXN0ZW5lcihcImFib3J0XCIsIG9uQWJvcnQpO1xuICAgIH1cbiAgfVxufVxuXG4vKipcbiAqIEltYWdlIHJlcXVlc3QgYm9keS4gT3B0aW9uYWwgbWVtYmVycyBhcmUgbGVmdCBgdW5kZWZpbmVkYCwgd2hpY2ggSlNPTi5zdHJpbmdpZnkgb21pdHMsIHNvIHRoZVxuICogc2VyaWFsaXplZCBrZXkgb3JkZXIgc3RheXMgdGhhdCBvZiB0aGUgdmVyaWZpZWQgcmVxdWVzdC5cbiAqL1xuaW50ZXJmYWNlIEdyb2tJbWFnZUJvZHkge1xuICBtb2RlbDogc3RyaW5nO1xuICBwcm9tcHQ6IHN0cmluZztcbiAgbjogbnVtYmVyO1xuICBhc3BlY3RfcmF0aW8/OiBHcm9rSW1hZ2VHZW5lcmF0ZVJlcXVlc3RbXCJhc3BlY3RSYXRpb1wiXTtcbiAgcmVzb2x1dGlvbjogTm9uTnVsbGFibGU8R3Jva0ltYWdlR2VuZXJhdGVSZXF1ZXN0W1wicmVzb2x1dGlvblwiXT47XG4gIHJlc3BvbnNlX2Zvcm1hdDogXCJiNjRfanNvblwiO1xuICBxdWFsaXR5PzogR3Jva0ltYWdlR2VuZXJhdGVSZXF1ZXN0W1wicXVhbGl0eVwiXTtcbiAgb3V0cHV0X2Zvcm1hdD86IEdyb2tJbWFnZUdlbmVyYXRlUmVxdWVzdFtcIm91dHB1dEZvcm1hdFwiXTtcbiAgaW1hZ2U/OiB7IHVybDogc3RyaW5nIH07XG4gIGltYWdlcz86IEFycmF5PHsgdXJsOiBzdHJpbmcgfT47XG59XG5cbi8qKiBWaWRlbyByZXF1ZXN0IGJvZHk7IGB1bmRlZmluZWRgIG1lbWJlcnMgYXJlIG9taXR0ZWQgZnJvbSB0aGUgc2VyaWFsaXplZCBKU09OLiAqL1xuaW50ZXJmYWNlIEdyb2tWaWRlb0JvZHkge1xuICBtb2RlbDogc3RyaW5nO1xuICBwcm9tcHQ6IHN0cmluZztcbiAgaW1hZ2U/OiB7IHVybDogc3RyaW5nIH07XG4gIGR1cmF0aW9uPzogbnVtYmVyO1xuICBhc3BlY3RfcmF0aW8/OiBHcm9rVmlkZW9TdGFydFJlcXVlc3RbXCJhc3BlY3RSYXRpb1wiXTtcbiAgcmVzb2x1dGlvbj86IEdyb2tWaWRlb1N0YXJ0UmVxdWVzdFtcInJlc29sdXRpb25cIl07XG4gIHJlZmVyZW5jZV9pbWFnZXM/OiBBcnJheTx7IHVybDogc3RyaW5nIH0+O1xuICBsYXN0X2ZyYW1lPzogeyB1cmw6IHN0cmluZyB9O1xufVxuXG5mdW5jdGlvbiBpbWFnZUJvZHkocmVxdWVzdDogR3Jva0ltYWdlR2VuZXJhdGVSZXF1ZXN0LCBtb2RlbDogc3RyaW5nKTogR3Jva0ltYWdlQm9keSB7XG4gIGNvbnN0IG4gPSByZXF1ZXN0Lm4gPz8gMTtcblxuICBpZiAoIU51bWJlci5pc1NhZmVJbnRlZ2VyKG4pIHx8IG4gPCAxIHx8IG4gPiBHUk9LX0lNQUdFX01BWF9QRVJfQ0FMTClcbiAgICB0aHJvdyBuZXcgUmFuZ2VFcnJvcihcbiAgICAgIGBHcm9rIGltYWdlIGNvdW50IG11c3QgYmUgYW4gaW50ZWdlciBmcm9tIDEgdG8gJHtHUk9LX0lNQUdFX01BWF9QRVJfQ0FMTH1gLFxuICAgICk7XG5cbiAgLy8gS2V5IG9yZGVyIG9mIHRoZSBVMC12ZXJpZmllZCByZXF1ZXN0IChpbWFnZV9nZW4vbW9kLnJzOjIzMS0yMzgpOyBTREsgb3B0aW9ucyBmb2xsb3cuXG4gIGNvbnN0IGJvZHk6IEdyb2tJbWFnZUJvZHkgPSB7XG4gICAgbW9kZWwsXG4gICAgcHJvbXB0OiByZXF1ZXN0LnByb21wdCxcbiAgICBuLFxuICAgIGFzcGVjdF9yYXRpbzogcmVxdWVzdC5hc3BlY3RSYXRpbyxcbiAgICByZXNvbHV0aW9uOiByZXF1ZXN0LnJlc29sdXRpb24gPz8gR1JPS19JTUFHRV9ERUZBVUxUX1JFU09MVVRJT04sXG4gICAgcmVzcG9uc2VfZm9ybWF0OiBcImI2NF9qc29uXCIsXG4gICAgcXVhbGl0eTogcmVxdWVzdC5xdWFsaXR5LFxuICAgIG91dHB1dF9mb3JtYXQ6IHJlcXVlc3Qub3V0cHV0Rm9ybWF0LFxuICB9O1xuXG4gIHJldHVybiBib2R5O1xufVxuXG5mdW5jdGlvbiB2aWRlb0JvZHkocmVxdWVzdDogR3Jva1ZpZGVvU3RhcnRSZXF1ZXN0KTogR3Jva1ZpZGVvQm9keSB7XG4gIC8vIGBlZGl0LXZpZGVvYCAvIGBleHRlbmQtdmlkZW9gIGFyZSBub3QgaW4gdGhlIHBvcnQgdHlwZTogdGhleSBwb3N0IHRvIC92aWRlb3MvZWRpdHMgYW5kXG4gIC8vIC92aWRlb3MvZXh0ZW5zaW9ucyB3aXRoIGEgc291cmNlIGB2aWRlbzoge3VybH1gICh4YWktdmlkZW8tbW9kZWwudHM6NTg2LTU5MywgMzkxLTM5NiksIGFuZCB0aGVcbiAgLy8gcG9ydCByZXF1ZXN0IGNhcnJpZXMgbm8gdmlkZW8gVVJMLlxuICBjb25zdCByZWZlcmVuY2VzID0gcmVxdWVzdC5yZWZlcmVuY2VJbWFnZXMgPz8gW107XG5cbiAgaWYgKHJlcXVlc3QubW9kZSA9PT0gXCJyZWZlcmVuY2UtdG8tdmlkZW9cIiAmJiByZWZlcmVuY2VzLmxlbmd0aCA9PT0gMClcbiAgICB0aHJvdyBuZXcgR3Jva0ludmFsaWRSZXF1ZXN0RXJyb3IoXCJHcm9rIHJlZmVyZW5jZS10by12aWRlbyBuZWVkcyBhdCBsZWFzdCBvbmUgcmVmZXJlbmNlIGltYWdlXCIpO1xuICBjb25zdCB7IGR1cmF0aW9uIH0gPSByZXF1ZXN0O1xuXG4gIGlmIChcbiAgICBkdXJhdGlvbiAhPT0gdW5kZWZpbmVkICYmXG4gICAgKCFOdW1iZXIuaXNTYWZlSW50ZWdlcihkdXJhdGlvbikgfHwgZHVyYXRpb24gPCAxIHx8IGR1cmF0aW9uID4gR1JPS19WSURFT19NQVhfRFVSQVRJT05fU0VDKVxuICApXG4gICAgdGhyb3cgbmV3IEdyb2tJbnZhbGlkUmVxdWVzdEVycm9yKFxuICAgICAgYEdyb2sgdmlkZW8gZHVyYXRpb24gbXVzdCBiZSBhbiBpbnRlZ2VyIGZyb20gMSB0byAke0dST0tfVklERU9fTUFYX0RVUkFUSU9OX1NFQ31gLFxuICAgICk7XG5cbiAgLy8gRmllbGQgb3JkZXIgb2YgZ3Jvay1idWlsZCBHZW5lcmF0ZVZpZGVvUGF5bG9hZCAodmlkZW9fZ2VuL21vZC5yczo4MTEtODI3KS4gYG1vZGVgIHNlbGVjdHMgdGhlXG4gIC8vIGVuZHBvaW50IGluIEBhaS1zZGsveGFpIGFuZCBpcyBuZXZlciBhIGJvZHkgZmllbGQ7IHJlZmVyZW5jZS10by12aWRlbyBpcyBpbmZlcnJlZCB1cHN0cmVhbVxuICAvLyBmcm9tIGByZWZlcmVuY2VfaW1hZ2VzYCAoeGFpLXZpZGVvLW1vZGVsLnRzOjE2OS0xOTQpLlxuICBjb25zdCBib2R5OiBHcm9rVmlkZW9Cb2R5ID0ge1xuICAgIG1vZGVsOiByZXF1ZXN0Lm1vZGVsLnRyaW0oKSB8fCBHUk9LX1ZJREVPX0RFRkFVTFRfTU9ERUwsXG4gICAgcHJvbXB0OiByZXF1ZXN0LnByb21wdCxcbiAgICBpbWFnZTogcmVxdWVzdC5pbWFnZSA9PT0gdW5kZWZpbmVkID8gdW5kZWZpbmVkIDogeyB1cmw6IHJlcXVlc3QuaW1hZ2UgfSxcbiAgICBkdXJhdGlvbixcbiAgICBhc3BlY3RfcmF0aW86IHJlcXVlc3QuYXNwZWN0UmF0aW8sXG4gICAgcmVzb2x1dGlvbjogcmVxdWVzdC5yZXNvbHV0aW9uLFxuICAgIHJlZmVyZW5jZV9pbWFnZXM6IHJlZmVyZW5jZXMubGVuZ3RoID09PSAwID8gdW5kZWZpbmVkIDogcmVmZXJlbmNlcy5tYXAoKHVybCkgPT4gKHsgdXJsIH0pKSxcbiAgICBsYXN0X2ZyYW1lOiByZXF1ZXN0Lmxhc3RGcmFtZSA9PT0gdW5kZWZpbmVkID8gdW5kZWZpbmVkIDogeyB1cmw6IHJlcXVlc3QubGFzdEZyYW1lIH0sXG4gIH07XG5cbiAgcmV0dXJuIGJvZHk7XG59XG5cbmZ1bmN0aW9uIHBhcnNlSnNvblRleHQodGV4dDogc3RyaW5nLCB3aGF0OiBzdHJpbmcpOiBKc29uVmFsdWUge1xuICB0cnkge1xuICAgIC8vIEpTT04ucGFyc2Ugd2l0aG91dCBhIHJldml2ZXIgeWllbGRzIG9ubHkgSlNPTiB2YWx1ZXMuXG4gICAgY29uc3QganNvbjogSnNvblZhbHVlID0gSlNPTi5wYXJzZSh0ZXh0KTtcblxuICAgIHJldHVybiBqc29uO1xuICB9IGNhdGNoIHtcbiAgICB0aHJvdyBuZXcgR3Jva1Byb3RvY29sRXJyb3IoYEdyb2sgJHt3aGF0fSByZXNwb25zZSBpcyBub3QgSlNPTmApO1xuICB9XG59XG5cbmZ1bmN0aW9uIHBhcnNlSnNvbjxUPihzY2hlbWE6IHouWm9kVHlwZTxUPiwgdGV4dDogc3RyaW5nLCB3aGF0OiBzdHJpbmcpOiBUIHtcbiAgY29uc3QgcGFyc2VkID0gc2NoZW1hLnNhZmVQYXJzZShwYXJzZUpzb25UZXh0KHRleHQsIHdoYXQpKTtcblxuICBpZiAoIXBhcnNlZC5zdWNjZXNzKSB0aHJvdyBuZXcgR3Jva1Byb3RvY29sRXJyb3IoYEdyb2sgJHt3aGF0fSByZXNwb25zZSBoYXMgYW4gdW5leHBlY3RlZCBzaGFwZWApO1xuXG4gIHJldHVybiBwYXJzZWQuZGF0YTtcbn1cblxuY29uc3QgSnNvbk9iamVjdCA9IHoucmVjb3JkKHouc3RyaW5nKCksIHoudW5rbm93bigpKTtcblxuY29uc3QgTG9vc2VWaWRlb1N0YXR1cyA9IHoubG9vc2VPYmplY3Qoe1xuICBzdGF0dXM6IHouc3RyaW5nKCkubnVsbGlzaCgpLFxuICB2aWRlbzogei5sb29zZU9iamVjdCh7IHVybDogei5zdHJpbmcoKS5udWxsaXNoKCkgfSkubnVsbGlzaCgpLFxufSk7XG5cbi8qKlxuICogMjAyIG1lYW5zIHBlbmRpbmcsIHBvc3NpYmx5IHdpdGggYW4gZW1wdHkgb3IgcGFydGlhbCBib2R5ICh4YWktdmlkZW8tbW9kZWwudHM6ODc2LTg5NDtcbiAqIGdyb2stYnVpbGQgdmlkZW9fZ2VuL21vZC5yczo0NDIgYWNjZXB0cyBpdCB0b28pLiBBIDIwMCB3aXRob3V0IGBzdGF0dXNgIGJ1dCB3aXRoIGEgdmlkZW8gVVJMXG4gKiBpcyBkb25lICh4YWktdmlkZW8tbW9kZWwudHM6NjczLTY3NikuXG4gKi9cbmZ1bmN0aW9uIHBhcnNlVmlkZW9TdGF0dXMoaHR0cFN0YXR1czogbnVtYmVyLCB0ZXh0OiBzdHJpbmcpOiBHcm9rVmlkZW9TdGF0dXMge1xuICBpZiAoaHR0cFN0YXR1cyA9PT0gMjAyKSB7XG4gICAgaWYgKCF0ZXh0LnRyaW0oKSkgcmV0dXJuIHsgc3RhdHVzOiBcInBlbmRpbmdcIiB9O1xuICAgIGxldCBqc29uOiB1bmtub3duO1xuXG4gICAgdHJ5IHtcbiAgICAgIGpzb24gPSBKU09OLnBhcnNlKHRleHQpO1xuICAgIH0gY2F0Y2gge1xuICAgICAgcmV0dXJuIHsgc3RhdHVzOiBcInBlbmRpbmdcIiB9O1xuICAgIH1cblxuICAgIGNvbnN0IG9iamVjdCA9IEpzb25PYmplY3Quc2FmZVBhcnNlKGpzb24pO1xuICAgIGNvbnN0IGxvb3NlID0gTG9vc2VWaWRlb1N0YXR1cy5zYWZlUGFyc2UoanNvbik7XG5cbiAgICBpZiAoIW9iamVjdC5zdWNjZXNzIHx8ICFsb29zZS5zdWNjZXNzKSByZXR1cm4geyBzdGF0dXM6IFwicGVuZGluZ1wiIH07XG5cbiAgICBjb25zdCBwYXJzZWQgPSBHcm9rVmlkZW9TdGF0dXMuc2FmZVBhcnNlKHtcbiAgICAgIC4uLm9iamVjdC5kYXRhLFxuICAgICAgc3RhdHVzOiBsb29zZS5kYXRhLnN0YXR1cyA/PyBcInBlbmRpbmdcIixcbiAgICB9KTtcblxuICAgIHJldHVybiBwYXJzZWQuc3VjY2VzcyA/IHBhcnNlZC5kYXRhIDogeyBzdGF0dXM6IFwicGVuZGluZ1wiIH07XG4gIH1cblxuICBjb25zdCBqc29uID0gcGFyc2VKc29uVGV4dCh0ZXh0LCBcInZpZGVvIHN0YXR1c1wiKTtcbiAgY29uc3Qgb2JqZWN0ID0gSnNvbk9iamVjdC5zYWZlUGFyc2UoanNvbik7XG4gIGNvbnN0IGxvb3NlID0gTG9vc2VWaWRlb1N0YXR1cy5zYWZlUGFyc2UoanNvbik7XG5cbiAgaWYgKCFvYmplY3Quc3VjY2VzcyB8fCAhbG9vc2Uuc3VjY2VzcylcbiAgICB0aHJvdyBuZXcgR3Jva1Byb3RvY29sRXJyb3IoXCJHcm9rIHZpZGVvIHN0YXR1cyByZXNwb25zZSBoYXMgYW4gdW5leHBlY3RlZCBzaGFwZVwiKTtcbiAgY29uc3Qgc3RhdHVzID0gbG9vc2UuZGF0YS5zdGF0dXMgPz8gKGxvb3NlLmRhdGEudmlkZW8/LnVybCA/IFwiZG9uZVwiIDogXCJwZW5kaW5nXCIpO1xuICBjb25zdCBwYXJzZWQgPSBHcm9rVmlkZW9TdGF0dXMuc2FmZVBhcnNlKHsgLi4ub2JqZWN0LmRhdGEsIHN0YXR1cyB9KTtcblxuICBpZiAoIXBhcnNlZC5zdWNjZXNzKVxuICAgIHRocm93IG5ldyBHcm9rUHJvdG9jb2xFcnJvcihcIkdyb2sgdmlkZW8gc3RhdHVzIHJlc3BvbnNlIGhhcyBhbiB1bmV4cGVjdGVkIHNoYXBlXCIpO1xuXG4gIHJldHVybiBwYXJzZWQuZGF0YTtcbn1cblxuLyoqIFJlYWRzIHRoZSBib2R5LCByZS1hcm1pbmcgdGhlIHJlYWQgdGltZXIgcGVyIGNodW5rLiBgdHJ1bmNhdGVgIGNhcHMgaW5zdGVhZCBvZiBmYWlsaW5nLiAqL1xuYXN5bmMgZnVuY3Rpb24gcmVhZEJvZHkoXG4gIHJlc3BvbnNlOiBSZXNwb25zZSxcbiAgbWF4Qnl0ZXM6IG51bWJlcixcbiAgb25DaHVuazogKCkgPT4gdm9pZCxcbiAgdHJ1bmNhdGU6IGJvb2xlYW4sXG4pOiBQcm9taXNlPHN0cmluZz4ge1xuICBpZiAoIXJlc3BvbnNlLmJvZHkpIHJldHVybiBcIlwiO1xuICBjb25zdCByZWFkZXIgPSByZXNwb25zZS5ib2R5LmdldFJlYWRlcigpO1xuICBjb25zdCBkZWNvZGVyID0gbmV3IFRleHREZWNvZGVyKCk7XG4gIGxldCB0ZXh0ID0gXCJcIjtcbiAgbGV0IHRvdGFsID0gMDtcblxuICBmb3IgKDs7KSB7XG4gICAgY29uc3QgeyBkb25lLCB2YWx1ZSB9ID0gYXdhaXQgcmVhZGVyLnJlYWQoKTtcblxuICAgIGlmIChkb25lKSBicmVhaztcbiAgICBvbkNodW5rKCk7XG4gICAgdG90YWwgKz0gdmFsdWUuYnl0ZUxlbmd0aDtcblxuICAgIGlmICh0b3RhbCA+IG1heEJ5dGVzKSB7XG4gICAgICBhd2FpdCByZWFkZXIuY2FuY2VsKCkuY2F0Y2goKCkgPT4gdW5kZWZpbmVkKTtcblxuICAgICAgaWYgKHRydW5jYXRlKVxuICAgICAgICByZXR1cm4gdGV4dCArIGRlY29kZXIuZGVjb2RlKHZhbHVlLnN1YmFycmF5KDAsIG1heEJ5dGVzIC0gKHRvdGFsIC0gdmFsdWUuYnl0ZUxlbmd0aCkpKTtcbiAgICAgIHRocm93IG5ldyBCb2R5TGltaXRFcnJvcihgR3JvayBtZWRpYSByZXNwb25zZSBleGNlZWRlZCAke21heEJ5dGVzfSBieXRlc2ApO1xuICAgIH1cblxuICAgIHRleHQgKz0gZGVjb2Rlci5kZWNvZGUodmFsdWUsIHsgc3RyZWFtOiB0cnVlIH0pO1xuICB9XG5cbiAgcmV0dXJuIHRleHQgKyBkZWNvZGVyLmRlY29kZSgpO1xufVxuIl0sIm1hcHBpbmdzIjoiOzs7Ozs7OztBQTBDQSxNQUFhLDhCQUE4QjtBQUMzQyxNQUFhLDZCQUE2QjtBQUcxQyxNQUFhLDhCQUE4QjtBQUMzQyxNQUFhLDZCQUE2QjtBQUcxQyxNQUFhLDBCQUEwQjtBQUd2QyxNQUFNLGdDQUFnQztBQUd0QyxNQUFNLGdDQUFnQztBQUd0QyxNQUFNLDhCQUE4QjtBQUVwQyxNQUFNLDJCQUEyQixLQUFLLE9BQU87QUFDN0MsTUFBTSwwQkFBMEIsT0FBTztBQUN2QyxNQUFNLHVCQUF1QixLQUFLO0FBU2xDLE1BQU0sbUJBQXNDO0NBQzFDLGNBQWM7Q0FDZCxhQUFhO0NBQ2IsY0FBYztDQUNkLGFBQWE7QUFDZjs7QUFHQSxJQUFhLHlCQUFiLGNBQTRDLE1BQU07Q0FDaEQsWUFBWSxNQUF5QjtFQUNuQyxNQUNFLEdBQUcsU0FBUyxVQUFVLFVBQVUsUUFBUSwyREFDMUM7RUFDQSxLQUFLLE9BQU87Q0FDZDtBQUNGOztBQUdBLElBQWEsd0JBQWIsY0FBMkMsTUFB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
|