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.
- package/README.md +37 -3
- package/build/background-jobs/lifecycle-client.js +1 -1
- package/build/background-jobs/lifecycle-control-server.js +1 -1
- package/build/background-jobs/main.js +9 -3
- package/build/cli/commands/db/migrate.js +3 -1
- package/build/cli/commands/db/tenants/migrate.js +4 -1
- package/build/cli/commands/db/tenants/migrations/pending.js +4 -1
- package/build/cli/index.js +1 -1
- package/build/cli/migration-execution-phase-argument.js +20 -0
- package/build/database/migration/index.js +21 -0
- package/build/database/migration-execution-phase.js +34 -0
- package/build/database/migrator.js +6 -1
- package/build/frontend-models/base.js +27 -29
- package/build/src/background-jobs/lifecycle-client.d.ts +1 -1
- package/build/src/background-jobs/lifecycle-client.d.ts.map +1 -1
- package/build/src/background-jobs/lifecycle-client.js +2 -2
- package/build/src/background-jobs/lifecycle-control-server.js +2 -2
- package/build/src/background-jobs/main.d.ts.map +1 -1
- package/build/src/background-jobs/main.js +11 -4
- package/build/src/cli/commands/db/migrate.d.ts.map +1 -1
- package/build/src/cli/commands/db/migrate.js +4 -2
- package/build/src/cli/commands/db/tenants/migrate.d.ts.map +1 -1
- package/build/src/cli/commands/db/tenants/migrate.js +5 -2
- package/build/src/cli/commands/db/tenants/migrations/pending.d.ts.map +1 -1
- package/build/src/cli/commands/db/tenants/migrations/pending.js +5 -2
- package/build/src/cli/index.js +2 -2
- package/build/src/cli/migration-execution-phase-argument.d.ts +7 -0
- package/build/src/cli/migration-execution-phase-argument.d.ts.map +1 -0
- package/build/src/cli/migration-execution-phase-argument.js +17 -0
- package/build/src/database/migration/index.d.ts +13 -0
- package/build/src/database/migration/index.d.ts.map +1 -1
- package/build/src/database/migration/index.js +19 -1
- package/build/src/database/migration-execution-phase.d.ts +18 -0
- package/build/src/database/migration-execution-phase.d.ts.map +1 -0
- package/build/src/database/migration-execution-phase.js +30 -0
- package/build/src/database/migrator.d.ts +4 -1
- package/build/src/database/migrator.d.ts.map +1 -1
- package/build/src/database/migrator.js +9 -2
- package/build/src/frontend-models/base.d.ts.map +1 -1
- package/build/src/frontend-models/base.js +26 -25
- package/build/tsconfig.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/src/background-jobs/lifecycle-client.js +1 -1
- package/src/background-jobs/lifecycle-control-server.js +1 -1
- package/src/background-jobs/main.js +9 -3
- package/src/cli/commands/db/migrate.js +3 -1
- package/src/cli/commands/db/tenants/migrate.js +4 -1
- package/src/cli/commands/db/tenants/migrations/pending.js +4 -1
- package/src/cli/index.js +1 -1
- package/src/cli/migration-execution-phase-argument.js +20 -0
- package/src/database/migration/index.js +21 -0
- package/src/database/migration-execution-phase.js +34 -0
- package/src/database/migrator.js +6 -1
- 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
|
-
|
|
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 =
|
|
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
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
}
|
package/build/cli/index.js
CHANGED
|
@@ -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
|
|
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
|
|
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
|
|
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 +1 @@
|
|
|
1
|
-
{"version":3,"file":"lifecycle-client.d.ts","sourceRoot":"","sources":["../../../src/background-jobs/lifecycle-client.js"],"names":[],"mappings":"AAQA,eAAO,MAAM,gCAAgC,
|
|
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 =
|
|
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==
|