velocious 1.0.634 → 1.0.636

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.
Files changed (54) hide show
  1. package/README.md +37 -3
  2. package/build/background-jobs/lifecycle-client.js +1 -1
  3. package/build/background-jobs/lifecycle-control-server.js +1 -1
  4. package/build/background-jobs/main.js +9 -3
  5. package/build/cli/commands/db/migrate.js +3 -1
  6. package/build/cli/commands/db/tenants/migrate.js +4 -1
  7. package/build/cli/commands/db/tenants/migrations/pending.js +4 -1
  8. package/build/cli/index.js +1 -1
  9. package/build/cli/migration-execution-phase-argument.js +20 -0
  10. package/build/database/migration/index.js +21 -0
  11. package/build/database/migration-execution-phase.js +34 -0
  12. package/build/database/migrator.js +6 -1
  13. package/build/frontend-models/base.js +27 -29
  14. package/build/src/background-jobs/lifecycle-client.d.ts +1 -1
  15. package/build/src/background-jobs/lifecycle-client.d.ts.map +1 -1
  16. package/build/src/background-jobs/lifecycle-client.js +2 -2
  17. package/build/src/background-jobs/lifecycle-control-server.js +2 -2
  18. package/build/src/background-jobs/main.d.ts.map +1 -1
  19. package/build/src/background-jobs/main.js +11 -4
  20. package/build/src/cli/commands/db/migrate.d.ts.map +1 -1
  21. package/build/src/cli/commands/db/migrate.js +4 -2
  22. package/build/src/cli/commands/db/tenants/migrate.d.ts.map +1 -1
  23. package/build/src/cli/commands/db/tenants/migrate.js +5 -2
  24. package/build/src/cli/commands/db/tenants/migrations/pending.d.ts.map +1 -1
  25. package/build/src/cli/commands/db/tenants/migrations/pending.js +5 -2
  26. package/build/src/cli/index.js +2 -2
  27. package/build/src/cli/migration-execution-phase-argument.d.ts +7 -0
  28. package/build/src/cli/migration-execution-phase-argument.d.ts.map +1 -0
  29. package/build/src/cli/migration-execution-phase-argument.js +17 -0
  30. package/build/src/database/migration/index.d.ts +13 -0
  31. package/build/src/database/migration/index.d.ts.map +1 -1
  32. package/build/src/database/migration/index.js +19 -1
  33. package/build/src/database/migration-execution-phase.d.ts +18 -0
  34. package/build/src/database/migration-execution-phase.d.ts.map +1 -0
  35. package/build/src/database/migration-execution-phase.js +30 -0
  36. package/build/src/database/migrator.d.ts +4 -1
  37. package/build/src/database/migrator.d.ts.map +1 -1
  38. package/build/src/database/migrator.js +9 -2
  39. package/build/src/frontend-models/base.d.ts.map +1 -1
  40. package/build/src/frontend-models/base.js +26 -25
  41. package/build/tsconfig.tsbuildinfo +1 -1
  42. package/package.json +1 -1
  43. package/src/background-jobs/lifecycle-client.js +1 -1
  44. package/src/background-jobs/lifecycle-control-server.js +1 -1
  45. package/src/background-jobs/main.js +9 -3
  46. package/src/cli/commands/db/migrate.js +3 -1
  47. package/src/cli/commands/db/tenants/migrate.js +4 -1
  48. package/src/cli/commands/db/tenants/migrations/pending.js +4 -1
  49. package/src/cli/index.js +1 -1
  50. package/src/cli/migration-execution-phase-argument.js +20 -0
  51. package/src/database/migration/index.js +21 -0
  52. package/src/database/migration-execution-phase.js +34 -0
  53. package/src/database/migrator.js +6 -1
  54. package/src/frontend-models/base.js +27 -29
package/README.md CHANGED
@@ -7,7 +7,7 @@
7
7
  * Connection-scoped advisory locks with automatic cleanup before pooled connections are reused or closed (see [docs/advisory-locks.md](docs/advisory-locks.md))
8
8
  * Built-in record auditing for model lifecycle changes (see [docs/auditing.md](docs/auditing.md))
9
9
  * Declarative state machines for models, with typed event methods generated into the base model (see [docs/state-machine.md](docs/state-machine.md))
10
- * Migrations for schema changes and UTC datetime storage, including recorded `changeTable` batches that combine operations into one `ALTER` on bulk-capable drivers (see [docs/database-migrations.md](docs/database-migrations.md) and [docs/change-table.md](docs/change-table.md))
10
+ * Migrations for schema changes and UTC datetime storage, including caller-selected `pre-runtime` and `post-publication` execution sets and recorded `changeTable` batches that combine operations into one `ALTER` on bulk-capable drivers (see [docs/database-migrations.md](docs/database-migrations.md), [docs/migration-execution-phases.md](docs/migration-execution-phases.md), and [docs/change-table.md](docs/change-table.md))
11
11
  * Tenant-selected base-model and structure generation with one immutable, fail-closed physical database context; tenant-only model metadata initializes only after that context is active (see [docs/tenant-selected-database-generation.md](docs/tenant-selected-database-generation.md))
12
12
  * Read-only tenant migration deploy preflight with stable JSON output and fail-closed ledger reads (see [docs/tenant-migration-deploy-preflight.md](docs/tenant-migration-deploy-preflight.md))
13
13
  * External packages (engines) that contribute data models, frontend-model resources and migrations to a consuming app (see [docs/packages.md](docs/packages.md))
@@ -59,6 +59,10 @@ npm install velocious
59
59
  npx velocious init
60
60
  ```
61
61
 
62
+ Pinned Git commits can be installed without lifecycle scripts by using a GitHub
63
+ commit archive. Velocious checks in generated `build/` output for this purpose;
64
+ see [Git dependency installation](docs/git-installation.md).
65
+
62
66
  By default, Velocious looks for your configuration in `src/config/configuration.js`. If you keep the configuration elsewhere, make sure your app imports it early and calls `configuration.setCurrent()`.
63
67
 
64
68
  Application initializers may implement `teardown()` and inspect their frozen
@@ -1029,10 +1033,16 @@ closure without overlapping stale and current bootstrap side effects.
1029
1033
 
1030
1034
  ## Lifecycle callbacks
1031
1035
 
1032
- Register lifecycle callbacks with either a function or an instance method name. Registrations run in order, so you can stack multiple callbacks on the same lifecycle hook.
1036
+ Records support implicit same-named lifecycle methods plus explicit function or
1037
+ string method-name registrations. Registrations run in order, so independent
1038
+ responsibilities can use multiple small named callbacks.
1033
1039
 
1034
1040
  ```js
1035
1041
  class Task extends Record {
1042
+ beforeSave() {
1043
+ this.setName(this.name().trim())
1044
+ }
1045
+
1036
1046
  async validateSomething() {
1037
1047
  await doSomethingElse()
1038
1048
  }
@@ -1045,6 +1055,14 @@ Task.beforeValidation(async (task) => {
1045
1055
  Task.beforeValidation("validateSomething")
1046
1056
  ```
1047
1057
 
1058
+ Function registrations receive the record argument; arrow-function `this` is
1059
+ lexical and is not rebound to the record. Keep implicit hooks cohesive, use
1060
+ multiple explicit registrations when concerns or ordering should be visible, and
1061
+ put irreversible effects behind `afterCommit` rather than directly in
1062
+ `afterSave`. See [Record lifecycle callbacks](docs/lifecycle-callbacks.md) for
1063
+ phase ordering, transaction boundaries, bulk-operation caveats, and testing
1064
+ guidance.
1065
+
1048
1066
  ## Preloading relationships
1049
1067
 
1050
1068
  ```js
@@ -1429,6 +1447,22 @@ Migrations that must be rerunnable can guard changes with `tableExists(...)`, `c
1429
1447
  npx velocious db:migrate
1430
1448
  ```
1431
1449
 
1450
+ Migrations default to the `pre-runtime` phase. A migration can declare
1451
+ `Migration.runInPhase("post-publication")`, and callers can run exactly one
1452
+ declared set while preserving timestamp order, package migrations, database
1453
+ targets, and ledger behavior:
1454
+
1455
+ ```bash
1456
+ npx velocious db:migrate --phase pre-runtime
1457
+ npx velocious db:migrate --phase post-publication
1458
+ ```
1459
+
1460
+ Omitting `--phase` remains backward-compatible and runs all pending migrations.
1461
+ Velocious does not choose when either set runs; the application or deployment
1462
+ caller owns invocation timing. See [migration execution phases](docs/migration-execution-phases.md)
1463
+ for the class API, programmatic selector, require-context behavior, and tenant
1464
+ commands.
1465
+
1432
1466
  Run project seeds from `src/db/seed.js` (default export should be an async function):
1433
1467
 
1434
1468
  ```bash
@@ -2041,7 +2075,7 @@ await client.close()
2041
2075
 
2042
2076
  For long-lived Node clients, the constructor also accepts opt-in liveness options (all default off, so browser/Expo usage is unchanged): `webSocketImplementation` (inject Node's `ws`, since the global/undici WebSocket exposes neither protocol ping nor an unref-able socket), `heartbeatIntervalMs` (a ping heartbeat that drops a socket whose peer stops ponging, so a client notices a vanished server), and `unref` (unref the underlying socket so an idle connection can't keep the process alive on its own). See [docs/websocket-channels.md](docs/websocket-channels.md).
2043
2077
 
2044
- `await client.close()` is a final graceful shutdown that releases resumable server-session state; unexpected transport drops first attempt to resume that state. On a multi-worker server, the client automatically puts the prior session identity in the reconnect upgrade URL so the host can route it to its owning worker; routing is session-based and never source-IP-based. A successful resume retains the existing server-side connection and channel instances. If the server instead rejects the old session with `session-gone`, SnapReq promotes the already-established fresh session, reopens still-live one-to-one connection handles, and re-subscribes still-live channel handles. Those public handles remain usable and channel readiness resolves on the fresh session; explicitly closed handles stay closed. See [the WebSocket channel lifecycle guarantees](docs/websocket-channels.md#lifecycle-guarantees-phase-1b).
2078
+ `await client.close()` is a final graceful shutdown that releases resumable server-session state; unexpected transport drops first attempt to resume that state. On a multi-worker server, the client automatically puts the prior session identity in the reconnect upgrade URL so the host can route it to its owning worker; routing is session-based and never source-IP-based. A successful resume retains the existing server-side connection and channel instances. If the server instead rejects the old session with `session-gone`, SnapReq promotes the already-established fresh session, reopens still-live one-to-one connection handles, and re-subscribes still-live channel handles. Those public handles remain usable and channel readiness resolves on the fresh session; explicitly closed handles stay closed. A channel that the server permanently closes or rejects remains terminal and is not automatically reopened; register a new listener after changing the authorization or request context. See [the WebSocket channel lifecycle guarantees](docs/websocket-channels.md#lifecycle-guarantees-phase-1b).
2045
2079
 
2046
2080
  ## Subscribe to events
2047
2081
 
@@ -6,7 +6,7 @@ import timeout from "awaitery/build/timeout.js"
6
6
  import JsonSocket from "./json-socket.js"
7
7
 
8
8
  const DEFAULT_REQUEST_TIMEOUT_MS = 10000
9
- export const MAX_LIFECYCLE_REQUEST_TIMEOUT_MS = 60000
9
+ export const MAX_LIFECYCLE_REQUEST_TIMEOUT_MS = 120000
10
10
 
11
11
  /** One-request acknowledged lifecycle client. */
12
12
  export default class BackgroundJobsLifecycleClient {
@@ -244,7 +244,7 @@ export default class BackgroundJobsLifecycleControlServer {
244
244
  try {
245
245
  this._validateRequest(message)
246
246
  if (action === "activate") await this.main.activate()
247
- else await this.main.retire()
247
+ else void this.main.retire()
248
248
 
249
249
  this._writeResponse(socket, {
250
250
  type: "background-jobs-lifecycle-ack",
@@ -602,10 +602,14 @@ export default class BackgroundJobsMain {
602
602
  * @returns {Promise<void>} - Activation completion.
603
603
  */
604
604
  async _activate() {
605
+ this.logger.info(() => ["Background jobs generation activation starting", {generationId: this.generationId}])
605
606
  await this._startActiveOwnership()
606
607
  this.lifecycleState = "active"
607
608
  this._creditReadyWorkers()
608
- await this._drain()
609
+ this.logger.info(() => ["Background jobs generation activation acknowledged", {generationId: this.generationId}])
610
+ void this._drain().catch((error) => {
611
+ this.logger.error(() => ["Background jobs generation post-activation drain failed", {error, generationId: this.generationId}])
612
+ })
609
613
  }
610
614
 
611
615
  /**
@@ -614,7 +618,7 @@ export default class BackgroundJobsMain {
614
618
  */
615
619
  retire() {
616
620
  if (!this.generationId) throw new Error("Background jobs generation retirement requires generation mode")
617
- if (this.lifecycleState === "retiring" || this.lifecycleState === "retired") return this._retirementPromise || Promise.resolve()
621
+ if (this.lifecycleState === "retiring" || this.lifecycleState === "retired") return Promise.resolve()
618
622
  if (this.lifecycleState !== "active") throw new Error(`Cannot retire background jobs generation from ${this.lifecycleState}`)
619
623
 
620
624
  this.lifecycleState = "retiring"
@@ -624,8 +628,9 @@ export default class BackgroundJobsMain {
624
628
  this._clearDispatchTimers()
625
629
  this._disconnectBeaconHandlers()
626
630
  this._retirementPromise = this._retire()
631
+ void this._retirementPromise.catch((error) => this._reportConnectionHandlerError(error))
627
632
 
628
- return this._retirementPromise
633
+ return Promise.resolve()
629
634
  }
630
635
 
631
636
  /**
@@ -636,6 +641,7 @@ export default class BackgroundJobsMain {
636
641
  await this.scheduler?.stop()
637
642
  this.scheduler = undefined
638
643
  if (this._drainPromise) await this._drainPromise
644
+ if (this._stopped) return
639
645
 
640
646
  for (const worker of this.workers) {
641
647
  worker.isDraining = true
@@ -1,11 +1,13 @@
1
1
  import BaseCommand from "../../base-command.js"
2
2
  import {digg} from "diggerize"
3
3
  import Migrator from "../../../database/migrator.js"
4
+ import migrationExecutionPhaseArgument from "../../migration-execution-phase-argument.js"
4
5
 
5
6
  export default class DbMigrate extends BaseCommand {
6
7
  async execute() {
8
+ const executionPhase = migrationExecutionPhaseArgument(this.processArgs || [])
7
9
  const migrations = await this.getEnvironmentHandler().findMigrations()
8
- const migrator = new Migrator({configuration: this.getConfiguration()})
10
+ const migrator = new Migrator({configuration: this.getConfiguration(), executionPhase})
9
11
 
10
12
  console.log(`Running ${migrations.length} migrations`)
11
13
 
@@ -4,6 +4,7 @@ import {digg} from "diggerize"
4
4
  import BaseCommand from "../../../base-command.js"
5
5
  import Migrator from "../../../../database/migrator.js"
6
6
  import TenantDatabaseCommandHelper from "../../../tenant-database-command-helper.js"
7
+ import migrationExecutionPhaseArgument from "../../../migration-execution-phase-argument.js"
7
8
 
8
9
  export default class DbTenantsMigrate extends BaseCommand {
9
10
  /**
@@ -11,6 +12,7 @@ export default class DbTenantsMigrate extends BaseCommand {
11
12
  * @returns {Promise<{identifier: string, migrationCount: number, tenantCount: number} | void>} - Result in test mode.
12
13
  */
13
14
  async execute() {
15
+ const executionPhase = migrationExecutionPhaseArgument(this.processArgs || [])
14
16
  const helper = new TenantDatabaseCommandHelper({
15
17
  command: this,
16
18
  identifier: this.processArgs?.[1]
@@ -19,7 +21,8 @@ export default class DbTenantsMigrate extends BaseCommand {
19
21
  const tenantCount = await helper.eachTenant(async ({databaseConfiguration, tenant}) => {
20
22
  const migrator = new Migrator({
21
23
  configuration: this.getConfiguration(),
22
- databaseIdentifiers: [helper.identifier]
24
+ databaseIdentifiers: [helper.identifier],
25
+ executionPhase
23
26
  })
24
27
 
25
28
  let migrationsApplied = 0
@@ -4,6 +4,8 @@ import {digg} from "diggerize"
4
4
  import BaseCommand from "../../../../base-command.js"
5
5
  import TenantDatabaseCommandHelper from "../../../../tenant-database-command-helper.js"
6
6
  import TenantMigrationPendingInspector from "../../../../../database/tenants/migration-pending-inspector.js"
7
+ import { migrationRunsInExecutionPhase } from "../../../../../database/migration-execution-phase.js"
8
+ import migrationExecutionPhaseArgument from "../../../../migration-execution-phase-argument.js"
7
9
 
8
10
  export default class DbTenantsMigrationsPending extends BaseCommand {
9
11
  /**
@@ -11,6 +13,7 @@ export default class DbTenantsMigrationsPending extends BaseCommand {
11
13
  * @returns {Promise<{hasPendingMigrations: boolean, identifier: string, migrationCount: number, pendingTenantCount: number, tenantCount: number}>} - Deploy preflight result.
12
14
  */
13
15
  async execute() {
16
+ const executionPhase = migrationExecutionPhaseArgument(this.processArgs || [])
14
17
  const helper = new TenantDatabaseCommandHelper({
15
18
  command: this,
16
19
  identifier: this.processArgs?.[1]
@@ -24,7 +27,7 @@ export default class DbTenantsMigrationsPending extends BaseCommand {
24
27
 
25
28
  const MigrationClass = await requireMigration(migration.fullPath)
26
29
 
27
- if ((MigrationClass.getDatabaseIdentifiers() || ["default"]).includes(helper.identifier)) {
30
+ if (migrationRunsInExecutionPhase(MigrationClass, executionPhase) && (MigrationClass.getDatabaseIdentifiers() || ["default"]).includes(helper.identifier)) {
28
31
  applicableMigrationVersions.push(migration.date)
29
32
  }
30
33
  }
@@ -1,6 +1,6 @@
1
1
  // @ts-check
2
2
 
3
- const COMMAND_VALUE_OPTIONS = new Set(["--generation", "--initial-generation-state", "--lifecycle-socket", "--socket", "--tenant"])
3
+ const COMMAND_VALUE_OPTIONS = new Set(["--generation", "--initial-generation-state", "--lifecycle-socket", "--phase", "--socket", "--tenant"])
4
4
 
5
5
  export default class VelociousCli {
6
6
  /**
@@ -0,0 +1,20 @@
1
+ // @ts-check
2
+
3
+ import { migrationExecutionPhase } from "../database/migration-execution-phase.js"
4
+
5
+ /**
6
+ * Reads an optional `--phase` value from one command's raw arguments.
7
+ * @param {string[]} processArgs - Raw command arguments including the command name.
8
+ * @returns {import("../database/migration-execution-phase.js").MigrationExecutionPhase | undefined} - Selected phase.
9
+ */
10
+ export default function migrationExecutionPhaseArgument(processArgs) {
11
+ const phaseArgumentIndex = processArgs.indexOf("--phase")
12
+
13
+ if (phaseArgumentIndex < 0) return undefined
14
+
15
+ const phase = processArgs[phaseArgumentIndex + 1]
16
+
17
+ if (!phase || phase.startsWith("-")) throw new Error("Missing value for --phase")
18
+
19
+ return migrationExecutionPhase(phase)
20
+ }
@@ -28,6 +28,7 @@
28
28
  import { convertLegacyDateValueToUtcStorage } from "../datetime-storage.js"
29
29
  import * as inflection from "inflection"
30
30
  import restArgsError from "../../utils/rest-args-error.js"
31
+ import { DEFAULT_MIGRATION_EXECUTION_PHASE, migrationExecutionPhase } from "../migration-execution-phase.js"
31
32
  import ChangeTable from "./change-table.js"
32
33
  import CreateIndexBase from "../query/create-index-base.js"
33
34
  import TableColumn from "../table-data/table-column.js"
@@ -38,6 +39,26 @@ class NotImplementedError extends Error {}
38
39
  export {NotImplementedError}
39
40
 
40
41
  export default class VelociousDatabaseMigration {
42
+ /** @type {import("../migration-execution-phase.js").MigrationExecutionPhase | undefined} */
43
+ static _executionPhase
44
+
45
+ /**
46
+ * Declares when this migration is eligible to run.
47
+ * @param {import("../migration-execution-phase.js").MigrationExecutionPhase} phase - Execution phase.
48
+ * @returns {void} - No return value.
49
+ */
50
+ static runInPhase(phase) {
51
+ this._executionPhase = migrationExecutionPhase(phase)
52
+ }
53
+
54
+ /**
55
+ * Gets the declared execution phase.
56
+ * @returns {import("../migration-execution-phase.js").MigrationExecutionPhase} - Declared execution phase.
57
+ */
58
+ static getExecutionPhase() {
59
+ return this._executionPhase || DEFAULT_MIGRATION_EXECUTION_PHASE
60
+ }
61
+
41
62
  /**
42
63
  * Runs on databases.
43
64
  * @param {string[]} databaseIdentifiers - Database identifiers.
@@ -0,0 +1,34 @@
1
+ // @ts-check
2
+
3
+ /** @typedef {"post-publication" | "pre-runtime"} MigrationExecutionPhase */
4
+
5
+ /** @type {MigrationExecutionPhase} */
6
+ export const DEFAULT_MIGRATION_EXECUTION_PHASE = "pre-runtime"
7
+
8
+ /**
9
+ * Validates and returns one supported migration execution phase.
10
+ * @param {string | undefined} phase - Migration execution phase.
11
+ * @returns {MigrationExecutionPhase} - Validated execution phase.
12
+ */
13
+ export function migrationExecutionPhase(phase) {
14
+ if (phase === undefined) {
15
+ throw new Error("Missing migration execution phase. Expected one of: pre-runtime, post-publication")
16
+ }
17
+ if (phase !== "pre-runtime" && phase !== "post-publication") {
18
+ throw new Error(`Unknown migration execution phase ${JSON.stringify(phase)}. Expected one of: pre-runtime, post-publication`)
19
+ }
20
+
21
+ return phase
22
+ }
23
+
24
+ /**
25
+ * Tests whether a migration class belongs to an optional selected phase.
26
+ * @param {typeof import("./migration/index.js").default} MigrationClass - Migration class.
27
+ * @param {MigrationExecutionPhase | undefined} executionPhase - Optional selected phase.
28
+ * @returns {boolean} - Whether the migration belongs to the selection.
29
+ */
30
+ export function migrationRunsInExecutionPhase(MigrationClass, executionPhase) {
31
+ if (executionPhase === undefined) return true
32
+
33
+ return MigrationClass.getExecutionPhase() === executionPhase
34
+ }
@@ -5,6 +5,7 @@ import * as inflection from "inflection"
5
5
  import Logger from "../logger.js"
6
6
  import MigrationsLedger from "./migrations-ledger.js"
7
7
  import {NotImplementedError} from "./migration/index.js"
8
+ import { migrationExecutionPhase, migrationRunsInExecutionPhase } from "./migration-execution-phase.js"
8
9
  import restArgsError from "../utils/rest-args-error.js"
9
10
 
10
11
  export default class VelociousDatabaseMigrator {
@@ -18,14 +19,16 @@ export default class VelociousDatabaseMigrator {
18
19
  * @param {object} args - Options object.
19
20
  * @param {import("../configuration.js").default} args.configuration - Configuration instance.
20
21
  * @param {string[]} [args.databaseIdentifiers] - Optional database identifiers to migrate.
22
+ * @param {import("./migration-execution-phase.js").MigrationExecutionPhase} [args.executionPhase] - Optional migration execution phase to select.
21
23
  */
22
- constructor({configuration, databaseIdentifiers, ...restArgs}) {
24
+ constructor({configuration, databaseIdentifiers, executionPhase, ...restArgs}) {
23
25
  restArgsError(restArgs)
24
26
 
25
27
  if (!configuration) throw new Error("configuration argument is required")
26
28
 
27
29
  this.configuration = configuration
28
30
  this.databaseIdentifiers = databaseIdentifiers
31
+ this.executionPhase = executionPhase === undefined ? undefined : migrationExecutionPhase(executionPhase)
29
32
  this.logger = new Logger(this)
30
33
  }
31
34
 
@@ -188,6 +191,7 @@ export default class VelociousDatabaseMigrator {
188
191
  if (!MigrationClass || typeof MigrationClass !== "function") {
189
192
  throw new Error(`Migration ${migration.file} must export a default migration class. Type: ${typeof MigrationClass}`)
190
193
  }
194
+ if (!migrationRunsInExecutionPhase(MigrationClass, this.executionPhase)) continue
191
195
  if (!(MigrationClass.getDatabaseIdentifiers() || ["default"]).includes(databaseIdentifier)) continue
192
196
 
193
197
  const migrationInstance = new MigrationClass({configuration: this.configuration, databaseIdentifier, db})
@@ -519,6 +523,7 @@ export default class VelociousDatabaseMigrator {
519
523
  if (!migrationClass || typeof migrationClass !== "function") {
520
524
  throw new Error(`Migration ${migration.file} must export a default migration class. Type: ${typeof migrationClass}`)
521
525
  }
526
+ if (direction == "up" && !migrationRunsInExecutionPhase(migrationClass, this.executionPhase)) return false
522
527
 
523
528
  const migrationDatabaseIdentifiers = migrationClass.getDatabaseIdentifiers() || ["default"]
524
529
 
@@ -1554,6 +1554,30 @@ class FrontendModelEventSubscription {
1554
1554
  return JSON.stringify(this.subscriptionParams())
1555
1555
  }
1556
1556
 
1557
+ /**
1558
+ * Runs register class callback.
1559
+ * @template {FrontendModelModelEventCallbackEntry | FrontendModelDestroyEventCallbackEntry} T
1560
+ * @param {Set<T>} callbacks - Callback set for the event type.
1561
+ * @param {T} entry - Callback entry.
1562
+ * @returns {Promise<() => void>} - Unsubscribe callback.
1563
+ */
1564
+ async registerClassCallback(callbacks, entry) {
1565
+ callbacks.add(entry)
1566
+
1567
+ try {
1568
+ await this.ensureSubscribed()
1569
+ } catch (error) {
1570
+ callbacks.delete(entry)
1571
+ this.maybeTeardown()
1572
+ throw error
1573
+ }
1574
+
1575
+ return () => {
1576
+ callbacks.delete(entry)
1577
+ this.maybeTeardown()
1578
+ }
1579
+ }
1580
+
1557
1581
  /**
1558
1582
  * Runs ensure subscribed.
1559
1583
  * @returns {Promise<void>} */
@@ -1599,14 +1623,6 @@ class FrontendModelEventSubscription {
1599
1623
  this.readyPromise = null
1600
1624
  this.subscriptionParamsKey = null
1601
1625
  this.instanceListeners.clear()
1602
-
1603
- const hasCallbacks = this.classCreateCallbacks.size > 0
1604
- || this.classUpdateCallbacks.size > 0
1605
- || this.classDestroyCallbacks.size > 0
1606
-
1607
- if (hasCallbacks && client.autoReconnect) {
1608
- void this.ensureSubscribed()
1609
- }
1610
1626
  }
1611
1627
  })
1612
1628
  await this.channelHandle.ready
@@ -3710,13 +3726,7 @@ export default class FrontendModelBase {
3710
3726
  const sub = ensureFrontendModelEventSubscription(this, frontendModelRequestContext())
3711
3727
  const entry = {callback, ...frontendModelEventOptionsPayload(this, options)}
3712
3728
 
3713
- sub.classCreateCallbacks.add(entry)
3714
- await sub.ensureSubscribed()
3715
-
3716
- return () => {
3717
- sub.classCreateCallbacks.delete(entry)
3718
- sub.maybeTeardown()
3719
- }
3729
+ return await sub.registerClassCallback(sub.classCreateCallbacks, entry)
3720
3730
  }
3721
3731
 
3722
3732
  /**
@@ -3730,13 +3740,7 @@ export default class FrontendModelBase {
3730
3740
  const sub = ensureFrontendModelEventSubscription(this, frontendModelRequestContext())
3731
3741
  const entry = {callback, ...frontendModelEventOptionsPayload(this, options)}
3732
3742
 
3733
- sub.classUpdateCallbacks.add(entry)
3734
- await sub.ensureSubscribed()
3735
-
3736
- return () => {
3737
- sub.classUpdateCallbacks.delete(entry)
3738
- sub.maybeTeardown()
3739
- }
3743
+ return await sub.registerClassCallback(sub.classUpdateCallbacks, entry)
3740
3744
  }
3741
3745
 
3742
3746
  /**
@@ -3752,13 +3756,7 @@ export default class FrontendModelBase {
3752
3756
  const sub = ensureFrontendModelEventSubscription(this, frontendModelRequestContext())
3753
3757
  const entry = {callback}
3754
3758
 
3755
- sub.classDestroyCallbacks.add(entry)
3756
- await sub.ensureSubscribed()
3757
-
3758
- return () => {
3759
- sub.classDestroyCallbacks.delete(entry)
3760
- sub.maybeTeardown()
3761
- }
3759
+ return await sub.registerClassCallback(sub.classDestroyCallbacks, entry)
3762
3760
  }
3763
3761
 
3764
3762
  /**
@@ -1,4 +1,4 @@
1
- export declare const MAX_LIFECYCLE_REQUEST_TIMEOUT_MS = 60000;
1
+ export declare const MAX_LIFECYCLE_REQUEST_TIMEOUT_MS = 120000;
2
2
  /** One-request acknowledged lifecycle client. */
3
3
  export default class BackgroundJobsLifecycleClient {
4
4
  generationId: string;
@@ -1 +1 @@
1
- {"version":3,"file":"lifecycle-client.d.ts","sourceRoot":"","sources":["../../../src/background-jobs/lifecycle-client.js"],"names":[],"mappings":"AAQA,eAAO,MAAM,gCAAgC,QAAQ,CAAA;AAErD,iDAAiD;AACjD,MAAM,CAAC,OAAO,OAAO,6BAA6B;IAezC,YAAY;IACZ,UAAU;IAIV,gBAAgB;IAnBvB;;;;;;;OAOG;IACH,YAAY,EAAC,aAAa,EAAE,YAAY,EAAE,UAAU,EAAE,gBAA6C,EAAC,EALjG;QAAoD,aAAa,EAAzD,OAAO,qBAAqB,EAAE,OAAO,CAC7C;QAAsB,YAAY,AAAlC,CACA,EADQ,MAAM,CACd;QAAsB,UAAU,AAAhC,CACA,EADQ,MAAM,CACd;QAAsB,gBAAgB,AAAtC,CACF,EADU,MAAM,CAChB;KACmG,EAcnG;IAED;;;OAGG;IACG,QAAQ,IAFD,OAAO,CAAC,OAAO,YAAY,EAAE,sCAAsC,CAAC,CAEtB;IAE3D;;;OAGG;IACG,MAAM,IAFC,OAAO,CAAC,OAAO,YAAY,EAAE,sCAAsC,CAAC,CAE1B;IAEvD;;;;OAIG;IACG,QAAQ,CAAC,MAAM,EAHV,UAAU,GAAG,QAGH,GAFR,OAAO,CAAC,OAAO,YAAY,EAAE,sCAAsC,CAAC,CAOhF;IAED;;;;;;OAMG;IACG,WAAW,CAAC,EAAC,MAAM,EAAE,MAAM,EAAC,EAJ/B;QAAoC,MAAM,EAAlC,UAAU,GAAG,QAAQ,CAC7B;QAA0B,MAAM,EAAxB,WAAW,CACnB;KAE+B,GAFrB,OAAO,CAAC,OAAO,YAAY,EAAE,sCAAsC,CAAC,CA4DhF;CACF"}
1
+ {"version":3,"file":"lifecycle-client.d.ts","sourceRoot":"","sources":["../../../src/background-jobs/lifecycle-client.js"],"names":[],"mappings":"AAQA,eAAO,MAAM,gCAAgC,SAAS,CAAA;AAEtD,iDAAiD;AACjD,MAAM,CAAC,OAAO,OAAO,6BAA6B;IAezC,YAAY;IACZ,UAAU;IAIV,gBAAgB;IAnBvB;;;;;;;OAOG;IACH,YAAY,EAAC,aAAa,EAAE,YAAY,EAAE,UAAU,EAAE,gBAA6C,EAAC,EALjG;QAAoD,aAAa,EAAzD,OAAO,qBAAqB,EAAE,OAAO,CAC7C;QAAsB,YAAY,AAAlC,CACA,EADQ,MAAM,CACd;QAAsB,UAAU,AAAhC,CACA,EADQ,MAAM,CACd;QAAsB,gBAAgB,AAAtC,CACF,EADU,MAAM,CAChB;KACmG,EAcnG;IAED;;;OAGG;IACG,QAAQ,IAFD,OAAO,CAAC,OAAO,YAAY,EAAE,sCAAsC,CAAC,CAEtB;IAE3D;;;OAGG;IACG,MAAM,IAFC,OAAO,CAAC,OAAO,YAAY,EAAE,sCAAsC,CAAC,CAE1B;IAEvD;;;;OAIG;IACG,QAAQ,CAAC,MAAM,EAHV,UAAU,GAAG,QAGH,GAFR,OAAO,CAAC,OAAO,YAAY,EAAE,sCAAsC,CAAC,CAOhF;IAED;;;;;;OAMG;IACG,WAAW,CAAC,EAAC,MAAM,EAAE,MAAM,EAAC,EAJ/B;QAAoC,MAAM,EAAlC,UAAU,GAAG,QAAQ,CAC7B;QAA0B,MAAM,EAAxB,WAAW,CACnB;KAE+B,GAFrB,OAAO,CAAC,OAAO,YAAY,EAAE,sCAAsC,CAAC,CA4DhF;CACF"}
@@ -4,7 +4,7 @@ import net from "node:net";
4
4
  import timeout from "awaitery/build/timeout.js";
5
5
  import JsonSocket from "./json-socket.js";
6
6
  const DEFAULT_REQUEST_TIMEOUT_MS = 10000;
7
- export const MAX_LIFECYCLE_REQUEST_TIMEOUT_MS = 60000;
7
+ export const MAX_LIFECYCLE_REQUEST_TIMEOUT_MS = 120000;
8
8
  /** One-request acknowledged lifecycle client. */
9
9
  export default class BackgroundJobsLifecycleClient {
10
10
  /**
@@ -123,4 +123,4 @@ export default class BackgroundJobsLifecycleClient {
123
123
  });
124
124
  }
125
125
  }
126
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibGlmZWN5Y2xlLWNsaWVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9iYWNrZ3JvdW5kLWpvYnMvbGlmZWN5Y2xlLWNsaWVudC5qcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxZQUFZO0FBRVosT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLGFBQWEsQ0FBQTtBQUN4QyxPQUFPLEdBQUcsTUFBTSxVQUFVLENBQUE7QUFDMUIsT0FBTyxPQUFPLE1BQU0sMkJBQTJCLENBQUE7QUFDL0MsT0FBTyxVQUFVLE1BQU0sa0JBQWtCLENBQUE7QUFFekMsTUFBTSwwQkFBMEIsR0FBRyxLQUFLLENBQUE7QUFDeEMsTUFBTSxDQUFDLE1BQU0sZ0NBQWdDLEdBQUcsS0FBSyxDQUFBO0FBRXJELGlEQUFpRDtBQUNqRCxNQUFNLENBQUMsT0FBTyxPQUFPLDZCQUE2QjtJQUNoRDs7Ozs7OztPQU9HO0lBQ0gsWUFBWSxFQUFDLGFBQWEsRUFBRSxZQUFZLEVBQUUsVUFBVSxFQUFFLGdCQUFnQixHQUFHLDBCQUEwQixFQUFDO1FBQ2xHLE1BQU0sZ0JBQWdCLEdBQUcsYUFBYSxDQUFDLHFDQUFxQyxDQUFDO1lBQzNFLFlBQVk7WUFDWixtQkFBbUIsRUFBRSxVQUFVO1lBQy9CLFVBQVUsRUFBRSwrQkFBK0I7U0FDNUMsQ0FBQyxDQUFBO1FBQ0YsSUFBSSxDQUFDLFlBQVksR0FBRyxnQkFBZ0IsQ0FBQyxZQUFZLENBQUE7UUFDakQsSUFBSSxDQUFDLFVBQVUsR0FBRyxnQkFBZ0IsQ0FBQyxtQkFBbUIsQ0FBQTtRQUN0RCxJQUFJLENBQUMsTUFBTSxDQUFDLFNBQVMsQ0FBQyxnQkFBZ0IsQ0FBQyxJQUFJLGdCQUFnQixHQUFHLENBQUMsSUFBSSxnQkFBZ0IsR0FBRyxnQ0FBZ0MsRUFBRSxDQUFDO1lBQ3ZILE1BQU0sSUFBSSxTQUFTLENBQUMscURBQXFELGdDQUFnQyxFQUFFLENBQUMsQ0FBQTtRQUM5RyxDQUFDO1FBQ0QsSUFBSSxDQUFDLGdC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Q0FBQyxLQUFLLEdBQUcsT0FBTyxDQUFDLEtBQUssQ0FBQyxLQUFLLENBQUE7b0JBQy9FLE1BQU0sQ0FBQyxFQUFFLEVBQUUsR0FBRyxFQUFFLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUE7b0JBQy9CLE9BQU07Z0JBQ1IsQ0FBQztnQkFDRCxJQUFJLE9BQU8sQ0FBQyxJQUFJLEtBQUssK0JBQStCLElBQUksT0FBTyxDQUFDLFlBQVksS0FBSyxJQUFJLENBQUMsWUFBWSxFQUFFLENBQUM7b0JBQ25HLE1BQU0sQ0FBQyxFQUFFLEVBQUUsR0FBRyxFQUFFLENBQUMsTUFBTSxDQUFDLElBQUksS0FBSyxDQUFDLG1EQUFtRCxDQUFDLENBQUMsQ0FBQyxDQUFBO29CQUN4RixPQUFNO2dCQUNSLENBQUM7Z0JBQ0QsTUFBTSxDQUFDLEVBQUUsRUFBRSxHQUFHLEVBQUUsQ0FBQyxPQUFPLENBQUMsT0FBTyxDQUFDLGNBQWMsQ0FBQyxDQUFDLENBQUE7WUFDbkQsQ0FBQyxDQUFDLENBQUE7WUFDRixNQUFNLENBQUMsSUFBSSxDQUFDLFNBQVMsRUFBRSxTQUFTLENBQUMsQ0FBQTtZQUNqQyxJQUFJLE1BQU0sQ0FBQyxPQUFPO2dCQUFFLE9BQU8sRUFBRSxDQUFBO1FBQy9CLENBQUMsQ0FBQyxDQUFBO0lBQ0osQ0FBQztDQUNGIiwic291cmNlc0NvbnRlbnQiOlsiLy8gQHRzLWNoZWNrXG5cbmltcG9ydCB7IHJhbmRvbVVVSUQgfSBmcm9tIFwibm9kZTpjcnlwdG9cIlxuaW1wb3J0IG5ldCBmcm9tIFwibm9kZTpuZXRcIlxuaW1wb3J0IHRpbWVvdXQgZnJvbSBcImF3YWl0ZXJ5L2J1aWxkL3RpbWVvdXQuanNcIlxuaW1wb3J0IEpzb25Tb2NrZXQgZnJvbSBcIi4vanNvbi1zb2NrZXQuanNcIlxuXG5jb25zdCBERUZBVUxUX1JFUVVFU1RfVElNRU9VVF9NUyA9IDEwMDAwXG5leHBvcnQgY29uc3QgTUFYX0xJRkVDWUNMRV9SRVFVRVNUX1RJTUVPVVRfTVMgPSA2MDAwMFxuXG4vKiogT25lLXJlcXVlc3QgYWNrbm93bGVkZ2VkIGxpZmVjeWNsZSBjbGllbnQuICovXG5leHBvcnQgZGVmYXVsdCBjbGFzcyBCYWNrZ3JvdW5kSm9ic0xpZmVjeWNsZUNsaWVudCB7XG4gIC8qKlxuICAgKiBDcmVhdGVzIGEgbGlmZWN5Y2xlIGNsaWVudC5cbiAgICogQHBhcmFtIHtvYmplY3R9IGFyZ3MgLSBDbGllbnQgb3B0aW9ucy5cbiAgICogQHBhcmFtIHtpbXBvcnQoXCIuLi9jb25maWd1cmF0aW9uLmpzXCIpLmRlZmF1bHR9IGFyZ3MuY29uZmlndXJhdGlvbiAtIENvbmZpZ3VyYXRpb24uXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBbYXJncy5nZW5lcmF0aW9uSWRdIC0gRXhwbGljaXQgZ2VuZXJhdGlvbiBpZGVudGl0eS5cbiAgICogQHBhcmFtIHtzdHJpbmd9IFthcmdzLnNvY2tldFBhdGhdIC0gRXhwbGljaXQgY29udHJvbCBzb2NrZXQgcGF0aC5cbiAgICogQHBhcmFtIHtudW1iZXJ9IFthcmdzLnJlcXVlc3RUaW1lb3V0TXNdIC0gUmVxdWVzdCBkZWFkbGluZSBiZWxvdyB0aGUgc3VwZXJ2aXNvciBob29rIHRpbWVvdXQgKGRlZmF1bHQ6IDEwMDAwKS5cbiAgICovXG4gIGNvbnN0cnVjdG9yKHtjb25maWd1cmF0aW9uLCBnZW5lcmF0aW9uSWQsIHNvY2tldFBhdGgsIHJlcXVlc3RUaW1lb3V0TXMgPSBERUZBVUxUX1JFUVVFU1RfVElNRU9VVF9NU30pIHtcbiAgICBjb25zdCBnZW5lcmF0aW9uQ29uZmlnID0gY29uZmlndXJhdGlvbi5yZXNvbHZlQmFja2dyb3VuZEpvYnNHZW5lcmF0aW9uQ29uZmlnKHtcbiAgICAgIGdlbmVyYXRpb25JZCxcbiAgICAgIGxpZmVjeWNsZVNvY2tldFBhdGg6IHNvY2tldFBhdGgsXG4gICAgICBzb3VyY2VOYW1lOiBcIkJhY2tncm91bmRKb2JzTGlmZWN5Y2xlQ2xpZW50XCJcbiAgICB9KVxuICAgIHRoaXMuZ2VuZXJhdGlvbklkID0gZ2VuZXJhdGlvbkNvbmZpZy5nZW5lcmF0aW9uSWRcbiAgICB0aGlzLnNvY2tldFBhdGggPSBnZW5lcmF0aW9uQ29uZmlnLmxpZmVjeWNsZVNvY2tldFBhdGhcbiAgICBpZiAoIU51bWJlci5pc0ludGVnZXIocmVxdWVzdFRpbWVvdXRNcykgfHwgcmVxdWVzdFRpbWVvdXRNcyA8IDEgfHwgcmVxdWVzdFRpbWVvdXRNcyA+IE1BWF9MSUZFQ1lDTEVfUkVRVUVTVF9USU1FT1VUX01TKSB7XG4gICAgICB0aHJvdyBuZXcgVHlwZUVycm9yKGByZXF1ZXN0VGltZW91dE1zIG11c3QgYmUgYW4gaW50ZWdlciBiZXR3ZWVuIDEgYW5kICR7TUFYX0xJRkVDWUNMRV9SRVFVRVNUX1RJTUVPVVRfTVN9YClcbiAgICB9XG4gICAgdGhpcy5yZXF1ZXN0VGltZW91dE1zID0gcmVxdWVzdFRpbWVvdXRNc1xuICAgIGlmICghdGhpcy5nZW5lcmF0aW9uSWQpIHRocm93IG5ldyBFcnJvcihcIkJhY2tncm91bmQgam9icyBsaWZlY3ljbGUgY2xpZW50IHJlcXVpcmVzIGdlbmVyYXRpb25JZFwiKVxuICAgIGlmICghdGhpcy5zb2NrZXRQYXRoKSB0aHJvdyBuZXcgRXJyb3IoXCJCYWNrZ3JvdW5kIGpvYnMgbGlmZWN5Y2xlIGNsaWVudCByZXF1aXJlcyBsaWZlY3ljbGVTb2NrZXRQYXRoXCIpXG4gIH1cblxuICAvKipcbiAgICogQWN0aXZhdGVzIHRoZSBnZW5lcmF0aW9uLlxuICAgKiBAcmV0dXJucyB7UHJvbWlzZTxpbXBvcnQoXCIuL3R5cGVzLmpzXCIpLkJhY2tncm91bmRKb2JzR2VuZXJhdGlvbkxpZmVjeWNsZVN0YXRlPn0gLSBSZXN1bHRpbmcgc3RhdGUuXG4gICAqL1xuICBhc3luYyBhY3RpdmF0ZSgpIHsgcmV0dXJuIGF3YWl0IHRoaXMuX3JlcXVlc3QoXCJhY3RpdmF0ZVwiKSB9XG5cbiAgLyoqXG4gICAqIFJldGlyZXMgdGhlIGdlbmVyYXRpb24uXG4gICAqIEByZXR1cm5zIHtQcm9taXNlPGltcG9ydChcIi4vdHlwZXMuanNcIikuQmFja2dyb3VuZEpvYnNHZW5lcmF0aW9uTGlmZWN5Y2xlU3RhdGU+fSAtIFJlc3VsdGluZyBzdGF0ZS5cbiAgICovXG4gIGFzeW5jIHJldGlyZSgpIHsgcmV0dXJuIGF3YWl0IHRoaXMuX3JlcXVlc3QoXCJyZXRpcmVcIikgfVxuXG4gIC8qKlxuICAgKiBTZW5kcyBleGFjdGx5IG9uZSBsaWZlY3ljbGUgcmVxdWVzdC5cbiAgICogQHBhcmFtIHtcImFjdGl2YXRlXCIgfCBcInJldGlyZVwifSBhY3Rpb24gLSBMaWZlY3ljbGUgYWN0aW9uLlxuICAgKiBAcmV0dXJucyB7UHJvbWlzZTxpbXBvcnQoXCIuL3R5cGVzLmpzXCIpLkJhY2tncm91bmRKb2JzR2VuZXJhdGlvbkxpZmVjeWNsZVN0YXRlPn0gLSBSZXN1bHRpbmcgc3RhdGUuXG4gICAqL1xuICBhc3luYyBfcmVxdWVzdChhY3Rpb24pIHtcbiAgICByZXR1cm4gYXdhaXQgdGltZW91dCh7XG4gICAgICBlcnJvck1lc3NhZ2U6IGBCYWNrZ3JvdW5kIGpvYnMgJHthY3Rpb259IHJlcXVlc3QgZm9yICR7dGhpcy5nZW5lcmF0aW9uSWR9IHRpbWVkIG91dCBhZnRlciAke3RoaXMucmVxdWVzdFRpbWVvdXRNc31tcyBhdCAke3RoaXMuc29ja2V0UGF0aH1gLFxuICAgICAgdGltZW91dDogdGhpcy5yZXF1ZXN0VGltZW91dE1zXG4gICAgfSwgYXN5bmMgKHtjb250cm9sfSkgPT4gYXdhaXQgdGhpcy5fcnVuUmVxdWVzdCh7YWN0aW9uLCBzaWduYWw6IGNvbnRyb2wuc2lnbmFsfSkpXG4gIH1cblxuICAvKipcbiAgICogU2VuZHMgdGhlIGxpZmVjeWNsZSByZXF1ZXN0IHVuZGVyIGl0cyBjYWxsZXItb3duZWQgZGVhZGxpbmUuXG4gICAqIEBwYXJhbSB7b2JqZWN0fSBhcmdzIC0gUmVxdWVzdCBkZXRhaWxzLlxuICAgKiBAcGFyYW0ge1wiYWN0aXZhdGVcIiB8IFwicmV0aXJlXCJ9IGFyZ3MuYWN0aW9uIC0gTGlmZWN5Y2xlIGFjdGlvbi5cbiAgICogQHBhcmFtIHtBYm9ydFNpZ25hbH0gYXJncy5zaWduYWwgLSBSZXF1ZXN0IGRlYWRsaW5lIHNpZ25hbC5cbiAgICogQHJldHVybnMge1Byb21pc2U8aW1wb3J0KFwiLi90eXBlcy5qc1wiKS5CYWNrZ3JvdW5kSm9ic0dlbmVyYXRpb25MaWZlY3ljbGVTdGF0ZT59IC0gUmVzdWx0aW5nIHN0YXRlLlxuICAgKi9cbiAgYXN5bmMgX3J1blJlcXVlc3Qoe2FjdGlvbiwgc2lnbmFsfSkge1xuICAgIGNvbnN0IHJlcXVlc3RJZCA9IHJhbmRvbVVVSUQoKVxuICAgIGNvbnN0IHNvY2tldCA9IG5ldC5jcmVhdGVDb25uZWN0aW9uKHRoaXMuc29ja2V0UGF0aClcbiAgICBjb25zdCBqc29uU29ja2V0ID0gbmV3IEpzb25Tb2NrZXQoc29ja2V0KVxuXG4gICAgcmV0dXJuIGF3YWl0IG5ldyBQcm9taXNlKChyZXNvbHZlLCByZWplY3QpID0+IHtcbiAgICAgIGxldCBmaW5pc2hlZCA9IGZhbHNlXG4gICAgICAvKipcbiAgICAgICAqIFNldHRsZXMgdGhlIHJlcXVlc3Qgb25jZS5cbiAgICAgICAqIEBwYXJhbSB7b2JqZWN0fSBvcHRpb25zIC0gVGVhcmRvd24gb3B0aW9ucy5cbiAgICAgICAqIEBwYXJhbSB7Ym9vbGVhbn0gW29wdGlvbnMuZGVzdHJveV0gLSBEZXN0cm95IGluc3RlYWQgb2YgY2xvc2luZy5cbiAgICAgICAqIEBwYXJhbSB7KCkgPT4gdm9pZH0gY2FsbGJhY2sgLSBTZXR0bGVtZW50IGNhbGxiYWNrLlxuICAgICAgICovXG4gICAgICBjb25zdCBmaW5pc2ggPSAoe2Rlc3Ryb3kgPSBmYWxzZX0sIGNhbGxiYWNrKSA9PiB7XG4gICAgICAgIGlmIChmaW5pc2hlZCkgcmV0dXJuXG4gICAgICAgIGZpbmlzaGVkID0gdHJ1ZVxuICAgICAgICBzaWduYWwucmVtb3ZlRXZlbnRMaXN0ZW5lcihcImFib3J0XCIsIG9uQWJvcnQpXG4gICAgICAgIHNvY2tldC5yZW1vdmVMaXN0ZW5lcihcImNvbm5lY3RcIiwgb25Db25uZWN0KVxuICAgICAgICBqc29uU29ja2V0LnJlbW92ZUFsbExpc3RlbmVycygpXG4gICAgICAgIGlmIChkZXN0cm95KSBqc29uU29ja2V0LmRlc3Ryb3koKVxuICAgICAgICBlbHNlIGpzb25Tb2NrZXQuY2xvc2UoKVxuICAgICAgICBjYWxsYmFjaygpXG4gICAgICB9XG5cbiAgICAgIGNvbnN0IG9uQWJvcnQgPSAoKSA9PiBmaW5pc2goe2Rlc3Ryb3k6IHRydWV9LCAoKSA9PiByZWplY3Qoc2lnbmFsLnJlYXNvbiBpbnN0YW5jZW9mIEVycm9yID8gc2lnbmFsLnJlYXNvbiA6IG5ldyBFcnJvcihcIkJhY2tncm91bmQgam9icyBsaWZlY3ljbGUgcmVxdWVzdCBhYm9ydGVkXCIpKSlcbiAgICAgIGNvbnN0IG9uQ29ubmVjdCA9ICgpID0+IHtcbiAgICAgICAganNvblNvY2tldC5zZW5kKHtcbiAgICAgICAgICB0eXBlOiBcImJhY2tncm91bmQtam9icy1saWZlY3ljbGVcIixcbiAgICAgICAgICBhY3Rpb24sXG4gICAgICAgICAgZ2VuZXJhdGlvbklkOiB0aGlzLmdlbmVyYXRpb25JZCxcbiAgICAgICAgICByZXF1ZXN0SWRcbiAgICAgICAgfSlcbiAgICAgIH1cblxuICAgICAgc2lnbmFsLmFkZEV2ZW50TGlzdGVuZXIoXCJhYm9ydFwiLCBvbkFib3J0KVxuICAgICAganNvblNvY2tldC5vbihcImVycm9yXCIsIChlcnJvcikgPT4gZmluaXNoKHt9LCAoKSA9PiByZWplY3QoZXJyb3IpKSlcbiAgICAgIGpzb25Tb2NrZXQub24oXCJjbG9zZVwiLCAoKSA9PiBmaW5pc2goe2Rlc3Ryb3k6IHRydWV9LCAoKSA9PiByZWplY3QobmV3IEVycm9yKFwiQmFja2dyb3VuZCBqb2JzIGxpZmVjeWNsZSBzb2NrZXQgY2xvc2VkIGJlZm9yZSBhY2tub3dsZWRnZW1lbnRcIikpKSlcbiAgICAgIGpzb25Tb2NrZXQub24oXCJtZXNzYWdlXCIsIChtZXNzYWdlKSA9PiB7XG4gICAgICAgIGlmIChtZXNzYWdlPy5yZXF1ZXN0SWQgIT09IHJlcXVlc3RJZCB8fCBtZXNzYWdlLmFjdGlvbiAhPT0gYWN0aW9uKSB7XG4gICAgICAgICAgZmluaXNoKHt9LCAoKSA9PiByZWplY3QobmV3IEVycm9yKFwiQmFja2dyb3VuZCBqb2JzIGxpZmVjeWNsZSByZXNwb25zZSBkaWQgbm90IG1hdGNoIGl0cyByZXF1ZXN0XCIpKSlcbiAgICAgICAgICByZXR1cm5cbiAgICAgICAgfVxuICAgICAgICBpZiAobWVzc2FnZS50eXBlID09PSBcImJhY2tncm91bmQtam9icy1saWZlY3ljbGUtZXJyb3JcIikge1xuICAgICAgICAgIGNvbnN0IGVycm9yID0gbmV3IEVycm9yKG1lc3NhZ2UuZXJyb3I/Lm1lc3NhZ2UgfHwgXCJCYWNrZ3JvdW5kIGpvYnMgbGlmZWN5Y2xlIHJlcXVlc3QgZmFpbGVkXCIpXG4gICAgICAgICAgaWYgKHR5cGVvZiBtZXNzYWdlLmVycm9yPy5uYW1lID09PSBcInN0cmluZ1wiKSBlcnJvci5uYW1lID0gbWVzc2FnZS5lcnJvci5uYW1lXG4gICAgICAgICAgaWYgKHR5cGVvZiBtZXNzYWdlLmVycm9yPy5zdGFjayA9PT0gXCJzdHJpbmdcIikgZXJyb3Iuc3RhY2sgPSBtZXNzYWdlLmVycm9yLnN0YWNrXG4gICAgICAgICAgZmluaXNoKHt9LCAoKSA9PiByZWplY3QoZXJyb3IpKVxuICAgICAgICAgIHJldHVyblxuICAgICAgICB9XG4gICAgICAgIGlmIChtZXNzYWdlLnR5cGUgIT09IFwiYmFja2dyb3VuZC1qb2JzLWxpZmVjeWNsZS1hY2tcIiB8fCBtZXNzYWdlLmdlbmVyYXRpb25JZCAhPT0gdGhpcy5nZW5lcmF0aW9uSWQpIHtcbiAgICAgICAgICBmaW5pc2goe30sICgpID0+IHJlamVjdChuZXcgRXJyb3IoXCJJbnZhbGlkIGJhY2tncm91bmQgam9icyBsaWZlY3ljbGUgYWNrbm93bGVkZ2VtZW50XCIpKSlcbiAgICAgICAgICByZXR1cm5cbiAgICAgICAgfVxuICAgICAgICBmaW5pc2goe30sICgpID0+IHJlc29sdmUobWVzc2FnZS5saWZlY3ljbGVTdGF0ZSkpXG4gICAgICB9KVxuICAgICAgc29ja2V0Lm9uY2UoXCJjb25uZWN0XCIsIG9uQ29ubmVjdClcbiAgICAgIGlmIChzaWduYWwuYWJvcnRlZCkgb25BYm9ydCgpXG4gICAgfSlcbiAgfVxufVxuIl19
126
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibGlmZWN5Y2xlLWNsaWVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9iYWNrZ3JvdW5kLWpvYnMvbGlmZWN5Y2xlLWNsaWVudC5qcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxZQUFZO0FBRVosT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLGFBQWEsQ0FBQTtBQUN4QyxPQUFPLEdBQUcsTUFBTSxVQUFVLENBQUE7QUFDMUIsT0FBTyxPQUFPLE1BQU0sMkJBQTJCLENBQUE7QUFDL0MsT0FBTyxVQUFVLE1BQU0sa0JBQWtCLENBQUE7QUFFekMsTUFBTSwwQkFBMEIsR0FBRyxLQUFLLENBQUE7QUFDeEMsTUFBTSxDQUFDLE1BQU0sZ0NBQWdDLEdBQUcsTUFBTSxDQUFBO0FBRXRELGlEQUFpRDtBQUNqRCxNQUFNLENBQUMsT0FBTyxPQUFPLDZCQUE2QjtJQUNoRDs7Ozs7OztPQU9HO0lBQ0gsWUFBWSxFQUFDLGFBQWEsRUFBRSxZQUFZLEVBQUUsVUFBVSxFQUFFLGdCQUFnQixHQUFHLDBCQUEwQixFQUFDO1FBQ2xHLE1BQU0sZ0JBQWdCLEdBQUcsYUFBYSxDQUFDLHFDQUFxQyxDQUFDO1lBQzNFLFlBQVk7WUFDWixtQkFBbUIsRUFBRSxVQUFVO1lBQy9CLFVBQVUsRUFBRSwrQkFBK0I7U0FDNUMsQ0FBQyxDQUFBO1FBQ0YsSUFBSSxDQUFDLFlBQVksR0FBRyxnQkFBZ0IsQ0FBQyxZQUFZLENBQUE7UUFDakQsSUFBSSxDQUFDLFVBQVUsR0FBRyxnQkFBZ0IsQ0FBQyxtQkFBbUIsQ0FBQTtRQUN0RCxJQUFJLENBQUMsTUFBTSxDQUFDLFNBQVMsQ0FBQyxnQkFBZ0IsQ0FBQyxJQUFJLGdCQUFnQixHQUFHLENBQUMsSUFBSSxnQkFBZ0IsR0FBRyxnQ0FBZ0MsRUFBRSxDQUFDO1lBQ3ZILE1BQU0sSUFBSSxTQUFTLENBQUMscURBQXFELGdDQUFnQyxFQUFFLENBQUMsQ0FBQTtRQUM5RyxDQUFDO1FBQ0QsSUFBSSxDQUFDLGdC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Q0FBQyxLQUFLLEdBQUcsT0FBTyxDQUFDLEtBQUssQ0FBQyxLQUFLLENBQUE7b0JBQy9FLE1BQU0sQ0FBQyxFQUFFLEVBQUUsR0FBRyxFQUFFLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUE7b0JBQy9CLE9BQU07Z0JBQ1IsQ0FBQztnQkFDRCxJQUFJLE9BQU8sQ0FBQyxJQUFJLEtBQUssK0JBQStCLElBQUksT0FBTyxDQUFDLFlBQVksS0FBSyxJQUFJLENBQUMsWUFBWSxFQUFFLENBQUM7b0JBQ25HLE1BQU0sQ0FBQyxFQUFFLEVBQUUsR0FBRyxFQUFFLENBQUMsTUFBTSxDQUFDLElBQUksS0FBSyxDQUFDLG1EQUFtRCxDQUFDLENBQUMsQ0FBQyxDQUFBO29CQUN4RixPQUFNO2dCQUNSLENBQUM7Z0JBQ0QsTUFBTSxDQUFDLEVBQUUsRUFBRSxHQUFHLEVBQUUsQ0FBQyxPQUFPLENBQUMsT0FBTyxDQUFDLGNBQWMsQ0FBQyxDQUFDLENBQUE7WUFDbkQsQ0FBQyxDQUFDLENBQUE7WUFDRixNQUFNLENBQUMsSUFBSSxDQUFDLFNBQVMsRUFBRSxTQUFTLENBQUMsQ0FBQTtZQUNqQyxJQUFJLE1BQU0sQ0FBQyxPQUFPO2dCQUFFLE9BQU8sRUFBRSxDQUFBO1FBQy9CLENBQUMsQ0FBQyxDQUFBO0lBQ0osQ0FBQztDQUNGIiwic291cmNlc0NvbnRlbnQiOlsiLy8gQHRzLWNoZWNrXG5cbmltcG9ydCB7IHJhbmRvbVVVSUQgfSBmcm9tIFwibm9kZTpjcnlwdG9cIlxuaW1wb3J0IG5ldCBmcm9tIFwibm9kZTpuZXRcIlxuaW1wb3J0IHRpbWVvdXQgZnJvbSBcImF3YWl0ZXJ5L2J1aWxkL3RpbWVvdXQuanNcIlxuaW1wb3J0IEpzb25Tb2NrZXQgZnJvbSBcIi4vanNvbi1zb2NrZXQuanNcIlxuXG5jb25zdCBERUZBVUxUX1JFUVVFU1RfVElNRU9VVF9NUyA9IDEwMDAwXG5leHBvcnQgY29uc3QgTUFYX0xJRkVDWUNMRV9SRVFVRVNUX1RJTUVPVVRfTVMgPSAxMjAwMDBcblxuLyoqIE9uZS1yZXF1ZXN0IGFja25vd2xlZGdlZCBsaWZlY3ljbGUgY2xpZW50LiAqL1xuZXhwb3J0IGRlZmF1bHQgY2xhc3MgQmFja2dyb3VuZEpvYnNMaWZlY3ljbGVDbGllbnQge1xuICAvKipcbiAgICogQ3JlYXRlcyBhIGxpZmVjeWNsZSBjbGllbnQuXG4gICAqIEBwYXJhbSB7b2JqZWN0fSBhcmdzIC0gQ2xpZW50IG9wdGlvbnMuXG4gICAqIEBwYXJhbSB7aW1wb3J0KFwiLi4vY29uZmlndXJhdGlvbi5qc1wiKS5kZWZhdWx0fSBhcmdzLmNvbmZpZ3VyYXRpb24gLSBDb25maWd1cmF0aW9uLlxuICAgKiBAcGFyYW0ge3N0cmluZ30gW2FyZ3MuZ2VuZXJhdGlvbklkXSAtIEV4cGxpY2l0IGdlbmVyYXRpb24gaWRlbnRpdHkuXG4gICAqIEBwYXJhbSB7c3RyaW5nfSBbYXJncy5zb2NrZXRQYXRoXSAtIEV4cGxpY2l0IGNvbnRyb2wgc29ja2V0IHBhdGguXG4gICAqIEBwYXJhbSB7bnVtYmVyfSBbYXJncy5yZXF1ZXN0VGltZW91dE1zXSAtIFJlcXVlc3QgZGVhZGxpbmUgYmVsb3cgdGhlIHN1cGVydmlzb3IgaG9vayB0aW1lb3V0IChkZWZhdWx0OiAxMDAwMCkuXG4gICAqL1xuICBjb25zdHJ1Y3Rvcih7Y29uZmlndXJhdGlvbiwgZ2VuZXJhdGlvbklkLCBzb2NrZXRQYXRoLCByZXF1ZXN0VGltZW91dE1zID0gREVGQVVMVF9SRVFVRVNUX1RJTUVPVVRfTVN9KSB7XG4gICAgY29uc3QgZ2VuZXJhdGlvbkNvbmZpZyA9IGNvbmZpZ3VyYXRpb24ucmVzb2x2ZUJhY2tncm91bmRKb2JzR2VuZXJhdGlvbkNvbmZpZyh7XG4gICAgICBnZW5lcmF0aW9uSWQsXG4gICAgICBsaWZlY3ljbGVTb2NrZXRQYXRoOiBzb2NrZXRQYXRoLFxuICAgICAgc291cmNlTmFtZTogXCJCYWNrZ3JvdW5kSm9ic0xpZmVjeWNsZUNsaWVudFwiXG4gICAgfSlcbiAgICB0aGlzLmdlbmVyYXRpb25JZCA9IGdlbmVyYXRpb25Db25maWcuZ2VuZXJhdGlvbklkXG4gICAgdGhpcy5zb2NrZXRQYXRoID0gZ2VuZXJhdGlvbkNvbmZpZy5saWZlY3ljbGVTb2NrZXRQYXRoXG4gICAgaWYgKCFOdW1iZXIuaXNJbnRlZ2VyKHJlcXVlc3RUaW1lb3V0TXMpIHx8IHJlcXVlc3RUaW1lb3V0TXMgPCAxIHx8IHJlcXVlc3RUaW1lb3V0TXMgPiBNQVhfTElGRUNZQ0xFX1JFUVVFU1RfVElNRU9VVF9NUykge1xuICAgICAgdGhyb3cgbmV3IFR5cGVFcnJvcihgcmVxdWVzdFRpbWVvdXRNcyBtdXN0IGJlIGFuIGludGVnZXIgYmV0d2VlbiAxIGFuZCAke01BWF9MSUZFQ1lDTEVfUkVRVUVTVF9USU1FT1VUX01TfWApXG4gICAgfVxuICAgIHRoaXMucmVxdWVzdFRpbWVvdXRNcyA9IHJlcXVlc3RUaW1lb3V0TXNcbiAgICBpZiAoIXRoaXMuZ2VuZXJhdGlvbklkKSB0aHJvdyBuZXcgRXJyb3IoXCJCYWNrZ3JvdW5kIGpvYnMgbGlmZWN5Y2xlIGNsaWVudCByZXF1aXJlcyBnZW5lcmF0aW9uSWRcIilcbiAgICBpZiAoIXRoaXMuc29ja2V0UGF0aCkgdGhyb3cgbmV3IEVycm9yKFwiQmFja2dyb3VuZCBqb2JzIGxpZmVjeWNsZSBjbGllbnQgcmVxdWlyZXMgbGlmZWN5Y2xlU29ja2V0UGF0aFwiKVxuICB9XG5cbiAgLyoqXG4gICAqIEFjdGl2YXRlcyB0aGUgZ2VuZXJhdGlvbi5cbiAgICogQHJldHVybnMge1Byb21pc2U8aW1wb3J0KFwiLi90eXBlcy5qc1wiKS5CYWNrZ3JvdW5kSm9ic0dlbmVyYXRpb25MaWZlY3ljbGVTdGF0ZT59IC0gUmVzdWx0aW5nIHN0YXRlLlxuICAgKi9cbiAgYXN5bmMgYWN0aXZhdGUoKSB7IHJldHVybiBhd2FpdCB0aGlzLl9yZXF1ZXN0KFwiYWN0aXZhdGVcIikgfVxuXG4gIC8qKlxuICAgKiBSZXRpcmVzIHRoZSBnZW5lcmF0aW9uLlxuICAgKiBAcmV0dXJucyB7UHJvbWlzZTxpbXBvcnQoXCIuL3R5cGVzLmpzXCIpLkJhY2tncm91bmRKb2JzR2VuZXJhdGlvbkxpZmVjeWNsZVN0YXRlPn0gLSBSZXN1bHRpbmcgc3RhdGUuXG4gICAqL1xuICBhc3luYyByZXRpcmUoKSB7IHJldHVybiBhd2FpdCB0aGlzLl9yZXF1ZXN0KFwicmV0aXJlXCIpIH1cblxuICAvKipcbiAgICogU2VuZHMgZXhhY3RseSBvbmUgbGlmZWN5Y2xlIHJlcXVlc3QuXG4gICAqIEBwYXJhbSB7XCJhY3RpdmF0ZVwiIHwgXCJyZXRpcmVcIn0gYWN0aW9uIC0gTGlmZWN5Y2xlIGFjdGlvbi5cbiAgICogQHJldHVybnMge1Byb21pc2U8aW1wb3J0KFwiLi90eXBlcy5qc1wiKS5CYWNrZ3JvdW5kSm9ic0dlbmVyYXRpb25MaWZlY3ljbGVTdGF0ZT59IC0gUmVzdWx0aW5nIHN0YXRlLlxuICAgKi9cbiAgYXN5bmMgX3JlcXVlc3QoYWN0aW9uKSB7XG4gICAgcmV0dXJuIGF3YWl0IHRpbWVvdXQoe1xuICAgICAgZXJyb3JNZXNzYWdlOiBgQmFja2dyb3VuZCBqb2JzICR7YWN0aW9ufSByZXF1ZXN0IGZvciAke3RoaXMuZ2VuZXJhdGlvbklkfSB0aW1lZCBvdXQgYWZ0ZXIgJHt0aGlzLnJlcXVlc3RUaW1lb3V0TXN9bXMgYXQgJHt0aGlzLnNvY2tldFBhdGh9YCxcbiAgICAgIHRpbWVvdXQ6IHRoaXMucmVxdWVzdFRpbWVvdXRNc1xuICAgIH0sIGFzeW5jICh7Y29udHJvbH0pID0+IGF3YWl0IHRoaXMuX3J1blJlcXVlc3Qoe2FjdGlvbiwgc2lnbmFsOiBjb250cm9sLnNpZ25hbH0pKVxuICB9XG5cbiAgLyoqXG4gICAqIFNlbmRzIHRoZSBsaWZlY3ljbGUgcmVxdWVzdCB1bmRlciBpdHMgY2FsbGVyLW93bmVkIGRlYWRsaW5lLlxuICAgKiBAcGFyYW0ge29iamVjdH0gYXJncyAtIFJlcXVlc3QgZGV0YWlscy5cbiAgICogQHBhcmFtIHtcImFjdGl2YXRlXCIgfCBcInJldGlyZVwifSBhcmdzLmFjdGlvbiAtIExpZmVjeWNsZSBhY3Rpb24uXG4gICAqIEBwYXJhbSB7QWJvcnRTaWduYWx9IGFyZ3Muc2lnbmFsIC0gUmVxdWVzdCBkZWFkbGluZSBzaWduYWwuXG4gICAqIEByZXR1cm5zIHtQcm9taXNlPGltcG9ydChcIi4vdHlwZXMuanNcIikuQmFja2dyb3VuZEpvYnNHZW5lcmF0aW9uTGlmZWN5Y2xlU3RhdGU+fSAtIFJlc3VsdGluZyBzdGF0ZS5cbiAgICovXG4gIGFzeW5jIF9ydW5SZXF1ZXN0KHthY3Rpb24sIHNpZ25hbH0pIHtcbiAgICBjb25zdCByZXF1ZXN0SWQgPSByYW5kb21VVUlEKClcbiAgICBjb25zdCBzb2NrZXQgPSBuZXQuY3JlYXRlQ29ubmVjdGlvbih0aGlzLnNvY2tldFBhdGgpXG4gICAgY29uc3QganNvblNvY2tldCA9IG5ldyBKc29uU29ja2V0KHNvY2tldClcblxuICAgIHJldHVybiBhd2FpdCBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XG4gICAgICBsZXQgZmluaXNoZWQgPSBmYWxzZVxuICAgICAgLyoqXG4gICAgICAgKiBTZXR0bGVzIHRoZSByZXF1ZXN0IG9uY2UuXG4gICAgICAgKiBAcGFyYW0ge29iamVjdH0gb3B0aW9ucyAtIFRlYXJkb3duIG9wdGlvbnMuXG4gICAgICAgKiBAcGFyYW0ge2Jvb2xlYW59IFtvcHRpb25zLmRlc3Ryb3ldIC0gRGVzdHJveSBpbnN0ZWFkIG9mIGNsb3NpbmcuXG4gICAgICAgKiBAcGFyYW0geygpID0+IHZvaWR9IGNhbGxiYWNrIC0gU2V0dGxlbWVudCBjYWxsYmFjay5cbiAgICAgICAqL1xuICAgICAgY29uc3QgZmluaXNoID0gKHtkZXN0cm95ID0gZmFsc2V9LCBjYWxsYmFjaykgPT4ge1xuICAgICAgICBpZiAoZmluaXNoZWQpIHJldHVyblxuICAgICAgICBmaW5pc2hlZCA9IHRydWVcbiAgICAgICAgc2lnbmFsLnJlbW92ZUV2ZW50TGlzdGVuZXIoXCJhYm9ydFwiLCBvbkFib3J0KVxuICAgICAgICBzb2NrZXQucmVtb3ZlTGlzdGVuZXIoXCJjb25uZWN0XCIsIG9uQ29ubmVjdClcbiAgICAgICAganNvblNvY2tldC5yZW1vdmVBbGxMaXN0ZW5lcnMoKVxuICAgICAgICBpZiAoZGVzdHJveSkganNvblNvY2tldC5kZXN0cm95KClcbiAgICAgICAgZWxzZSBqc29uU29ja2V0LmNsb3NlKClcbiAgICAgICAgY2FsbGJhY2soKVxuICAgICAgfVxuXG4gICAgICBjb25zdCBvbkFib3J0ID0gKCkgPT4gZmluaXNoKHtkZXN0cm95OiB0cnVlfSwgKCkgPT4gcmVqZWN0KHNpZ25hbC5yZWFzb24gaW5zdGFuY2VvZiBFcnJvciA/IHNpZ25hbC5yZWFzb24gOiBuZXcgRXJyb3IoXCJCYWNrZ3JvdW5kIGpvYnMgbGlmZWN5Y2xlIHJlcXVlc3QgYWJvcnRlZFwiKSkpXG4gICAgICBjb25zdCBvbkNvbm5lY3QgPSAoKSA9PiB7XG4gICAgICAgIGpzb25Tb2NrZXQuc2VuZCh7XG4gICAgICAgICAgdHlwZTogXCJiYWNrZ3JvdW5kLWpvYnMtbGlmZWN5Y2xlXCIsXG4gICAgICAgICAgYWN0aW9uLFxuICAgICAgICAgIGdlbmVyYXRpb25JZDogdGhpcy5nZW5lcmF0aW9uSWQsXG4gICAgICAgICAgcmVxdWVzdElkXG4gICAgICAgIH0pXG4gICAgICB9XG5cbiAgICAgIHNpZ25hbC5hZGRFdmVudExpc3RlbmVyKFwiYWJvcnRcIiwgb25BYm9ydClcbiAgICAgIGpzb25Tb2NrZXQub24oXCJlcnJvclwiLCAoZXJyb3IpID0+IGZpbmlzaCh7fSwgKCkgPT4gcmVqZWN0KGVycm9yKSkpXG4gICAgICBqc29uU29ja2V0Lm9uKFwiY2xvc2VcIiwgKCkgPT4gZmluaXNoKHtkZXN0cm95OiB0cnVlfSwgKCkgPT4gcmVqZWN0KG5ldyBFcnJvcihcIkJhY2tncm91bmQgam9icyBsaWZlY3ljbGUgc29ja2V0IGNsb3NlZCBiZWZvcmUgYWNrbm93bGVkZ2VtZW50XCIpKSkpXG4gICAgICBqc29uU29ja2V0Lm9uKFwibWVzc2FnZVwiLCAobWVzc2FnZSkgPT4ge1xuICAgICAgICBpZiAobWVzc2FnZT8ucmVxdWVzdElkICE9PSByZXF1ZXN0SWQgfHwgbWVzc2FnZS5hY3Rpb24gIT09IGFjdGlvbikge1xuICAgICAgICAgIGZpbmlzaCh7fSwgKCkgPT4gcmVqZWN0KG5ldyBFcnJvcihcIkJhY2tncm91bmQgam9icyBsaWZlY3ljbGUgcmVzcG9uc2UgZGlkIG5vdCBtYXRjaCBpdHMgcmVxdWVzdFwiKSkpXG4gICAgICAgICAgcmV0dXJuXG4gICAgICAgIH1cbiAgICAgICAgaWYgKG1lc3NhZ2UudHlwZSA9PT0gXCJiYWNrZ3JvdW5kLWpvYnMtbGlmZWN5Y2xlLWVycm9yXCIpIHtcbiAgICAgICAgICBjb25zdCBlcnJvciA9IG5ldyBFcnJvcihtZXNzYWdlLmVycm9yPy5tZXNzYWdlIHx8IFwiQmFja2dyb3VuZCBqb2JzIGxpZmVjeWNsZSByZXF1ZXN0IGZhaWxlZFwiKVxuICAgICAgICAgIGlmICh0eXBlb2YgbWVzc2FnZS5lcnJvcj8ubmFtZSA9PT0gXCJzdHJpbmdcIikgZXJyb3IubmFtZSA9IG1lc3NhZ2UuZXJyb3IubmFtZVxuICAgICAgICAgIGlmICh0eXBlb2YgbWVzc2FnZS5lcnJvcj8uc3RhY2sgPT09IFwic3RyaW5nXCIpIGVycm9yLnN0YWNrID0gbWVzc2FnZS5lcnJvci5zdGFja1xuICAgICAgICAgIGZpbmlzaCh7fSwgKCkgPT4gcmVqZWN0KGVycm9yKSlcbiAgICAgICAgICByZXR1cm5cbiAgICAgICAgfVxuICAgICAgICBpZiAobWVzc2FnZS50eXBlICE9PSBcImJhY2tncm91bmQtam9icy1saWZlY3ljbGUtYWNrXCIgfHwgbWVzc2FnZS5nZW5lcmF0aW9uSWQgIT09IHRoaXMuZ2VuZXJhdGlvbklkKSB7XG4gICAgICAgICAgZmluaXNoKHt9LCAoKSA9PiByZWplY3QobmV3IEVycm9yKFwiSW52YWxpZCBiYWNrZ3JvdW5kIGpvYnMgbGlmZWN5Y2xlIGFja25vd2xlZGdlbWVudFwiKSkpXG4gICAgICAgICAgcmV0dXJuXG4gICAgICAgIH1cbiAgICAgICAgZmluaXNoKHt9LCAoKSA9PiByZXNvbHZlKG1lc3NhZ2UubGlmZWN5Y2xlU3RhdGUpKVxuICAgICAgfSlcbiAgICAgIHNvY2tldC5vbmNlKFwiY29ubmVjdFwiLCBvbkNvbm5lY3QpXG4gICAgICBpZiAoc2lnbmFsLmFib3J0ZWQpIG9uQWJvcnQoKVxuICAgIH0pXG4gIH1cbn1cbiJdfQ==