@crowdin/app-project-module 2.0.0 → 2.2.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/out/index.d.ts CHANGED
@@ -6,6 +6,7 @@ export { getRequestCredentialsMasker, postRequestCredentialsMasker, maskKey };
6
6
  export * from './types';
7
7
  export { Cron } from './util/cron';
8
8
  export { express };
9
+ export { reportInsight as reportAdvisorInsight } from './modules/advisor-inspector/report-insight';
9
10
  export declare const metadataStore: CrowdinMetadataStore;
10
11
  export declare function createApp(clientConfig: ClientConfig): void;
11
12
  export declare function addCrowdinEndpoints(app: Express, clientConfig: Config | ClientConfig): CrowdinAppUtilities;
package/out/index.js CHANGED
@@ -48,7 +48,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
48
48
  return (mod && mod.__esModule) ? mod : { "default": mod };
49
49
  };
50
50
  Object.defineProperty(exports, "__esModule", { value: true });
51
- exports.metadataStore = exports.express = exports.maskKey = exports.postRequestCredentialsMasker = exports.getRequestCredentialsMasker = void 0;
51
+ exports.metadataStore = exports.reportAdvisorInsight = exports.express = exports.maskKey = exports.postRequestCredentialsMasker = exports.getRequestCredentialsMasker = void 0;
52
52
  exports.createApp = createApp;
53
53
  exports.addCrowdinEndpoints = addCrowdinEndpoints;
54
54
  const logsFormatter = __importStar(require("@crowdin/logs-formatter"));
@@ -90,6 +90,7 @@ const spellCheckApp = __importStar(require("./modules/custom-spell-check"));
90
90
  const aiProvider = __importStar(require("./modules/ai-provider"));
91
91
  const aiPromptProvider = __importStar(require("./modules/ai-prompt-provider"));
92
92
  const editorRightPanelApp = __importStar(require("./modules/editor-right-panel"));
93
+ const advisorInspector = __importStar(require("./modules/advisor-inspector"));
93
94
  const externalQaCheck = __importStar(require("./modules/external-qa-check"));
94
95
  const fileProcessingApps = __importStar(require("./modules/file-processing"));
95
96
  const integrationApp = __importStar(require("./modules/integration"));
@@ -110,6 +111,8 @@ const automationAction = __importStar(require("./modules/automation-action"));
110
111
  const authGuard = __importStar(require("./modules/auth-guard"));
111
112
  const subscription_1 = require("./util/subscription");
112
113
  __exportStar(require("./types"), exports);
114
+ var report_insight_1 = require("./modules/advisor-inspector/report-insight");
115
+ Object.defineProperty(exports, "reportAdvisorInsight", { enumerable: true, get: function () { return report_insight_1.reportInsight; } });
113
116
  exports.metadataStore = {
114
117
  getMetadata: (id) => {
115
118
  return storage.getStorage().getMetadata(id);
@@ -257,6 +260,7 @@ function addCrowdinEndpoints(app, clientConfig) {
257
260
  aiProvider.register({ config, app });
258
261
  aiPromptProvider.register({ config, app });
259
262
  externalQaCheck.register({ config, app });
263
+ advisorInspector.register({ config, app });
260
264
  webhooks.register({ config, app });
261
265
  workflowStepType.register({ config, app });
262
266
  aiRequestProcessors.register({ config, app });
@@ -0,0 +1,4 @@
1
+ import { Response } from 'express';
2
+ import { AdvisorInspectorModule } from '../types';
3
+ import { CrowdinClientRequest } from '../../../types';
4
+ export default function handle(inspector: AdvisorInspectorModule, moduleKey: string): (req: import("express").Request | CrowdinClientRequest, res: Response, next: Function) => void;
@@ -0,0 +1,44 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.default = handle;
13
+ const util_1 = require("../../../util");
14
+ const logger_1 = require("../../../util/logger");
15
+ function handle(inspector, moduleKey) {
16
+ return (0, util_1.runAsyncWrapper)((req, res) => __awaiter(this, void 0, void 0, function* () {
17
+ const body = req.body;
18
+ (0, logger_1.log)(`Received advisor-inspector recheck nudge: ${JSON.stringify(body)}`);
19
+ // Ack first — BE expects a fast 2xx; the callback runs after the response flushes.
20
+ res.send({ data: { accepted: true } });
21
+ // Capture context locals BEFORE scheduling — Express may recycle `req` post-response.
22
+ const projectId = body.projectId;
23
+ const inspectorId = body.inspectorKey;
24
+ const crowdinId = req.crowdinContext.crowdinId;
25
+ const context = req.crowdinContext;
26
+ const client = req.crowdinApiClient;
27
+ // queueMicrotask is universal (works on Node AND Cloudflare Workers; setImmediate is Node-only).
28
+ queueMicrotask(() => __awaiter(this, void 0, void 0, function* () {
29
+ try {
30
+ yield inspector.onRecheck({
31
+ projectId,
32
+ moduleKey,
33
+ inspectorId,
34
+ crowdinId,
35
+ client,
36
+ context,
37
+ });
38
+ }
39
+ catch (e) {
40
+ (0, logger_1.log)(`advisor-inspector onRecheck error: ${(0, logger_1.getErrorMessage)(e)}`);
41
+ }
42
+ }));
43
+ }));
44
+ }
@@ -0,0 +1,6 @@
1
+ import { Express } from 'express';
2
+ import { Config } from '../../types';
3
+ export declare function register({ config, app }: {
4
+ config: Config;
5
+ app: Express;
6
+ }): void;
@@ -0,0 +1,35 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.register = register;
7
+ const crowdin_client_1 = require("../../middlewares/crowdin-client");
8
+ const json_response_1 = require("../../middlewares/json-response");
9
+ const render_ui_module_1 = __importDefault(require("../../middlewares/render-ui-module"));
10
+ const ui_module_1 = __importDefault(require("../../middlewares/ui-module"));
11
+ const recheck_1 = __importDefault(require("./handlers/recheck"));
12
+ const key_1 = require("./key");
13
+ function register({ config, app }) {
14
+ if (!config.advisorInspector) {
15
+ return;
16
+ }
17
+ const items = config.advisorInspector;
18
+ const isSingle = items.length === 1;
19
+ for (const [index, inspector] of items.entries()) {
20
+ const key = (0, key_1.resolveAdvisorInspectorKey)(config, inspector, index, isSingle);
21
+ const base = `/advisor-inspector/${key}`;
22
+ // Recheck nudge endpoint (BE → app, fire-and-forget).
23
+ // checkSubscriptionExpiration=false: nudges are platform traffic; 402-ing here
24
+ // would mask the async flow. App-paid features should gate inside onRecheck.
25
+ app.post(`${base}/recheck`, json_response_1.handle, (0, crowdin_client_1.handle)({
26
+ config,
27
+ optional: false,
28
+ checkSubscriptionExpiration: false,
29
+ moduleKey: key,
30
+ }), (0, recheck_1.default)(inspector, key));
31
+ if (inspector.uiPath || inspector.formSchema) {
32
+ app.use(`${base}/iframe`, (0, ui_module_1.default)({ config, moduleType: key }), (0, render_ui_module_1.default)(Object.assign(Object.assign({}, inspector), { key }), config));
33
+ }
34
+ }
35
+ }
@@ -0,0 +1,4 @@
1
+ import { AdvisorInspectorModule } from './types';
2
+ export declare function resolveAdvisorInspectorKey(config: {
3
+ identifier: string;
4
+ }, item: AdvisorInspectorModule, index: number, isSingle: boolean): string;
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.resolveAdvisorInspectorKey = resolveAdvisorInspectorKey;
4
+ const normalize_module_1 = require("../../util/normalize-module");
5
+ function resolveAdvisorInspectorKey(config, item, index, isSingle) {
6
+ return (0, normalize_module_1.resolveInstanceKey)({
7
+ identifier: config.identifier,
8
+ suffix: 'advisor-inspector',
9
+ item,
10
+ index,
11
+ isSingle,
12
+ });
13
+ }
@@ -0,0 +1,3 @@
1
+ import { Config } from '../../types';
2
+ import { ReportInsightArgs } from './types';
3
+ export declare function reportInsight(config: Config, args: ReportInsightArgs): Promise<void>;
@@ -0,0 +1,61 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ var __importDefault = (this && this.__importDefault) || function (mod) {
12
+ return (mod && mod.__esModule) ? mod : { "default": mod };
13
+ };
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.reportInsight = reportInsight;
16
+ const axios_1 = __importDefault(require("axios"));
17
+ const storage_1 = require("../../storage");
18
+ const connection_1 = require("../../util/connection");
19
+ const logger_1 = require("../../util/logger");
20
+ function buildBody(args) {
21
+ var _a, _b;
22
+ return Object.assign(Object.assign(Object.assign({ outcome: args.outcome }, (args.checkedAt !== undefined && { checkedAt: args.checkedAt })), { metrics: (_a = args.metrics) !== null && _a !== void 0 ? _a : [], recommendations: (_b = args.recommendations) !== null && _b !== void 0 ? _b : [] }), (args.payload !== undefined && { payload: args.payload }));
23
+ }
24
+ function put(url_1, body_1, token_1) {
25
+ return __awaiter(this, arguments, void 0, function* (url, body, token, timeoutMs = 300000) {
26
+ yield axios_1.default.put(url, body, {
27
+ headers: { Authorization: `Bearer ${token}` },
28
+ timeout: timeoutMs,
29
+ });
30
+ });
31
+ }
32
+ function isUnauthorized(e) {
33
+ const response = e === null || e === void 0 ? void 0 : e.response;
34
+ return !!response && response.status === 401;
35
+ }
36
+ function reportInsight(config, args) {
37
+ return __awaiter(this, void 0, void 0, function* () {
38
+ const credentials = yield (0, storage_1.getStorage)().getCrowdinCredentials(args.crowdinId);
39
+ if (!credentials) {
40
+ throw new Error(`reportInsight: no credentials for crowdinId=${args.crowdinId}`);
41
+ }
42
+ const body = buildBody(args);
43
+ const initial = yield (0, connection_1.prepareCrowdinClient)({ config, credentials, autoRenew: true });
44
+ let token = initial.token;
45
+ const url = `${initial.client.url}/projects/${args.projectId}` +
46
+ `/applications/${config.identifier}` +
47
+ `/modules/${args.moduleKey}/advisors/insights`;
48
+ try {
49
+ yield put(url, body, token, args.timeoutMs);
50
+ }
51
+ catch (e) {
52
+ if (isUnauthorized(e)) {
53
+ ({ token } = yield (0, connection_1.prepareCrowdinClient)({ config, credentials, autoRenew: true }));
54
+ yield put(url, body, token, args.timeoutMs);
55
+ return;
56
+ }
57
+ (0, logger_1.log)(`reportInsight PUT failed: ${(0, logger_1.getErrorMessage)(e)}`);
58
+ throw e;
59
+ }
60
+ });
61
+ }
@@ -0,0 +1,59 @@
1
+ import Crowdin from '@crowdin/crowdin-api-client';
2
+ import { CrowdinContextInfo, Environments, ModuleKey, UiModule } from '../../types';
3
+ export type AdvisorInspectorSeverity = 'high' | 'medium' | 'low';
4
+ export type AdvisorInspectorRefreshPolicy = 'hourly' | 'daily';
5
+ export type AdvisorInspectorCategory = 'context';
6
+ export type AdvisorInspectorOutcome = 'flagged' | 'clear' | 'not_applicable';
7
+ export interface AdvisorInspectorMetric {
8
+ key: string;
9
+ value: number;
10
+ unit?: 'percent' | 'count';
11
+ /** Comparison baseline shown in the UI */
12
+ threshold?: number;
13
+ tone?: 'default' | 'success' | 'danger';
14
+ checkedAt?: string;
15
+ }
16
+ export interface AdvisorInspectorRecommendation {
17
+ id: string;
18
+ primary?: boolean;
19
+ params?: Record<string, unknown>;
20
+ }
21
+ export interface AdvisorInspectorRecheckArgs {
22
+ projectId: number;
23
+ moduleKey: string;
24
+ /** prefixed, BE-supplied (e.g. 'app:my-app:daily-llm-check') */
25
+ inspectorId: string;
26
+ crowdinId: string;
27
+ client?: Crowdin;
28
+ context: CrowdinContextInfo;
29
+ }
30
+ export interface AdvisorInspectorRecheckRequest {
31
+ projectId: number;
32
+ inspectorKey: string;
33
+ }
34
+ export interface ReportInsightArgs {
35
+ crowdinId: string;
36
+ projectId: number;
37
+ moduleKey: string;
38
+ outcome: AdvisorInspectorOutcome;
39
+ metrics?: AdvisorInspectorMetric[];
40
+ recommendations?: AdvisorInspectorRecommendation[];
41
+ /**
42
+ * Free-form payload surfaced to the FE iframe via `formData`. BE requires an array
43
+ * (PHP-style — indexed or associative) and rejects raw scalars.
44
+ */
45
+ payload?: unknown[] | Record<string, unknown>;
46
+ /** RFC3339; BE defaults to now() and clamps if >1h future / >7d past */
47
+ checkedAt?: string;
48
+ /** PUT request timeout in ms; default 300_000 (5 minutes) */
49
+ timeoutMs?: number;
50
+ }
51
+ export interface AdvisorInspectorModule extends Environments, ModuleKey, UiModule {
52
+ title: string;
53
+ /** Optional summary line; ≤70 chars */
54
+ summary?: string;
55
+ severity: AdvisorInspectorSeverity;
56
+ category: AdvisorInspectorCategory;
57
+ refreshPolicy: AdvisorInspectorRefreshPolicy;
58
+ onRecheck: (args: AdvisorInspectorRecheckArgs) => Promise<void>;
59
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -369,52 +369,71 @@ function updateCrowdinFromWebhookRequest(args) {
369
369
  }
370
370
  function listenQueueMessage(_a) {
371
371
  return __awaiter(this, arguments, void 0, function* ({ config, integration, queueName, queueUrl, }) {
372
- let reconnectAttempts = 0;
373
- const connect = () => __awaiter(this, void 0, void 0, function* () {
374
- try {
375
- const connection = yield amqplib_1.default.connect(queueUrl, {
376
- heartbeat: connectionHeartbeat, // 60 seconds heartbeat
377
- });
378
- // Reset reconnect attempts on successful connection
379
- reconnectAttempts = 0;
380
- connection.on('error', (err) => {
381
- (0, logger_1.logError)(`AMQP connection error: ${err.message}`);
382
- });
383
- connection.on('close', () => __awaiter(this, void 0, void 0, function* () {
384
- (0, logger_1.logError)('AMQP connection closed, attempting to reconnect...');
385
- yield scheduleReconnect();
386
- }));
387
- const channel = yield connection.createChannel();
388
- if (channel) {
389
- yield channel.assertQueue(queueName, { durable: true });
390
- yield channel.prefetch(prefetchCount);
391
- channel.on('error', (err) => {
392
- (0, logger_1.logError)(`AMQP channel error: ${err.message}`);
393
- });
394
- channel.on('close', () => {
395
- (0, logger_1.logError)('AMQP channel closed');
396
- });
397
- const onMessage = consumer({ channel, config, integration });
398
- yield channel.consume(queueName, onMessage, { noAck: false });
399
- }
400
- }
401
- catch (e) {
402
- (0, logger_1.logError)(`Failed to connect to AMQP: ${e}`);
403
- yield scheduleReconnect();
404
- }
372
+ let parsedUrl;
373
+ try {
374
+ parsedUrl = new URL(queueUrl);
375
+ }
376
+ catch (err) {
377
+ (0, logger_1.logError)(`Invalid AMQP queueUrl: ${err}`);
378
+ return;
379
+ }
380
+ const setup = (model) => __awaiter(this, void 0, void 0, function* () {
381
+ const channel = yield model.createChannel();
382
+ yield channel.assertQueue(queueName, { durable: true });
383
+ yield channel.prefetch(prefetchCount);
384
+ channel.on('error', (err) => {
385
+ (0, logger_1.logError)(`AMQP channel error: ${err.message}`);
386
+ });
387
+ channel.on('close', () => {
388
+ (0, logger_1.logError)('AMQP channel closed');
389
+ });
390
+ channel.on('handler-error', (err, eventName) => {
391
+ (0, logger_1.logError)(`AMQP channel handler error on event '${eventName}': ${err}`);
392
+ });
393
+ const onMessage = consumer({ channel, config, integration });
394
+ yield channel.consume(queueName, onMessage, { noAck: false });
405
395
  });
406
- const scheduleReconnect = () => __awaiter(this, void 0, void 0, function* () {
407
- if (reconnectAttempts >= maxReconnectAttempts) {
408
- (0, logger_1.logError)(`Max reconnection attempts (${maxReconnectAttempts}) reached. Stopping reconnection.`);
409
- return;
410
- }
411
- reconnectAttempts++;
412
- const delay = Math.min(baseReconnectDelay * Math.pow(2, reconnectAttempts - 1), 30000); // Exponential backoff up to 30s
413
- setTimeout(() => __awaiter(this, void 0, void 0, function* () {
414
- yield connect();
415
- }), delay);
396
+ let connection;
397
+ try {
398
+ connection = yield amqplib_1.default.connect({
399
+ protocol: parsedUrl.protocol.replace(/:$/, ''),
400
+ hostname: parsedUrl.hostname,
401
+ port: parsedUrl.port ? Number(parsedUrl.port) : undefined,
402
+ username: parsedUrl.username || undefined,
403
+ password: parsedUrl.password || undefined,
404
+ vhost: parsedUrl.pathname && parsedUrl.pathname !== '/'
405
+ ? decodeURIComponent(parsedUrl.pathname.slice(1))
406
+ : undefined,
407
+ heartbeat: connectionHeartbeat,
408
+ }, {
409
+ recovery: {
410
+ initialDelay: baseReconnectDelay,
411
+ maxDelay: 30000,
412
+ factor: 2,
413
+ maxRetries: maxReconnectAttempts,
414
+ setup,
415
+ },
416
+ });
417
+ }
418
+ catch (err) {
419
+ (0, logger_1.logError)(`Failed to connect to AMQP: ${err}`);
420
+ return;
421
+ }
422
+ connection.on('connect', () => {
423
+ (0, logger_1.log)('AMQP connection established');
424
+ });
425
+ connection.on('disconnect', (err) => {
426
+ (0, logger_1.logError)(`AMQP connection closed, attempting to reconnect: ${err === null || err === void 0 ? void 0 : err.message}`);
427
+ });
428
+ connection.on('reconnect-scheduled', ({ attempt, delay }) => {
429
+ (0, logger_1.logError)(`AMQP reconnecting (attempt ${attempt}, delay ${delay}ms)`);
430
+ });
431
+ connection.on('reconnect-failed', (err) => {
432
+ (0, logger_1.logError)(`AMQP max reconnection attempts (${maxReconnectAttempts}) reached: ${err}`);
433
+ });
434
+ connection.on('error', (err) => {
435
+ (0, logger_1.logError)(`AMQP connection error: ${err.message}`);
416
436
  });
417
- yield connect();
418
437
  });
419
438
  }
420
439
  function consumer({ channel, config, integration, }) {
@@ -463,15 +482,11 @@ function consumer({ channel, config, integration, }) {
463
482
  }
464
483
  if (messagesCounter < prefetchCount) {
465
484
  // if all messages are not received, wait 10 seconds to force process messages
466
- timeoutId = setTimeout(() => __awaiter(this, void 0, void 0, function* () {
467
- yield processMessages({
468
- webhooksData,
469
- webhooksInfo,
470
- channel,
471
- messagesToAck,
472
- });
473
- resetStateVariables();
474
- }), forceProcessDelay);
485
+ timeoutId = setTimeout(() => {
486
+ processMessages({ webhooksData, webhooksInfo, channel, messagesToAck })
487
+ .then(() => resetStateVariables())
488
+ .catch((err) => (0, logger_1.logError)(`Error in deferred message processing: ${err}`));
489
+ }, forceProcessDelay);
475
490
  return;
476
491
  }
477
492
  clearTimeout(timeoutId);
@@ -542,7 +557,7 @@ function processMessages(_a) {
542
557
  }
543
558
  }
544
559
  catch (e) {
545
- (0, logger_1.log)(`Error in processMessages: ${e}`);
560
+ (0, logger_1.logError)(`Error in processMessages: ${e}`);
546
561
  for (const msg of messagesToAck) {
547
562
  try {
548
563
  if (isRetryableError(e)) {
@@ -9,6 +9,7 @@ const api_1 = require("./api/api");
9
9
  const util_2 = require("./workflow-step-type/util");
10
10
  const index_1 = require("./automation-action/util/index");
11
11
  const ai_request_processors_1 = require("./ai-request-processors");
12
+ const key_1 = require("./advisor-inspector/key");
12
13
  function normalizeEnvironments(environments) {
13
14
  if (Array.isArray(environments)) {
14
15
  return environments;
@@ -475,6 +476,20 @@ function handle(config) {
475
476
  return Object.assign(Object.assign({ key, name: item.name || config.name, description: item.description || config.description, runQaCheckUrl: `${base}/validate` }, (item.batchSize ? { getBatchSizeUrl: `${base}/batch-size` } : {})), (uiModule ? { url: `${base}/settings/` + (uiModule.fileName || 'index.html') } : {}));
476
477
  });
477
478
  }
479
+ if (config.advisorInspector) {
480
+ config.advisorInspector = config.advisorInspector.map((item) => (Object.assign({}, item)));
481
+ const items = config.advisorInspector;
482
+ const isSingle = items.length === 1;
483
+ modules['advisor-inspector'] = items.map((item, index) => {
484
+ const key = (0, key_1.resolveAdvisorInspectorKey)(config, item, index, isSingle);
485
+ item.key = key;
486
+ const base = `/advisor-inspector/${key}`;
487
+ const hasIframe = !!(item.uiPath || item.formSchema);
488
+ return Object.assign(Object.assign(Object.assign(Object.assign({ key, name: item.name || config.name, title: item.title }, (item.summary && { summary: item.summary })), { severity: item.severity, category: item.category, refreshPolicy: item.refreshPolicy, recheckUrl: `${base}/recheck` }), (hasIframe && {
489
+ url: `${base}/iframe/${item.fileName || 'index.html'}`,
490
+ })), (item.environments && { environments: normalizeEnvironments(item.environments) }));
491
+ });
492
+ }
478
493
  if (config.workflowStepType) {
479
494
  // prevent possible overrides of the other modules
480
495
  config.workflowStepType = config.workflowStepType.map((workflowStep) => (Object.assign({}, workflowStep)));
@@ -115,17 +115,17 @@
115
115
  function requireScheduler_production_min () {
116
116
  if (hasRequiredScheduler_production_min) return scheduler_production_min;
117
117
  hasRequiredScheduler_production_min = 1;
118
- (function (exports$1) {
118
+ (function (exports) {
119
119
  function f(a,b){var c=a.length;a.push(b);a:for(;0<c;){var d=c-1>>>1,e=a[d];if(0<g(e,b))a[d]=b,a[c]=e,c=d;else break a}}function h(a){return 0===a.length?null:a[0]}function k(a){if(0===a.length)return null;var b=a[0],c=a.pop();if(c!==b){a[0]=c;a:for(var d=0,e=a.length,w=e>>>1;d<w;){var m=2*(d+1)-1,C=a[m],n=m+1,x=a[n];if(0>g(C,c))n<e&&0>g(x,C)?(a[d]=x,a[n]=c,d=n):(a[d]=C,a[m]=c,d=m);else if(n<e&&0>g(x,c))a[d]=x,a[n]=c,d=n;else break a}}return b}
120
- function g(a,b){var c=a.sortIndex-b.sortIndex;return 0!==c?c:a.id-b.id}if("object"===typeof performance&&"function"===typeof performance.now){var l=performance;exports$1.unstable_now=function(){return l.now()};}else {var p=Date,q=p.now();exports$1.unstable_now=function(){return p.now()-q};}var r=[],t=[],u=1,v=null,y=3,z=false,A=false,B=false,D="function"===typeof setTimeout?setTimeout:null,E="function"===typeof clearTimeout?clearTimeout:null,F="undefined"!==typeof setImmediate?setImmediate:null;
120
+ function g(a,b){var c=a.sortIndex-b.sortIndex;return 0!==c?c:a.id-b.id}if("object"===typeof performance&&"function"===typeof performance.now){var l=performance;exports.unstable_now=function(){return l.now()};}else {var p=Date,q=p.now();exports.unstable_now=function(){return p.now()-q};}var r=[],t=[],u=1,v=null,y=3,z=false,A=false,B=false,D="function"===typeof setTimeout?setTimeout:null,E="function"===typeof clearTimeout?clearTimeout:null,F="undefined"!==typeof setImmediate?setImmediate:null;
121
121
  "undefined"!==typeof navigator&&void 0!==navigator.scheduling&&void 0!==navigator.scheduling.isInputPending&&navigator.scheduling.isInputPending.bind(navigator.scheduling);function G(a){for(var b=h(t);null!==b;){if(null===b.callback)k(t);else if(b.startTime<=a)k(t),b.sortIndex=b.expirationTime,f(r,b);else break;b=h(t);}}function H(a){B=false;G(a);if(!A)if(null!==h(r))A=true,I(J);else {var b=h(t);null!==b&&K(H,b.startTime-a);}}
122
- function J(a,b){A=false;B&&(B=false,E(L),L=-1);z=true;var c=y;try{G(b);for(v=h(r);null!==v&&(!(v.expirationTime>b)||a&&!M());){var d=v.callback;if("function"===typeof d){v.callback=null;y=v.priorityLevel;var e=d(v.expirationTime<=b);b=exports$1.unstable_now();"function"===typeof e?v.callback=e:v===h(r)&&k(r);G(b);}else k(r);v=h(r);}if(null!==v)var w=!0;else {var m=h(t);null!==m&&K(H,m.startTime-b);w=!1;}return w}finally{v=null,y=c,z=false;}}var N=false,O=null,L=-1,P=5,Q=-1;
123
- function M(){return exports$1.unstable_now()-Q<P?false:true}function R(){if(null!==O){var a=exports$1.unstable_now();Q=a;var b=true;try{b=O(!0,a);}finally{b?S():(N=false,O=null);}}else N=false;}var S;if("function"===typeof F)S=function(){F(R);};else if("undefined"!==typeof MessageChannel){var T=new MessageChannel,U=T.port2;T.port1.onmessage=R;S=function(){U.postMessage(null);};}else S=function(){D(R,0);};function I(a){O=a;N||(N=true,S());}function K(a,b){L=D(function(){a(exports$1.unstable_now());},b);}
124
- exports$1.unstable_IdlePriority=5;exports$1.unstable_ImmediatePriority=1;exports$1.unstable_LowPriority=4;exports$1.unstable_NormalPriority=3;exports$1.unstable_Profiling=null;exports$1.unstable_UserBlockingPriority=2;exports$1.unstable_cancelCallback=function(a){a.callback=null;};exports$1.unstable_continueExecution=function(){A||z||(A=true,I(J));};
125
- exports$1.unstable_forceFrameRate=function(a){0>a||125<a?console.error("forceFrameRate takes a positive int between 0 and 125, forcing frame rates higher than 125 fps is not supported"):P=0<a?Math.floor(1E3/a):5;};exports$1.unstable_getCurrentPriorityLevel=function(){return y};exports$1.unstable_getFirstCallbackNode=function(){return h(r)};exports$1.unstable_next=function(a){switch(y){case 1:case 2:case 3:var b=3;break;default:b=y;}var c=y;y=b;try{return a()}finally{y=c;}};exports$1.unstable_pauseExecution=function(){};
126
- exports$1.unstable_requestPaint=function(){};exports$1.unstable_runWithPriority=function(a,b){switch(a){case 1:case 2:case 3:case 4:case 5:break;default:a=3;}var c=y;y=a;try{return b()}finally{y=c;}};
127
- exports$1.unstable_scheduleCallback=function(a,b,c){var d=exports$1.unstable_now();"object"===typeof c&&null!==c?(c=c.delay,c="number"===typeof c&&0<c?d+c:d):c=d;switch(a){case 1:var e=-1;break;case 2:e=250;break;case 5:e=1073741823;break;case 4:e=1E4;break;default:e=5E3;}e=c+e;a={id:u++,callback:b,priorityLevel:a,startTime:c,expirationTime:e,sortIndex:-1};c>d?(a.sortIndex=c,f(t,a),null===h(r)&&a===h(t)&&(B?(E(L),L=-1):B=true,K(H,c-d))):(a.sortIndex=e,f(r,a),A||z||(A=true,I(J)));return a};
128
- exports$1.unstable_shouldYield=M;exports$1.unstable_wrapCallback=function(a){var b=y;return function(){var c=y;y=b;try{return a.apply(this,arguments)}finally{y=c;}}};
122
+ function J(a,b){A=false;B&&(B=false,E(L),L=-1);z=true;var c=y;try{G(b);for(v=h(r);null!==v&&(!(v.expirationTime>b)||a&&!M());){var d=v.callback;if("function"===typeof d){v.callback=null;y=v.priorityLevel;var e=d(v.expirationTime<=b);b=exports.unstable_now();"function"===typeof e?v.callback=e:v===h(r)&&k(r);G(b);}else k(r);v=h(r);}if(null!==v)var w=!0;else {var m=h(t);null!==m&&K(H,m.startTime-b);w=!1;}return w}finally{v=null,y=c,z=false;}}var N=false,O=null,L=-1,P=5,Q=-1;
123
+ function M(){return exports.unstable_now()-Q<P?false:true}function R(){if(null!==O){var a=exports.unstable_now();Q=a;var b=true;try{b=O(!0,a);}finally{b?S():(N=false,O=null);}}else N=false;}var S;if("function"===typeof F)S=function(){F(R);};else if("undefined"!==typeof MessageChannel){var T=new MessageChannel,U=T.port2;T.port1.onmessage=R;S=function(){U.postMessage(null);};}else S=function(){D(R,0);};function I(a){O=a;N||(N=true,S());}function K(a,b){L=D(function(){a(exports.unstable_now());},b);}
124
+ exports.unstable_IdlePriority=5;exports.unstable_ImmediatePriority=1;exports.unstable_LowPriority=4;exports.unstable_NormalPriority=3;exports.unstable_Profiling=null;exports.unstable_UserBlockingPriority=2;exports.unstable_cancelCallback=function(a){a.callback=null;};exports.unstable_continueExecution=function(){A||z||(A=true,I(J));};
125
+ exports.unstable_forceFrameRate=function(a){0>a||125<a?console.error("forceFrameRate takes a positive int between 0 and 125, forcing frame rates higher than 125 fps is not supported"):P=0<a?Math.floor(1E3/a):5;};exports.unstable_getCurrentPriorityLevel=function(){return y};exports.unstable_getFirstCallbackNode=function(){return h(r)};exports.unstable_next=function(a){switch(y){case 1:case 2:case 3:var b=3;break;default:b=y;}var c=y;y=b;try{return a()}finally{y=c;}};exports.unstable_pauseExecution=function(){};
126
+ exports.unstable_requestPaint=function(){};exports.unstable_runWithPriority=function(a,b){switch(a){case 1:case 2:case 3:case 4:case 5:break;default:a=3;}var c=y;y=a;try{return b()}finally{y=c;}};
127
+ exports.unstable_scheduleCallback=function(a,b,c){var d=exports.unstable_now();"object"===typeof c&&null!==c?(c=c.delay,c="number"===typeof c&&0<c?d+c:d):c=d;switch(a){case 1:var e=-1;break;case 2:e=250;break;case 5:e=1073741823;break;case 4:e=1E4;break;default:e=5E3;}e=c+e;a={id:u++,callback:b,priorityLevel:a,startTime:c,expirationTime:e,sortIndex:-1};c>d?(a.sortIndex=c,f(t,a),null===h(r)&&a===h(t)&&(B?(E(L),L=-1):B=true,K(H,c-d))):(a.sortIndex=e,f(r,a),A||z||(A=true,I(J)));return a};
128
+ exports.unstable_shouldYield=M;exports.unstable_wrapCallback=function(a){var b=y;return function(){var c=y;y=b;try{return a.apply(this,arguments)}finally{y=c;}}};
129
129
  } (scheduler_production_min));
130
130
  return scheduler_production_min;
131
131
  }